<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="nb">
	<id>https://www.wikisida.no/index.php?action=history&amp;feed=atom&amp;title=Modul%3AIP</id>
	<title>Modul:IP - Sideversjonshistorikk</title>
	<link rel="self" type="application/atom+xml" href="https://www.wikisida.no/index.php?action=history&amp;feed=atom&amp;title=Modul%3AIP"/>
	<link rel="alternate" type="text/html" href="https://www.wikisida.no/index.php?title=Modul:IP&amp;action=history"/>
	<updated>2026-04-09T14:13:27Z</updated>
	<subtitle>Versjonshistorikk for denne siden på wikien</subtitle>
	<generator>MediaWiki 1.45.1</generator>
	<entry>
		<id>https://www.wikisida.no/index.php?title=Modul:IP&amp;diff=8716&amp;oldid=prev</id>
		<title>Wikisida: Én sideversjon ble importert</title>
		<link rel="alternate" type="text/html" href="https://www.wikisida.no/index.php?title=Modul:IP&amp;diff=8716&amp;oldid=prev"/>
		<updated>2026-02-09T12:41:01Z</updated>

		<summary type="html">&lt;p&gt;Én sideversjon ble importert&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;nb&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Eldre sideversjon&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Sideversjonen fra 9. feb. 2026 kl. 12:41&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;4&quot; class=&quot;diff-notice&quot; lang=&quot;nb&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(Ingen forskjell)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;!-- diff cache key c1wiki:diff:1.41:old-8715:rev-8716 --&gt;
&lt;/table&gt;</summary>
		<author><name>Wikisida</name></author>
	</entry>
	<entry>
		<id>https://www.wikisida.no/index.php?title=Modul:IP&amp;diff=8715&amp;oldid=prev</id>
		<title>nb&gt;EdoAug: Én sideversjon ble importert fra :en:Module:IP: For å løse en skriptfeil som stammer fra Modul:IPAddress</title>
		<link rel="alternate" type="text/html" href="https://www.wikisida.no/index.php?title=Modul:IP&amp;diff=8715&amp;oldid=prev"/>
		<updated>2025-06-12T09:08:30Z</updated>

		<summary type="html">&lt;p&gt;Én sideversjon ble importert fra &lt;a href=&quot;https://en.wikipedia.org/wiki/Module:IP&quot; class=&quot;extiw&quot; title=&quot;en:Module:IP&quot;&gt;en:Module:IP&lt;/a&gt;: For å løse en skriptfeil som stammer fra Modul:IPAddress&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Ny side&lt;/b&gt;&lt;/p&gt;&lt;div&gt;-- IP library&lt;br /&gt;
