Skip to main content
Edit this page

Functions for Working with IPv4 and IPv6 Addresses

IPv4NumToString(num)​

Takes a UInt32 number. Interprets it as an IPv4 address in big endian. Returns a string containing the corresponding IPv4 address in the format A.B.C.d (dot-separated numbers in decimal form).

Alias: INET_NTOA.

IPv4StringToNum(s)​

The reverse function of IPv4NumToString. If the IPv4 address has an invalid format, it throws exception.

Alias: INET_ATON.

IPv4StringToNumOrDefault(s)​

Same as IPv4StringToNum, but if the IPv4 address has an invalid format, it returns 0.

IPv4StringToNumOrNull(s)​

Same as IPv4StringToNum, but if the IPv4 address has an invalid format, it returns null.

IPv4NumToStringClassC(num)​

Similar to IPv4NumToString, but using xxx instead of the last octet.

Example:

SELECT
IPv4NumToStringClassC(ClientIP) AS k,
count() AS c
FROM test.hits
GROUP BY k
ORDER BY c DESC
LIMIT 10
β”Œβ”€k──────────────┬─────c─┐
β”‚ 83.149.9.xxx β”‚ 26238 β”‚
β”‚ 217.118.81.xxx β”‚ 26074 β”‚
β”‚ 213.87.129.xxx β”‚ 25481 β”‚
β”‚ 83.149.8.xxx β”‚ 24984 β”‚
β”‚ 217.118.83.xxx β”‚ 22797 β”‚
β”‚ 78.25.120.xxx β”‚ 22354 β”‚
β”‚ 213.87.131.xxx β”‚ 21285 β”‚
β”‚ 78.25.121.xxx β”‚ 20887 β”‚
β”‚ 188.162.65.xxx β”‚ 19694 β”‚
β”‚ 83.149.48.xxx β”‚ 17406 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”˜

Since using β€˜xxx’ is highly unusual, this may be changed in the future. We recommend that you do not rely on the exact format of this fragment.

IPv6NumToString(x)​

Accepts a FixedString(16) value containing the IPv6 address in binary format. Returns a string containing this address in text format. IPv6-mapped IPv4 addresses are output in the format ::ffff:111.222.33.44.

Alias: INET6_NTOA.

Examples:

SELECT IPv6NumToString(toFixedString(unhex('2A0206B8000000000000000000000011'), 16)) AS addr;
β”Œβ”€addr─────────┐
β”‚ 2a02:6b8::11 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
SELECT
IPv6NumToString(ClientIP6 AS k),
count() AS c
FROM hits_all
WHERE EventDate = today() AND substring(ClientIP6, 1, 12) != unhex('00000000000000000000FFFF')
GROUP BY k
ORDER BY c DESC
LIMIT 10
β”Œβ”€IPv6NumToString(ClientIP6)──────────────┬─────c─┐
β”‚ 2a02:2168:aaa:bbbb::2 β”‚ 24695 β”‚
β”‚ 2a02:2698:abcd:abcd:abcd:abcd:8888:5555 β”‚ 22408 β”‚
β”‚ 2a02:6b8:0:fff::ff β”‚ 16389 β”‚
β”‚ 2a01:4f8:111:6666::2 β”‚ 16016 β”‚
β”‚ 2a02:2168:888:222::1 β”‚ 15896 β”‚
β”‚ 2a01:7e00::ffff:ffff:ffff:222 β”‚ 14774 β”‚
β”‚ 2a02:8109:eee:ee:eeee:eeee:eeee:eeee β”‚ 14443 β”‚
β”‚ 2a02:810b:8888:888:8888:8888:8888:8888 β”‚ 14345 β”‚
β”‚ 2a02:6b8:0:444:4444:4444:4444:4444 β”‚ 14279 β”‚
β”‚ 2a01:7e00::ffff:ffff:ffff:ffff β”‚ 13880 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”˜
SELECT
IPv6NumToString(ClientIP6 AS k),
count() AS c
FROM hits_all
WHERE EventDate = today()
GROUP BY k
ORDER BY c DESC
LIMIT 10
β”Œβ”€IPv6NumToString(ClientIP6)─┬──────c─┐
β”‚ ::ffff:94.26.111.111 β”‚ 747440 β”‚
β”‚ ::ffff:37.143.222.4 β”‚ 529483 β”‚
β”‚ ::ffff:5.166.111.99 β”‚ 317707 β”‚
β”‚ ::ffff:46.38.11.77 β”‚ 263086 β”‚
β”‚ ::ffff:79.105.111.111 β”‚ 186611 β”‚
β”‚ ::ffff:93.92.111.88 β”‚ 176773 β”‚
β”‚ ::ffff:84.53.111.33 β”‚ 158709 β”‚
β”‚ ::ffff:217.118.11.22 β”‚ 154004 β”‚
β”‚ ::ffff:217.118.11.33 β”‚ 148449 β”‚
β”‚ ::ffff:217.118.11.44 β”‚ 148243 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”˜

