diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 13b787ef..427a27f7 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -6,7 +6,7 @@ on: - main jobs: test: - timeout-minutes: 10 + timeout-minutes: 90 runs-on: ubuntu-latest strategy: matrix: @@ -23,10 +23,10 @@ jobs: - name: Get Playwright version id: playwright-version - run: echo "PLAYWRIGHT_VERSION=$(jq -r .dependencies.playwright package.json)" >> "$GITHUB_OUTPUT" + run: echo "PLAYWRIGHT_VERSION=$(jq -r '.devDependencies["@playwright/test"]' package.json)" >> "$GITHUB_OUTPUT" - name: Install dependencies - run: pnpm install + run: pnpm install --ignore-scripts - name: Build app run: pnpm build @@ -40,8 +40,41 @@ jobs: ${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.PLAYWRIGHT_VERSION }}- ${{ runner.os }}-playwright- - - name: Install Playwright Browsers - run: pnpm exec playwright install --with-deps + # --with-deps bundles an apt-get run for the full browser dependency + # set; the ubuntu archive is intermittently very slow, so it gets its + # own step with a generous timeout, retries, and an apt-cache entry so + # a one-time successful run seeds later ones + - name: Restore apt cache for Playwright dependencies + uses: actions/cache@v3 + with: + path: ~/apt-playwright-cache + key: ${{ runner.os }}-apt-${{ steps.playwright-version.outputs.PLAYWRIGHT_VERSION }} + + - name: Install Playwright system dependencies + timeout-minutes: 45 + run: | + for attempt in 1 2 3 4 5; do + if timeout 1500 ./node_modules/.bin/playwright install-deps; then + exit 0 + fi + echo "playwright install-deps attempt $attempt failed (attempt timeout 25 min), retrying in 20s" + sleep 20 + done + exit 1 + + - name: Install Playwright browsers + timeout-minutes: 10 + env: + PLAYWRIGHT_DOWNLOAD_CONNECTION_TIMEOUT: 60000 + run: | + for attempt in 1 2 3; do + if ./node_modules/.bin/playwright install; then + exit 0 + fi + echo "playwright install attempt $attempt failed, retrying in 15s" + sleep 15 + done + exit 1 - name: Run Playwright tests run: pnpm run test:e2e --shard=${{ matrix.shard }} diff --git a/package.json b/package.json index 5738b632..cda06f3f 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "@antfu/eslint-config": "^0.41.0", "@iconify-json/mdi": "^1.1.50", "@intlify/unplugin-vue-i18n": "^2.0.0", - "@playwright/test": "^1.32.3", + "@playwright/test": "^1.62.1", "@rushstack/eslint-patch": "^1.2.0", "@tsconfig/node18": "^18.2.0", "@types/bcryptjs": "^2.4.2", @@ -149,5 +149,10 @@ "vitest": "^0.34.0", "workbox-window": "^7.0.0", "zx": "^7.2.1" + }, + "pnpm": { + "overrides": { + "@vueuse/shared": "10.3.0" + } } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5d113893..b74d3b61 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,9 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + '@vueuse/shared': 10.3.0 + importers: .: @@ -49,7 +52,7 @@ importers: version: 10.3.0(vue@3.3.4) '@vueuse/head': specifier: ^1.0.0 - version: 1.0.0(typescript@5.2.2)(vue@3.3.4) + version: 1.0.0(vue@3.3.4) '@vueuse/router': specifier: ^10.0.0 version: 10.0.0(vue-router@4.1.6(vue@3.3.4))(vue@3.3.4) @@ -220,8 +223,8 @@ importers: specifier: ^2.0.0 version: 2.0.0(rollup@2.79.2)(vue-i18n@9.9.1(vue@3.3.4)) '@playwright/test': - specifier: ^1.32.3 - version: 1.32.3 + specifier: ^1.62.1 + version: 1.63.0 '@rushstack/eslint-patch': specifier: ^1.2.0 version: 1.2.0 @@ -332,7 +335,7 @@ importers: version: 4.0.0 vitest: specifier: ^0.34.0 - version: 0.34.0(jsdom@22.0.0)(less@4.1.3)(terser@5.37.0) + version: 0.34.0(jsdom@22.0.0)(less@4.1.3)(playwright@1.63.0)(terser@5.37.0) workbox-window: specifier: ^7.0.0 version: 7.0.0 @@ -356,17 +359,20 @@ packages: '@antfu/eslint-config-basic@0.41.0': resolution: {integrity: sha512-zcwFv+nEV/NroeeVWriNdnIGd9soOLRG8wIiVz4VVJ0BjONrqQR56HLG/gDxH/1GUYBnQCEcVxGUmegce08cnw==} + deprecated: Deprecated, please migrate to @antfu/eslint-config with the flat config peerDependencies: eslint: '>=7.4.0' '@antfu/eslint-config-ts@0.41.0': resolution: {integrity: sha512-ng3GYpJGZgrxGwBVda/MgUpveH3LbEqdPCFi1+S5e62W4kf8rmEVbhc0I8w7/aKN0uNqir5SInYg8gob2maDAQ==} + deprecated: Deprecated, please migrate to @antfu/eslint-config with the flat config peerDependencies: eslint: '>=7.4.0' typescript: '>=3.9' '@antfu/eslint-config-vue@0.41.0': resolution: {integrity: sha512-iJiEGRUgRmT3mQCmGl0hTMwq/ShXRjRPjpgsDcphKJyEF06ZIR/4gxHn+utQRLT2hD39DQN8gk0ZbpV3gWtf/g==} + deprecated: Deprecated, please migrate to @antfu/eslint-config with the flat config peerDependencies: eslint: '>=7.4.0' @@ -1464,6 +1470,7 @@ packages: '@humanwhocodes/config-array@0.11.10': resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} @@ -1471,6 +1478,7 @@ packages: '@humanwhocodes/object-schema@1.2.1': resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + deprecated: Use @eslint/object-schema instead '@iconify-json/mdi@1.1.50': resolution: {integrity: sha512-SgbT5w5eHCdOG74ZWPz7HlTGk6VsifIJhNi6lAsxj/5Nlqt6Cz4LlQmSa9eecU9p075Jub2aAx/o7YI+GCahRQ==} @@ -1626,9 +1634,9 @@ packages: resolution: {integrity: sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@playwright/test@1.32.3': - resolution: {integrity: sha512-BvWNvK0RfBriindxhLVabi8BRe3X0J9EVjKlcmhxjg4giWBD/xleLcg2dz7Tx0agu28rczjNIPQWznwzDwVsZQ==} - engines: {node: '>=14'} + '@playwright/test@1.63.0': + resolution: {integrity: sha512-oxMK4vllB9RK5NQ2l1pq1IfOf2AvnEuj/vYGDj0H2nMtmtZpKtCwt/l00GEO6xjGfpBNAvjovvYdCm50dRQkpQ==} + engines: {node: '>=20'} hasBin: true '@polka/url@1.0.0-next.28': @@ -2303,9 +2311,6 @@ packages: '@vue/compiler-core@3.3.7': resolution: {integrity: sha512-pACdY6YnTNVLXsB86YD8OF9ihwpolzhhtdLVHhBL6do/ykr6kKXNYABRtNMGrsQXpEXXyAdwvWWkuTbs4MFtPQ==} - '@vue/compiler-core@3.5.13': - resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==} - '@vue/compiler-dom@3.2.47': resolution: {integrity: sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==} @@ -2315,18 +2320,12 @@ packages: '@vue/compiler-dom@3.3.7': resolution: {integrity: sha512-0LwkyJjnUPssXv/d1vNJ0PKfBlDoQs7n81CbO6Q0zdL7H1EzqYRrTVXDqdBVqro0aJjo/FOa1qBAPVI4PGSHBw==} - '@vue/compiler-dom@3.5.13': - resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} - '@vue/compiler-sfc@3.2.47': resolution: {integrity: sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==} '@vue/compiler-sfc@3.3.4': resolution: {integrity: sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==} - '@vue/compiler-sfc@3.5.13': - resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==} - '@vue/compiler-ssr@3.2.47': resolution: {integrity: sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==} @@ -2336,9 +2335,6 @@ packages: '@vue/compiler-ssr@3.3.7': resolution: {integrity: sha512-TxOfNVVeH3zgBc82kcUv+emNHo+vKnlRrkv8YvQU5+Y5LJGJwSNzcmLUoxD/dNzv0bhQ/F0s+InlgV0NrApJZg==} - '@vue/compiler-ssr@3.5.13': - resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==} - '@vue/devtools-api@6.5.0': resolution: {integrity: sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==} @@ -2359,21 +2355,12 @@ packages: '@vue/reactivity@3.3.4': resolution: {integrity: sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==} - '@vue/reactivity@3.5.13': - resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==} - '@vue/runtime-core@3.3.4': resolution: {integrity: sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA==} - '@vue/runtime-core@3.5.13': - resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==} - '@vue/runtime-dom@3.3.4': resolution: {integrity: sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ==} - '@vue/runtime-dom@3.5.13': - resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==} - '@vue/server-renderer@3.3.4': resolution: {integrity: sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ==} peerDependencies: @@ -2384,11 +2371,6 @@ packages: peerDependencies: vue: 3.3.7 - '@vue/server-renderer@3.5.13': - resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==} - peerDependencies: - vue: 3.5.13 - '@vue/shared@3.2.47': resolution: {integrity: sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==} @@ -2398,9 +2380,6 @@ packages: '@vue/shared@3.3.7': resolution: {integrity: sha512-N/tbkINRUDExgcPTBvxNkvHGu504k8lzlNQRITVnm6YjOjwa4r0nnbd4Jb01sNpur5hAllyRJzSK5PvB9PPwRg==} - '@vue/shared@3.5.13': - resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} - '@vue/test-utils@2.3.2': resolution: {integrity: sha512-hJnVaYhbrIm0yBS0+e1Y0Sj85cMyAi+PAbK4JHqMRUZ6S622Goa+G7QzkRSyvCteG8wop7tipuEbHoZo26wsSA==} peerDependencies: @@ -2428,20 +2407,15 @@ packages: peerDependencies: vue-router: '>=4.0.0-rc.1' - '@vueuse/shared@10.0.0': - resolution: {integrity: sha512-Zh3LgJqvUBWVY3SiMvXanTcfAneGbt63QPczBRDNgQ6jd/ehodO9a1lCFzaA6SWJJoI+ugVTjHFYJdoR656DVQ==} - '@vueuse/shared@10.3.0': resolution: {integrity: sha512-kGqCTEuFPMK4+fNWy6dUOiYmxGcUbtznMwBZLC1PubidF4VZY05B+Oht7Jh7/6x4VOWGpvu3R37WHi81cKpiqg==} - '@vueuse/shared@12.0.0': - resolution: {integrity: sha512-3i6qtcq2PIio5i/vVYidkkcgvmTjCqrf26u+Fd4LhnbBmIT6FN8y6q/GJERp8lfcB9zVEfjdV0Br0443qZuJpw==} - '@zhead/schema@1.0.0-beta.13': resolution: {integrity: sha512-P1A1vRGFBhITco8Iw4/hvnDYoE/SoVrd71dW1pBFdXJb3vP+pBtoOuhbEKy0ROJGOyzQuqvFibcwzyLlWMqNiQ==} abab@2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} + deprecated: Use your platform's native atob() and btoa() methods instead abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} @@ -2552,6 +2526,7 @@ packages: babel-merge@3.0.0: resolution: {integrity: sha512-eBOBtHnzt9xvnjpYNI5HmaPp/b2vMveE5XggzqHnQeHJ8mFIBrBv6WZEVIj5jJ2uwTItkqKo9gWzEEcBxEq0yw==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. peerDependencies: '@babel/core': ^7.0.0 @@ -2798,7 +2773,7 @@ packages: hasBin: true concat-map@0.0.1: - resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} @@ -2850,6 +2825,7 @@ packages: crypto-js@4.1.1: resolution: {integrity: sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==} + deprecated: Active development of CryptoJS has been discontinued. This library is no longer maintained. crypto-random-string@2.0.0: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} @@ -2896,9 +2872,6 @@ packages: csstype@3.1.2: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - dash-get@1.0.2: resolution: {integrity: sha512-4FbVrHDwfOASx7uQVxeiCTo7ggSdYZbqs8lH+WU6ViypPlDbe9y6IP5VVUDQBv9DcnyaiPT5XT0UWHgJ64zLeQ==} @@ -3054,6 +3027,7 @@ packages: domexception@4.0.0: resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} engines: {node: '>=12'} + deprecated: Use your platform's native DOMException instead domhandler@5.0.3: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} @@ -3246,6 +3220,7 @@ packages: eslint-plugin-i@2.28.0-2: resolution: {integrity: sha512-z48kG4qmE4TmiLcxbmvxMT5ycwvPkXaWW0XpU1L768uZaTbiDbxsHMEdV24JHlOR1xDsPpKW39BfP/pRdYIwFA==} engines: {node: '>=12'} + deprecated: Please migrate to the brand new `eslint-plugin-import-x` instead peerDependencies: eslint: ^7.2.0 || ^8 @@ -3271,6 +3246,7 @@ packages: eslint-plugin-markdown@3.0.1: resolution: {integrity: sha512-8rqoc148DWdGdmYF6WSQFT3uQ6PO7zXYgeBpHAOAakX/zpq+NvFYbDA/H7PYzHajwtmaOzAwfxyl++x0g1/N9A==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: Please use @eslint/markdown instead peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -3337,6 +3313,7 @@ packages: eslint@8.47.0: resolution: {integrity: sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true espree@9.6.1: @@ -3499,11 +3476,6 @@ packages: fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -3566,10 +3538,12 @@ packages: glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me glob@8.1.0: resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} engines: {node: '>=12'} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} @@ -3758,6 +3732,7 @@ packages: inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -4172,6 +4147,7 @@ packages: loupe@2.3.6: resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==} + deprecated: Please upgrade to 2.3.7 which fixes GHSA-4q6p-r6v2-jvc5 lower-case-first@1.0.2: resolution: {integrity: sha512-UuxaYakO7XeONbKrZf5FEgkantPf5DUqDayzP5VXZrtRPdH86s4kN47I8B3TW10S4QKiE3ziHNf3kRN//okHjA==} @@ -4380,6 +4356,7 @@ packages: node-domexception@1.0.0: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead node-fetch-native@1.6.4: resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==} @@ -4610,10 +4587,16 @@ packages: plausible-tracker@0.3.8: resolution: {integrity: sha512-lmOWYQ7s9KOUJ1R+YTOR3HrjdbxIS2Z4de0P/Jx2dQPteznJl2eX3tXxKClpvbfyGP59B5bbhW8ftN59HbbFSg==} engines: {node: '>=10'} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - playwright-core@1.32.3: - resolution: {integrity: sha512-SB+cdrnu74ZIn5Ogh/8278ngEh9NEEV0vR4sJFmK04h2iZpybfbqBY0bX6+BLYWVdV12JLLI+JEFtSnYgR+mWg==} - engines: {node: '>=14'} + playwright-core@1.63.0: + resolution: {integrity: sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==} + engines: {node: '>=20'} + hasBin: true + + playwright@1.63.0: + resolution: {integrity: sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==} + engines: {node: '>=20'} hasBin: true pluralize@8.0.0: @@ -4868,10 +4851,6 @@ packages: resolution: {integrity: sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==} hasBin: true - resolve@1.22.8: - resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} - hasBin: true - resolve@1.22.9: resolution: {integrity: sha512-QxrmX1DzraFIi9PxdG5VkRfRwIgjwyud+z/iBwfRRrVmHc+P9Q7u2lSSpQ6bjr2gy5lrqIiU9vb6iAeGf2400A==} hasBin: true @@ -4894,6 +4873,7 @@ packages: rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rollup@2.79.2: @@ -5071,9 +5051,11 @@ packages: source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} + deprecated: The work that was done in this beta branch won't be included in future versions sourcemap-codec@1.4.8: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} + deprecated: Please use @jridgewell/sourcemap-codec instead spdx-correct@3.2.0: resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} @@ -5544,6 +5526,7 @@ packages: uuid@9.0.0: resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true validate-npm-package-license@3.0.4: @@ -5569,6 +5552,7 @@ packages: vite-plugin-vue-markdown@0.23.5: resolution: {integrity: sha512-NXTZ4y+n691gLPWayMBbh4jldQeaqDp9e9WjWUYbn9obsLqS9qU+hr4RAruDq5kP4siTOp7JDV34Sw5eA7WxLg==} + deprecated: '`vite-plugin-vue-markdown` is renamed to `unplugin-vue-markdown`. For usages in Vite, you also need to change the import path to `unplugin-vue-markdown/vite`.' peerDependencies: vite: ^2.0.0 || ^3.0.0-0 || ^4.0.0 @@ -5675,6 +5659,7 @@ packages: vue-i18n@9.9.1: resolution: {integrity: sha512-xyQ4VspLdNSPTKBFBPWa1tvtj+9HuockZwgFeD2OhxxXuC2CWeNvV4seu2o9+vbQOyQbhAM5Ez56oxUrrnTWdw==} engines: {node: '>= 16'} + deprecated: v9 and v10 no longer supported. please migrate to v11. about maintenance status, see https://vue-i18n.intlify.dev/guide/maintenance.html peerDependencies: vue: ^3.0.0 @@ -5701,14 +5686,6 @@ packages: vue@3.3.4: resolution: {integrity: sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==} - vue@3.5.13: - resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - vuedraggable@4.1.0: resolution: {integrity: sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==} peerDependencies: @@ -5754,6 +5731,7 @@ packages: whatwg-encoding@2.0.0: resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} engines: {node: '>=12'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation whatwg-mimetype@3.0.0: resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} @@ -6117,7 +6095,7 @@ snapshots: '@babel/traverse': 7.23.2 '@babel/types': 7.23.0 convert-source-map: 2.0.0 - debug: 4.3.4 + debug: 4.4.0 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -7030,7 +7008,7 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 '@babel/parser': 7.23.0 '@babel/types': 7.23.0 - debug: 4.3.4 + debug: 4.4.0 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -7401,7 +7379,7 @@ snapshots: '@linaria/logger@4.0.0': dependencies: - debug: 4.3.4 + debug: 4.4.0 picocolors: 1.0.0 transitivePeerDependencies: - supports-color @@ -7462,12 +7440,9 @@ snapshots: tiny-glob: 0.2.9 tslib: 2.5.0 - '@playwright/test@1.32.3': + '@playwright/test@1.63.0': dependencies: - '@types/node': 18.15.11 - playwright-core: 1.32.3 - optionalDependencies: - fsevents: 2.3.2 + playwright: 1.63.0 '@polka/url@1.0.0-next.28': {} @@ -7922,7 +7897,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 6.4.1(typescript@5.2.2) '@typescript-eslint/utils': 6.4.1(eslint@8.47.0)(typescript@5.2.2) - debug: 4.3.4 + debug: 4.4.0 eslint: 8.47.0 ts-api-utils: 1.0.1(typescript@5.2.2) optionalDependencies: @@ -7940,10 +7915,10 @@ snapshots: dependencies: '@typescript-eslint/types': 5.60.0 '@typescript-eslint/visitor-keys': 5.60.0 - debug: 4.3.4 + debug: 4.4.0 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.5.4 + semver: 7.6.3 tsutils: 3.21.0(typescript@5.2.2) optionalDependencies: typescript: 5.2.2 @@ -7954,10 +7929,10 @@ snapshots: dependencies: '@typescript-eslint/types': 6.4.1 '@typescript-eslint/visitor-keys': 6.4.1 - debug: 4.3.4 + debug: 4.4.0 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.5.4 + semver: 7.6.3 ts-api-utils: 1.0.1(typescript@5.2.2) optionalDependencies: typescript: 5.2.2 @@ -7968,10 +7943,10 @@ snapshots: dependencies: '@typescript-eslint/types': 6.9.1 '@typescript-eslint/visitor-keys': 6.9.1 - debug: 4.3.4 + debug: 4.4.0 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.5.4 + semver: 7.6.3 ts-api-utils: 1.0.1(typescript@5.2.2) optionalDependencies: typescript: 5.2.2 @@ -7988,7 +7963,7 @@ snapshots: '@typescript-eslint/typescript-estree': 5.60.0(typescript@5.2.2) eslint: 8.47.0 eslint-scope: 5.1.1 - semver: 7.5.4 + semver: 7.6.3 transitivePeerDependencies: - supports-color - typescript @@ -8002,7 +7977,7 @@ snapshots: '@typescript-eslint/types': 6.4.1 '@typescript-eslint/typescript-estree': 6.4.1(typescript@5.2.2) eslint: 8.47.0 - semver: 7.5.4 + semver: 7.6.3 transitivePeerDependencies: - supports-color - typescript @@ -8049,15 +8024,15 @@ snapshots: dependencies: '@unhead/schema': 0.5.1 - '@unhead/vue@0.5.1(typescript@5.2.2)(vue@3.3.4)': + '@unhead/vue@0.5.1(vue@3.3.4)': dependencies: '@unhead/dom': 0.5.1 '@unhead/schema': 0.5.1 - '@vueuse/shared': 12.0.0(typescript@5.2.2) + '@vueuse/shared': 10.3.0(vue@3.3.4) unhead: 0.5.1 vue: 3.3.4 transitivePeerDependencies: - - typescript + - '@vue/composition-api' '@unocss/astro@0.65.1(rollup@2.79.2)(vite@4.4.9(@types/node@18.15.11)(less@4.1.3)(terser@5.37.0))(vue@3.3.4)': dependencies: @@ -8341,14 +8316,6 @@ snapshots: source-map-js: 1.0.2 optional: true - '@vue/compiler-core@3.5.13': - dependencies: - '@babel/parser': 7.26.3 - '@vue/shared': 3.5.13 - entities: 4.5.0 - estree-walker: 2.0.2 - source-map-js: 1.2.1 - '@vue/compiler-dom@3.2.47': dependencies: '@vue/compiler-core': 3.2.47 @@ -8365,11 +8332,6 @@ snapshots: '@vue/shared': 3.3.7 optional: true - '@vue/compiler-dom@3.5.13': - dependencies: - '@vue/compiler-core': 3.5.13 - '@vue/shared': 3.5.13 - '@vue/compiler-sfc@3.2.47': dependencies: '@babel/parser': 7.21.4 @@ -8396,18 +8358,6 @@ snapshots: postcss: 8.4.28 source-map-js: 1.0.2 - '@vue/compiler-sfc@3.5.13': - dependencies: - '@babel/parser': 7.26.3 - '@vue/compiler-core': 3.5.13 - '@vue/compiler-dom': 3.5.13 - '@vue/compiler-ssr': 3.5.13 - '@vue/shared': 3.5.13 - estree-walker: 2.0.2 - magic-string: 0.30.15 - postcss: 8.4.49 - source-map-js: 1.2.1 - '@vue/compiler-ssr@3.2.47': dependencies: '@vue/compiler-dom': 3.2.47 @@ -8424,11 +8374,6 @@ snapshots: '@vue/shared': 3.3.7 optional: true - '@vue/compiler-ssr@3.5.13': - dependencies: - '@vue/compiler-dom': 3.5.13 - '@vue/shared': 3.5.13 - '@vue/devtools-api@6.5.0': {} '@vue/language-core@1.8.1(typescript@5.2.2)': @@ -8464,33 +8409,17 @@ snapshots: dependencies: '@vue/shared': 3.3.4 - '@vue/reactivity@3.5.13': - dependencies: - '@vue/shared': 3.5.13 - '@vue/runtime-core@3.3.4': dependencies: '@vue/reactivity': 3.3.4 '@vue/shared': 3.3.4 - '@vue/runtime-core@3.5.13': - dependencies: - '@vue/reactivity': 3.5.13 - '@vue/shared': 3.5.13 - '@vue/runtime-dom@3.3.4': dependencies: '@vue/runtime-core': 3.3.4 '@vue/shared': 3.3.4 csstype: 3.1.2 - '@vue/runtime-dom@3.5.13': - dependencies: - '@vue/reactivity': 3.5.13 - '@vue/runtime-core': 3.5.13 - '@vue/shared': 3.5.13 - csstype: 3.1.3 - '@vue/server-renderer@3.3.4(vue@3.3.4)': dependencies: '@vue/compiler-ssr': 3.3.4 @@ -8504,12 +8433,6 @@ snapshots: vue: 3.3.4 optional: true - '@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.2.2))': - dependencies: - '@vue/compiler-ssr': 3.5.13 - '@vue/shared': 3.5.13 - vue: 3.5.13(typescript@5.2.2) - '@vue/shared@3.2.47': {} '@vue/shared@3.3.4': {} @@ -8517,8 +8440,6 @@ snapshots: '@vue/shared@3.3.7': optional: true - '@vue/shared@3.5.13': {} - '@vue/test-utils@2.3.2(vue@3.3.4)': dependencies: js-beautify: 1.14.6 @@ -8546,33 +8467,26 @@ snapshots: - '@vue/composition-api' - vue - '@vueuse/head@1.0.0(typescript@5.2.2)(vue@3.3.4)': + '@vueuse/head@1.0.0(vue@3.3.4)': dependencies: '@unhead/schema': 0.5.1 '@unhead/ssr': 0.5.1 - '@unhead/vue': 0.5.1(typescript@5.2.2)(vue@3.3.4) + '@unhead/vue': 0.5.1(vue@3.3.4) vue: 3.3.4 transitivePeerDependencies: - - typescript + - '@vue/composition-api' '@vueuse/metadata@10.3.0': {} '@vueuse/router@10.0.0(vue-router@4.1.6(vue@3.3.4))(vue@3.3.4)': dependencies: - '@vueuse/shared': 10.0.0(vue@3.3.4) + '@vueuse/shared': 10.3.0(vue@3.3.4) vue-demi: 0.14.5(vue@3.3.4) vue-router: 4.1.6(vue@3.3.4) transitivePeerDependencies: - '@vue/composition-api' - vue - '@vueuse/shared@10.0.0(vue@3.3.4)': - dependencies: - vue-demi: 0.14.5(vue@3.3.4) - transitivePeerDependencies: - - '@vue/composition-api' - - vue - '@vueuse/shared@10.3.0(vue@3.3.4)': dependencies: vue-demi: 0.14.5(vue@3.3.4) @@ -8580,12 +8494,6 @@ snapshots: - '@vue/composition-api' - vue - '@vueuse/shared@12.0.0(typescript@5.2.2)': - dependencies: - vue: 3.5.13(typescript@5.2.2) - transitivePeerDependencies: - - typescript - '@zhead/schema@1.0.0-beta.13': {} abab@2.0.6: {} @@ -8780,7 +8688,7 @@ snapshots: builtins@5.0.1: dependencies: - semver: 7.5.4 + semver: 7.6.3 bundle-require@5.0.0(esbuild@0.23.1): dependencies: @@ -9084,8 +8992,6 @@ snapshots: csstype@3.1.2: {} - csstype@3.1.3: {} - dash-get@1.0.2: {} data-uri-to-buffer@4.0.1: {} @@ -9817,9 +9723,6 @@ snapshots: fs.realpath@1.0.0: {} - fsevents@2.3.2: - optional: true - fsevents@2.3.3: optional: true @@ -10753,7 +10656,7 @@ snapshots: normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.8 + resolve: 1.22.9 semver: 5.7.2 validate-npm-package-license: 3.0.4 @@ -10972,7 +10875,11 @@ snapshots: plausible-tracker@0.3.8: {} - playwright-core@1.32.3: {} + playwright-core@1.63.0: {} + + playwright@1.63.0: + dependencies: + playwright-core: 1.63.0 pluralize@8.0.0: {} @@ -11271,12 +11178,6 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - resolve@1.22.8: - dependencies: - is-core-module: 2.13.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - resolve@1.22.9: dependencies: is-core-module: 2.16.0 @@ -12073,7 +11974,7 @@ snapshots: less: 4.1.3 terser: 5.37.0 - vitest@0.34.0(jsdom@22.0.0)(less@4.1.3)(terser@5.37.0): + vitest@0.34.0(jsdom@22.0.0)(less@4.1.3)(playwright@1.63.0)(terser@5.37.0): dependencies: '@types/chai': 4.3.5 '@types/chai-subset': 1.3.3 @@ -12101,6 +12002,7 @@ snapshots: why-is-node-running: 2.2.2 optionalDependencies: jsdom: 22.0.0 + playwright: 1.63.0 transitivePeerDependencies: - less - lightningcss @@ -12125,14 +12027,14 @@ snapshots: vue-eslint-parser@9.3.1(eslint@8.47.0): dependencies: - debug: 4.3.4 + debug: 4.4.0 eslint: 8.47.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 esquery: 1.5.0 lodash: 4.17.21 - semver: 7.5.4 + semver: 7.6.3 transitivePeerDependencies: - supports-color @@ -12180,16 +12082,6 @@ snapshots: '@vue/server-renderer': 3.3.4(vue@3.3.4) '@vue/shared': 3.3.4 - vue@3.5.13(typescript@5.2.2): - dependencies: - '@vue/compiler-dom': 3.5.13 - '@vue/compiler-sfc': 3.5.13 - '@vue/runtime-dom': 3.5.13 - '@vue/server-renderer': 3.5.13(vue@3.5.13(typescript@5.2.2)) - '@vue/shared': 3.5.13 - optionalDependencies: - typescript: 5.2.2 - vuedraggable@4.1.0(vue@3.3.4): dependencies: sortablejs: 1.14.0 diff --git a/src/tools/index.ts b/src/tools/index.ts index 388cfaf4..84836e31 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -36,6 +36,7 @@ import { tool as httpStatusCodes } from './http-status-codes'; import { tool as yamlToJson } from './yaml-to-json-converter'; import { tool as jsonToYaml } from './json-to-yaml-converter'; import { tool as ipv6UlaGenerator } from './ipv6-ula-generator'; +import { tool as ipv6SubnetCalculator } from './ipv6-subnet-calculator'; import { tool as ipv4AddressConverter } from './ipv4-address-converter'; import { tool as benchmarkBuilder } from './benchmark-builder'; import { tool as userAgentParser } from './user-agent-parser'; @@ -164,7 +165,7 @@ export const toolsByCategory: ToolCategory[] = [ }, { name: 'Network', - components: [ipv4SubnetCalculator, ipv4AddressConverter, ipv4RangeExpander, macAddressLookup, macAddressGenerator, ipv6UlaGenerator], + components: [ipv4SubnetCalculator, ipv6SubnetCalculator, ipv4AddressConverter, ipv4RangeExpander, macAddressLookup, macAddressGenerator, ipv6UlaGenerator], }, { name: 'Math', diff --git a/src/tools/ipv6-subnet-calculator/index.ts b/src/tools/ipv6-subnet-calculator/index.ts new file mode 100644 index 00000000..a44352d8 --- /dev/null +++ b/src/tools/ipv6-subnet-calculator/index.ts @@ -0,0 +1,12 @@ +import { Api } from '@vicons/tabler'; +import { defineTool } from '../tool'; + +export const tool = defineTool({ + name: 'IPv6 subnet calculator', + path: '/ipv6-subnet-calculator', + description: 'Expand, compress and dissect IPv6 addresses: network bounds, address count, netmask and address type', + keywords: ['ipv6', 'subnet', 'cidr', 'calculator', 'network', 'address', 'prefix'], + component: () => import('./ipv6-subnet-calculator.vue'), + icon: Api, + createdAt: new Date('2026-10-01'), +}); diff --git a/src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.differential.test.ts b/src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.differential.test.ts new file mode 100644 index 00000000..2d6fcf11 --- /dev/null +++ b/src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.differential.test.ts @@ -0,0 +1,39 @@ +// Differential test: the IPv6 calculator must agree with Python's `ipaddress` +// stdlib on 124 random + hand-picked cases (fixture generated by CPython). +import { readFileSync } from 'node:fs'; +import { describe, expect, it } from 'vitest'; +import { describeIpv6 } from './ipv6-subnet-calculator.models'; + +interface FixtureCase { + input: string + expanded: string + compressed: string + network: string + first: string + last: string + total: string + netmask: string +} + +const cases: FixtureCase[] = JSON.parse( + readFileSync(new URL('./ipv6.fixture.json', import.meta.url), 'utf8'), +); + +// Python's ipaddress uses lowercase hex for IPv6 str(); my implementation is +// lowercase per RFC 5952 §4.3 recommendation. Normalize for comparison. +const lower = (s: string) => s.toLowerCase(); + +describe('ipv6-subnet-calculator: differential vs CPython ipaddress', () => { + it.each(cases.map(c => [c.input, c]))('case %s', (_input, c) => { + const info = describeIpv6(c.input); + expect(lower(info.expanded)).toBe(lower(c.expanded)); + // compression: compare the network VALUE (Python may pick a different + // zero-run on ties; the address itself must match) plus the prefix + expect(lower(info.network.split('/')[0])).toBe(lower(c.network.split('/')[0])); + expect(info.network.endsWith(`/${c.network.split('/')[1]}`)).toBe(true); + expect(lower(info.firstAddress)).toBe(lower(c.first)); + expect(lower(info.lastAddress)).toBe(lower(c.last)); + expect(info.totalAddresses).toBe(c.total); + expect(lower(info.mask)).toBe(lower(c.netmask)); + }); +}); diff --git a/src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.models.test.ts b/src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.models.test.ts new file mode 100644 index 00000000..79a611fe --- /dev/null +++ b/src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.models.test.ts @@ -0,0 +1,73 @@ +import { describe, expect, it } from 'vitest'; +import { compressIpv6, describeIpv6, expandIpv6 } from './ipv6-subnet-calculator.models'; + +describe('ipv6-subnet-calculator: expansion', () => { + it('expands compressed forms', () => { + expect(expandIpv6('2001:db8::1')).toBe('2001:0db8:0000:0000:0000:0000:0000:0001'); + expect(expandIpv6('::1')).toBe('0000:0000:0000:0000:0000:0000:0000:0001'); + expect(expandIpv6('::')).toBe('0000:0000:0000:0000:0000:0000:0000:0000'); + expect(expandIpv6('fe80::1%eth0')).toBe('fe80:0000:0000:0000:0000:0000:0000:0001'); + }); + + it('passes already-expanded addresses through', () => { + expect(expandIpv6('2001:0DB8:0:0:0:0:0:1')).toBe('2001:0db8:0000:0000:0000:0000:0000:0001'); + }); + + it('rejects malformed addresses', () => { + expect(() => expandIpv6('2001::db8::1')).toThrow('Invalid IPv6'); + expect(() => expandIpv6('12345::')).toThrow('Invalid IPv6'); + expect(() => expandIpv6('2001:db8:0:0:0:0:0')).toThrow('Invalid IPv6'); + }); +}); + +describe('ipv6-subnet-calculator: compression', () => { + it('compresses the longest zero run once', () => { + expect(compressIpv6('2001:0db8:0000:0000:0000:0000:0000:0001')).toBe('2001:db8::1'); + expect(compressIpv6('0000:0000:0000:0000:0000:0000:0000:0001')).toBe('::1'); + // leftmost of two equal runs + // the trailing 4-zero run is the longest, so it is compressed + expect(compressIpv6('0000:0000:0001:0002:0000:0000:0000:0000')).toBe('0:0:1:2::'); + // a single zero group is not compressed + expect(compressIpv6('2001:0db8:0000:000a:000b:000c:000d:000e')).toBe('2001:db8:0:a:b:c:d:e'); + }); +}); + +describe('ipv6-subnet-calculator: subnet math', () => { + it('computes network bounds for a /48', () => { + const info = describeIpv6('2001:db8:1234:5678::1/48'); + expect(info.network).toBe('2001:db8:1234::/48'); + expect(info.firstAddress).toBe('2001:db8:1234::'); + expect(info.lastAddress).toBe('2001:db8:1234:ffff:ffff:ffff:ffff:ffff'); + expect(info.totalAddresses).toBe((2n ** 80n).toString()); + expect(info.mask).toBe('ffff:ffff:ffff::'); + }); + + it('handles the host address itself at /128', () => { + const info = describeIpv6('::1/128'); + expect(info.network).toBe('::1/128'); + expect(info.firstAddress).toBe('::1'); + expect(info.lastAddress).toBe('::1'); + expect(info.totalAddresses).toBe('1'); + }); + + it('handles the whole space at /0', () => { + const info = describeIpv6('2001:db8::1/0'); + expect(info.network).toBe('::/0'); + expect(info.firstAddress).toBe('::'); + expect(info.lastAddress).toBe('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'); + expect(info.totalAddresses).toBe((2n ** 128n).toString()); + }); + + it('classifies common address types', () => { + expect(describeIpv6('2001:db8::1/64').type).toContain('Documentation'); + expect(describeIpv6('fe80::1/64').type).toContain('Link-local'); + expect(describeIpv6('::1/128').type).toBe('Loopback'); + expect(describeIpv6('ff02::1/64').type).toContain('Multicast'); + expect(describeIpv6('fd00::1/64').type).toContain('Unique local'); + }); + + it('rejects invalid prefixes', () => { + expect(() => describeIpv6('2001:db8::1/129')).toThrow('Invalid prefix'); + expect(() => describeIpv6('2001:db8::1/-1')).toThrow('Invalid prefix'); + }); +}); diff --git a/src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.models.ts b/src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.models.ts new file mode 100644 index 00000000..b29f9d4f --- /dev/null +++ b/src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.models.ts @@ -0,0 +1,161 @@ +export interface Ipv6Info { + /** Fully expanded lowercase form, e.g. 2001:0db8:0000:...:0000. */ + expanded: string + /** RFC 5952 compressed form, e.g. 2001:db8::1. */ + compressed: string + /** `prefix` as typed, normalized. */ + network: string + prefix: number + type: string + scope: string + totalAddresses: string + firstAddress: string + lastAddress: string + mask: string +} + +const IPV6_HEX_RE = /^[0-9a-fA-F]{1,4}$/; + +/** Expand an address (without prefix) to the full 39-char lowercase form. */ +export function expandIpv6(address: string): string { + let value = address.trim().toLowerCase(); + if (value.includes('%')) { + value = value.slice(0, value.indexOf('%')); // drop zone id + } + + const parts = value.split('::'); + if (parts.length > 2) { + throw new Error(`Invalid IPv6 address: ${address}`); + } + + const head = parts[0] === '' ? [] : parts[0]!.split(':'); + const tail = parts.length === 2 ? (parts[1] === '' ? [] : parts[1]!.split(':')) : []; + const missing = 8 - head.length - tail.length; + if (parts.length === 1 && head.length !== 8) { + throw new Error(`Invalid IPv6 address: ${address}`); + } + if (missing < 0) { + throw new Error(`Invalid IPv6 address: ${address}`); + } + const groups = [...head, ...Array.from({ length: parts.length === 2 ? missing : 0 }, () => '0'), ...tail]; + if (groups.length !== 8 || !groups.every(group => IPV6_HEX_RE.test(group))) { + throw new Error(`Invalid IPv6 address: ${address}`); + } + return groups.map(group => group.padStart(4, '0')).join(':'); +} + +/** RFC 5952 compression: longest :: run, leftmost on tie, drop leading zeros. */ +export function compressIpv6(expanded: string): string { + const groups = expanded.split(':'); + const best = { start: -1, length: 0 }; + let currentStart = -1; + let currentLength = 0; + groups.forEach((group, index) => { + if (group === '0000') { + if (currentStart === -1) { + currentStart = index; + } + currentLength++; + if (currentLength > best.length) { + best.start = currentStart; + best.length = currentLength; + } + } + else { + currentStart = -1; + currentLength = 0; + } + }); + + const trimmed = groups.map(group => group.replace(/^0+(?=.)/, '')); + if (best.length < 2) { + return trimmed.join(':'); + } + const head = trimmed.slice(0, best.start).join(':'); + const tail = trimmed.slice(best.start + best.length).join(':'); + return `${head}::${tail}`; +} + +function ipv6ToBigInt(expanded: string): bigint { + return BigInt(`0x${expanded.replace(/:/g, '')}`); +} + +function bigIntToIpv6(value: bigint): string { + const hex = value.toString(16).padStart(32, '0'); + return (hex.match(/.{4}/g) ?? []).join(':'); +} + +function parseIpv6Cidr(input: string): { address: string; prefix: number } { + const trimmed = input.trim(); + const [address, prefixRaw] = trimmed.split('/'); + const prefix = prefixRaw === undefined ? 128 : Number(prefixRaw); + if (!Number.isInteger(prefix) || prefix < 0 || prefix > 128) { + throw new Error(`Invalid prefix length: ${prefixRaw ?? ''}`); + } + return { address: expandIpv6(address ?? ''), prefix }; +} + +function describeType(expanded: string): { type: string; scope: string } { + const value = ipv6ToBigInt(expanded); + const first16 = Number(value >> 112n); + + if (value === 0n) { + return { type: 'Unspecified', scope: 'this host' }; + } + if (value === 1n) { + return { type: 'Loopback', scope: 'this host' }; + } + if (first16 === 0xFE80) { + return { type: 'Link-local unicast (fe80::/10)', scope: 'link' }; + } + if (first16 >= 0xFC00 && first16 <= 0xFDFF) { + return { type: 'Unique local (ULA, fc00::/7)', scope: 'organization' }; + } + if (first16 === 0xFFFF) { + return { type: 'Multicast', scope: 'well-known' }; + } + if (first16 >= 0xFF00 && first16 <= 0xFFFF) { + return { type: 'Multicast (ff00::/8)', scope: 'assigned' }; + } + if (first16 === 0x2002) { + return { type: '6to4 (2002::/16)', scope: 'global' }; + } + if (value >> 96n === 0x20010DB8n) { + return { type: 'Documentation (2001:db8::/32)', scope: 'global' }; + } + if (first16 >= 0x2000 && first16 <= 0x3FFF) { + return { type: 'Global unicast (2000::/3)', scope: 'global' }; + } + return { type: 'Reserved or other', scope: 'n/a' }; +} + +export function describeIpv6(cidr: string): Ipv6Info { + const { address, prefix } = parseIpv6Cidr(cidr); + const addressValue = ipv6ToBigInt(address); + + const hostBits = 128 - prefix; + const networkValue = prefix === 0 ? 0n : (addressValue >> BigInt(hostBits)) << BigInt(hostBits); + const total = 1n << BigInt(hostBits); + const firstValue = networkValue; + const lastValue = networkValue + total - 1n; + + // Top `prefix` bits set. (2^p - 1) << (128 - p) is exact for every p in + // 0..128 — the old special case for hostBits === 0 was inverted and + // produced an all-zero netmask for /128 (#differential fixture). + const maskValue = ((1n << BigInt(prefix)) - 1n) << BigInt(128 - prefix); + + const { type, scope } = describeType(address); + + return { + expanded: address, + compressed: compressIpv6(address), + network: `${compressIpv6(bigIntToIpv6(networkValue))}/${prefix}`, + prefix, + type, + scope, + totalAddresses: total.toString(), + firstAddress: compressIpv6(bigIntToIpv6(firstValue)), + lastAddress: compressIpv6(bigIntToIpv6(lastValue)), + mask: compressIpv6(bigIntToIpv6(maskValue)), + }; +} diff --git a/src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.vue b/src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.vue new file mode 100644 index 00000000..12ad9803 --- /dev/null +++ b/src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/src/tools/ipv6-subnet-calculator/ipv6.fixture.json b/src/tools/ipv6-subnet-calculator/ipv6.fixture.json new file mode 100644 index 00000000..0bba7744 --- /dev/null +++ b/src/tools/ipv6-subnet-calculator/ipv6.fixture.json @@ -0,0 +1,1242 @@ +[ + { + "input": "9417:7dc:8770:f0b6:d75d:f7ee:5c1f:aa9f/64", + "expanded": "9417:07dc:8770:f0b6:d75d:f7ee:5c1f:aa9f", + "compressed": "9417:7dc:8770:f0b6::", + "network": "9417:7dc:8770:f0b6::/64", + "first": "9417:7dc:8770:f0b6::", + "last": "9417:7dc:8770:f0b6:ffff:ffff:ffff:ffff", + "total": "18446744073709551616", + "netmask": "ffff:ffff:ffff:ffff::" + }, + { + "input": "d2ed:d018:cbf9:952f:e408:726b:6455:1fdf/128", + "expanded": "d2ed:d018:cbf9:952f:e408:726b:6455:1fdf", + "compressed": "d2ed:d018:cbf9:952f:e408:726b:6455:1fdf", + "network": "d2ed:d018:cbf9:952f:e408:726b:6455:1fdf/128", + "first": "d2ed:d018:cbf9:952f:e408:726b:6455:1fdf", + "last": "d2ed:d018:cbf9:952f:e408:726b:6455:1fdf", + "total": "1", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + }, + { + "input": "bbb0:d683:c286:c20e:302f:ae0:2661:ddfe/127", + "expanded": "bbb0:d683:c286:c20e:302f:0ae0:2661:ddfe", + "compressed": "bbb0:d683:c286:c20e:302f:ae0:2661:ddfe", + "network": "bbb0:d683:c286:c20e:302f:ae0:2661:ddfe/127", + "first": "bbb0:d683:c286:c20e:302f:ae0:2661:ddfe", + "last": "bbb0:d683:c286:c20e:302f:ae0:2661:ddff", + "total": "2", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe" + }, + { + "input": "2fcb:5832:e466:e705:98a:4df0:22e3:f570/128", + "expanded": "2fcb:5832:e466:e705:098a:4df0:22e3:f570", + "compressed": "2fcb:5832:e466:e705:98a:4df0:22e3:f570", + "network": "2fcb:5832:e466:e705:98a:4df0:22e3:f570/128", + "first": "2fcb:5832:e466:e705:98a:4df0:22e3:f570", + "last": "2fcb:5832:e466:e705:98a:4df0:22e3:f570", + "total": "1", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + }, + { + "input": "9091:3a1f:3106:4483:572d:2d7e:36bf:7fec/96", + "expanded": "9091:3a1f:3106:4483:572d:2d7e:36bf:7fec", + "compressed": "9091:3a1f:3106:4483:572d:2d7e::", + "network": "9091:3a1f:3106:4483:572d:2d7e::/96", + "first": "9091:3a1f:3106:4483:572d:2d7e::", + "last": "9091:3a1f:3106:4483:572d:2d7e:ffff:ffff", + "total": "4294967296", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff::" + }, + { + "input": "ce0b:d65b:6406:d27d:d0c9:5e2c:411b:ff12/48", + "expanded": "ce0b:d65b:6406:d27d:d0c9:5e2c:411b:ff12", + "compressed": "ce0b:d65b:6406::", + "network": "ce0b:d65b:6406::/48", + "first": "ce0b:d65b:6406::", + "last": "ce0b:d65b:6406:ffff:ffff:ffff:ffff:ffff", + "total": "1208925819614629174706176", + "netmask": "ffff:ffff:ffff::" + }, + { + "input": "3b22:e7de:dc4b:cc23:697:b18c:5006:e38/32", + "expanded": "3b22:e7de:dc4b:cc23:0697:b18c:5006:0e38", + "compressed": "3b22:e7de::", + "network": "3b22:e7de::/32", + "first": "3b22:e7de::", + "last": "3b22:e7de:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "79228162514264337593543950336", + "netmask": "ffff:ffff::" + }, + { + "input": "7ad9:3428:4356:2f72:bf9b:4438:3f98:f1bb/120", + "expanded": "7ad9:3428:4356:2f72:bf9b:4438:3f98:f1bb", + "compressed": "7ad9:3428:4356:2f72:bf9b:4438:3f98:f100", + "network": "7ad9:3428:4356:2f72:bf9b:4438:3f98:f100/120", + "first": "7ad9:3428:4356:2f72:bf9b:4438:3f98:f100", + "last": "7ad9:3428:4356:2f72:bf9b:4438:3f98:f1ff", + "total": "256", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00" + }, + { + "input": "b213:3a63:80f9:1ecf:6362:8ff7:5c31:d441/16", + "expanded": "b213:3a63:80f9:1ecf:6362:8ff7:5c31:d441", + "compressed": "b213::", + "network": "b213::/16", + "first": "b213::", + "last": "b213:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "5192296858534827628530496329220096", + "netmask": "ffff::" + }, + { + "input": "9780:2716:63b2:5992:7314:4f18:e87:7968/105", + "expanded": "9780:2716:63b2:5992:7314:4f18:0e87:7968", + "compressed": "9780:2716:63b2:5992:7314:4f18:e80:0", + "network": "9780:2716:63b2:5992:7314:4f18:e80:0/105", + "first": "9780:2716:63b2:5992:7314:4f18:e80:0", + "last": "9780:2716:63b2:5992:7314:4f18:eff:ffff", + "total": "8388608", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ff80:0" + }, + { + "input": "ad4f:23b9:d437:df60:1b91:e6b0:1f49:1554/112", + "expanded": "ad4f:23b9:d437:df60:1b91:e6b0:1f49:1554", + "compressed": "ad4f:23b9:d437:df60:1b91:e6b0:1f49:0", + "network": "ad4f:23b9:d437:df60:1b91:e6b0:1f49:0/112", + "first": "ad4f:23b9:d437:df60:1b91:e6b0:1f49:0", + "last": "ad4f:23b9:d437:df60:1b91:e6b0:1f49:ffff", + "total": "65536", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0" + }, + { + "input": "6c5f:e71b:2d0a:56c:ffc8:3d74:61ad:5f4b/112", + "expanded": "6c5f:e71b:2d0a:056c:ffc8:3d74:61ad:5f4b", + "compressed": "6c5f:e71b:2d0a:56c:ffc8:3d74:61ad:0", + "network": "6c5f:e71b:2d0a:56c:ffc8:3d74:61ad:0/112", + "first": "6c5f:e71b:2d0a:56c:ffc8:3d74:61ad:0", + "last": "6c5f:e71b:2d0a:56c:ffc8:3d74:61ad:ffff", + "total": "65536", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0" + }, + { + "input": "48ed:81e7:86ba:40f1:ba9b:6711:a1e3:e16/16", + "expanded": "48ed:81e7:86ba:40f1:ba9b:6711:a1e3:0e16", + "compressed": "48ed::", + "network": "48ed::/16", + "first": "48ed::", + "last": "48ed:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "5192296858534827628530496329220096", + "netmask": "ffff::" + }, + { + "input": "e555:9766:f57c:b482:42a:39bb:71a3:4991/112", + "expanded": "e555:9766:f57c:b482:042a:39bb:71a3:4991", + "compressed": "e555:9766:f57c:b482:42a:39bb:71a3:0", + "network": "e555:9766:f57c:b482:42a:39bb:71a3:0/112", + "first": "e555:9766:f57c:b482:42a:39bb:71a3:0", + "last": "e555:9766:f57c:b482:42a:39bb:71a3:ffff", + "total": "65536", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0" + }, + { + "input": "abc2:4062:f12b:e2a9:7035:85e3:3da9:4211/127", + "expanded": "abc2:4062:f12b:e2a9:7035:85e3:3da9:4211", + "compressed": "abc2:4062:f12b:e2a9:7035:85e3:3da9:4210", + "network": "abc2:4062:f12b:e2a9:7035:85e3:3da9:4210/127", + "first": "abc2:4062:f12b:e2a9:7035:85e3:3da9:4210", + "last": "abc2:4062:f12b:e2a9:7035:85e3:3da9:4211", + "total": "2", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe" + }, + { + "input": "bbd2:aef0:794c:6dcc:2215:207b:73ad:86d2/120", + "expanded": "bbd2:aef0:794c:6dcc:2215:207b:73ad:86d2", + "compressed": "bbd2:aef0:794c:6dcc:2215:207b:73ad:8600", + "network": "bbd2:aef0:794c:6dcc:2215:207b:73ad:8600/120", + "first": "bbd2:aef0:794c:6dcc:2215:207b:73ad:8600", + "last": "bbd2:aef0:794c:6dcc:2215:207b:73ad:86ff", + "total": "256", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00" + }, + { + "input": "178d:1501:3f49:b96b:3907:7d6a:94fc:f4a/48", + "expanded": "178d:1501:3f49:b96b:3907:7d6a:94fc:0f4a", + "compressed": "178d:1501:3f49::", + "network": "178d:1501:3f49::/48", + "first": "178d:1501:3f49::", + "last": "178d:1501:3f49:ffff:ffff:ffff:ffff:ffff", + "total": "1208925819614629174706176", + "netmask": "ffff:ffff:ffff::" + }, + { + "input": "54eb:2a62:91a8:9407:d20:e53b:358f:bdc1/32", + "expanded": "54eb:2a62:91a8:9407:0d20:e53b:358f:bdc1", + "compressed": "54eb:2a62::", + "network": "54eb:2a62::/32", + "first": "54eb:2a62::", + "last": "54eb:2a62:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "79228162514264337593543950336", + "netmask": "ffff:ffff::" + }, + { + "input": "5ec4:90ff:1d67:7adb:ff67:a2f0:7025:e6b3/32", + "expanded": "5ec4:90ff:1d67:7adb:ff67:a2f0:7025:e6b3", + "compressed": "5ec4:90ff::", + "network": "5ec4:90ff::/32", + "first": "5ec4:90ff::", + "last": "5ec4:90ff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "79228162514264337593543950336", + "netmask": "ffff:ffff::" + }, + { + "input": "25e7:2d19:14de:550:a739:d0a9:c49e:d36/127", + "expanded": "25e7:2d19:14de:0550:a739:d0a9:c49e:0d36", + "compressed": "25e7:2d19:14de:550:a739:d0a9:c49e:d36", + "network": "25e7:2d19:14de:550:a739:d0a9:c49e:d36/127", + "first": "25e7:2d19:14de:550:a739:d0a9:c49e:d36", + "last": "25e7:2d19:14de:550:a739:d0a9:c49e:d37", + "total": "2", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe" + }, + { + "input": "faff:5682:776e:b9f9:a6e1:e81:d2bf:8f1a/112", + "expanded": "faff:5682:776e:b9f9:a6e1:0e81:d2bf:8f1a", + "compressed": "faff:5682:776e:b9f9:a6e1:e81:d2bf:0", + "network": "faff:5682:776e:b9f9:a6e1:e81:d2bf:0/112", + "first": "faff:5682:776e:b9f9:a6e1:e81:d2bf:0", + "last": "faff:5682:776e:b9f9:a6e1:e81:d2bf:ffff", + "total": "65536", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0" + }, + { + "input": "8977:335b:43d1:494f:7fca:59fa:5f46:c048/120", + "expanded": "8977:335b:43d1:494f:7fca:59fa:5f46:c048", + "compressed": "8977:335b:43d1:494f:7fca:59fa:5f46:c000", + "network": "8977:335b:43d1:494f:7fca:59fa:5f46:c000/120", + "first": "8977:335b:43d1:494f:7fca:59fa:5f46:c000", + "last": "8977:335b:43d1:494f:7fca:59fa:5f46:c0ff", + "total": "256", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00" + }, + { + "input": "ae77:2a0e:ac28:37fd:310c:23ec:255f:40a9/120", + "expanded": "ae77:2a0e:ac28:37fd:310c:23ec:255f:40a9", + "compressed": "ae77:2a0e:ac28:37fd:310c:23ec:255f:4000", + "network": "ae77:2a0e:ac28:37fd:310c:23ec:255f:4000/120", + "first": "ae77:2a0e:ac28:37fd:310c:23ec:255f:4000", + "last": "ae77:2a0e:ac28:37fd:310c:23ec:255f:40ff", + "total": "256", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00" + }, + { + "input": "77be:3105:c3c:2a77:f102:3e57:71d5:77b5/64", + "expanded": "77be:3105:0c3c:2a77:f102:3e57:71d5:77b5", + "compressed": "77be:3105:c3c:2a77::", + "network": "77be:3105:c3c:2a77::/64", + "first": "77be:3105:c3c:2a77::", + "last": "77be:3105:c3c:2a77:ffff:ffff:ffff:ffff", + "total": "18446744073709551616", + "netmask": "ffff:ffff:ffff:ffff::" + }, + { + "input": "82cb:c6bb:e13:1eae:8b36:5edc:3a41:8cb1/32", + "expanded": "82cb:c6bb:0e13:1eae:8b36:5edc:3a41:8cb1", + "compressed": "82cb:c6bb::", + "network": "82cb:c6bb::/32", + "first": "82cb:c6bb::", + "last": "82cb:c6bb:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "79228162514264337593543950336", + "netmask": "ffff:ffff::" + }, + { + "input": "3bd3:d84f:11ca:205b:21cd:3df5:72eb:411b/96", + "expanded": "3bd3:d84f:11ca:205b:21cd:3df5:72eb:411b", + "compressed": "3bd3:d84f:11ca:205b:21cd:3df5::", + "network": "3bd3:d84f:11ca:205b:21cd:3df5::/96", + "first": "3bd3:d84f:11ca:205b:21cd:3df5::", + "last": "3bd3:d84f:11ca:205b:21cd:3df5:ffff:ffff", + "total": "4294967296", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff::" + }, + { + "input": "b07d:e339:fcf6:3f58:ccc8:c0c3:7843:5b2d/16", + "expanded": "b07d:e339:fcf6:3f58:ccc8:c0c3:7843:5b2d", + "compressed": "b07d::", + "network": "b07d::/16", + "first": "b07d::", + "last": "b07d:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "5192296858534827628530496329220096", + "netmask": "ffff::" + }, + { + "input": "325d:34f5:2fe2:69cd:3820:b09e:4f20:1ad2/71", + "expanded": "325d:34f5:2fe2:69cd:3820:b09e:4f20:1ad2", + "compressed": "325d:34f5:2fe2:69cd:3800::", + "network": "325d:34f5:2fe2:69cd:3800::/71", + "first": "325d:34f5:2fe2:69cd:3800::", + "last": "325d:34f5:2fe2:69cd:39ff:ffff:ffff:ffff", + "total": "144115188075855872", + "netmask": "ffff:ffff:ffff:ffff:fe00::" + }, + { + "input": "5cab:94ea:da11:7fb:f0b9:498a:f3d4:9b6/64", + "expanded": "5cab:94ea:da11:07fb:f0b9:498a:f3d4:09b6", + "compressed": "5cab:94ea:da11:7fb::", + "network": "5cab:94ea:da11:7fb::/64", + "first": "5cab:94ea:da11:7fb::", + "last": "5cab:94ea:da11:7fb:ffff:ffff:ffff:ffff", + "total": "18446744073709551616", + "netmask": "ffff:ffff:ffff:ffff::" + }, + { + "input": "34ed:765a:8f61:5618:cfca:16d7:8b80:d0b1/128", + "expanded": "34ed:765a:8f61:5618:cfca:16d7:8b80:d0b1", + "compressed": "34ed:765a:8f61:5618:cfca:16d7:8b80:d0b1", + "network": "34ed:765a:8f61:5618:cfca:16d7:8b80:d0b1/128", + "first": "34ed:765a:8f61:5618:cfca:16d7:8b80:d0b1", + "last": "34ed:765a:8f61:5618:cfca:16d7:8b80:d0b1", + "total": "1", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + }, + { + "input": "198f:ceaf:2969:8004:471a:b649:b13c:2bc6/16", + "expanded": "198f:ceaf:2969:8004:471a:b649:b13c:2bc6", + "compressed": "198f::", + "network": "198f::/16", + "first": "198f::", + "last": "198f:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "5192296858534827628530496329220096", + "netmask": "ffff::" + }, + { + "input": "2ee8:62e0:c166:83e0:2e98:d91e:7978:f0df/112", + "expanded": "2ee8:62e0:c166:83e0:2e98:d91e:7978:f0df", + "compressed": "2ee8:62e0:c166:83e0:2e98:d91e:7978:0", + "network": "2ee8:62e0:c166:83e0:2e98:d91e:7978:0/112", + "first": "2ee8:62e0:c166:83e0:2e98:d91e:7978:0", + "last": "2ee8:62e0:c166:83e0:2e98:d91e:7978:ffff", + "total": "65536", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0" + }, + { + "input": "d39e:bc2d:ae60:33c5:b14e:60af:2de7:bfdf/128", + "expanded": "d39e:bc2d:ae60:33c5:b14e:60af:2de7:bfdf", + "compressed": "d39e:bc2d:ae60:33c5:b14e:60af:2de7:bfdf", + "network": "d39e:bc2d:ae60:33c5:b14e:60af:2de7:bfdf/128", + "first": "d39e:bc2d:ae60:33c5:b14e:60af:2de7:bfdf", + "last": "d39e:bc2d:ae60:33c5:b14e:60af:2de7:bfdf", + "total": "1", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + }, + { + "input": "eede:2813:52ee:6543:ed90:916d:889e:9b1f/16", + "expanded": "eede:2813:52ee:6543:ed90:916d:889e:9b1f", + "compressed": "eede::", + "network": "eede::/16", + "first": "eede::", + "last": "eede:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "5192296858534827628530496329220096", + "netmask": "ffff::" + }, + { + "input": "a1b4:89e6:916:9ffd:ca1b:3df9:4073:88aa/96", + "expanded": "a1b4:89e6:0916:9ffd:ca1b:3df9:4073:88aa", + "compressed": "a1b4:89e6:916:9ffd:ca1b:3df9::", + "network": "a1b4:89e6:916:9ffd:ca1b:3df9::/96", + "first": "a1b4:89e6:916:9ffd:ca1b:3df9::", + "last": "a1b4:89e6:916:9ffd:ca1b:3df9:ffff:ffff", + "total": "4294967296", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff::" + }, + { + "input": "9e24:7801:e1c7:5423:430:85b3:381d:c887/32", + "expanded": "9e24:7801:e1c7:5423:0430:85b3:381d:c887", + "compressed": "9e24:7801::", + "network": "9e24:7801::/32", + "first": "9e24:7801::", + "last": "9e24:7801:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "79228162514264337593543950336", + "netmask": "ffff:ffff::" + }, + { + "input": "c480:401c:b3e6:c357:3760:a7a2:a271:9a30/0", + "expanded": "c480:401c:b3e6:c357:3760:a7a2:a271:9a30", + "compressed": "::", + "network": "::/0", + "first": "::", + "last": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "340282366920938463463374607431768211456", + "netmask": "::" + }, + { + "input": "ff15:610d:b112:508d:def1:f844:2642:3b52/120", + "expanded": "ff15:610d:b112:508d:def1:f844:2642:3b52", + "compressed": "ff15:610d:b112:508d:def1:f844:2642:3b00", + "network": "ff15:610d:b112:508d:def1:f844:2642:3b00/120", + "first": "ff15:610d:b112:508d:def1:f844:2642:3b00", + "last": "ff15:610d:b112:508d:def1:f844:2642:3bff", + "total": "256", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00" + }, + { + "input": "e346:ecf7:dd96:791f:8aed:8606:d446:6c73/16", + "expanded": "e346:ecf7:dd96:791f:8aed:8606:d446:6c73", + "compressed": "e346::", + "network": "e346::/16", + "first": "e346::", + "last": "e346:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "5192296858534827628530496329220096", + "netmask": "ffff::" + }, + { + "input": "501e:616d:55f7:4ad1:8220:442b:8197:dbca/8", + "expanded": "501e:616d:55f7:4ad1:8220:442b:8197:dbca", + "compressed": "5000::", + "network": "5000::/8", + "first": "5000::", + "last": "50ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "1329227995784915872903807060280344576", + "netmask": "ff00::" + }, + { + "input": "655b:b1c9:a105:6ef0:8b57:d9f7:4ad3:c1de/48", + "expanded": "655b:b1c9:a105:6ef0:8b57:d9f7:4ad3:c1de", + "compressed": "655b:b1c9:a105::", + "network": "655b:b1c9:a105::/48", + "first": "655b:b1c9:a105::", + "last": "655b:b1c9:a105:ffff:ffff:ffff:ffff:ffff", + "total": "1208925819614629174706176", + "netmask": "ffff:ffff:ffff::" + }, + { + "input": "3e34:d1e8:efaa:2482:ccb5:ccd7:a3b3:e98d/64", + "expanded": "3e34:d1e8:efaa:2482:ccb5:ccd7:a3b3:e98d", + "compressed": "3e34:d1e8:efaa:2482::", + "network": "3e34:d1e8:efaa:2482::/64", + "first": "3e34:d1e8:efaa:2482::", + "last": "3e34:d1e8:efaa:2482:ffff:ffff:ffff:ffff", + "total": "18446744073709551616", + "netmask": "ffff:ffff:ffff:ffff::" + }, + { + "input": "e5c5:f401:5367:5b10:ba14:7595:f9b6:9fee/0", + "expanded": "e5c5:f401:5367:5b10:ba14:7595:f9b6:9fee", + "compressed": "::", + "network": "::/0", + "first": "::", + "last": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "340282366920938463463374607431768211456", + "netmask": "::" + }, + { + "input": "a150:bd4:e6a9:d736:dede:da1a:c018:6f1a/112", + "expanded": "a150:0bd4:e6a9:d736:dede:da1a:c018:6f1a", + "compressed": "a150:bd4:e6a9:d736:dede:da1a:c018:0", + "network": "a150:bd4:e6a9:d736:dede:da1a:c018:0/112", + "first": "a150:bd4:e6a9:d736:dede:da1a:c018:0", + "last": "a150:bd4:e6a9:d736:dede:da1a:c018:ffff", + "total": "65536", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0" + }, + { + "input": "7ee1:59b1:968b:634e:6a55:76e9:c4f7:fcc9/128", + "expanded": "7ee1:59b1:968b:634e:6a55:76e9:c4f7:fcc9", + "compressed": "7ee1:59b1:968b:634e:6a55:76e9:c4f7:fcc9", + "network": "7ee1:59b1:968b:634e:6a55:76e9:c4f7:fcc9/128", + "first": "7ee1:59b1:968b:634e:6a55:76e9:c4f7:fcc9", + "last": "7ee1:59b1:968b:634e:6a55:76e9:c4f7:fcc9", + "total": "1", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + }, + { + "input": "927c:8dce:5f64:413f:54fa:395f:cafd:6bf4/120", + "expanded": "927c:8dce:5f64:413f:54fa:395f:cafd:6bf4", + "compressed": "927c:8dce:5f64:413f:54fa:395f:cafd:6b00", + "network": "927c:8dce:5f64:413f:54fa:395f:cafd:6b00/120", + "first": "927c:8dce:5f64:413f:54fa:395f:cafd:6b00", + "last": "927c:8dce:5f64:413f:54fa:395f:cafd:6bff", + "total": "256", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00" + }, + { + "input": "28e3:e05d:978a:c29d:4404:ff5c:5aaa:b3de/16", + "expanded": "28e3:e05d:978a:c29d:4404:ff5c:5aaa:b3de", + "compressed": "28e3::", + "network": "28e3::/16", + "first": "28e3::", + "last": "28e3:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "5192296858534827628530496329220096", + "netmask": "ffff::" + }, + { + "input": "2702:49f8:9a68:1906:9e54:f8e2:6098:a5a7/0", + "expanded": "2702:49f8:9a68:1906:9e54:f8e2:6098:a5a7", + "compressed": "::", + "network": "::/0", + "first": "::", + "last": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "340282366920938463463374607431768211456", + "netmask": "::" + }, + { + "input": "f18e:e9e2:40ce:d139:5d5a:e2c6:28c1:cbef/127", + "expanded": "f18e:e9e2:40ce:d139:5d5a:e2c6:28c1:cbef", + "compressed": "f18e:e9e2:40ce:d139:5d5a:e2c6:28c1:cbee", + "network": "f18e:e9e2:40ce:d139:5d5a:e2c6:28c1:cbee/127", + "first": "f18e:e9e2:40ce:d139:5d5a:e2c6:28c1:cbee", + "last": "f18e:e9e2:40ce:d139:5d5a:e2c6:28c1:cbef", + "total": "2", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe" + }, + { + "input": "bd73:90d9:98f3:5cda:162f:bef0:2915:7ee9/32", + "expanded": "bd73:90d9:98f3:5cda:162f:bef0:2915:7ee9", + "compressed": "bd73:90d9::", + "network": "bd73:90d9::/32", + "first": "bd73:90d9::", + "last": "bd73:90d9:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "79228162514264337593543950336", + "netmask": "ffff:ffff::" + }, + { + "input": "a9b1:76a8:d95b:dd70:1aa5:4781:a6a5:df81/112", + "expanded": "a9b1:76a8:d95b:dd70:1aa5:4781:a6a5:df81", + "compressed": "a9b1:76a8:d95b:dd70:1aa5:4781:a6a5:0", + "network": "a9b1:76a8:d95b:dd70:1aa5:4781:a6a5:0/112", + "first": "a9b1:76a8:d95b:dd70:1aa5:4781:a6a5:0", + "last": "a9b1:76a8:d95b:dd70:1aa5:4781:a6a5:ffff", + "total": "65536", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0" + }, + { + "input": "40f3:9e7:a2c6:ed:579c:8abc:abb2:b433/16", + "expanded": "40f3:09e7:a2c6:00ed:579c:8abc:abb2:b433", + "compressed": "40f3::", + "network": "40f3::/16", + "first": "40f3::", + "last": "40f3:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "5192296858534827628530496329220096", + "netmask": "ffff::" + }, + { + "input": "4fea:b48:81fb:fa8b:ecbe:3d27:fc85:9246/0", + "expanded": "4fea:0b48:81fb:fa8b:ecbe:3d27:fc85:9246", + "compressed": "::", + "network": "::/0", + "first": "::", + "last": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "340282366920938463463374607431768211456", + "netmask": "::" + }, + { + "input": "475f:94b8:c186:78ee:d2fd:fec:e11f:218/19", + "expanded": "475f:94b8:c186:78ee:d2fd:0fec:e11f:0218", + "compressed": "475f:8000::", + "network": "475f:8000::/19", + "first": "475f:8000::", + "last": "475f:9fff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "649037107316853453566312041152512", + "netmask": "ffff:e000::" + }, + { + "input": "e1b9:546d:b494:48f0:d40b:878:e166:75a1/96", + "expanded": "e1b9:546d:b494:48f0:d40b:0878:e166:75a1", + "compressed": "e1b9:546d:b494:48f0:d40b:878::", + "network": "e1b9:546d:b494:48f0:d40b:878::/96", + "first": "e1b9:546d:b494:48f0:d40b:878::", + "last": "e1b9:546d:b494:48f0:d40b:878:ffff:ffff", + "total": "4294967296", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff::" + }, + { + "input": "260c:59d9:221c:b082:3049:62f2:d58e:117c/128", + "expanded": "260c:59d9:221c:b082:3049:62f2:d58e:117c", + "compressed": "260c:59d9:221c:b082:3049:62f2:d58e:117c", + "network": "260c:59d9:221c:b082:3049:62f2:d58e:117c/128", + "first": "260c:59d9:221c:b082:3049:62f2:d58e:117c", + "last": "260c:59d9:221c:b082:3049:62f2:d58e:117c", + "total": "1", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + }, + { + "input": "e09c:707b:2a37:d5a0:7168:61f5:ae74:f180/48", + "expanded": "e09c:707b:2a37:d5a0:7168:61f5:ae74:f180", + "compressed": "e09c:707b:2a37::", + "network": "e09c:707b:2a37::/48", + "first": "e09c:707b:2a37::", + "last": "e09c:707b:2a37:ffff:ffff:ffff:ffff:ffff", + "total": "1208925819614629174706176", + "netmask": "ffff:ffff:ffff::" + }, + { + "input": "9598:4315:18aa:2a2f:2e66:ed88:9c73:68f4/112", + "expanded": "9598:4315:18aa:2a2f:2e66:ed88:9c73:68f4", + "compressed": "9598:4315:18aa:2a2f:2e66:ed88:9c73:0", + "network": "9598:4315:18aa:2a2f:2e66:ed88:9c73:0/112", + "first": "9598:4315:18aa:2a2f:2e66:ed88:9c73:0", + "last": "9598:4315:18aa:2a2f:2e66:ed88:9c73:ffff", + "total": "65536", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0" + }, + { + "input": "dfe:cf73:2e0d:44f8:4d2:5a12:9d46:6102/8", + "expanded": "0dfe:cf73:2e0d:44f8:04d2:5a12:9d46:6102", + "compressed": "d00::", + "network": "d00::/8", + "first": "d00::", + "last": "dff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "1329227995784915872903807060280344576", + "netmask": "ff00::" + }, + { + "input": "3f85:4cc6:a23c:3b83:a3fa:2956:9aab:badf/96", + "expanded": "3f85:4cc6:a23c:3b83:a3fa:2956:9aab:badf", + "compressed": "3f85:4cc6:a23c:3b83:a3fa:2956::", + "network": "3f85:4cc6:a23c:3b83:a3fa:2956::/96", + "first": "3f85:4cc6:a23c:3b83:a3fa:2956::", + "last": "3f85:4cc6:a23c:3b83:a3fa:2956:ffff:ffff", + "total": "4294967296", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff::" + }, + { + "input": "8336:8aef:af2f:c97b:5082:2850:9640:34a/128", + "expanded": "8336:8aef:af2f:c97b:5082:2850:9640:034a", + "compressed": "8336:8aef:af2f:c97b:5082:2850:9640:34a", + "network": "8336:8aef:af2f:c97b:5082:2850:9640:34a/128", + "first": "8336:8aef:af2f:c97b:5082:2850:9640:34a", + "last": "8336:8aef:af2f:c97b:5082:2850:9640:34a", + "total": "1", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + }, + { + "input": "3e90:6fe:f57e:4fe7:ee99:20cd:38bb:b09b/67", + "expanded": "3e90:06fe:f57e:4fe7:ee99:20cd:38bb:b09b", + "compressed": "3e90:6fe:f57e:4fe7:e000::", + "network": "3e90:6fe:f57e:4fe7:e000::/67", + "first": "3e90:6fe:f57e:4fe7:e000::", + "last": "3e90:6fe:f57e:4fe7:ffff:ffff:ffff:ffff", + "total": "2305843009213693952", + "netmask": "ffff:ffff:ffff:ffff:e000::" + }, + { + "input": "1b34:c4e5:afe9:ea28:5ec6:31e:b3bf:397d/0", + "expanded": "1b34:c4e5:afe9:ea28:5ec6:031e:b3bf:397d", + "compressed": "::", + "network": "::/0", + "first": "::", + "last": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "340282366920938463463374607431768211456", + "netmask": "::" + }, + { + "input": "b99d:74f2:613:53ab:8a8e:b637:25b4:7ac9/0", + "expanded": "b99d:74f2:0613:53ab:8a8e:b637:25b4:7ac9", + "compressed": "::", + "network": "::/0", + "first": "::", + "last": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "340282366920938463463374607431768211456", + "netmask": "::" + }, + { + "input": "c20b:288c:ca0e:d457:b3da:5a41:2ec8:d178/64", + "expanded": "c20b:288c:ca0e:d457:b3da:5a41:2ec8:d178", + "compressed": "c20b:288c:ca0e:d457::", + "network": "c20b:288c:ca0e:d457::/64", + "first": "c20b:288c:ca0e:d457::", + "last": "c20b:288c:ca0e:d457:ffff:ffff:ffff:ffff", + "total": "18446744073709551616", + "netmask": "ffff:ffff:ffff:ffff::" + }, + { + "input": "e357:2ec:a639:a585:66a9:2ec5:7242:15bc/96", + "expanded": "e357:02ec:a639:a585:66a9:2ec5:7242:15bc", + "compressed": "e357:2ec:a639:a585:66a9:2ec5::", + "network": "e357:2ec:a639:a585:66a9:2ec5::/96", + "first": "e357:2ec:a639:a585:66a9:2ec5::", + "last": "e357:2ec:a639:a585:66a9:2ec5:ffff:ffff", + "total": "4294967296", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff::" + }, + { + "input": "7290:b736:fc98:cac9:7ee4:9a13:599c:9217/48", + "expanded": "7290:b736:fc98:cac9:7ee4:9a13:599c:9217", + "compressed": "7290:b736:fc98::", + "network": "7290:b736:fc98::/48", + "first": "7290:b736:fc98::", + "last": "7290:b736:fc98:ffff:ffff:ffff:ffff:ffff", + "total": "1208925819614629174706176", + "netmask": "ffff:ffff:ffff::" + }, + { + "input": "1140:a84:ee48:1be4:b8b2:5aa:a179:9913/48", + "expanded": "1140:0a84:ee48:1be4:b8b2:05aa:a179:9913", + "compressed": "1140:a84:ee48::", + "network": "1140:a84:ee48::/48", + "first": "1140:a84:ee48::", + "last": "1140:a84:ee48:ffff:ffff:ffff:ffff:ffff", + "total": "1208925819614629174706176", + "netmask": "ffff:ffff:ffff::" + }, + { + "input": "c2b6:366e:66ca:a6d8:bf0c:a9e7:506f:2859/120", + "expanded": "c2b6:366e:66ca:a6d8:bf0c:a9e7:506f:2859", + "compressed": "c2b6:366e:66ca:a6d8:bf0c:a9e7:506f:2800", + "network": "c2b6:366e:66ca:a6d8:bf0c:a9e7:506f:2800/120", + "first": "c2b6:366e:66ca:a6d8:bf0c:a9e7:506f:2800", + "last": "c2b6:366e:66ca:a6d8:bf0c:a9e7:506f:28ff", + "total": "256", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00" + }, + { + "input": "c0c4:21d6:aaf8:70be:623e:e0d8:d9de:29d4/64", + "expanded": "c0c4:21d6:aaf8:70be:623e:e0d8:d9de:29d4", + "compressed": "c0c4:21d6:aaf8:70be::", + "network": "c0c4:21d6:aaf8:70be::/64", + "first": "c0c4:21d6:aaf8:70be::", + "last": "c0c4:21d6:aaf8:70be:ffff:ffff:ffff:ffff", + "total": "18446744073709551616", + "netmask": "ffff:ffff:ffff:ffff::" + }, + { + "input": "4c86:a104:ae41:cdc6:46da:61c1:1471:5d8d/17", + "expanded": "4c86:a104:ae41:cdc6:46da:61c1:1471:5d8d", + "compressed": "4c86:8000::", + "network": "4c86:8000::/17", + "first": "4c86:8000::", + "last": "4c86:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "2596148429267413814265248164610048", + "netmask": "ffff:8000::" + }, + { + "input": "9b36:36a1:370:e3a1:19d8:1335:7e27:ed8c/8", + "expanded": "9b36:36a1:0370:e3a1:19d8:1335:7e27:ed8c", + "compressed": "9b00::", + "network": "9b00::/8", + "first": "9b00::", + "last": "9bff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "1329227995784915872903807060280344576", + "netmask": "ff00::" + }, + { + "input": "dcc8:d464:e187:60c2:9575:b959:9460:8eba/112", + "expanded": "dcc8:d464:e187:60c2:9575:b959:9460:8eba", + "compressed": "dcc8:d464:e187:60c2:9575:b959:9460:0", + "network": "dcc8:d464:e187:60c2:9575:b959:9460:0/112", + "first": "dcc8:d464:e187:60c2:9575:b959:9460:0", + "last": "dcc8:d464:e187:60c2:9575:b959:9460:ffff", + "total": "65536", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0" + }, + { + "input": "958f:af5f:15d6:37d3:dad1:9a2e:8ed7:a7de/16", + "expanded": "958f:af5f:15d6:37d3:dad1:9a2e:8ed7:a7de", + "compressed": "958f::", + "network": "958f::/16", + "first": "958f::", + "last": "958f:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "5192296858534827628530496329220096", + "netmask": "ffff::" + }, + { + "input": "4d78:4cf6:56e7:f631:c5fa:f642:a42e:9862/128", + "expanded": "4d78:4cf6:56e7:f631:c5fa:f642:a42e:9862", + "compressed": "4d78:4cf6:56e7:f631:c5fa:f642:a42e:9862", + "network": "4d78:4cf6:56e7:f631:c5fa:f642:a42e:9862/128", + "first": "4d78:4cf6:56e7:f631:c5fa:f642:a42e:9862", + "last": "4d78:4cf6:56e7:f631:c5fa:f642:a42e:9862", + "total": "1", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + }, + { + "input": "4b37:4243:e505:cfb8:12f8:672c:1bee:b052/112", + "expanded": "4b37:4243:e505:cfb8:12f8:672c:1bee:b052", + "compressed": "4b37:4243:e505:cfb8:12f8:672c:1bee:0", + "network": "4b37:4243:e505:cfb8:12f8:672c:1bee:0/112", + "first": "4b37:4243:e505:cfb8:12f8:672c:1bee:0", + "last": "4b37:4243:e505:cfb8:12f8:672c:1bee:ffff", + "total": "65536", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0" + }, + { + "input": "be7b:4e4a:50b4:e754:fd9a:fe4:1b77:c003/72", + "expanded": "be7b:4e4a:50b4:e754:fd9a:0fe4:1b77:c003", + "compressed": "be7b:4e4a:50b4:e754:fd00::", + "network": "be7b:4e4a:50b4:e754:fd00::/72", + "first": "be7b:4e4a:50b4:e754:fd00::", + "last": "be7b:4e4a:50b4:e754:fdff:ffff:ffff:ffff", + "total": "72057594037927936", + "netmask": "ffff:ffff:ffff:ffff:ff00::" + }, + { + "input": "558b:3eab:135e:f5b4:6443:f696:5850:59cc/8", + "expanded": "558b:3eab:135e:f5b4:6443:f696:5850:59cc", + "compressed": "5500::", + "network": "5500::/8", + "first": "5500::", + "last": "55ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "1329227995784915872903807060280344576", + "netmask": "ff00::" + }, + { + "input": "90ee:d86c:be7e:bba3:ac67:9c31:ade3:9e76/128", + "expanded": "90ee:d86c:be7e:bba3:ac67:9c31:ade3:9e76", + "compressed": "90ee:d86c:be7e:bba3:ac67:9c31:ade3:9e76", + "network": "90ee:d86c:be7e:bba3:ac67:9c31:ade3:9e76/128", + "first": "90ee:d86c:be7e:bba3:ac67:9c31:ade3:9e76", + "last": "90ee:d86c:be7e:bba3:ac67:9c31:ade3:9e76", + "total": "1", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + }, + { + "input": "26f2:2878:8083:1b41:fbd9:43cc:de84:39f8/112", + "expanded": "26f2:2878:8083:1b41:fbd9:43cc:de84:39f8", + "compressed": "26f2:2878:8083:1b41:fbd9:43cc:de84:0", + "network": "26f2:2878:8083:1b41:fbd9:43cc:de84:0/112", + "first": "26f2:2878:8083:1b41:fbd9:43cc:de84:0", + "last": "26f2:2878:8083:1b41:fbd9:43cc:de84:ffff", + "total": "65536", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0" + }, + { + "input": "3eb5:191a:5ce5:d005:65d9:297a:d6d:83a8/16", + "expanded": "3eb5:191a:5ce5:d005:65d9:297a:0d6d:83a8", + "compressed": "3eb5::", + "network": "3eb5::/16", + "first": "3eb5::", + "last": "3eb5:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "5192296858534827628530496329220096", + "netmask": "ffff::" + }, + { + "input": "f447:80d9:165d:e1d0:3349:d7df:2967:6032/112", + "expanded": "f447:80d9:165d:e1d0:3349:d7df:2967:6032", + "compressed": "f447:80d9:165d:e1d0:3349:d7df:2967:0", + "network": "f447:80d9:165d:e1d0:3349:d7df:2967:0/112", + "first": "f447:80d9:165d:e1d0:3349:d7df:2967:0", + "last": "f447:80d9:165d:e1d0:3349:d7df:2967:ffff", + "total": "65536", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0" + }, + { + "input": "8b84:b1a6:5ec2:f1c4:3665:d7f:81a2:b9ef/64", + "expanded": "8b84:b1a6:5ec2:f1c4:3665:0d7f:81a2:b9ef", + "compressed": "8b84:b1a6:5ec2:f1c4::", + "network": "8b84:b1a6:5ec2:f1c4::/64", + "first": "8b84:b1a6:5ec2:f1c4::", + "last": "8b84:b1a6:5ec2:f1c4:ffff:ffff:ffff:ffff", + "total": "18446744073709551616", + "netmask": "ffff:ffff:ffff:ffff::" + }, + { + "input": "5ce0:2425:9b97:8600:97c4:46d2:af01:a32e/64", + "expanded": "5ce0:2425:9b97:8600:97c4:46d2:af01:a32e", + "compressed": "5ce0:2425:9b97:8600::", + "network": "5ce0:2425:9b97:8600::/64", + "first": "5ce0:2425:9b97:8600::", + "last": "5ce0:2425:9b97:8600:ffff:ffff:ffff:ffff", + "total": "18446744073709551616", + "netmask": "ffff:ffff:ffff:ffff::" + }, + { + "input": "913e:f412:115a:2519:9bff:41fb:565b:d076/128", + "expanded": "913e:f412:115a:2519:9bff:41fb:565b:d076", + "compressed": "913e:f412:115a:2519:9bff:41fb:565b:d076", + "network": "913e:f412:115a:2519:9bff:41fb:565b:d076/128", + "first": "913e:f412:115a:2519:9bff:41fb:565b:d076", + "last": "913e:f412:115a:2519:9bff:41fb:565b:d076", + "total": "1", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + }, + { + "input": "59ae:9d25:7937:7e1d:4c9d:17:4111:dc92/48", + "expanded": "59ae:9d25:7937:7e1d:4c9d:0017:4111:dc92", + "compressed": "59ae:9d25:7937::", + "network": "59ae:9d25:7937::/48", + "first": "59ae:9d25:7937::", + "last": "59ae:9d25:7937:ffff:ffff:ffff:ffff:ffff", + "total": "1208925819614629174706176", + "netmask": "ffff:ffff:ffff::" + }, + { + "input": "cc18:3f1d:2ccc:4ea1:76f:f2e3:6dfc:c8c3/64", + "expanded": "cc18:3f1d:2ccc:4ea1:076f:f2e3:6dfc:c8c3", + "compressed": "cc18:3f1d:2ccc:4ea1::", + "network": "cc18:3f1d:2ccc:4ea1::/64", + "first": "cc18:3f1d:2ccc:4ea1::", + "last": "cc18:3f1d:2ccc:4ea1:ffff:ffff:ffff:ffff", + "total": "18446744073709551616", + "netmask": "ffff:ffff:ffff:ffff::" + }, + { + "input": "a60a:1728:772c:9eb4:ebb8:b295:cd1d:dcf2/48", + "expanded": "a60a:1728:772c:9eb4:ebb8:b295:cd1d:dcf2", + "compressed": "a60a:1728:772c::", + "network": "a60a:1728:772c::/48", + "first": "a60a:1728:772c::", + "last": "a60a:1728:772c:ffff:ffff:ffff:ffff:ffff", + "total": "1208925819614629174706176", + "netmask": "ffff:ffff:ffff::" + }, + { + "input": "2fe0:6b3f:47c4:b01d:b6c7:ba64:10e0:9a9e/16", + "expanded": "2fe0:6b3f:47c4:b01d:b6c7:ba64:10e0:9a9e", + "compressed": "2fe0::", + "network": "2fe0::/16", + "first": "2fe0::", + "last": "2fe0:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "5192296858534827628530496329220096", + "netmask": "ffff::" + }, + { + "input": "8d74:b745:dc63:e395:1386:f436:4145:a0d/8", + "expanded": "8d74:b745:dc63:e395:1386:f436:4145:0a0d", + "compressed": "8d00::", + "network": "8d00::/8", + "first": "8d00::", + "last": "8dff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "1329227995784915872903807060280344576", + "netmask": "ff00::" + }, + { + "input": "497d:2804:3bf4:d14e:5a62:879a:ceb1:a861/120", + "expanded": "497d:2804:3bf4:d14e:5a62:879a:ceb1:a861", + "compressed": "497d:2804:3bf4:d14e:5a62:879a:ceb1:a800", + "network": "497d:2804:3bf4:d14e:5a62:879a:ceb1:a800/120", + "first": "497d:2804:3bf4:d14e:5a62:879a:ceb1:a800", + "last": "497d:2804:3bf4:d14e:5a62:879a:ceb1:a8ff", + "total": "256", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00" + }, + { + "input": "4b0:a9f9:dcf5:1c22:f3a4:2e40:ef77:39d8/128", + "expanded": "04b0:a9f9:dcf5:1c22:f3a4:2e40:ef77:39d8", + "compressed": "4b0:a9f9:dcf5:1c22:f3a4:2e40:ef77:39d8", + "network": "4b0:a9f9:dcf5:1c22:f3a4:2e40:ef77:39d8/128", + "first": "4b0:a9f9:dcf5:1c22:f3a4:2e40:ef77:39d8", + "last": "4b0:a9f9:dcf5:1c22:f3a4:2e40:ef77:39d8", + "total": "1", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + }, + { + "input": "236:9ae8:8988:94a8:d7c:5347:3992:5d80/48", + "expanded": "0236:9ae8:8988:94a8:0d7c:5347:3992:5d80", + "compressed": "236:9ae8:8988::", + "network": "236:9ae8:8988::/48", + "first": "236:9ae8:8988::", + "last": "236:9ae8:8988:ffff:ffff:ffff:ffff:ffff", + "total": "1208925819614629174706176", + "netmask": "ffff:ffff:ffff::" + }, + { + "input": "25a6:7c98:3ecb:ea8f:8a7b:d164:9ffa:4b06/128", + "expanded": "25a6:7c98:3ecb:ea8f:8a7b:d164:9ffa:4b06", + "compressed": "25a6:7c98:3ecb:ea8f:8a7b:d164:9ffa:4b06", + "network": "25a6:7c98:3ecb:ea8f:8a7b:d164:9ffa:4b06/128", + "first": "25a6:7c98:3ecb:ea8f:8a7b:d164:9ffa:4b06", + "last": "25a6:7c98:3ecb:ea8f:8a7b:d164:9ffa:4b06", + "total": "1", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + }, + { + "input": "1b7e:1f1:1c52:1ced:d6b5:c135:fdf:f6b0/0", + "expanded": "1b7e:01f1:1c52:1ced:d6b5:c135:0fdf:f6b0", + "compressed": "::", + "network": "::/0", + "first": "::", + "last": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "340282366920938463463374607431768211456", + "netmask": "::" + }, + { + "input": "f6c9:6c5d:5764:60fa:5afe:c2ac:3e56:a9c/112", + "expanded": "f6c9:6c5d:5764:60fa:5afe:c2ac:3e56:0a9c", + "compressed": "f6c9:6c5d:5764:60fa:5afe:c2ac:3e56:0", + "network": "f6c9:6c5d:5764:60fa:5afe:c2ac:3e56:0/112", + "first": "f6c9:6c5d:5764:60fa:5afe:c2ac:3e56:0", + "last": "f6c9:6c5d:5764:60fa:5afe:c2ac:3e56:ffff", + "total": "65536", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0" + }, + { + "input": "2024:574d:ad9d:301c:247b:c9df:f1f8:21ac/127", + "expanded": "2024:574d:ad9d:301c:247b:c9df:f1f8:21ac", + "compressed": "2024:574d:ad9d:301c:247b:c9df:f1f8:21ac", + "network": "2024:574d:ad9d:301c:247b:c9df:f1f8:21ac/127", + "first": "2024:574d:ad9d:301c:247b:c9df:f1f8:21ac", + "last": "2024:574d:ad9d:301c:247b:c9df:f1f8:21ad", + "total": "2", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe" + }, + { + "input": "2606:a34f:f9ba:8bdf:d202:9ef2:da0d:3062/64", + "expanded": "2606:a34f:f9ba:8bdf:d202:9ef2:da0d:3062", + "compressed": "2606:a34f:f9ba:8bdf::", + "network": "2606:a34f:f9ba:8bdf::/64", + "first": "2606:a34f:f9ba:8bdf::", + "last": "2606:a34f:f9ba:8bdf:ffff:ffff:ffff:ffff", + "total": "18446744073709551616", + "netmask": "ffff:ffff:ffff:ffff::" + }, + { + "input": "c211:c8fc:87ae:8263:6863:a2f2:4c86:608/112", + "expanded": "c211:c8fc:87ae:8263:6863:a2f2:4c86:0608", + "compressed": "c211:c8fc:87ae:8263:6863:a2f2:4c86:0", + "network": "c211:c8fc:87ae:8263:6863:a2f2:4c86:0/112", + "first": "c211:c8fc:87ae:8263:6863:a2f2:4c86:0", + "last": "c211:c8fc:87ae:8263:6863:a2f2:4c86:ffff", + "total": "65536", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0" + }, + { + "input": "f0a:9ec9:a88f:f088:912d:6fbf:5229:532/112", + "expanded": "0f0a:9ec9:a88f:f088:912d:6fbf:5229:0532", + "compressed": "f0a:9ec9:a88f:f088:912d:6fbf:5229:0", + "network": "f0a:9ec9:a88f:f088:912d:6fbf:5229:0/112", + "first": "f0a:9ec9:a88f:f088:912d:6fbf:5229:0", + "last": "f0a:9ec9:a88f:f088:912d:6fbf:5229:ffff", + "total": "65536", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0" + }, + { + "input": "a495:c942:eb61:c7e5:6fea:edb6:3963:5737/127", + "expanded": "a495:c942:eb61:c7e5:6fea:edb6:3963:5737", + "compressed": "a495:c942:eb61:c7e5:6fea:edb6:3963:5736", + "network": "a495:c942:eb61:c7e5:6fea:edb6:3963:5736/127", + "first": "a495:c942:eb61:c7e5:6fea:edb6:3963:5736", + "last": "a495:c942:eb61:c7e5:6fea:edb6:3963:5737", + "total": "2", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe" + }, + { + "input": "ba33:4f18:7d1f:2df3:57d7:f904:7ff9:5325/120", + "expanded": "ba33:4f18:7d1f:2df3:57d7:f904:7ff9:5325", + "compressed": "ba33:4f18:7d1f:2df3:57d7:f904:7ff9:5300", + "network": "ba33:4f18:7d1f:2df3:57d7:f904:7ff9:5300/120", + "first": "ba33:4f18:7d1f:2df3:57d7:f904:7ff9:5300", + "last": "ba33:4f18:7d1f:2df3:57d7:f904:7ff9:53ff", + "total": "256", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00" + }, + { + "input": "4c90:ba63:1a47:a1e0:a46a:4d18:2201:45c/16", + "expanded": "4c90:ba63:1a47:a1e0:a46a:4d18:2201:045c", + "compressed": "4c90::", + "network": "4c90::/16", + "first": "4c90::", + "last": "4c90:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "5192296858534827628530496329220096", + "netmask": "ffff::" + }, + { + "input": "c5e5:66ec:57c8:8d64:deaf:b009:86de:8608/32", + "expanded": "c5e5:66ec:57c8:8d64:deaf:b009:86de:8608", + "compressed": "c5e5:66ec::", + "network": "c5e5:66ec::/32", + "first": "c5e5:66ec::", + "last": "c5e5:66ec:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "79228162514264337593543950336", + "netmask": "ffff:ffff::" + }, + { + "input": "292b:2dd5:e721:3ad6:84d6:3863:94f4:3c38/0", + "expanded": "292b:2dd5:e721:3ad6:84d6:3863:94f4:3c38", + "compressed": "::", + "network": "::/0", + "first": "::", + "last": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "340282366920938463463374607431768211456", + "netmask": "::" + }, + { + "input": "d27:58c0:d3c4:be41:b3c3:939a:852f:daaa/96", + "expanded": "0d27:58c0:d3c4:be41:b3c3:939a:852f:daaa", + "compressed": "d27:58c0:d3c4:be41:b3c3:939a::", + "network": "d27:58c0:d3c4:be41:b3c3:939a::/96", + "first": "d27:58c0:d3c4:be41:b3c3:939a::", + "last": "d27:58c0:d3c4:be41:b3c3:939a:ffff:ffff", + "total": "4294967296", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff::" + }, + { + "input": "6120:efc2:f931:5bd9:b479:6767:9bfd:1be8/78", + "expanded": "6120:efc2:f931:5bd9:b479:6767:9bfd:1be8", + "compressed": "6120:efc2:f931:5bd9:b478::", + "network": "6120:efc2:f931:5bd9:b478::/78", + "first": "6120:efc2:f931:5bd9:b478::", + "last": "6120:efc2:f931:5bd9:b47b:ffff:ffff:ffff", + "total": "1125899906842624", + "netmask": "ffff:ffff:ffff:ffff:fffc::" + }, + { + "input": "67d4:783f:2550:6155:5381:a20c:2cc6:a7c9/112", + "expanded": "67d4:783f:2550:6155:5381:a20c:2cc6:a7c9", + "compressed": "67d4:783f:2550:6155:5381:a20c:2cc6:0", + "network": "67d4:783f:2550:6155:5381:a20c:2cc6:0/112", + "first": "67d4:783f:2550:6155:5381:a20c:2cc6:0", + "last": "67d4:783f:2550:6155:5381:a20c:2cc6:ffff", + "total": "65536", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0" + }, + { + "input": "27fe:1b8d:931d:6f52:2189:83b4:443:9a74/32", + "expanded": "27fe:1b8d:931d:6f52:2189:83b4:0443:9a74", + "compressed": "27fe:1b8d::", + "network": "27fe:1b8d::/32", + "first": "27fe:1b8d::", + "last": "27fe:1b8d:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "79228162514264337593543950336", + "netmask": "ffff:ffff::" + }, + { + "input": "ec12:91fb:d418:ec30:25ee:efdf:41c9:2450/48", + "expanded": "ec12:91fb:d418:ec30:25ee:efdf:41c9:2450", + "compressed": "ec12:91fb:d418::", + "network": "ec12:91fb:d418::/48", + "first": "ec12:91fb:d418::", + "last": "ec12:91fb:d418:ffff:ffff:ffff:ffff:ffff", + "total": "1208925819614629174706176", + "netmask": "ffff:ffff:ffff::" + }, + { + "input": "4955:71af:6f48:a7a4:ca95:6fb5:da62:a5ec/64", + "expanded": "4955:71af:6f48:a7a4:ca95:6fb5:da62:a5ec", + "compressed": "4955:71af:6f48:a7a4::", + "network": "4955:71af:6f48:a7a4::/64", + "first": "4955:71af:6f48:a7a4::", + "last": "4955:71af:6f48:a7a4:ffff:ffff:ffff:ffff", + "total": "18446744073709551616", + "netmask": "ffff:ffff:ffff:ffff::" + }, + { + "input": "5d74:a6d0:6a1b:8f59:b668:2ddf:4eaa:dd3d/0", + "expanded": "5d74:a6d0:6a1b:8f59:b668:2ddf:4eaa:dd3d", + "compressed": "::", + "network": "::/0", + "first": "::", + "last": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "340282366920938463463374607431768211456", + "netmask": "::" + }, + { + "input": "33a3:4fc4:95fd:6371:5900:fcbf:7396:1976/8", + "expanded": "33a3:4fc4:95fd:6371:5900:fcbf:7396:1976", + "compressed": "3300::", + "network": "3300::/8", + "first": "3300::", + "last": "33ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "1329227995784915872903807060280344576", + "netmask": "ff00::" + }, + { + "input": "1323:5c54:9cab:29f0:fefc:1c78:8469:63b3/78", + "expanded": "1323:5c54:9cab:29f0:fefc:1c78:8469:63b3", + "compressed": "1323:5c54:9cab:29f0:fefc::", + "network": "1323:5c54:9cab:29f0:fefc::/78", + "first": "1323:5c54:9cab:29f0:fefc::", + "last": "1323:5c54:9cab:29f0:feff:ffff:ffff:ffff", + "total": "1125899906842624", + "netmask": "ffff:ffff:ffff:ffff:fffc::" + }, + { + "input": "e4aa:a90a:8e91:69bf:666f:b767:c446:5154/112", + "expanded": "e4aa:a90a:8e91:69bf:666f:b767:c446:5154", + "compressed": "e4aa:a90a:8e91:69bf:666f:b767:c446:0", + "network": "e4aa:a90a:8e91:69bf:666f:b767:c446:0/112", + "first": "e4aa:a90a:8e91:69bf:666f:b767:c446:0", + "last": "e4aa:a90a:8e91:69bf:666f:b767:c446:ffff", + "total": "65536", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0" + }, + { + "input": "a8e0:8be9:c459:69b4:1639:a42c:2b0f:4eb0/127", + "expanded": "a8e0:8be9:c459:69b4:1639:a42c:2b0f:4eb0", + "compressed": "a8e0:8be9:c459:69b4:1639:a42c:2b0f:4eb0", + "network": "a8e0:8be9:c459:69b4:1639:a42c:2b0f:4eb0/127", + "first": "a8e0:8be9:c459:69b4:1639:a42c:2b0f:4eb0", + "last": "a8e0:8be9:c459:69b4:1639:a42c:2b0f:4eb1", + "total": "2", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe" + }, + { + "input": "6873:aebd:568d:f472:1b15:f2eb:e795:c2bb/64", + "expanded": "6873:aebd:568d:f472:1b15:f2eb:e795:c2bb", + "compressed": "6873:aebd:568d:f472::", + "network": "6873:aebd:568d:f472::/64", + "first": "6873:aebd:568d:f472::", + "last": "6873:aebd:568d:f472:ffff:ffff:ffff:ffff", + "total": "18446744073709551616", + "netmask": "ffff:ffff:ffff:ffff::" + }, + { + "input": "57be:4b91:1b6:504e:bc58:db82:4991:1f5c/127", + "expanded": "57be:4b91:01b6:504e:bc58:db82:4991:1f5c", + "compressed": "57be:4b91:1b6:504e:bc58:db82:4991:1f5c", + "network": "57be:4b91:1b6:504e:bc58:db82:4991:1f5c/127", + "first": "57be:4b91:1b6:504e:bc58:db82:4991:1f5c", + "last": "57be:4b91:1b6:504e:bc58:db82:4991:1f5d", + "total": "2", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe" + }, + { + "input": "1809:f938:aeed:f7ef:b74b:8ba3:e23a:c71d/48", + "expanded": "1809:f938:aeed:f7ef:b74b:8ba3:e23a:c71d", + "compressed": "1809:f938:aeed::", + "network": "1809:f938:aeed::/48", + "first": "1809:f938:aeed::", + "last": "1809:f938:aeed:ffff:ffff:ffff:ffff:ffff", + "total": "1208925819614629174706176", + "netmask": "ffff:ffff:ffff::" + }, + { + "input": "9526:b027:caa9:4081:c0c9:dd10:1c2c:6dc4/120", + "expanded": "9526:b027:caa9:4081:c0c9:dd10:1c2c:6dc4", + "compressed": "9526:b027:caa9:4081:c0c9:dd10:1c2c:6d00", + "network": "9526:b027:caa9:4081:c0c9:dd10:1c2c:6d00/120", + "first": "9526:b027:caa9:4081:c0c9:dd10:1c2c:6d00", + "last": "9526:b027:caa9:4081:c0c9:dd10:1c2c:6dff", + "total": "256", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00" + }, + { + "input": "2001:db8::1/64", + "expanded": "2001:0db8:0000:0000:0000:0000:0000:0001", + "compressed": "2001:db8::", + "network": "2001:db8::/64", + "first": "2001:db8::", + "last": "2001:db8::ffff:ffff:ffff:ffff", + "total": "18446744073709551616", + "netmask": "ffff:ffff:ffff:ffff::" + }, + { + "input": "fe80::1/10", + "expanded": "fe80:0000:0000:0000:0000:0000:0000:0001", + "compressed": "fe80::", + "network": "fe80::/10", + "first": "fe80::", + "last": "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "332306998946228968225951765070086144", + "netmask": "ffc0::" + }, + { + "input": "::1/128", + "expanded": "0000:0000:0000:0000:0000:0000:0000:0001", + "compressed": "::1", + "network": "::1/128", + "first": "::1", + "last": "::1", + "total": "1", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + }, + { + "input": "::/0", + "expanded": "0000:0000:0000:0000:0000:0000:0000:0000", + "compressed": "::", + "network": "::/0", + "first": "::", + "last": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "total": "340282366920938463463374607431768211456", + "netmask": "::" + } +] \ No newline at end of file