-- This library contains classes for working with IP addresses and IP ranges.&lt;br /&gt;
&lt;br /&gt;
-- Load modules&lt;br /&gt;
require(&amp;#039;strict&amp;#039;)&lt;br /&gt;
local bit32 = require(&amp;#039;bit32&amp;#039;)&lt;br /&gt;
local libraryUtil = require(&amp;#039;libraryUtil&amp;#039;)&lt;br /&gt;
local checkType = libraryUtil.checkType&lt;br /&gt;
local checkTypeMulti = libraryUtil.checkTypeMulti&lt;br /&gt;
local makeCheckSelfFunction = libraryUtil.makeCheckSelfFunction&lt;br /&gt;
&lt;br /&gt;
-- Constants&lt;br /&gt;
local V4 = &amp;#039;IPv4&amp;#039;&lt;br /&gt;
local V6 = &amp;#039;IPv6&amp;#039;&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- Helper functions&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local function makeValidationFunction(className, isObjectFunc)&lt;br /&gt;
	-- Make a function for validating a specific object.&lt;br /&gt;
	return function (methodName, argIdx, arg)&lt;br /&gt;
		if not isObjectFunc(arg) then&lt;br /&gt;
			error(string.format(&lt;br /&gt;
				&amp;quot;bad argument #%d to &amp;#039;%s&amp;#039; (not a valid %s object)&amp;quot;,&lt;br /&gt;
				argIdx, methodName, className&lt;br /&gt;
			), 3)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- Collection class&lt;br /&gt;
-- This is a table used to hold items.&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local Collection = {}&lt;br /&gt;
Collection.__index = Collection&lt;br /&gt;
&lt;br /&gt;
function Collection:add(item)&lt;br /&gt;
	if item ~= nil then&lt;br /&gt;
		self.n = self.n + 1&lt;br /&gt;
		self[self.n] = item&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Collection:join(sep)&lt;br /&gt;
	return table.concat(self, sep)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Collection:remove(pos)&lt;br /&gt;
	if self.n &amp;gt; 0 and (pos == nil or (0 &amp;lt; pos and pos &amp;lt;= self.n)) then&lt;br /&gt;
		self.n = self.n - 1&lt;br /&gt;
		return table.remove(self, pos)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Collection:sort(comp)&lt;br /&gt;
	table.sort(self, comp)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Collection:deobjectify()&lt;br /&gt;
	-- Turns the collection into a plain array without any special properties&lt;br /&gt;
	-- or methods.&lt;br /&gt;
	self.n = nil&lt;br /&gt;
	setmetatable(self, nil)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Collection.new()&lt;br /&gt;
	return setmetatable({n = 0}, Collection)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- RawIP class&lt;br /&gt;
-- Numeric representation of an IPv4 or IPv6 address. Used internally.&lt;br /&gt;
-- A RawIP object is constructed by adding data to a Collection object and&lt;br /&gt;
-- then giving it a new metatable. This is to avoid the memory overhead of&lt;br /&gt;
-- copying the data to a new table.&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local RawIP = {}&lt;br /&gt;
RawIP.__index = RawIP&lt;br /&gt;
&lt;br /&gt;
-- Constructors&lt;br /&gt;
function RawIP.newFromIPv4(ipStr)&lt;br /&gt;
	-- Return a RawIP object if ipStr is a valid IPv4 string. Otherwise,&lt;br /&gt;
	-- return nil.&lt;br /&gt;
	-- This representation is for compatibility with IPv6 addresses.&lt;br /&gt;
	local octets = Collection.new()&lt;br /&gt;
	local s = ipStr:match(&amp;#039;^%s*(.-)%s*$&amp;#039;) .. &amp;#039;.&amp;#039;&lt;br /&gt;
	for item in s:gmatch(&amp;#039;(.-)%.&amp;#039;) do&lt;br /&gt;
		octets:add(item)&lt;br /&gt;
	end&lt;br /&gt;
	if octets.n == 4 then&lt;br /&gt;
		for i, s in ipairs(octets) do&lt;br /&gt;
			if s:match(&amp;#039;^%d+$&amp;#039;) then&lt;br /&gt;
				local num = tonumber(s)&lt;br /&gt;
				if 0 &amp;lt;= num and num &amp;lt;= 255 then&lt;br /&gt;
					if num &amp;gt; 0 and s:match(&amp;#039;^0&amp;#039;) then&lt;br /&gt;
						-- A redundant leading zero is for an IP in octal.&lt;br /&gt;
						return nil&lt;br /&gt;
					end&lt;br /&gt;
					octets[i] = num&lt;br /&gt;
				else&lt;br /&gt;
					return nil&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				return nil&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		local parts = Collection.new()&lt;br /&gt;
		for i = 1, 3, 2 do&lt;br /&gt;
			parts:add(octets[i] * 256 + octets[i+1])&lt;br /&gt;
		end&lt;br /&gt;
		return setmetatable(parts, RawIP)&lt;br /&gt;
	end&lt;br /&gt;
	return nil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function RawIP.newFromIPv6(ipStr)&lt;br /&gt;
	-- Return a RawIP object if ipStr is a valid IPv6 string. Otherwise,&lt;br /&gt;
	-- return nil.&lt;br /&gt;
	ipStr = ipStr:match(&amp;#039;^%s*(.-)%s*$&amp;#039;)&lt;br /&gt;
	local _, n = ipStr:gsub(&amp;#039;:&amp;#039;, &amp;#039;:&amp;#039;)&lt;br /&gt;
	if n &amp;lt; 7 then&lt;br /&gt;
		ipStr = ipStr:gsub(&amp;#039;::&amp;#039;, string.rep(&amp;#039;:&amp;#039;, 9 - n))&lt;br /&gt;
	end&lt;br /&gt;
	local parts = Collection.new()&lt;br /&gt;
	for item in (ipStr .. &amp;#039;:&amp;#039;):gmatch(&amp;#039;(.-):&amp;#039;) do&lt;br /&gt;
		parts:add(item)&lt;br /&gt;
	end&lt;br /&gt;
	if parts.n == 8 then&lt;br /&gt;
		for i, s in ipairs(parts) do&lt;br /&gt;
			if s == &amp;#039;&amp;#039; then&lt;br /&gt;
				parts[i] = 0&lt;br /&gt;
			else&lt;br /&gt;
				if s:match(&amp;#039;^%x+$&amp;#039;) then&lt;br /&gt;
					local num = tonumber(s, 16)&lt;br /&gt;
					if num and 0 &amp;lt;= num and num &amp;lt;= 65535 then&lt;br /&gt;
						parts[i] = num&lt;br /&gt;
					else&lt;br /&gt;
						return nil&lt;br /&gt;
					end&lt;br /&gt;
				else&lt;br /&gt;
					return nil&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return setmetatable(parts, RawIP)&lt;br /&gt;
	end&lt;br /&gt;
	return nil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function RawIP.newFromIP(ipStr)&lt;br /&gt;
	-- Return a new RawIP object from either an IPv4 string or an IPv6&lt;br /&gt;
	-- string. If ipStr is not a valid IPv4 or IPv6 string, then return&lt;br /&gt;
	-- nil.&lt;br /&gt;
	return RawIP.newFromIPv4(ipStr) or RawIP.newFromIPv6(ipStr)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Methods&lt;br /&gt;
function RawIP:getVersion()&lt;br /&gt;
	-- Return a string with the version of the IP protocol we are using.&lt;br /&gt;
	return self.n == 2 and V4 or V6&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function RawIP:isIPv4()&lt;br /&gt;
	-- Return true if this is an IPv4 representation, and false otherwise.&lt;br /&gt;
	return self.n == 2&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function RawIP:isIPv6()&lt;br /&gt;
	-- Return true if this is an IPv6 representation, and false otherwise.&lt;br /&gt;
	return self.n == 8&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function RawIP:getBitLength()&lt;br /&gt;
	-- Return the bit length of the IP address.&lt;br /&gt;
	return self.n * 16&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function RawIP:getAdjacent(previous)&lt;br /&gt;
	-- Return a RawIP object for an adjacent IP address. If previous is true&lt;br /&gt;
	-- then the previous IP is returned; otherwise the next IP is returned.&lt;br /&gt;
	-- Will wraparound:&lt;br /&gt;
	--   next      255.255.255.255 → 0.0.0.0&lt;br /&gt;
	--             ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff → ::&lt;br /&gt;
	--   previous  0.0.0.0 → 255.255.255.255&lt;br /&gt;
	--             :: → ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff&lt;br /&gt;
	local result = Collection.new()&lt;br /&gt;
	result.n = self.n&lt;br /&gt;
	local carry = previous and 0xffff or 1&lt;br /&gt;
	for i = self.n, 1, -1 do&lt;br /&gt;
		local sum = self[i] + carry&lt;br /&gt;
		if sum &amp;gt;= 0x10000 then&lt;br /&gt;
			carry = previous and 0x10000 or 1&lt;br /&gt;
			sum = sum - 0x10000&lt;br /&gt;
		else&lt;br /&gt;
			carry = previous and 0xffff or 0&lt;br /&gt;
		end&lt;br /&gt;
		result[i] = sum&lt;br /&gt;
	end&lt;br /&gt;
	return setmetatable(result, RawIP)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function RawIP:getPrefix(bitLength)&lt;br /&gt;
	-- Return a RawIP object for the prefix of the current IP Address with a&lt;br /&gt;
	-- bit length of bitLength.&lt;br /&gt;
	local result = Collection.new()&lt;br /&gt;
	result.n = self.n&lt;br /&gt;
	for i = 1, self.n do&lt;br /&gt;
		if bitLength &amp;gt; 0 then&lt;br /&gt;
			if bitLength &amp;gt;= 16 then&lt;br /&gt;
				result[i] = self[i]&lt;br /&gt;
				bitLength = bitLength - 16&lt;br /&gt;
			else&lt;br /&gt;
				result[i] = bit32.replace(self[i], 0, 0, 16 - bitLength)&lt;br /&gt;
				bitLength = 0&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			result[i] = 0&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return setmetatable(result, RawIP)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function RawIP:getHighestHost(bitLength)&lt;br /&gt;
	-- Return a RawIP object for the highest IP with the prefix of length&lt;br /&gt;
	-- bitLength. In other words, the network (the most-significant bits)&lt;br /&gt;
	-- is the same as the current IP&amp;#039;s, but the host bits (the&lt;br /&gt;
	-- least-significant bits) are all set to 1.&lt;br /&gt;
	local bits = self.n * 16&lt;br /&gt;
	local width&lt;br /&gt;
	if bitLength &amp;lt;= 0 then&lt;br /&gt;
		width = bits&lt;br /&gt;
	elseif bitLength &amp;gt;= bits then&lt;br /&gt;
		width = 0&lt;br /&gt;
	else&lt;br /&gt;
		width = bits - bitLength&lt;br /&gt;
	end&lt;br /&gt;
	local result = Collection.new()&lt;br /&gt;
	result.n = self.n&lt;br /&gt;
	for i = self.n, 1, -1 do&lt;br /&gt;
		if width &amp;gt; 0 then&lt;br /&gt;
			if width &amp;gt;= 16 then&lt;br /&gt;
				result[i] = 0xffff&lt;br /&gt;
				width = width - 16&lt;br /&gt;
			else&lt;br /&gt;
				result[i] = bit32.replace(self[i], 0xffff, 0, width)&lt;br /&gt;
				width = 0&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			result[i] = self[i]&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return setmetatable(result, RawIP)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function RawIP:_makeIPv6String()&lt;br /&gt;
	-- Return an IPv6 string representation of the object. Behavior is&lt;br /&gt;
	-- undefined if the current object is IPv4.&lt;br /&gt;
	local z1, z2  -- indices of run of zeroes to be displayed as &amp;quot;::&amp;quot;&lt;br /&gt;
	local zstart, zcount&lt;br /&gt;
	for i = 1, 9 do&lt;br /&gt;
		-- Find left-most occurrence of longest run of two or more zeroes.&lt;br /&gt;
		if i &amp;lt; 9 and self[i] == 0 then&lt;br /&gt;
			if zstart then&lt;br /&gt;
				zcount = zcount + 1&lt;br /&gt;
			else&lt;br /&gt;
				zstart = i&lt;br /&gt;
				zcount = 1&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			if zcount and zcount &amp;gt; 1 then&lt;br /&gt;
				if not z1 or zcount &amp;gt; z2 - z1 + 1 then&lt;br /&gt;
					z1 = zstart&lt;br /&gt;
					z2 = zstart + zcount - 1&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			zstart = nil&lt;br /&gt;
			zcount = nil&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local parts = Collection.new()&lt;br /&gt;
	for i = 1, 8 do&lt;br /&gt;
		if z1 and z1 &amp;lt;= i and i &amp;lt;= z2 then&lt;br /&gt;
			if i == z1 then&lt;br /&gt;
				if z1 == 1 or z2 == 8 then&lt;br /&gt;
					if z1 == 1 and z2 == 8 then&lt;br /&gt;
						return &amp;#039;::&amp;#039;&lt;br /&gt;
					end&lt;br /&gt;
					parts:add(&amp;#039;:&amp;#039;)&lt;br /&gt;
				else&lt;br /&gt;
					parts:add(&amp;#039;&amp;#039;)&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			parts:add(string.format(&amp;#039;%x&amp;#039;, self[i]))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return parts:join(&amp;#039;:&amp;#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function RawIP:_makeIPv4String()&lt;br /&gt;
	-- Return an IPv4 string representation of the object. Behavior is&lt;br /&gt;
	-- undefined if the current object is IPv6.&lt;br /&gt;
	local parts = Collection.new()&lt;br /&gt;
	for i = 1, 2 do&lt;br /&gt;
		local w = self[i]&lt;br /&gt;
		parts:add(math.floor(w / 256))&lt;br /&gt;
		parts:add(w % 256)&lt;br /&gt;
	end&lt;br /&gt;
	return parts:join(&amp;#039;.&amp;#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function RawIP:__tostring()&lt;br /&gt;
	-- Return a string equivalent to given IP address (IPv4 or IPv6).&lt;br /&gt;
	if self.n == 2 then&lt;br /&gt;
		return self:_makeIPv4String()&lt;br /&gt;
	else&lt;br /&gt;
		return self:_makeIPv6String()&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function RawIP:__lt(obj)&lt;br /&gt;
	if self.n == obj.n then&lt;br /&gt;
		for i = 1, self.n do&lt;br /&gt;
			if self[i] ~= obj[i] then&lt;br /&gt;
				return self[i] &amp;lt; obj[i]&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	return self.n &amp;lt; obj.n&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function RawIP:__eq(obj)&lt;br /&gt;
	if self.n == obj.n then&lt;br /&gt;
		for i = 1, self.n do&lt;br /&gt;
			if self[i] ~= obj[i] then&lt;br /&gt;
				return false&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return true&lt;br /&gt;
	end&lt;br /&gt;
	return false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- Initialize private methods available to IPAddress and Subnet&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
-- Both IPAddress and Subnet need access to each others&amp;#039; private constructor&lt;br /&gt;
-- functions. IPAddress must be able to make Subnet objects from CIDR strings&lt;br /&gt;
-- and from RawIP objects, and Subnet must be able to make IPAddress objects&lt;br /&gt;
-- from IP strings and from RawIP objects. These constructors must all be&lt;br /&gt;
-- private to ensure correct error levels and to stop other modules from having&lt;br /&gt;
-- to worry about RawIP objects. Because they are private, they must be&lt;br /&gt;
-- initialized here.&lt;br /&gt;
local makeIPAddress, makeIPAddressFromRaw, makeSubnet, makeSubnetFromRaw&lt;br /&gt;
&lt;br /&gt;
-- Objects need to be able to validate other objects that they are passed&lt;br /&gt;
-- as input, so initialize those functions here as well.&lt;br /&gt;
local validateCollection, validateIPAddress, validateSubnet&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- IPAddress class&lt;br /&gt;
-- Represents a single IPv4 or IPv6 address.&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local IPAddress = {}&lt;br /&gt;
&lt;br /&gt;
do&lt;br /&gt;
	-- dataKey is a unique key to access objects&amp;#039; internal data. This is needed&lt;br /&gt;
	-- to access the RawIP objects contained in other IPAddress objects so that&lt;br /&gt;
	-- they can be compared with the current object&amp;#039;s RawIP object. This data&lt;br /&gt;
	-- is not available to other classes or other modules.&lt;br /&gt;
	local dataKey = {}&lt;br /&gt;
&lt;br /&gt;
	-- Private static methods&lt;br /&gt;
	local function isIPAddressObject(val)&lt;br /&gt;
		return type(val) == &amp;#039;table&amp;#039; and val[dataKey] ~= nil&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	validateIPAddress = makeValidationFunction(&amp;#039;IPAddress&amp;#039;, isIPAddressObject)&lt;br /&gt;
&lt;br /&gt;
	-- Metamethods that don&amp;#039;t need upvalues&lt;br /&gt;
	local function ipEquals(ip1, ip2)&lt;br /&gt;
		return ip1[dataKey].rawIP == ip2[dataKey].rawIP&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function ipLessThan(ip1, ip2)&lt;br /&gt;
		return ip1[dataKey].rawIP &amp;lt; ip2[dataKey].rawIP&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function concatIP(ip, val)&lt;br /&gt;
		return tostring(ip) .. tostring(val)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function ipToString(ip)&lt;br /&gt;
		return ip:getIP()&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Constructors&lt;br /&gt;
	makeIPAddressFromRaw = function (rawIP)&lt;br /&gt;
		-- Constructs a new IPAddress object from a rawIP object. This function&lt;br /&gt;
		-- is for internal use; it is called by IPAddress.new and from other&lt;br /&gt;
		-- IPAddress methods, and should be available to the Subnet class, but&lt;br /&gt;
		-- should not be available to other modules.&lt;br /&gt;
		assert(type(rawIP) == &amp;#039;table&amp;#039;, &amp;#039;rawIP was type &amp;#039; .. type(rawIP) .. &amp;#039;; expected type table&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
		-- Set up structure&lt;br /&gt;
		local obj = {}&lt;br /&gt;
		local data = {}&lt;br /&gt;
		data.rawIP = rawIP&lt;br /&gt;
&lt;br /&gt;
		-- A function to check whether methods are called with a valid self&lt;br /&gt;
		-- parameter.&lt;br /&gt;
		local checkSelf = makeCheckSelfFunction(&lt;br /&gt;
			&amp;#039;IP&amp;#039;,&lt;br /&gt;
			&amp;#039;ipAddress&amp;#039;,&lt;br /&gt;
			obj,&lt;br /&gt;
			&amp;#039;IPAddress object&amp;#039;&lt;br /&gt;
		)&lt;br /&gt;
&lt;br /&gt;
		-- Public methods&lt;br /&gt;
		function obj:getIP()&lt;br /&gt;
			checkSelf(self, &amp;#039;getIP&amp;#039;)&lt;br /&gt;
			return tostring(data.rawIP)&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		function obj:getVersion()&lt;br /&gt;
			checkSelf(self, &amp;#039;getVersion&amp;#039;)&lt;br /&gt;
			return data.rawIP:getVersion()&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		function obj:isIPv4()&lt;br /&gt;
			checkSelf(self, &amp;#039;isIPv4&amp;#039;)&lt;br /&gt;
			return data.rawIP:isIPv4()&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		function obj:isIPv6()&lt;br /&gt;
			checkSelf(self, &amp;#039;isIPv6&amp;#039;)&lt;br /&gt;
			return data.rawIP:isIPv6()&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		function obj:isInCollection(collection)&lt;br /&gt;
			checkSelf(self, &amp;#039;isInCollection&amp;#039;)&lt;br /&gt;
			validateCollection(&amp;#039;isInCollection&amp;#039;, 1, collection)&lt;br /&gt;
			return collection:containsIP(self)&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		function obj:isInSubnet(subnet)&lt;br /&gt;
			checkSelf(self, &amp;#039;isInSubnet&amp;#039;)&lt;br /&gt;
			local tp = type(subnet)&lt;br /&gt;
			if tp == &amp;#039;string&amp;#039; then&lt;br /&gt;
				subnet = makeSubnet(subnet)&lt;br /&gt;
			elseif tp == &amp;#039;table&amp;#039; then&lt;br /&gt;
				validateSubnet(&amp;#039;isInSubnet&amp;#039;, 1, subnet)&lt;br /&gt;
			else&lt;br /&gt;
				checkTypeMulti(&amp;#039;isInSubnet&amp;#039;, 1, subnet, {&amp;#039;string&amp;#039;, &amp;#039;table&amp;#039;})&lt;br /&gt;
			end&lt;br /&gt;
			return subnet:containsIP(self)&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		function obj:getSubnet(bitLength)&lt;br /&gt;
			checkSelf(self, &amp;#039;getSubnet&amp;#039;)&lt;br /&gt;
			checkType(&amp;#039;getSubnet&amp;#039;, 1, bitLength, &amp;#039;number&amp;#039;)&lt;br /&gt;
			if bitLength &amp;lt; 0&lt;br /&gt;
				or bitLength &amp;gt; data.rawIP:getBitLength()&lt;br /&gt;
				or bitLength ~= math.floor(bitLength)&lt;br /&gt;
			then&lt;br /&gt;
				error(string.format(&lt;br /&gt;
					&amp;quot;bad argument #1 to &amp;#039;getSubnet&amp;#039; (must be an integer between 0 and %d)&amp;quot;,&lt;br /&gt;
					data.rawIP:getBitLength()&lt;br /&gt;
				), 2)&lt;br /&gt;
			end&lt;br /&gt;
			return makeSubnetFromRaw(data.rawIP, bitLength)&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		function obj:getNextIP()&lt;br /&gt;
			checkSelf(self, &amp;#039;getNextIP&amp;#039;)&lt;br /&gt;
			return makeIPAddressFromRaw(data.rawIP:getAdjacent())&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		function obj:getPreviousIP()&lt;br /&gt;
			checkSelf(self, &amp;#039;getPreviousIP&amp;#039;)&lt;br /&gt;
			return makeIPAddressFromRaw(data.rawIP:getAdjacent(true))&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		-- Metamethods&lt;br /&gt;
		return setmetatable(obj, {&lt;br /&gt;
			__eq = ipEquals,&lt;br /&gt;
			__lt = ipLessThan,&lt;br /&gt;
			__concat = concatIP,&lt;br /&gt;
			__tostring = ipToString,&lt;br /&gt;
			__index = function (self, key)&lt;br /&gt;
				-- If any code knows the unique data key, allow it to access&lt;br /&gt;
				-- the data table.&lt;br /&gt;
				if key == dataKey then&lt;br /&gt;
					return data&lt;br /&gt;
				end&lt;br /&gt;
			end,&lt;br /&gt;
			__metatable = false, -- don&amp;#039;t allow access to the metatable&lt;br /&gt;
		})&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	makeIPAddress = function (ip)&lt;br /&gt;
		local rawIP = RawIP.newFromIP(ip)&lt;br /&gt;
		if not rawIP then&lt;br /&gt;
			error(string.format(&amp;quot;&amp;#039;%s&amp;#039; is an invalid IP address&amp;quot;, ip), 3)&lt;br /&gt;
		end&lt;br /&gt;
		return makeIPAddressFromRaw(rawIP)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	function IPAddress.new(ip)&lt;br /&gt;
		checkType(&amp;#039;IPAddress.new&amp;#039;, 1, ip, &amp;#039;string&amp;#039;)&lt;br /&gt;
		return makeIPAddress(ip)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- Subnet class&lt;br /&gt;
-- Represents a block of IPv4 or IPv6 addresses.&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local Subnet = {}&lt;br /&gt;
&lt;br /&gt;
do&lt;br /&gt;
	-- uniqueKey is a unique, private key used to test whether a given object&lt;br /&gt;
	-- is a Subnet object.&lt;br /&gt;
	local uniqueKey = {}&lt;br /&gt;
&lt;br /&gt;
	-- Metatable&lt;br /&gt;
	local mt = {&lt;br /&gt;
		__index = function (self, key)&lt;br /&gt;
			if key == uniqueKey then&lt;br /&gt;
				return true&lt;br /&gt;
			end&lt;br /&gt;
		end,&lt;br /&gt;
		__eq = function (self, obj)&lt;br /&gt;
			return self:getCIDR() == obj:getCIDR()&lt;br /&gt;
		end,&lt;br /&gt;
		__concat = function (self, obj)&lt;br /&gt;
			return tostring(self) .. tostring(obj)&lt;br /&gt;
		end,&lt;br /&gt;
		__tostring = function (self)&lt;br /&gt;
			return self:getCIDR()&lt;br /&gt;
		end,&lt;br /&gt;
		__metatable = false&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	-- Private static methods&lt;br /&gt;
	local function isSubnetObject(val)&lt;br /&gt;
		-- Return true if val is a Subnet object, and false otherwise.&lt;br /&gt;
		return type(val) == &amp;#039;table&amp;#039; and val[uniqueKey] ~= nil&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Function to validate subnet objects.&lt;br /&gt;
	-- Params:&lt;br /&gt;
	-- methodName (string) - the name of the method being validated&lt;br /&gt;
	-- argIdx (number) - the position of the argument in the argument list&lt;br /&gt;
	-- arg - the argument to be validated&lt;br /&gt;
	validateSubnet = makeValidationFunction(&amp;#039;Subnet&amp;#039;, isSubnetObject)&lt;br /&gt;
&lt;br /&gt;
	-- Constructors&lt;br /&gt;
	makeSubnetFromRaw = function (rawIP, bitLength)&lt;br /&gt;
		-- Set up structure&lt;br /&gt;
		local obj = setmetatable({}, mt)&lt;br /&gt;
		local data = {&lt;br /&gt;
			rawIP = rawIP,&lt;br /&gt;
			bitLength = bitLength,&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		-- A function to check whether methods are called with a valid self&lt;br /&gt;
		-- parameter.&lt;br /&gt;
		local checkSelf = makeCheckSelfFunction(&lt;br /&gt;
			&amp;#039;IP&amp;#039;,&lt;br /&gt;
			&amp;#039;subnet&amp;#039;,&lt;br /&gt;
			obj,&lt;br /&gt;
			&amp;#039;Subnet object&amp;#039;&lt;br /&gt;
		)&lt;br /&gt;
&lt;br /&gt;
		-- Public methods&lt;br /&gt;
		function obj:getPrefix()&lt;br /&gt;
			checkSelf(self, &amp;#039;getPrefix&amp;#039;)&lt;br /&gt;
			if not data.prefix then&lt;br /&gt;
				data.prefix = makeIPAddressFromRaw(&lt;br /&gt;
					data.rawIP:getPrefix(data.bitLength)&lt;br /&gt;
				)&lt;br /&gt;
			end&lt;br /&gt;
			return data.prefix&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		function obj:getHighestIP()&lt;br /&gt;
			checkSelf(self, &amp;#039;getHighestIP&amp;#039;)&lt;br /&gt;
			if not data.highestIP then&lt;br /&gt;
				data.highestIP = makeIPAddressFromRaw(&lt;br /&gt;
					data.rawIP:getHighestHost(data.bitLength)&lt;br /&gt;
				)&lt;br /&gt;
			end&lt;br /&gt;
			return data.highestIP&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		function obj:getBitLength()&lt;br /&gt;
			checkSelf(self, &amp;#039;getBitLength&amp;#039;)&lt;br /&gt;
			return data.bitLength&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		function obj:getCIDR()&lt;br /&gt;
			checkSelf(self, &amp;#039;getCIDR&amp;#039;)&lt;br /&gt;
			return string.format(&lt;br /&gt;
				&amp;#039;%s/%d&amp;#039;,&lt;br /&gt;
				tostring(self:getPrefix()), self:getBitLength()&lt;br /&gt;
			)&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		function obj:getVersion()&lt;br /&gt;
			checkSelf(self, &amp;#039;getVersion&amp;#039;)&lt;br /&gt;
			return data.rawIP:getVersion()&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		function obj:isIPv4()&lt;br /&gt;
			checkSelf(self, &amp;#039;isIPv4&amp;#039;)&lt;br /&gt;
			return data.rawIP:isIPv4()&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		function obj:isIPv6()&lt;br /&gt;
			checkSelf(self, &amp;#039;isIPv6&amp;#039;)&lt;br /&gt;
			return data.rawIP:isIPv6()&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		function obj:containsIP(ip)&lt;br /&gt;
			checkSelf(self, &amp;#039;containsIP&amp;#039;)&lt;br /&gt;
			local tp = type(ip)&lt;br /&gt;
			if tp == &amp;#039;string&amp;#039; then&lt;br /&gt;
				ip = makeIPAddress(ip)&lt;br /&gt;
			elseif tp == &amp;#039;table&amp;#039; then&lt;br /&gt;
				validateIPAddress(&amp;#039;containsIP&amp;#039;, 1, ip)&lt;br /&gt;
			else&lt;br /&gt;
				checkTypeMulti(&amp;#039;containsIP&amp;#039;, 1, ip, {&amp;#039;string&amp;#039;, &amp;#039;table&amp;#039;})&lt;br /&gt;
			end&lt;br /&gt;
			if self:getVersion() == ip:getVersion() then&lt;br /&gt;
				return self:getPrefix() &amp;lt;= ip and ip &amp;lt;= self:getHighestIP()&lt;br /&gt;
			end&lt;br /&gt;
			return false&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		function obj:overlapsCollection(collection)&lt;br /&gt;
			checkSelf(self, &amp;#039;overlapsCollection&amp;#039;)&lt;br /&gt;
			validateCollection(&amp;#039;overlapsCollection&amp;#039;, 1, collection)&lt;br /&gt;
			return collection:overlapsSubnet(self)&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		function obj:overlapsSubnet(subnet)&lt;br /&gt;
			checkSelf(self, &amp;#039;overlapsSubnet&amp;#039;)&lt;br /&gt;
			local tp = type(subnet)&lt;br /&gt;
			if tp == &amp;#039;string&amp;#039; then&lt;br /&gt;
				subnet = makeSubnet(subnet)&lt;br /&gt;
			elseif tp == &amp;#039;table&amp;#039; then&lt;br /&gt;
				validateSubnet(&amp;#039;overlapsSubnet&amp;#039;, 1, subnet)&lt;br /&gt;
			else&lt;br /&gt;
				checkTypeMulti(&amp;#039;overlapsSubnet&amp;#039;, 1, subnet, {&amp;#039;string&amp;#039;, &amp;#039;table&amp;#039;})&lt;br /&gt;
			end&lt;br /&gt;
			if self:getVersion() == subnet:getVersion() then&lt;br /&gt;
				return (&lt;br /&gt;
					subnet:getHighestIP() &amp;gt;= self:getPrefix() and&lt;br /&gt;
					subnet:getPrefix() &amp;lt;= self:getHighestIP()&lt;br /&gt;
				)&lt;br /&gt;
			end&lt;br /&gt;
			return false&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		function obj:walk()&lt;br /&gt;
			checkSelf(self, &amp;#039;walk&amp;#039;)&lt;br /&gt;
			local started&lt;br /&gt;
			local current = self:getPrefix()&lt;br /&gt;
			local highest = self:getHighestIP()&lt;br /&gt;
			return function ()&lt;br /&gt;
				if not started then&lt;br /&gt;
					started = true&lt;br /&gt;
					return current&lt;br /&gt;
				end&lt;br /&gt;
				if current &amp;lt; highest then&lt;br /&gt;
					current = current:getNextIP()&lt;br /&gt;
					return current&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		return obj&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	makeSubnet = function (cidr)&lt;br /&gt;
		-- Return a Subnet object from a CIDR string. If the CIDR string is&lt;br /&gt;
		-- invalid, throw an error.&lt;br /&gt;
		local lhs, rhs = cidr:match(&amp;#039;^%s*(.-)/(%d+)%s*$&amp;#039;)&lt;br /&gt;
		if lhs then&lt;br /&gt;
			local bits = lhs:find(&amp;#039;:&amp;#039;, 1, true) and 128 or 32&lt;br /&gt;
			local n = tonumber(rhs)&lt;br /&gt;
			if n and n &amp;lt;= bits and (n == 0 or not rhs:find(&amp;#039;^0&amp;#039;)) then&lt;br /&gt;
				-- The right-hand side is a number between 0 and 32 (for IPv4)&lt;br /&gt;
				-- or 0 and 128 (for IPv6) and doesn&amp;#039;t have any leading zeroes.&lt;br /&gt;
				local base = RawIP.newFromIP(lhs)&lt;br /&gt;
				if base then&lt;br /&gt;
					-- The left-hand side is a valid IP address.&lt;br /&gt;
					local prefix = base:getPrefix(n)&lt;br /&gt;
					if base == prefix then&lt;br /&gt;
						-- The left-hand side is the lowest IP in the subnet.&lt;br /&gt;
						return makeSubnetFromRaw(prefix, n)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		error(string.format(&amp;quot;&amp;#039;%s&amp;#039; is an invalid CIDR string&amp;quot;, cidr), 3)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	function Subnet.new(cidr)&lt;br /&gt;
		checkType(&amp;#039;Subnet.new&amp;#039;, 1, cidr, &amp;#039;string&amp;#039;)&lt;br /&gt;
		return makeSubnet(cidr)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- Ranges class&lt;br /&gt;
-- Holds a list of IPAdress pairs representing contiguous IP ranges.&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local Ranges = Collection.new()&lt;br /&gt;
Ranges.__index = Ranges&lt;br /&gt;
&lt;br /&gt;
function Ranges.new()&lt;br /&gt;
	return setmetatable({}, Ranges)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Ranges:add(ip1, ip2)&lt;br /&gt;
	validateIPAddress(&amp;#039;add&amp;#039;, 1, ip1)&lt;br /&gt;
	if ip2 ~= nil then&lt;br /&gt;
		validateIPAddress(&amp;#039;add&amp;#039;, 2, ip2)&lt;br /&gt;
		if ip1 &amp;gt; ip2 then&lt;br /&gt;
			error(&amp;#039;The first IP must be less than or equal to the second&amp;#039;, 2)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	Collection.add(self, {ip1, ip2 or ip1})&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Ranges:merge()&lt;br /&gt;
	self:sort(&lt;br /&gt;
		function (lhs, rhs)&lt;br /&gt;
			-- Sort by second value, then first.&lt;br /&gt;
			if lhs[2] == rhs[2] then&lt;br /&gt;
				return lhs[1] &amp;lt; rhs[1]&lt;br /&gt;
			end&lt;br /&gt;
			return lhs[2] &amp;lt; rhs[2]&lt;br /&gt;
		end&lt;br /&gt;
	)&lt;br /&gt;
	local pos = self.n&lt;br /&gt;
	while pos &amp;gt; 1 do&lt;br /&gt;
		for i = pos - 1, 1, -1 do&lt;br /&gt;
			local ip1 = self[i][2]&lt;br /&gt;
			local ip2 = ip1:getNextIP()&lt;br /&gt;
			if ip2 &amp;lt; ip1 then&lt;br /&gt;
				ip2 = ip1  -- don&amp;#039;t wrap around&lt;br /&gt;
			end&lt;br /&gt;
			if self[pos][1] &amp;gt; ip2 then&lt;br /&gt;
				break&lt;br /&gt;
			end&lt;br /&gt;
			ip1 = self[i][1]&lt;br /&gt;
			ip2 = self[pos][1]&lt;br /&gt;
			self[i] = {ip1 &amp;gt; ip2 and ip2 or ip1, self[pos][2]}&lt;br /&gt;
			self:remove(pos)&lt;br /&gt;
			pos = pos - 1&lt;br /&gt;
			if pos &amp;lt;= 1 then&lt;br /&gt;
				break&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		pos = pos - 1&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- IPCollection class&lt;br /&gt;
-- Holds a list of IP addresses/subnets. Used internally.&lt;br /&gt;
-- Each address/subnet has the same version (either IPv4 or IPv6).&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local IPCollection = {}&lt;br /&gt;
IPCollection.__index = IPCollection&lt;br /&gt;
&lt;br /&gt;
function IPCollection.new(version)&lt;br /&gt;
	assert(&lt;br /&gt;
		version == V4 or version == V6,&lt;br /&gt;
		&amp;#039;IPCollection.new called with an invalid version&amp;#039;&lt;br /&gt;
	)&lt;br /&gt;
	local obj = {&lt;br /&gt;
		version = version,               -- V4 or V6&lt;br /&gt;
		addresses = Collection.new(),    -- valid IP addresses&lt;br /&gt;
		subnets = Collection.new(),      -- valid subnets&lt;br /&gt;
		omitted = Collection.new(),      -- not-quite valid strings&lt;br /&gt;
	}&lt;br /&gt;
	return obj&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function IPCollection:getVersion()&lt;br /&gt;
	-- Return a string with the IP version of addresses in this collection.&lt;br /&gt;
	return self.version&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function IPCollection:_store(hit, stripColons)&lt;br /&gt;
	local maker, location&lt;br /&gt;
	if hit:find(&amp;#039;/&amp;#039;, 1, true) then&lt;br /&gt;
		maker = Subnet.new&lt;br /&gt;
		location = self.subnets&lt;br /&gt;
	else&lt;br /&gt;
		maker = IPAddress.new&lt;br /&gt;
		location = self.addresses&lt;br /&gt;
	end&lt;br /&gt;
	local success, obj = pcall(maker, hit)&lt;br /&gt;
	if success then&lt;br /&gt;
		location:add(obj)&lt;br /&gt;
	else&lt;br /&gt;
		if stripColons then&lt;br /&gt;
			local colons, hit = hit:match(&amp;#039;^(:*)(.*)&amp;#039;)&lt;br /&gt;
			if colons ~= &amp;#039;&amp;#039; then&lt;br /&gt;
				self:_store(hit)&lt;br /&gt;
				return&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		self.omitted:add(hit)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function IPCollection:_assertVersion(version, msg)&lt;br /&gt;
	if self.version ~= version then&lt;br /&gt;
		error(msg, 3)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function IPCollection:addIP(ip)&lt;br /&gt;
	local tp = type(ip)&lt;br /&gt;
	if tp == &amp;#039;string&amp;#039; then&lt;br /&gt;
		ip = makeIPAddress(ip)&lt;br /&gt;
	elseif tp == &amp;#039;table&amp;#039; then&lt;br /&gt;
		validateIPAddress(&amp;#039;addIP&amp;#039;, 1, ip)&lt;br /&gt;
	else&lt;br /&gt;
		checkTypeMulti(&amp;#039;addIP&amp;#039;, 1, ip, {&amp;#039;string&amp;#039;, &amp;#039;table&amp;#039;})&lt;br /&gt;
	end&lt;br /&gt;
	self:_assertVersion(ip:getVersion(), &amp;#039;addIP called with incorrect IP version&amp;#039;)&lt;br /&gt;
	self.addresses:add(ip)&lt;br /&gt;
	return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function IPCollection:addSubnet(subnet)&lt;br /&gt;
	local tp = type(subnet)&lt;br /&gt;
	if tp == &amp;#039;string&amp;#039; then&lt;br /&gt;
		subnet = makeSubnet(subnet)&lt;br /&gt;
	elseif tp == &amp;#039;table&amp;#039; then&lt;br /&gt;
		validateSubnet(&amp;#039;addSubnet&amp;#039;, 1, subnet)&lt;br /&gt;
	else&lt;br /&gt;
		checkTypeMulti(&amp;#039;addSubnet&amp;#039;, 1, subnet, {&amp;#039;string&amp;#039;, &amp;#039;table&amp;#039;})&lt;br /&gt;
	end&lt;br /&gt;
	self:_assertVersion(subnet:getVersion(), &amp;#039;addSubnet called with incorrect subnet version&amp;#039;)&lt;br /&gt;
	self.subnets:add(subnet)&lt;br /&gt;
	return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function IPCollection:containsIP(ip)&lt;br /&gt;
	-- Return true, obj if ip is in this collection,&lt;br /&gt;
	-- where obj is the first IPAddress or Subnet with the ip.&lt;br /&gt;
	-- Otherwise, return false.&lt;br /&gt;
	local tp = type(ip)&lt;br /&gt;
	if tp == &amp;#039;string&amp;#039; then&lt;br /&gt;
		ip = makeIPAddress(ip)&lt;br /&gt;
	elseif tp == &amp;#039;table&amp;#039; then&lt;br /&gt;
		validateIPAddress(&amp;#039;containsIP&amp;#039;, 1, ip)&lt;br /&gt;
	else&lt;br /&gt;
		checkTypeMulti(&amp;#039;containsIP&amp;#039;, 1, ip, {&amp;#039;string&amp;#039;, &amp;#039;table&amp;#039;})&lt;br /&gt;
	end&lt;br /&gt;
	if self:getVersion() == ip:getVersion() then&lt;br /&gt;
		for _, item in ipairs(self.addresses) do&lt;br /&gt;
			if item == ip then&lt;br /&gt;
				return true, item&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		for _, item in ipairs(self.subnets) do&lt;br /&gt;
			if item:containsIP(ip) then&lt;br /&gt;
				return true, item&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function IPCollection:getRanges()&lt;br /&gt;
	-- Return a sorted table of IP pairs equivalent to the collection.&lt;br /&gt;
	-- Each IP pair is a table representing a contiguous range of&lt;br /&gt;
	-- IP addresses from pair[1] to pair[2] inclusive (IPAddress objects).&lt;br /&gt;
	local ranges = Ranges.new()&lt;br /&gt;
	for _, item in ipairs(self.addresses) do&lt;br /&gt;
		ranges:add(item)&lt;br /&gt;
	end&lt;br /&gt;
	for _, item in ipairs(self.subnets) do&lt;br /&gt;
		ranges:add(item:getPrefix(), item:getHighestIP())&lt;br /&gt;
	end&lt;br /&gt;
	ranges:merge()&lt;br /&gt;
	ranges:deobjectify()&lt;br /&gt;
	return ranges&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function IPCollection:overlapsSubnet(subnet)&lt;br /&gt;
	-- Return true, obj if subnet overlaps this collection,&lt;br /&gt;
	-- where obj is the first IPAddress or Subnet overlapping the subnet.&lt;br /&gt;
	-- Otherwise, return false.&lt;br /&gt;
	local tp = type(subnet)&lt;br /&gt;
	if tp == &amp;#039;string&amp;#039; then&lt;br /&gt;
		subnet = makeSubnet(subnet)&lt;br /&gt;
	elseif tp == &amp;#039;table&amp;#039; then&lt;br /&gt;
		validateSubnet(&amp;#039;overlapsSubnet&amp;#039;, 1, subnet)&lt;br /&gt;
	else&lt;br /&gt;
		checkTypeMulti(&amp;#039;overlapsSubnet&amp;#039;, 1, subnet, {&amp;#039;string&amp;#039;, &amp;#039;table&amp;#039;})&lt;br /&gt;
	end&lt;br /&gt;
	if self:getVersion() == subnet:getVersion() then&lt;br /&gt;
		for _, item in ipairs(self.addresses) do&lt;br /&gt;
			if subnet:containsIP(item) then&lt;br /&gt;
				return true, item&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		for _, item in ipairs(self.subnets) do&lt;br /&gt;
			if subnet:overlapsSubnet(item) then&lt;br /&gt;
				return true, item&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- IPv4Collection class&lt;br /&gt;
-- Holds a list of IPv4 addresses/subnets.&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local IPv4Collection = setmetatable({}, IPCollection)&lt;br /&gt;
IPv4Collection.__index = IPv4Collection&lt;br /&gt;
&lt;br /&gt;
function IPv4Collection.new()&lt;br /&gt;
	return setmetatable(IPCollection.new(V4), IPv4Collection)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function IPv4Collection:addFromString(text)&lt;br /&gt;
	-- Extract any IPv4 addresses or CIDR subnets from given text.&lt;br /&gt;
	checkType(&amp;#039;addFromString&amp;#039;, 1, text, &amp;#039;string&amp;#039;)&lt;br /&gt;
	text = text:gsub(&amp;#039;[:!&amp;quot;#&amp;amp;\&amp;#039;()+,%-;&amp;lt;=&amp;gt;?[%]_{|}]&amp;#039;, &amp;#039; &amp;#039;)&lt;br /&gt;
	for hit in text:gmatch(&amp;#039;%S+&amp;#039;) do&lt;br /&gt;
		if hit:match(&amp;#039;^%d+%.%d+[%.%d/]+$&amp;#039;) then&lt;br /&gt;
			local _, n = hit:gsub(&amp;#039;%.&amp;#039;, &amp;#039;.&amp;#039;)&lt;br /&gt;
			if n &amp;gt;= 3 then&lt;br /&gt;
				self:_store(hit)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- IPv6Collection class&lt;br /&gt;
-- Holds a list of IPv6 addresses/subnets.&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local IPv6Collection = setmetatable({}, IPCollection)&lt;br /&gt;
IPv6Collection.__index = IPv6Collection&lt;br /&gt;
&lt;br /&gt;
do&lt;br /&gt;
	-- Private static methods&lt;br /&gt;
	local function isCollectionObject(val)&lt;br /&gt;
		-- Return true if val is probably derived from an IPCollection object,&lt;br /&gt;
		-- otherwise return false.&lt;br /&gt;
		if type(val) == &amp;#039;table&amp;#039; then&lt;br /&gt;
			local mt = getmetatable(val)&lt;br /&gt;
			if mt == IPv4Collection or mt == IPv6Collection then&lt;br /&gt;
				return true&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	validateCollection = makeValidationFunction(&amp;#039;IPCollection&amp;#039;, isCollectionObject)&lt;br /&gt;
&lt;br /&gt;
	function IPv6Collection.new()&lt;br /&gt;
		return setmetatable(IPCollection.new(V6), IPv6Collection)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	function IPv6Collection:addFromString(text)&lt;br /&gt;
		-- Extract any IPv6 addresses or CIDR subnets from given text.&lt;br /&gt;
		-- Want to accept all valid IPv6 despite the fact that addresses used&lt;br /&gt;
		-- are unlikely to start with &amp;#039;:&amp;#039;.&lt;br /&gt;
		-- Also want to be able to parse arbitrary wikitext which might use&lt;br /&gt;
		-- colons for indenting.&lt;br /&gt;
		-- Therefore, if an address at the start of a line is valid, use it;&lt;br /&gt;
		-- otherwise strip any leading colons and try again.&lt;br /&gt;
		checkType(&amp;#039;addFromString&amp;#039;, 1, text, &amp;#039;string&amp;#039;)&lt;br /&gt;
		for line in string.gmatch(text .. &amp;#039;\n&amp;#039;, &amp;#039;[\t ]*(.-)[\t\r ]*\n&amp;#039;) do&lt;br /&gt;
			line = line:gsub(&amp;#039;[!&amp;quot;#&amp;amp;\&amp;#039;()+,%-;&amp;lt;=&amp;gt;?[%]_{|}]&amp;#039;, &amp;#039; &amp;#039;)&lt;br /&gt;
			for position, hit in line:gmatch(&amp;#039;()(%S+)&amp;#039;) do&lt;br /&gt;
				local ip = hit:match(&amp;#039;^([:%x]+)/?%d*$&amp;#039;)&lt;br /&gt;
				if ip then&lt;br /&gt;
					local _, n = ip:gsub(&amp;#039;:&amp;#039;, &amp;#039;:&amp;#039;)&lt;br /&gt;
					if n &amp;gt;= 2 then&lt;br /&gt;
						self:_store(hit, position == 1)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return self&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return {&lt;br /&gt;
	IPAddress = IPAddress,&lt;br /&gt;
	Subnet = Subnet,&lt;br /&gt;
	IPv4Collection = IPv4Collection,&lt;br /&gt;
	IPv6Collection = IPv6Collection,&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>nb&gt;EdoAug</name></author>
	</entry>
</feed>