IPv6StringToNum​

The reverse function of IPv6NumToString. If the IPv6 address has an invalid format, it throws exception.

If the input string contains a valid IPv4 address, returns its IPv6 equivalent. HEX can be uppercase or lowercase.

Alias: INET6_ATON.

Syntax

IPv6StringToNum(string)

Argument

  • string β€” IP address. String.

Returned value

Example

Query:

SELECT addr, cutIPv6(IPv6StringToNum(addr), 0, 0) FROM (SELECT ['notaddress', '127.0.0.1', '1111::ffff'] AS addr) ARRAY JOIN addr;

Result:

β”Œβ”€addr───────┬─cutIPv6(IPv6StringToNum(addr), 0, 0)─┐
β”‚ notaddress β”‚ :: β”‚
β”‚ 127.0.0.1 β”‚ ::ffff:127.0.0.1 β”‚
β”‚ 1111::ffff β”‚ 1111::ffff β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

See Also

IPv6StringToNumOrDefault(s)​

Same as IPv6StringToNum, but if the IPv6 address has an invalid format, it returns 0.

IPv6StringToNumOrNull(s)​

Same as IPv6StringToNum, but if the IPv6 address has an invalid format, it returns null.

IPv4ToIPv6(x)​

Takes a UInt32 number. Interprets it as an IPv4 address in big endian. Returns a FixedString(16) value containing the IPv6 address in binary format. Examples:

SELECT IPv6NumToString(IPv4ToIPv6(IPv4StringToNum('192.168.0.1'))) AS addr;
β”Œβ”€addr───────────────┐
β”‚ ::ffff:192.168.0.1 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

cutIPv6(x, bytesToCutForIPv6, bytesToCutForIPv4)​

Accepts a FixedString(16) value containing the IPv6 address in binary format. Returns a string containing the address of the specified number of bytes removed in text format. For example:

WITH
IPv6StringToNum('2001:0DB8:AC10:FE01:FEED:BABE:CAFE:F00D') AS ipv6,
IPv4ToIPv6(IPv4StringToNum('192.168.0.1')) AS ipv4
SELECT
cutIPv6(ipv6, 2, 0),
cutIPv6(ipv4, 0, 2)
β”Œβ”€cutIPv6(ipv6, 2, 0)─────────────────┬─cutIPv6(ipv4, 0, 2)─┐
β”‚ 2001:db8:ac10:fe01:feed:babe:cafe:0 β”‚ ::ffff:192.168.0.0 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

IPv4CIDRToRange(ipv4, Cidr),​

Accepts an IPv4 and an UInt8 value containing the CIDR. Return a tuple with two IPv4 containing the lower range and the higher range of the subnet.

SELECT IPv4CIDRToRange(toIPv4('192.168.5.2'), 16);
β”Œβ”€IPv4CIDRToRange(toIPv4('192.168.5.2'), 16)─┐
β”‚ ('192.168.0.0','192.168.255.255') β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

IPv6CIDRToRange(ipv6, Cidr),​

Accepts an IPv6 and an UInt8 value containing the CIDR. Return a tuple with two IPv6 containing the lower range and the higher range of the subnet.

SELECT IPv6CIDRToRange(toIPv6('2001:0db8:0000:85a3:0000:0000:ac1f:8001'), 32);
β”Œβ”€IPv6CIDRToRange(toIPv6('2001:0db8:0000:85a3:0000:0000:ac1f:8001'), 32)─┐
β”‚ ('2001:db8::','2001:db8:ffff:ffff:ffff:ffff:ffff:ffff') β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

toIPv4​

Like IPv4StringToNum but takes a string form of IPv4 address and returns value of IPv4 type.

Syntax

toIPv4(string)

Arguments

  • string β€” IPv4 address. String.

Returned value

  • string converted to the IPv4 address. IPv4.

Examples

Query:

SELECT toIPv4('171.225.130.45');

Result:

β”Œβ”€toIPv4('171.225.130.45')─┐
β”‚ 171.225.130.45 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Query:

