https://en.wikipedia.org/w/index.php?action=history&feed=atom&title=Module%3AIPblock%2Fsandbox
Module:IPblock/sandbox - Revision history
2025-05-26T04:49:05Z
Revision history for this page on the wiki
MediaWiki 1.45.0-wmf.2
https://en.wikipedia.org/w/index.php?title=Module:IPblock/sandbox&diff=810439138&oldid=prev
Johnuniq: announce new release
2017-11-15T07:01:56Z
<p>announce new release</p>
<table style="background-color: #fff; color: #202122;" data-mw="interface">
<col class="diff-marker" />
<col class="diff-content" />
<col class="diff-marker" />
<col class="diff-content" />
<tr class="diff-title" lang="en">
<td colspan="2" style="background-color: #fff; color: #202122; text-align: center;">← Previous revision</td>
<td colspan="2" style="background-color: #fff; color: #202122; text-align: center;">Revision as of 07:01, 15 November 2017</td>
</tr><tr>
<td colspan="2" class="diff-lineno">Line 978:</td>
<td colspan="2" class="diff-lineno">Line 978:</td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> local lines = Collection.new()</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> local lines = Collection.new()</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> if not options.noannounce then</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> if not options.noannounce then</div></td>
</tr>
<tr>
<td class="diff-marker" data-marker="−"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div> -- Commented out April 2016 as expired.</div></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> --<ins style="font-weight: bold; text-decoration: none;"> 1:</ins> Commented out April 2016 as expired.</div></td>
</tr>
<tr>
<td class="diff-marker" data-marker="−"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div> -- lines:add("'''Please see [[Template talk:Blockcalc#Version February 2016|this announcement]].'''")</div></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> --<ins style="font-weight: bold; text-decoration: none;"> 1:</ins> lines:add("'''Please see [[Template talk:Blockcalc#Version February 2016|this announcement]].'''")</div></td>
</tr>
<tr>
<td colspan="2" class="diff-empty diff-side-deleted"></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> lines:add("'''By default, links now use [[Special:Contributions]] per [[Template talk:IP range calculator#Version November 2017|this announcement]].'''")</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> end</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> end</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> process_ips(lines, v4list, v4omitted)</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> process_ips(lines, v4list, v4omitted)</div></td>
</tr>
</table>
Johnuniq
https://en.wikipedia.org/w/index.php?title=Module:IPblock/sandbox&diff=810284000&oldid=prev
Johnuniq: first draft to use Special:Contributions
2017-11-14T09:48:05Z
<p>first draft to use Special:Contributions</p>
<table style="background-color: #fff; color: #202122;" data-mw="interface">
<col class="diff-marker" />
<col class="diff-content" />
<col class="diff-marker" />
<col class="diff-content" />
<tr class="diff-title" lang="en">
<td colspan="2" style="background-color: #fff; color: #202122; text-align: center;">← Previous revision</td>
<td colspan="2" style="background-color: #fff; color: #202122; text-align: center;">Revision as of 09:48, 14 November 2017</td>
</tr><tr>
<td colspan="2" class="diff-lineno">Line 44:</td>
<td colspan="2" class="diff-lineno">Line 44:</td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> local key = code .. months</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> local key = code .. months</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> if not timestamps[key] then</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> if not timestamps[key] then</div></td>
</tr>
<tr>
<td class="diff-marker" data-marker="−"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div> -- A local test can set the global variable to produce fixed results.</div></td>
<td colspan="2" class="diff-empty diff-side-added"></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> local date = os.date('!*t') -- today's UTC date</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> local date = os.date('!*t') -- today's UTC date</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> local y, m, d = date.year, date.month, date.day -- full year, month (1-12), day (1-31)</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> local y, m, d = date.year, date.month, date.day -- full year, month (1-12), day (1-31)</div></td>
</tr>
<tr>
<td colspan="2" class="diff-lineno">Line 616:</td>
<td colspan="2" class="diff-lineno">Line 615:</td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> -- or return an empty string if cannot do anything useful.</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> -- or return an empty string if cannot do anything useful.</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> -- The given address is a string of either a single IP or a CIDR range.</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> -- The given address is a string of either a single IP or a CIDR range.</div></td>
</tr>
<tr>
<td class="diff-marker" data-marker="−"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div> -- For IPv6 CIDR, return a Special:Contributions link using an asterisk</div></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> --<ins style="font-weight: bold; text-decoration: none;"> If using old system:</ins></div></td>
</tr>
<tr>
<td colspan="2" class="diff-empty diff-side-deleted"></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div><ins style="font-weight: bold; text-decoration: none;"> -- </ins> For IPv6 CIDR, return a Special:Contributions link using an asterisk</div></td>
</tr>
<tr>
<td class="diff-marker" data-marker="−"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div> -- wildcard which should work if the user has enabled the gadget</div></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> --<ins style="font-weight: bold; text-decoration: none;"> </ins> wildcard which should work if the user has enabled the gadget</div></td>
</tr>
<tr>
<td class="diff-marker" data-marker="−"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div> -- "Allow /16, /24 and /27 – /32 CIDR ranges on Special:Contributions".</div></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> --<ins style="font-weight: bold; text-decoration: none;"> </ins> "Allow /16, /24 and /27 – /32 CIDR ranges on Special:Contributions".</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> local encoded, count = address:gsub('/', '%%2F')</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> local encoded, count = address:gsub('/', '%%2F')</div></td>
</tr>
<tr>
<td class="diff-marker" data-marker="−"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div> if count > 0 then</div></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> if<ins style="font-weight: bold; text-decoration: none;"> strings.want_old and</ins> count > 0 then</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> make_note(strings, 'range')</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> make_note(strings, 'range')</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> if address:find(':', 1, true) then</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> if address:find(':', 1, true) then</div></td>
</tr>
<tr>
<td colspan="2" class="diff-lineno">Line 843:</td>
<td colspan="2" class="diff-lineno">Line 843:</td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> local strings = iplist.want_plain and plaintext or wikitable</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> local strings = iplist.want_plain and plaintext or wikitable</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> strings.notes = nil -- needed when module is kept loaded for multiple tests</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> strings.notes = nil -- needed when module is kept loaded for multiple tests</div></td>
</tr>
<tr>
<td colspan="2" class="diff-empty diff-side-deleted"></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> strings.want_old = iplist.want_old</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> strings.nonote = iplist.nonote</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> strings.nonote = iplist.nonote</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> strings.months = iplist.months</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> strings.months = iplist.months</div></td>
</tr>
<tr>
<td colspan="2" class="diff-lineno">Line 873:</td>
<td colspan="2" class="diff-lineno">Line 874:</td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> options.comment = args.comment</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> options.comment = args.comment</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> end</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> end</div></td>
</tr>
<tr>
<td colspan="2" class="diff-empty diff-side-deleted"></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> -- Parameter 'months' is only used if 'old' is also used.</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> local months = math.floor(tonumber(args.months) or tonumber(args.month) or 1)</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> local months = math.floor(tonumber(args.months) or tonumber(args.month) or 1)</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> if months < 1 then</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> if months < 1 then</div></td>
</tr>
<tr>
<td colspan="2" class="diff-lineno">Line 906:</td>
<td colspan="2" class="diff-lineno">Line 908:</td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> -- If an argument matches k, an option named v is set to true.</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> -- If an argument matches k, an option named v is set to true.</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> ok = 'noannounce',</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> ok = 'noannounce',</div></td>
</tr>
<tr>
<td colspan="2" class="diff-empty diff-side-deleted"></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> old = 'want_old',</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> nolist = 'nolist',</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> nolist = 'nolist',</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> nonote = 'nonote',</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> nonote = 'nonote',</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> text = 'text',</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> text = 'text',</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> }</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> }</div></td>
</tr>
<tr>
<td colspan="2" class="diff-empty diff-side-deleted"></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> local want_old</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> for i, arg in ipairs(args) do</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> for i, arg in ipairs(args) do</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> local flag = keywords[arg:match('^%s*(%w+)%s*$')]</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> local flag = keywords[arg:match('^%s*(%w+)%s*$')]</div></td>
</tr>
<tr>
<td colspan="2" class="diff-lineno">Line 915:</td>
<td colspan="2" class="diff-lineno">Line 919:</td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> options[i] = 'skip'</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> options[i] = 'skip'</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> options[flag] = true</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> options[flag] = true</div></td>
</tr>
<tr>
<td colspan="2" class="diff-empty diff-side-deleted"></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> if flag == 'want_old' then</div></td>
</tr>
<tr>
<td colspan="2" class="diff-empty diff-side-deleted"></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> want_old = true</div></td>
</tr>
<tr>
<td colspan="2" class="diff-empty diff-side-deleted"></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> end</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> end</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> end</div></td>
</tr>
<tr>
<td colspan="2" class="diff-empty diff-side-deleted"></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> end</div></td>
</tr>
<tr>
<td colspan="2" class="diff-empty diff-side-deleted"></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> if not want_old then</div></td>
</tr>
<tr>
<td colspan="2" class="diff-empty diff-side-deleted"></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> options.nonote = true</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> end</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> end</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> return options</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> return options</div></td>
</tr>
<tr>
<td colspan="2" class="diff-lineno">Line 939:</td>
<td colspan="2" class="diff-lineno">Line 949:</td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> v6list.minsize = 19 -- or /19 for IPv6 ($wgBlockCIDRLimit)</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> v6list.minsize = 19 -- or /19 for IPv6 ($wgBlockCIDRLimit)</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> end</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> end</div></td>
</tr>
<tr>
<td class="diff-marker" data-marker="−"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div> for _, k in ipairs({'maxresults', 'months', 'nolist', 'nonote'}) do</div></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> for _, k in ipairs({'maxresults', 'months<ins style="font-weight: bold; text-decoration: none;">', 'want_old</ins>', 'nolist', 'nonote'}) do</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> v4list[k] = options[k]</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> v4list[k] = options[k]</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> v6list[k] = options[k]</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> v6list[k] = options[k]</div></td>
</tr>
</table>
Johnuniq
https://en.wikipedia.org/w/index.php?title=Module:IPblock/sandbox&diff=809919418&oldid=prev
Johnuniq: clean-up prior to fixing to use new ranges ability of Special:Contributions
2017-11-12T09:28:28Z
<p>clean-up prior to fixing to use new ranges ability of <a href="/wiki/Special:Contributions" title="Special:Contributions">Special:Contributions</a></p>
<a href="//en.wikipedia.org/w/index.php?title=Module:IPblock/sandbox&diff=809919418&oldid=717169640">Show changes</a>
Johnuniq
https://en.wikipedia.org/w/index.php?title=Module:IPblock/sandbox&diff=717169640&oldid=prev
Johnuniq: show contribs link for IPv6 ranges (user must enable gadget); show notes for contribs links including age of contribs; can set age with months=N; disable "ok" for now as not needed
2016-04-26T04:06:25Z
<p>show contribs link for IPv6 ranges (user must enable gadget); show notes for contribs links including age of contribs; can set age with months=N; disable "ok" for now as not needed</p>
<a href="//en.wikipedia.org/w/index.php?title=Module:IPblock/sandbox&diff=717169640&oldid=702381574">Show changes</a>
Johnuniq
https://en.wikipedia.org/w/index.php?title=Module:IPblock/sandbox&diff=702381574&oldid=prev
Johnuniq: fix pre tags for plain text
2016-01-30T06:08:38Z
<p>fix pre tags for plain text</p>
<table style="background-color: #fff; color: #202122;" data-mw="interface">
<col class="diff-marker" />
<col class="diff-content" />
<col class="diff-marker" />
<col class="diff-content" />
<tr class="diff-title" lang="en">
<td colspan="2" style="background-color: #fff; color: #202122; text-align: center;">← Previous revision</td>
<td colspan="2" style="background-color: #fff; color: #202122; text-align: center;">Revision as of 06:08, 30 January 2016</td>
</tr><tr>
<td colspan="2" class="diff-lineno">Line 675:</td>
<td colspan="2" class="diff-lineno">Line 675:</td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> )</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> )</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> end</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> end</div></td>
</tr>
<tr>
<td colspan="2" class="diff-empty diff-side-deleted"></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> -- Pre tags returned by a module are html tags, not like wikitext <pre>...</pre>.</div></td>
</tr>
<tr>
<td class="diff-marker" data-marker="−"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div> lines:add(s)</div></td>
<td colspan="2" class="diff-empty diff-side-added"></td>
</tr>
<tr>
<td colspan="2" class="diff-empty diff-side-deleted"></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> lines:add(want_plain and mw.text.nowiki(s) or s)</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> end</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> end</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div>end</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div>end</div></td>
</tr>
</table>
Johnuniq
https://en.wikipedia.org/w/index.php?title=Module:IPblock/sandbox&diff=702332102&oldid=prev
Johnuniq: major upgrade: IPv4 and IPv6; look for best summary; results in a table
2016-01-29T22:52:19Z
<p>major upgrade: IPv4 and IPv6; look for best summary; results in a table</p>
<p><b>New page</b></p><div>-- Calculate the minimum-sized blocks of IP addresses that covers each<br />
-- IPv4 or IPv6 address entered in the arguments.<br />
<br />
local bit32 = require('bit32')<br />
<br />
local function collection()<br />
-- Return a table to hold items.<br />
return {<br />
n = 0,<br />
add = function (self, item)<br />
self.n = self.n + 1<br />
self[self.n] = item<br />
end,<br />
join = function (self, sep)<br />
return table.concat(self, sep)<br />
end,<br />
remove = function (self, pos)<br />
if self.n > 0 and (pos == nil or (0 < pos and pos <= self.n)) then<br />
self.n = self.n - 1<br />
return table.remove(self, pos)<br />
end<br />
end,<br />
sort = function (self, comp)<br />
table.sort(self, comp)<br />
end,<br />
}<br />
end<br />
<br />
local function empty(text)<br />
-- Return true if text is nil or empty (assuming a string).<br />
return text == nil or text == ''<br />
end<br />
<br />
local function describe_total(total, isalloc)<br />
-- Return text describing given number of addresses or /64 allocations.<br />
if total <= 9999 then<br />
-- Can have fractions if total is the number of /64 allocations.<br />
if total < 9 then<br />
return (string.format('%.1f', total):gsub('%.0$', ''))<br />
end<br />
return string.format('%.0f', total)<br />
end<br />
if not isalloc then<br />
local alloc = 2^64<br />
if total >= alloc then<br />
return describe_total(total / alloc, true) .. ' /64'<br />
end<br />
end<br />
total = total/1024<br />
local suffix = 'K'<br />
if total >= 1024 then<br />
total = total/1024<br />
suffix = 'M'<br />
if total >= 1024 then<br />
total = total/1024<br />
suffix = 'G'<br />
if total > 64 then<br />
return '>64G'<br />
end<br />
end<br />
end<br />
return string.format('%.0f', total) .. suffix<br />
end<br />
<br />
local function describe_size(ipsize, size)<br />
-- Return text describing how many IPs are in a range with size = prefix length.<br />
local function numtext(n)<br />
if n <= 16 then<br />
return tostring(2^n)<br />
end<br />
if n <= 19 then<br />
return tostring(2^(n - 10)) .. 'K'<br />
end<br />
if n <= 29 then<br />
return tostring(2^(n - 20)) .. 'M'<br />
end<br />
if n <= 36 then<br />
return tostring(2^(n - 30)) .. 'G'<br />
end<br />
return '>64G'<br />
end<br />
local host = ipsize - size<br />
if host <= 32 then<br />
-- IPv4 or IPv6.<br />
return numtext(host)<br />
end<br />
-- Must be IPv6.<br />
if host <= 64 then<br />
local s = ({<br />
[64] = '1', [63] = '50%', [62] = '25%', [61] = '12%',<br />
[60] = '6%', [59] = '3%', [58] = '2%'<br />
})[host] or '<1%'<br />
return s .. ' /64'<br />
end<br />
-- IPv6 with size < 64.<br />
return numtext(host - 64) .. ' /64'<br />
end<br />
<br />
local function ipv6_string(ip)<br />
-- Return a string equivalent to given IPv6 address.<br />
local z1, z2 -- indices of run of zeros to be displayed as "::"<br />
local zstart, zcount<br />
for i = 1, 9 do<br />
-- Find left-most occurrence of longest run of two or more zeros.<br />
if i < 9 and ip[i] == 0 then<br />
if zstart then<br />
zcount = zcount + 1<br />
else<br />
zstart = i<br />
zcount = 1<br />
end<br />
else<br />
if zcount and zcount > 1 then<br />
if not z1 or zcount > z2 - z1 + 1 then<br />
z1 = zstart<br />
z2 = zstart + zcount - 1<br />
end<br />
end<br />
zstart = nil<br />
zcount = nil<br />
end<br />
end<br />
local parts = collection()<br />
for i = 1, 8 do<br />
if z1 and z1 <= i and i <= z2 then<br />
if i == z1 then<br />
if z1 == 1 or z2 == 8 then<br />
if z1 == 1 and z2 == 8 then<br />
return '::'<br />
end<br />
parts:add(':')<br />
else<br />
parts:add('')<br />
end<br />
end<br />
else<br />
parts:add(string.format('%x', ip[i]))<br />
end<br />
end<br />
return table.concat(parts, ':')<br />
end<br />
<br />
local function ip_string(ip)<br />
-- Return a string equivalent to given IP address (IPv4 or IPv6).<br />
local floor = math.floor<br />
local parts = {}<br />
if ip.n == 2 then<br />
-- IPv4.<br />
for i = 1, 2 do<br />
local w = ip[i]<br />
local q = i == 1 and 1 or 3<br />
parts[q] = floor(w / 256)<br />
parts[q+1] = w % 256<br />
end<br />
return table.concat(parts, '.')<br />
end<br />
return ipv6_string(ip)<br />
end<br />
<br />
-- Metatable for some operations on IP addresses.<br />
local ipmt = {<br />
__eq = function (lhs, rhs)<br />
-- Return true if values in numbered tables match.<br />
if lhs.n == rhs.n then<br />
for i = 1, lhs.n do<br />
if lhs[i] ~= rhs[i] then<br />
return false<br />
end<br />
end<br />
return true<br />
end<br />
return false<br />
end,<br />
__lt = function (lhs, rhs)<br />
-- Return true if lhs < rhs; for sort.<br />
if lhs.n == rhs.n then<br />
for i = 1, lhs.n do<br />
if lhs[i] ~= rhs[i] then<br />
return lhs[i] < rhs[i]<br />
end<br />
end<br />
return false<br />
end<br />
return lhs.n < rhs.n -- sort IPv4 before IPv6, although not needed<br />
end,<br />
}<br />
<br />
local function ipv4_address(ip_str)<br />
-- Return a collection of two 16-bit words (numbers) equivalent<br />
-- to the IPv4 address given as a quad-dotted string, or<br />
-- return nil if invalid.<br />
-- This representation is for compatibility with IPv6 addresses.<br />
local parts = collection()<br />
local s = ip_str:match('^%s*(.-)%s*$') .. '.'<br />
for item in s:gmatch('(.-)%.') do<br />
parts:add(item)<br />
end<br />
if parts.n == 4 then<br />
for i, s in ipairs(parts) do<br />
if s:match('^%d+$') then<br />
local num = tonumber(s)<br />
if 0 <= num and num <= 255 then<br />
if num > 0 and s:match('^0') then<br />
-- A redundant leading zero is an error because it is for an IP in octal.<br />
return nil<br />
end<br />
parts[i] = num<br />
else<br />
return nil<br />
end<br />
else<br />
return nil<br />
end<br />
end<br />
local result = collection()<br />
for i = 1, 3, 2 do<br />
result:add(parts[i] * 256 + parts[i+1])<br />
end<br />
return setmetatable(result, ipmt)<br />
end<br />
return nil<br />
end<br />
<br />
local function ipv6_address(ip_str)<br />
-- Return a collection of eight 16-bit words (numbers) equivalent<br />
-- to the IPv6 address given as a colon-delimited string, or<br />
-- return nil if invalid.<br />
local _, n = ip_str:gsub(':', ':')<br />
if n < 7 then<br />
ip_str, n = ip_str:gsub('::', string.rep(':', 9 - n))<br />
end<br />
local parts = collection()<br />
for item in (ip_str .. ':'):gmatch('(.-):') do<br />
parts:add(item)<br />
end<br />
if parts.n == 8 then<br />
for i, s in ipairs(parts) do<br />
if s == '' then<br />
parts[i] = 0<br />
else<br />
local num = tonumber('0x' .. s)<br />
if num and 0 <= num and num <= 65535 then<br />
parts[i] = num<br />
else<br />
return nil<br />
end<br />
end<br />
end<br />
return setmetatable(parts, ipmt)<br />
end<br />
return nil<br />
end<br />
<br />
local function common_length(num1, num2, nr_bits)<br />
-- Return number of prefix bits that two integers have in common.<br />
-- Number of bits in each number is nr_bits = 16, 8, 4, 2 or 1.<br />
if nr_bits <= 1 then<br />
return num1 == num2 and 1 or 0<br />
end<br />
local half = nr_bits / 2<br />
local splitter = 2^half<br />
local upper1, lower1 = math.modf(num1 / splitter)<br />
local upper2, lower2 = math.modf(num2 / splitter)<br />
if upper1 == upper2 then<br />
lower1 = math.floor(lower1 * splitter + 0.5)<br />
lower2 = math.floor(lower2 * splitter + 0.5)<br />
return half + common_length(lower1, lower2, half)<br />
end<br />
return common_length(upper1, upper2, half)<br />
end<br />
<br />
local function common_prefix_length(ip1, ip2)<br />
-- Return number of prefix bits that two IPs have in common.<br />
-- Caller ensures that both IPs are IPv4 or both are IPv6.<br />
local size = 0<br />
for i = 1, ip1.n do<br />
local w1, w2 = ip1[i], ip2[i]<br />
if w1 == w2 then<br />
size = size + 16<br />
else<br />
return size + common_length(w1, w2, 16)<br />
end<br />
end<br />
return size<br />
end<br />
<br />
local function ip_prefix(ip, length)<br />
-- Return a copy of ip masked to contain only the prefix of given length.<br />
local result = { n = ip.n }<br />
for i = 1, ip.n do<br />
if length > 0 then<br />
if length >= 16 then<br />
result[i] = ip[i]<br />
length = length - 16<br />
else<br />
result[i] = bit32.band(ip[i], bit32.arshift(0xffff8000, length - 1))<br />
length = 0<br />
end<br />
else<br />
result[i] = 0<br />
end<br />
end<br />
return setmetatable(result, ipmt)<br />
end<br />
<br />
local function ip_incremented(ip)<br />
-- Return a new IP equal to ip + 1.<br />
-- Will wraparound (255.255.255.255 + 1 = 0.0.0.0)!<br />
local result = { n = ip.n }<br />
local carry = 1<br />
for i = ip.n, 1, -1 do<br />
local sum = ip[i] + carry<br />
if sum >= 0x10000 then<br />
carry = 1<br />
sum = sum - 0x10000<br />
else<br />
carry = 0<br />
end<br />
result[i] = sum<br />
end<br />
return setmetatable(result, ipmt)<br />
end<br />
<br />
local function is_next_ip(ip1, ip2)<br />
-- Return true if ip2 is the next IP after ip1 (ip2 == ip1 + 1).<br />
-- IPs are sorted and unique so ip1 < ip2 and can ignore wrapping to zero.<br />
-- This is lower overhead than making a new incremented IP then comparing.<br />
if ip1 and ip2 then<br />
local carry = 1<br />
for i = ip1.n, 1, -1 do<br />
local sum = ip1[i] + carry<br />
if sum >= 0x10000 then<br />
carry = 1<br />
sum = sum - 0x10000<br />
else<br />
carry = 0<br />
end<br />
if sum ~= ip2[i] then<br />
return false<br />
end<br />
end<br />
return true<br />
end<br />
end<br />
<br />
-- Each IP in a range except for the last IP has a 'common' field which is<br />
-- a number specifying how many bits are common between the prefixes of this<br />
-- IP and the next IP (0 if this IP starts with 0 and the next starts with 1).<br />
-- Each non-empty range has exactly one "minimum common", that is, its value<br />
-- of common is smaller than all others. That there is only one minimum common<br />
-- follows from the fact that the IPs are unique and sorted.<br />
local function make_range(iplist, ifirst, ilast)<br />
-- Return a table for the range of IPs from iplist[ifirst] to iplist[ilast] inclusive.<br />
local imin, vmin, done<br />
if ifirst < ilast then<br />
for i = ifirst, ilast - 1 do<br />
-- Find the (unique) minimum of common lengths.<br />
local common = iplist[i].common<br />
if vmin then<br />
if vmin > common then<br />
vmin = common<br />
imin = i<br />
end<br />
else<br />
vmin = common<br />
imin = i<br />
end<br />
end<br />
else<br />
vmin = iplist.ipsize<br />
imin = ifirst<br />
done = true<br />
end<br />
if vmin > iplist.allocation then<br />
-- For IPv6, the default allocation is /64 and there is no point having<br />
-- more precise ranges as they add unnecessary complexity.<br />
-- However, using results=all sets allocation = 128 so vmin is not changed.<br />
vmin = iplist.allocation<br />
end<br />
return {<br />
ifirst = ifirst, -- index of first IP<br />
ilast = ilast, -- index of last IP<br />
imin = imin, -- index of IP with minimum common<br />
size = vmin, -- number of common bits in prefix (the minimum)<br />
prefix = ip_prefix(iplist[imin], vmin), -- IP table of the base IP<br />
done = done, -- true if know that this range cannot be improved<br />
}<br />
end<br />
<br />
local function split_range(iplist, range, depth)<br />
-- Return a table of two or more ranges that more precisely target<br />
-- the IPs in range, or return nothing if unable to improve range.<br />
depth = depth and depth + 1 or 0<br />
if depth <= 20 and -- 20 examines 1M contiguous addresses down to individual IPs<br />
not range.done and<br />
range.size < iplist.allocation and<br />
range.ifirst < range.ilast then<br />
local imin = range.imin<br />
assert(imin and range.ifirst <= imin and imin < range.ilast)<br />
local r1 = make_range(iplist, range.ifirst, range.imin)<br />
local r2 = make_range(iplist, range.imin + 1, range.ilast)<br />
local pointless = range.size + 1<br />
if r1.size > pointless or r2.size > pointless then<br />
return { r1, r2 }<br />
end<br />
local result = collection()<br />
local function store_split(range)<br />
local split = split_range(iplist, range, depth)<br />
if split then<br />
for _, r in ipairs(split) do<br />
result:add(r)<br />
end<br />
return true<br />
else<br />
result:add(range)<br />
end<br />
end<br />
local improved1 = store_split(r1)<br />
local improved2 = store_split(r2)<br />
if improved1 or improved2 then<br />
return result<br />
end<br />
end<br />
range.done = true<br />
end<br />
<br />
local function better_summary(iplist, summary)<br />
-- Return a better summary that more precisely targets the specified IPs,<br />
-- or return nil if unable to improve the summary.<br />
local better = collection()<br />
local improved<br />
for _, range in ipairs(summary) do<br />
local split = split_range(iplist, range)<br />
if split then<br />
improved = true<br />
for _, r in ipairs(split) do<br />
better:add(r)<br />
end<br />
else<br />
better:add(range)<br />
end<br />
end<br />
return improved and better<br />
end<br />
<br />
local function make_summaries(iplist)<br />
-- Return a collection where each item is a summary.<br />
-- A summary is a table of one or more ranges.<br />
-- A summary covers all the given IPs and probably more.<br />
-- A range is a table representing a CIDR block such as 1.2.248.0/21.<br />
-- The first summary found is a single range; each subsequent summary<br />
-- (if any) uses more ranges to better target the given IPs.<br />
-- The result omits any summary with a range size that is too small (too many IPs).<br />
local function good_size(summary)<br />
for _, range in ipairs(summary) do<br />
if range.size < iplist.minsize then<br />
return false<br />
end<br />
end<br />
return true<br />
end<br />
local summaries = collection()<br />
if iplist.n > 0 then<br />
for i = 1, iplist.n - 1 do<br />
-- Set length of prefixes common between each pair of IPs.<br />
iplist[i].common = common_prefix_length(iplist[i], iplist[i+1])<br />
end<br />
local summary = { make_range(iplist, 1, iplist.n) }<br />
while summary and summaries.n < iplist.maxresults do<br />
if good_size(summary) then<br />
summaries:add(summary)<br />
end<br />
summary = better_summary(iplist, summary)<br />
end<br />
end<br />
return summaries<br />
end<br />
<br />
local function extract_ipv4(result, omitted, line)<br />
-- Extract any IPv4 addresses from given line or throw error.<br />
-- Accept CIDR /n to specify a range (only accept 16 to 32).<br />
-- Addresses must be delimited with whitespace to reduce false positives.<br />
local function store(hit)<br />
local n = 32<br />
local lhs, rhs = hit:match('^(.-)/(%d+)$')<br />
if lhs then<br />
hit = lhs<br />
n = tonumber(rhs)<br />
if not (n and 16 <= n and n <= 32) then<br />
error('CIDR /n only accepts n = 16 to 32, invalid: ' .. lhs .. '/' .. rhs, 0)<br />
end<br />
end<br />
local ip = ipv4_address(hit)<br />
if ip then<br />
if n == 32 then<br />
result:add(ip)<br />
else<br />
if ip ~= ip_prefix(ip, n) then<br />
error('Invalid base address (host bits should be zero): ' .. hit, 0)<br />
end<br />
for _ = 1, 2^(32 - n) do<br />
result:add(ip)<br />
ip = ip_incremented(ip)<br />
end<br />
end<br />
else<br />
omitted:add(hit)<br />
end<br />
end<br />
line = line:gsub(':', ' ') -- so wikitext indents or other colons don't obscure an IVp4 address<br />
for hit in line:gmatch('%S+') do<br />
if hit:match('^%d+%.%d+[%.%d/]+$') then<br />
local _, n = hit:gsub('%.', '.')<br />
if n >= 3 then<br />
store(hit)<br />
end<br />
end<br />
end<br />
end<br />
<br />
local function extract_ipv6(result, omitted, line)<br />
-- Extract any IPv6 addresses from given line or throw error.<br />
-- Addresses must be delimited with whitespace to reduce false positives.<br />
-- Want to accept all valid IPv6 despite the fact that contributors will<br />
-- not have an address starting with ':'.<br />
-- Also want to be able to parse arbitrary wikitext which might use colons<br />
-- for indenting. To achieve that, if an address at the start of a line<br />
-- is valid, use it; otherwise strip any leading colons and try again.<br />
for pos, hit in line:gmatch('()(%S+)') do<br />
local ipstr, length = hit:match('^([:%x]+)(/?%d*)$')<br />
if ipstr then<br />
local _, n = ipstr:gsub(':', ':')<br />
if n >= 2 then<br />
local ip = ipv6_address(ipstr)<br />
if not ip and pos == 1 then<br />
ipstr, n = ipstr:gsub('^:+', '')<br />
if n > 0 then<br />
ip = ipv6_address(ipstr)<br />
end<br />
end<br />
if ip then<br />
if length and #length > 0 then<br />
error('CIDR /n not accepted for IPv6: ' .. hit, 0)<br />
end<br />
result:add(ip)<br />
else<br />
omitted:add(hit)<br />
end<br />
end<br />
end<br />
end<br />
end<br />
<br />
local function contribs(address)<br />
-- Return a URL or wikilink to list the contributions for an IP or IP range,<br />
-- or return an empty string if cannot do anything useful (IPv6 CIDR).<br />
-- The given address is a string of either a single IP or a CIDR range.<br />
local encoded, count = address:gsub('/', '%%2F')<br />
if count > 0 then<br />
if address:find(':', 1, true) then<br />
return '' -- no contributions link is available for a CIDR IPv6 range<br />
end<br />
local url = '[https://tools.wmflabs.org/xtools/rangecontribs/?project=en.wikipedia.org&namespace=all&limit=50&text=%s&begin=%s c]'<br />
-- %s = IPv4 CIDR range with '/' changed to '%2F'<br />
-- %s = Start date formatted 'yyyy-mm-dd' (am using today's date less one month)<br />
local date = os.date('!*t') -- table with today's UTC date<br />
local y, m, d = date.year, date.month, date.day -- full year, month (1-12), day (1-31)<br />
if m > 1 then<br />
m = m - 1<br />
else<br />
m = 12<br />
y = y - 1<br />
end<br />
return string.format(url,<br />
encoded,<br />
string.format('%d-%02d-%02d', y, m, d)<br />
)<br />
end<br />
return '[[Special:Contributions/' .. address .. '|c]]'<br />
end<br />
<br />
-- Strings for results using plain text.<br />
-- The pre tags used are html which do not provide "nowiki",<br />
-- but that is not required by the text used.<br />
local plaintext = {<br />
<br />
header = [=[<br />
<pre><br />
Total Affected Given Range]=],<br />
<br />
footer = '</pre>',<br />
<br />
sumfirst = [=[<br />
----------------------------------------------------------<br />
%s%-12s %-12s %-11d %s%s]=],<br />
-- %s = empty string (dummy for compatibility)<br />
-- %s = total affected<br />
-- %s = affected<br />
-- %d = given (number of addresses given in input covered by this range)<br />
-- %s = IP address range<br />
-- %s = empty string<br />
<br />
sumnext = [=[<br />
%-12s %-11d %s%s]=],<br />
-- %s = affected<br />
-- %d = given<br />
-- %s = IP address range<br />
-- %s = empty string<br />
<br />
}<br />
<br />
-- Strings for results using a table in wikitext.<br />
local wikitable = {<br />
<br />
header = [=[<br />
{| class="wikitable"<br />
! Total<br />affected !! Affected<br />addresses !! Given<br />addresses !! Range !! Contribs]=],<br />
<br />
footer = '|}',<br />
<br />
sumfirst = [=[<br />
|- style="background: darkgray; height: 6px;"<br />
|colspan="5" |<br />
|- style="vertical-align: top;"<br />
|rowspan="%s" |%s ||%s ||%d ||%s ||%s]=],<br />
-- %s = string of number of ranges in summary (number of rows)<br />
-- %s = total affected<br />
-- %s = affected<br />
-- %d = given<br />
-- %s = IP address range<br />
-- %s = contributions link<br />
<br />
sumnext = [=[<br />
|-<br />
|%s ||%d ||%s ||%s]=],<br />
-- %s = affected<br />
-- %d = given<br />
-- %s = IP address range<br />
-- %s = contributions link<br />
<br />
}<br />
<br />
local function show_summary(lines, iplist, summary)<br />
-- Show the summary by adding table wikitext or plain text to lines.<br />
local want_plain = iplist.want_plain<br />
local total = 0<br />
for _, range in ipairs(summary) do<br />
-- A number is a double which easily handles 2^128 = 3.4e38.<br />
total = total + 2^(iplist.ipsize - range.size)<br />
end<br />
local str = want_plain and plaintext or wikitable<br />
for i, range in ipairs(summary) do<br />
local prefix = ip_string(range.prefix)<br />
local size = range.size<br />
local affected = describe_size(iplist.ipsize, size)<br />
local given = range.ilast - range.ifirst + 1<br />
local address<br />
if size == iplist.ipsize then<br />
address = prefix<br />
else<br />
address = prefix .. '/' .. size<br />
end<br />
local s<br />
if i == 1 then<br />
s = string.format(str.sumfirst,<br />
want_plain and '' or tostring(#summary),<br />
describe_total(total),<br />
affected, given, address,<br />
want_plain and '' or contribs(address)<br />
)<br />
else<br />
s = string.format(str.sumnext,<br />
affected, given, address,<br />
want_plain and '' or contribs(address)<br />
)<br />
end<br />
lines:add(s)<br />
end<br />
end<br />
<br />
local function process_ips(lines, iplist, omitted)<br />
-- Process a list of IP addresses, adding text of results to lines.<br />
-- The list should contain either all IPv4 addresses, or all IPv6 (not a mixture).<br />
local seq1, seq2, seqmany<br />
local function show_sequence()<br />
if seq1 and seq2 then<br />
local text = ip_string(seq1)<br />
if seqmany then<br />
seqmany = false<br />
text = text .. ' – ' .. ip_string(seq2)<br />
end<br />
seq1 = nil<br />
seq2 = nil<br />
local markup = text:sub(1, 1) == ':' and ':<nowiki/>' or ':'<br />
lines:add(markup .. text)<br />
end<br />
end<br />
local function show_ip(ip)<br />
-- Show IP or record it to be included in a "from to" sequence of IPs.<br />
if is_next_ip(seq2, ip) then<br />
seq2 = ip<br />
seqmany = true<br />
else<br />
show_sequence()<br />
seq1 = ip<br />
seq2 = ip<br />
seqmany = false<br />
end<br />
end<br />
if iplist.n < 1 then<br />
return<br />
end<br />
if lines.n > 0 then<br />
lines:add('')<br />
end<br />
if omitted.n > 0 then<br />
lines:add('Warning, omitted as invalid: ' .. omitted:join(' '))<br />
lines:add('')<br />
end<br />
lines:add('') -- this blank line is replaced with a heading<br />
local heading_line = lines.n<br />
local duplicates = collection()<br />
local previous<br />
iplist:sort()<br />
-- Check for duplicates which can interfere with method to get ranges.<br />
for i, ip in ipairs(iplist) do<br />
if previous == ip then<br />
duplicates:add(i) -- index to omit duplicate later<br />
elseif not iplist.nolist then<br />
show_ip(ip)<br />
end<br />
previous = ip<br />
end<br />
show_sequence()<br />
local duplicate_text = ''<br />
if duplicates.n > 0 then<br />
duplicate_text = ' (after omitting some duplicates)'<br />
for i = duplicates.n, 1, -1 do<br />
iplist:remove(duplicates[i])<br />
end<br />
end<br />
local heading_text = string.format('Sorted %d %s address%s',<br />
iplist.n,<br />
iplist.ipname,<br />
iplist.n == 1 and '' or 'es'<br />
)<br />
lines[heading_line] = heading_text .. duplicate_text .. ':'<br />
local str = iplist.want_plain and plaintext or wikitable<br />
lines:add(str.header)<br />
local upto = lines.n<br />
for _, summary in ipairs(make_summaries(iplist)) do<br />
show_summary(lines, iplist, summary)<br />
end<br />
lines:add(str.footer)<br />
if upto + 1 == lines.n then<br />
-- Show message in the very unlikely event that no results are found.<br />
lines:add('----')<br />
lines:add('No suitable ranges found; use <code>|results=all</code> to see all ranges.')<br />
end<br />
end<br />
<br />
local function make_options(args)<br />
-- Return table of options from validated args or throw error.<br />
local options = {}<br />
if not empty(args.comment) then<br />
options.comment = args.comment<br />
end<br />
local allocation<br />
if not empty(args.allocation) then<br />
allocation = tonumber(args.allocation)<br />
if not (allocation and 48 <= allocation and allocation <= 128) then<br />
error('Invalid allocation "' .. args.allocation .. '" (should be 48 to 128; default is 64)', 0)<br />
end<br />
end<br />
local maxresults<br />
if not empty(args.results) then<br />
if args.results == 'all' then<br />
options.all = true<br />
allocation = allocation or 128<br />
maxresults = 1000<br />
else<br />
maxresults = tonumber(args.results)<br />
if not (maxresults and 1 <= maxresults and maxresults <= 100) then<br />
error('Invalid results "' .. args.results .. '" (should be 1 to 100)', 0)<br />
end<br />
end<br />
end<br />
options.allocation = allocation or 64<br />
options.maxresults = maxresults or 10<br />
local keywords = {<br />
-- Table of k, v strings.<br />
-- If an argument matches k, an option named v is set to true.<br />
ok = 'noannounce',<br />
nolist = 'nolist',<br />
text = 'text',<br />
}<br />
for i, arg in ipairs(args) do<br />
local flag = keywords[arg:match('^%s*(%w+)%s*$')]<br />
if flag then<br />
options[i] = 'skip'<br />
options[flag] = true<br />
end<br />
end<br />
return options<br />
end<br />
<br />
local function _IPblock(args)<br />
-- Process given args; can be called from another module.<br />
-- Throw an error if need to report a problem.<br />
local options = make_options(args)<br />
local v4list, v4omitted = collection(), collection()<br />
local v6list, v6omitted = collection(), collection()<br />
v4list.ipsize = 32<br />
v4list.ipname = 'IPv4'<br />
v6list.ipsize = 128<br />
v6list.ipname = 'IPv6'<br />
v4list.allocation = 32<br />
v6list.allocation = options.allocation<br />
if options.all then<br />
v4list.minsize = 0<br />
v6list.minsize = 0<br />
else<br />
v4list.minsize = 16 -- cannot block more IPs than /16 for IPv4<br />
v6list.minsize = 19 -- or /19 for IPv6 ($wgBlockCIDRLimit)<br />
end<br />
v4list.maxresults = options.maxresults<br />
v6list.maxresults = options.maxresults<br />
v4list.nolist = options.nolist<br />
v6list.nolist = options.nolist<br />
if options.text then<br />
v4list.want_plain = true<br />
v6list.want_plain = true<br />
end<br />
for i, arg in ipairs(args) do<br />
if options[i] ~= 'skip' then<br />
for line in string.gmatch(arg .. '\n', '[\t ]*(.-)[\t\r ]*\n') do<br />
-- Skip line if is empty or a comment.<br />
if line ~= '' then<br />
local comment = options.comment<br />
if not (comment and line:sub(1, #comment) == comment) then<br />
-- Replace accepted delimiters with a space.<br />
line = line:gsub('[!"#&\'()+,%-;<=>?[%]_{|}]', ' ')<br />
extract_ipv4(v4list, v4omitted, line)<br />
extract_ipv6(v6list, v6omitted, line)<br />
end<br />
end<br />
end<br />
end<br />
end<br />
if v4list.n < 1 and v6list.n < 1 then<br />
error('No valid IPv4 or IPv6 address in arguments', 0)<br />
end<br />
local lines = collection()<br />
if not options.noannounce then<br />
lines:add("'''Please see [[Template talk:Blockcalc#Version February 2016|this announcement]].'''")<br />
end<br />
process_ips(lines, v4list, v4omitted)<br />
process_ips(lines, v6list, v6omitted)<br />
return lines:join('\n')<br />
end<br />
<br />
local function IPblock(frame)<br />
-- Return wikitext to display the smallest IPv4 or IPv6 CIDR range that<br />
-- covers each address given in the arguments, or return error text.<br />
-- An IP starting with '#' is ignored (commented out).<br />
-- Input can have any mixture of IPs; IPv4 and IPv6 are processed separately.<br />
local ok, msg = pcall(_IPblock, frame:getParent().args)<br />
if ok then<br />
return msg<br />
end<br />
return '<strong class="error">Error: ' .. msg .. '</strong>'<br />
end<br />
<br />
return { IPblock = IPblock, _IPblock = _IPblock }</div>
Johnuniq