WITH
'171.225.130.45' as IPv4_string
SELECT
hex(IPv4StringToNum(IPv4_string)),
hex(toIPv4(IPv4_string))

Result:

β”Œβ”€hex(IPv4StringToNum(IPv4_string))─┬─hex(toIPv4(IPv4_string))─┐
β”‚ ABE1822D β”‚ ABE1822D β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

toIPv4OrDefault​

Same as toIPv4, but if the IPv4 address has an invalid format, it returns 0.0.0.0 (0 IPv4), or the provided IPv4 default.

Syntax

toIPv4OrDefault(string[, default])

Arguments

  • value β€” IP address. String.
  • default (optional) β€” The value to return if string has an invalid format. IPv4.

Returned value

  • string converted to the current IPv4 address. String.

Example

Query:

WITH
'::ffff:127.0.0.1' AS valid_IPv6_string,
'fe80:2030:31:24' AS invalid_IPv6_string
SELECT
toIPv4OrDefault(valid_IPv6_string) AS valid,
toIPv4OrDefault(invalid_IPv6_string) AS default,
toIPv4OrDefault(invalid_IPv6_string, toIPv4('1.1.1.1')) AS provided_default;

Result:

β”Œβ”€valid───┬─default─┬─provided_default─┐
β”‚ 0.0.0.0 β”‚ 0.0.0.0 β”‚ 1.1.1.1 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

toIPv4OrNull​

Same as toIPv4, but if the IPv4 address has an invalid format, it returns null.

Syntax

toIPv4OrNull(string)

Arguments

  • string β€” IP address. String.

Returned value

  • string converted to the current IPv4 address, or null if string is an invalid address. String.

Example

Query:

WITH 'fe80:2030:31:24' AS invalid_IPv6_string
SELECT toIPv4OrNull(invalid_IPv6_string);

Result:

β”Œβ”€toIPv4OrNull(invalid_IPv6_string)─┐
β”‚ ᴺᡁᴸᴸ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

toIPv4OrZero​

Same as toIPv4, but if the IPv4 address has an invalid format, it returns 0.0.0.0.

Syntax

toIPv4OrZero(string)

Arguments

  • string β€” IP address. String.

Returned value

  • string converted to the current IPv4 address, or 0.0.0.0 if string is an invalid address. String.

Example

Query:

WITH 'Not an IP address' AS invalid_IPv6_string
SELECT toIPv4OrZero(invalid_IPv6_string);

Result:

β”Œβ”€toIPv4OrZero(invalid_IPv6_string)─┐
β”‚ 0.0.0.0 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

toIPv6​

Converts a string form of IPv6 address to IPv6 type. If the IPv6 address has an invalid format, returns an empty value. Similar to IPv6StringToNum function, which converts IPv6 address to binary format.

If the input string contains a valid IPv4 address, then the IPv6 equivalent of the IPv4 address is returned.

Syntax

toIPv6(string)

Argument

  • string β€” IP address. String.

Returned value

Examples

Query:

WITH '2001:438:ffff::407d:1bc1' AS IPv6_string
SELECT
hex(IPv6StringToNum(IPv6_string)),
hex(toIPv6(IPv6_string));

Result:

β”Œβ”€hex(IPv6StringToNum(IPv6_string))─┬─hex(toIPv6(IPv6_string))─────────┐
β”‚ 20010438FFFF000000000000407D1BC1 β”‚ 20010438FFFF000000000000407D1BC1 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Query:

SELECT toIPv6('127.0.0.1');

Result:

β”Œβ”€toIPv6('127.0.0.1')─┐
β”‚ ::ffff:127.0.0.1 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

toIPv6OrDefault​

Same as toIPv6, but if the IPv6 address has an invalid format, it returns :: (0 IPv6) or the provided IPv6 default.

Syntax

toIPv6OrDefault(string[, default])

Argument

  • string β€” IP address. String.
  • default (optional) β€” The value to return if string has an invalid format. IPv6.

Returned value

  • IPv6 address IPv6, otherwise :: or the provided optional default if string has an invalid format.

Example

Query:

WITH
'127.0.0.1' AS valid_IPv4_string,
'127.0.0.1.6' AS invalid_IPv4_string
SELECT
toIPv6OrDefault(valid_IPv4_string) AS valid,
toIPv6OrDefault(invalid_IPv4_string) AS default,
toIPv6OrDefault(invalid_IPv4_string, toIPv6('1.1.1.1')) AS provided_default

Result:

β”Œβ”€valid────────────┬─default─┬─provided_default─┐
β”‚ ::ffff:127.0.0.1 β”‚ :: β”‚ ::ffff:1.1.1.1 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

toIPv6OrNull​

Same as toIPv6, but if the IPv6 address has an invalid format, it returns null.

Syntax

toIPv6OrNull(string)

Argument

  • string β€” IP address. String.

Returned value

  • IP address. IPv6, or null if string is not a valid format.

Example

Query:

WITH '127.0.0.1.6' AS invalid_IPv4_string
SELECT toIPv6OrNull(invalid_IPv4_string);

Result:

β”Œβ”€toIPv6OrNull(invalid_IPv4_string)─┐
β”‚ ᴺᡁᴸᴸ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

toIPv6OrZero​

Same as toIPv6, but if the IPv6 address has an invalid format, it returns ::.

Syntax

toIPv6OrZero(string)

Argument

  • string β€” IP address. String.

Returned value

  • IP address. IPv6, or :: if string is not a valid format.

Example

Query:

WITH '127.0.0.1.6' AS invalid_IPv4_string
SELECT toIPv6OrZero(invalid_IPv4_string);

Result:

β”Œβ”€toIPv6OrZero(invalid_IPv4_string)─┐
β”‚ :: β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

IPv6StringToNumOrDefault(s)​

Same as toIPv6, but if the IPv6 address has an invalid format, it returns 0.

IPv6StringToNumOrNull(s)​

Same as toIPv6, but if the IPv6 address has an invalid format, it returns null.

isIPv4String​

Determines whether the input string is an IPv4 address or not. If string is IPv6 address returns 0.

Syntax

isIPv4String(string)

Arguments

  • string β€” IP address. String.

Returned value

  • 1 if string is IPv4 address, 0 otherwise. UInt8.

Examples

Query:

SELECT addr, isIPv4String(addr) FROM ( SELECT ['0.0.0.0', '127.0.0.1', '::ffff:127.0.0.1'] AS addr ) ARRAY JOIN addr;

Result:

β”Œβ”€addr─────────────┬─isIPv4String(addr)─┐
β”‚ 0.0.0.0 β”‚ 1 β”‚
β”‚ 127.0.0.1 β”‚ 1 β”‚
β”‚ ::ffff:127.0.0.1 β”‚ 0 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

isIPv6String​

Determines whether the input string is an IPv6 address or not. If string is IPv4 address returns 0.

Syntax

isIPv6String(string)

Arguments

  • string β€” IP address. String.

Returned value

  • 1 if string is IPv6 address, 0 otherwise. UInt8.

Examples

Query:

SELECT addr, isIPv6String(addr) FROM ( SELECT ['::', '1111::ffff', '::ffff:127.0.0.1', '127.0.0.1'] AS addr ) ARRAY JOIN addr;

Result:

β”Œβ”€addr─────────────┬─isIPv6String(addr)─┐
β”‚ :: β”‚ 1 β”‚
β”‚ 1111::ffff β”‚ 1 β”‚
β”‚ ::ffff:127.0.0.1 β”‚ 1 β”‚
β”‚ 127.0.0.1 β”‚ 0 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

isIPAddressInRange​

Determines if an IP address is contained in a network represented in the CIDR notation. Returns 1 if true, or 0 otherwise.

Syntax

isIPAddressInRange(address, prefix)

This function accepts both IPv4 and IPv6 addresses (and networks) represented as strings. It returns 0 if the IP version of the address and the CIDR don't match.

Arguments

  • address β€” An IPv4 or IPv6 address. String.
  • prefix β€” An IPv4 or IPv6 network prefix in CIDR. String.

Returned value

Example

Query:

SELECT isIPAddressInRange('127.0.0.1', '127.0.0.0/8');

Result:

β”Œβ”€isIPAddressInRange('127.0.0.1', '127.0.0.0/8')─┐
β”‚ 1 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Query:

SELECT isIPAddressInRange('127.0.0.1', 'ffff::/16');

Result:

β”Œβ”€isIPAddressInRange('127.0.0.1', 'ffff::/16')─┐
β”‚ 0 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Query:

SELECT isIPAddressInRange('::ffff:192.168.0.1', '::ffff:192.168.0.4/128');

Result:

β”Œβ”€isIPAddressInRange('::ffff:192.168.0.1', '::ffff:192.168.0.4/128')─┐
β”‚ 0 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