"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var hosts_exports = {};
__export(hosts_exports, {
  commands: () => commands,
  pages: () => pages,
  visualizeRangeList: () => visualizeRangeList
});
module.exports = __toCommonJS(hosts_exports);
var import_lib = require("../../lib");
const HOST_SUFFIXES = ["res", "proxy", "mobile"];
const SUFFIX_ALIASES = {
  residential: "res"
};
const WHITELISTED_USERIDS = [];
function checkCanPerform(context, user, permission = "lockdown") {
  if (!WHITELISTED_USERIDS.includes(user.id))
    context.checkCan(permission);
}
function getHostType(type) {
  type = toID(type);
  if (HOST_SUFFIXES.includes(type))
    return type;
  if (SUFFIX_ALIASES[type])
    return SUFFIX_ALIASES[type];
  throw new Chat.ErrorMessage(`'${type}' is not a valid host type. Please specify one of ${HOST_SUFFIXES.join(", ")}.`);
}
function visualizeRangeList(ranges) {
  let html = `<tr><th>Lowest IP address</th><th>Highest IP address</th><th>Host</th></tr>`;
  for (const range of ranges) {
    html += `<tr>`;
    html += `<td>${IPTools.numberToIP(range.minIP)}</td>`;
    html += `<td>${IPTools.numberToIP(range.maxIP)}</td>`;
    html += import_lib.Utils.html`<td>${range.host}</td>`;
    html += `</tr>`;
  }
  return html;
}
function formatRange(range, includeModlogBrackets) {
  const startBracket = includeModlogBrackets ? "[" : "";
  const endBracket = includeModlogBrackets ? "]" : "";
  let result = `${startBracket}${IPTools.numberToIP(range.minIP)}${endBracket}`;
  result += `-${startBracket}${IPTools.numberToIP(range.maxIP)}${endBracket}`;
  if (range.host)
    result += ` (${range.host})`;
  return result;
}
const pages = {
  proxies(query, user) {
    this.title = "[Proxies]";
    checkCanPerform(this, user, "globalban");
    const openProxies = [...IPTools.singleIPOpenProxies];
    const proxyHosts = [...IPTools.proxyHosts];
    import_lib.Utils.sortBy(openProxies, (ip) => {
      const number = IPTools.ipToNumber(ip);
      if (number === null) {
        Rooms.get("upperstaff")?.add(`|error|Invalid IP address in IPTools.singleIPOpenProxies: '${ip}'`);
        return -1;
      }
      return number;
    });
    proxyHosts.sort();
    IPTools.sortRanges();
    let html = `<div class="ladder pad"><h2>Single IP proxies:</h2><table><tr><th>IP</th><th>Type</th></tr>`;
    for (const proxyIP of openProxies) {
      html += `<tr><td>${proxyIP}</td><td>Single IP open proxy</td></tr>`;
    }
    html += `</table></div>`;
    html += `<div class="ladder pad"><h2>Proxy hosts:</h2><table><tr><th>Host</th><th>Type</th></tr>`;
    for (const proxyHost of proxyHosts) {
      html += `<tr><td>${proxyHost}</td><td>Proxy host</td></tr>`;
    }
    html += `</table></div>`;
    html += `<div class="ladder pad"><h2>Proxy IP Ranges:</h2><table>`;
    html += visualizeRangeList(IPTools.ranges.filter((r) => r.host?.endsWith("/proxy")));
    html += `</table></div>`;
    return html;
  },
  hosts(query, user) {
    this.title = "[Hosts]";
    checkCanPerform(this, user, "globalban");
    const type = toID(query[0]) || "all";
    IPTools.sortRanges();
    const mobileHosts = ["all", "mobile"].includes(type) ? [...IPTools.mobileHosts] : [];
    const residentialHosts = ["all", "residential", "res"].includes(type) ? [...IPTools.residentialHosts] : [];
    const hostRanges = ["all", "ranges", "isps"].includes(type) ? IPTools.ranges.filter((r) => r.host && !r.host.endsWith("/proxy")) : [];
    mobileHosts.sort();
    residentialHosts.sort();
    let html = `<div class="ladder pad"><h2>Mobile hosts:</h2><table><tr><th>Host</th><th>Type</th></tr>`;
    for (const mobileHost of mobileHosts) {
      html += `<tr><td>${mobileHost}</td><td>Mobile host</td></tr>`;
    }
    html += `</table></div>`;
    html += `<div class="ladder pad"><h2>Residential hosts:</h2><table><tr><th>Host</th><th>Type</th></tr>`;
    for (const resHost of residentialHosts) {
      html += `<tr><td>${resHost}</td><td>Residential host</td></tr>`;
    }
    html += `</table></div>`;
    html += `<div class="ladder pad"><h2>ISP IP Ranges:</h2><table>`;
    html += visualizeRangeList(hostRanges);
    html += `</table></div>`;
    return html;
  },
  ranges(query, user) {
    this.title = "[IP Ranges]";
    checkCanPerform(this, user, "globalban");
    const type = toID(query[0]) || "all";
    IPTools.sortRanges();
    let html = ``;
    if (["all", "mobile"].includes(type)) {
      html += `<div class="ladder pad"><h2>Mobile IP Ranges:</h2><table>`;
      html += visualizeRangeList(IPTools.ranges.filter((range) => range.host?.endsWith("/mobile")));
      html += `</table></div>`;
    }
    if (["all", "res", "residential"].includes(type)) {
      html += `<div class="ladder pad"><h2>Residential IP Ranges:</h2><table>`;
      html += visualizeRangeList(IPTools.ranges.filter((range) => range.host?.endsWith("/res")));
      html += `</table></div>`;
    }
    if (["all", "proxy", "proxies"].includes(type)) {
      html += `<div class="ladder pad"><h2>Proxy IP Ranges:</h2><table>`;
      html += visualizeRangeList(IPTools.ranges.filter((range) => range.host?.endsWith("/proxy")));
      html += `</table></div>`;
    }
    if (["all", "openproxy"].includes(type)) {
      html += `<div class="ladder pad"><h2>Single-IP Open Proxies:</h2><table>`;
      for (const ip of IPTools.singleIPOpenProxies) {
        html += `<tr><td>${ip}</td></tr>`;
      }
      html += `</table></div>`;
    }
    return html;
  },
  sharedipblacklist(args, user, connection) {
    this.title = `[Shared IP Blacklist]`;
    checkCanPerform(this, user, "lock");
    let buf = `<div class="pad"><h2>IPs blocked from being marked as shared</h2>`;
    if (!Punishments.sharedIpBlacklist.size) {
      buf += `<p>None currently.</p>`;
    } else {
      buf += `<div class="ladder"><table><tr><th>IP</th><th>Reason</th></tr>`;
      const sortedSharedIPBlacklist = [...Punishments.sharedIpBlacklist];
      import_lib.Utils.sortBy(sortedSharedIPBlacklist, ([ipOrRange]) => {
        if (IPTools.ipRegex.test(ipOrRange)) {
          const number = IPTools.ipToNumber(ipOrRange);
          if (number === null) {
            Monitor.error(`Invalid blacklisted-from-markshared IP: '${ipOrRange}`);
            return -1;
          }
          return number;
        }
        return IPTools.stringToRange(ipOrRange).minIP;
      });
      for (const [ip, reason] of sortedSharedIPBlacklist) {
        buf += `<tr><td>${ip}</td><td>${reason}</td></tr>`;
      }
      buf += `</table></div>`;
    }
    buf += `</div>`;
    return buf;
  },
  sharedips(args, user, connection) {
    this.title = `[Shared IPs]`;
    checkCanPerform(this, user, "globalban");
    let buf = `<div class="pad"><h2>IPs marked as shared</h2>`;
    if (!Punishments.sharedIps.size) {
      buf += `<p>None currently.</p>`;
    } else {
      buf += `<div class="ladder"><table><tr><th>IP</th><th>Location</th></tr>`;
      const sortedSharedIPs = [...Punishments.sharedIps];
      import_lib.Utils.sortBy(sortedSharedIPs, ([ip]) => {
        const number = IPTools.ipToNumber(ip);
        if (number === null) {
          Monitor.error(`Invalid shared IP address: '${ip}'`);
          return -1;
        }
        return number;
      });
      for (const [ip, location] of sortedSharedIPs) {
        buf += `<tr><td>${ip}</td><td>${location}</td></tr>`;
      }
      buf += `</table></div>`;
    }
    buf += `</div>`;
    return buf;
  }
};
const commands = {
  dc: "ipranges",
  datacenter: "ipranges",
  datacenters: "ipranges",
  iprange: "ipranges",
  ipranges: {
    "": "help",
    help() {
      return this.parse("/help ipranges");
    },
    show: "view",
    view(target, room, user) {
      checkCanPerform(this, user, "globalban");
      const types = ["all", "residential", "res", "mobile", "proxy", "openproxy"];
      const type = target ? toID(target) : "all";
      if (!types.includes(type)) {
        return this.errorReply(`'${type}' isn't a valid host type. Specify one of ${types.join(", ")}.`);
      }
      return this.parse(`/join view-ranges-${type}`);
    },
    viewhelp: [
      `/ipranges view - View the list of all IP ranges. Requires: hosts manager @ ~`,
      `/ipranges view [type] - View the list of a particular type of IP range ('residential', 'mobile', or 'proxy'). Requires: hosts manager @ ~`
    ],
    // Originally by Zarel
    widen: "add",
    add(target, room, user, connection, cmd) {
      checkCanPerform(this, user, "globalban");
      if (!target)
        return this.parse("/help ipranges add");
      const widen = cmd.includes("widen");
      const [typeString, stringRange, host] = target.split(",").map((part) => part.trim());
      if (!host || !IPTools.hostRegex.test(host)) {
        return this.errorReply(`Invalid data: ${target}`);
      }
      const type = getHostType(typeString);
      const range = IPTools.stringToRange(stringRange);
      if (!range)
        return this.errorReply(`Couldn't parse IP range '${stringRange}'.`);
      range.host = `${IPTools.urlToHost(host)}?/${type}`;
      IPTools.sortRanges();
      let result;
      try {
        result = IPTools.checkRangeConflicts(range, IPTools.ranges, widen);
      } catch (e) {
        return this.errorReply(e.message);
      }
      if (typeof result === "number") {
        IPTools.removeRange(IPTools.ranges[result].minIP, IPTools.ranges[result].maxIP);
      }
      IPTools.addRange(range);
      this.privateGlobalModAction(`${user.name} added the IP range ${formatRange(range)} to the list of ${type} ranges.`);
      this.globalModlog("IPRANGE ADD", null, formatRange(range, true));
    },
    addhelp: [
      `/ipranges add [type], [low]-[high], [host] - Adds an IP range. Requires: hosts manager ~`,
      `/ipranges widen [type], [low]-[high], [host] - Adds an IP range, allowing a new range to completely cover an old range. Requires: hosts manager ~`,
      `For example: /ipranges add proxy, 5.152.192.0 - 5.152.223.255, redstation.com`,
      `Get datacenter info from whois; [low], [high] are the range in the last inetnum; [type] is one of res, proxy, or mobile.`
    ],
    remove(target, room, user) {
      checkCanPerform(this, user);
      if (!target)
        return this.parse("/help ipranges remove");
      const range = IPTools.stringToRange(target);
      if (!range)
        return this.errorReply(`Couldn't parse the IP range '${target}'.`);
      if (!IPTools.getRange(range.minIP, range.maxIP))
        return this.errorReply(`No IP range found at '${target}'.`);
      void IPTools.removeRange(range.minIP, range.maxIP);
      this.privateGlobalModAction(`${user.name} removed the IP range ${formatRange(range)}.`);
      this.globalModlog("IPRANGE REMOVE", null, formatRange(range, true));
    },
    removehelp: [
      `/ipranges remove [low IP]-[high IP] - Removes an IP range. Requires: hosts manager ~`,
      `Example: /ipranges remove 5.152.192.0-5.152.223.255`
    ],
    rename(target, room, user) {
      checkCanPerform(this, user);
      if (!target)
        return this.parse("/help ipranges rename");
      const [type, rangeString, url] = target.split(",").map((part) => part.trim());
      if (!url) {
        return this.parse("/help ipranges rename");
      }
      const toRename = IPTools.stringToRange(rangeString);
      if (!toRename)
        return this.errorReply(`Couldn't parse IP range '${rangeString}'.`);
      const exists = IPTools.getRange(toRename.minIP, toRename.maxIP);
      if (!exists)
        return this.errorReply(`No IP range found at '${rangeString}'.`);
      const range = {
        minIP: toRename.minIP,
        maxIP: toRename.maxIP,
        host: `${IPTools.urlToHost(url)}?/${type}`
      };
      void IPTools.addRange(range);
      this.privateGlobalModAction(`${user.name} renamed the IP range ${formatRange(toRename)} to ${range.host}.`);
      this.globalModlog("IPRANGE RENAME", null, `IP range ${formatRange(toRename, true)} to ${range.host}`);
    },
    renamehelp: [
      `/ipranges rename [type], [low IP]-[high IP], [host] - Changes the host an IP range resolves to.  Requires: hosts manager ~`
    ]
  },
  iprangeshelp() {
    const help = [
      `<code>/ipranges view [type]</code>: view the list of a particular type of IP range (<code>residential</code>, <code>mobile</code>, or <code>proxy</code>). Requires: hosts manager @ ~`,
      `<code>/ipranges add [type], [low IP]-[high IP], [host]</code>: add IP ranges (can be multiline). Requires: hosts manager ~</summary><code>/ipranges view</code>: view the list of all IP ranges. Requires: hosts manager @ ~`,
      `<code>/ipranges widen [type], [low IP]-[high IP], [host]</code>: add IP ranges, allowing a new range to completely cover an old range. Requires: hosts manager ~`,
      `For example: <code>/ipranges add proxy, 5.152.192.0-5.152.223.255, redstation.com</code>.`,
      `Get datacenter info from <code>/whois</code>; <code>[low IP]</code>, <code>[high IP]</code> are the range in the last inetnum.`,
      `<code>/ipranges remove [low IP]-[high IP]</code>: remove IP range(s). Can be multiline. Requires: hosts manager ~`,
      `For example: <code>/ipranges remove 5.152.192.0, 5.152.223.255</code>.`,
      `<code>/ipranges rename [type], [low IP]-[high IP], [host]</code>: changes the host an IP range resolves to. Requires: hosts manager ~`
    ];
    return this.sendReply(`|html|<details class="readmore"><summary>${help.join("<br />")}`);
  },
  viewhosts(target, room, user) {
    checkCanPerform(this, user, "globalban");
    const types = ["all", "residential", "mobile", "ranges"];
    const type = target ? toID(target) : "all";
    if (!types.includes(type)) {
      return this.errorReply(`'${type}' isn't a valid host type. Specify one of ${types.join(", ")}.`);
    }
    return this.parse(`/join view-hosts-${type}`);
  },
  viewhostshelp: [
    `/viewhosts - View the list of hosts. Requires: hosts manager @ ~`,
    `/viewhosts [type] - View the list of a particular type of host. Requires: hosts manager @ ~`,
    `Host types are: 'all', 'residential', 'mobile', and 'ranges'.`
  ],
  removehost: "addhosts",
  removehosts: "addhosts",
  addhost: "addhosts",
  addhosts(target, room, user, connection, cmd) {
    checkCanPerform(this, user);
    const removing = cmd.includes("remove");
    let [type, ...hosts] = target.split(",");
    type = toID(type);
    hosts = hosts.map((host) => host.trim());
    if (!hosts.length)
      return this.parse("/help addhosts");
    switch (type) {
      case "openproxy":
        for (const host of hosts) {
          if (!IPTools.ipRegex.test(host))
            return this.errorReply(`'${host}' is not a valid IP address.`);
          if (removing !== IPTools.singleIPOpenProxies.has(host)) {
            return this.errorReply(`'${host}' is ${removing ? "not" : "already"} in the list of proxy IPs.`);
          }
        }
        if (removing) {
          void IPTools.removeOpenProxies(hosts);
        } else {
          void IPTools.addOpenProxies(hosts);
        }
        break;
      case "proxy":
        for (const host of hosts) {
          if (!IPTools.hostRegex.test(host))
            return this.errorReply(`'${host}' is not a valid host.`);
          if (removing !== IPTools.proxyHosts.has(host)) {
            return this.errorReply(`'${host}' is ${removing ? "not" : "already"} in the list of proxy hosts.`);
          }
        }
        if (removing) {
          void IPTools.removeProxyHosts(hosts);
        } else {
          void IPTools.addProxyHosts(hosts);
        }
        break;
      case "residential":
        for (const host of hosts) {
          if (!IPTools.hostRegex.test(host))
            return this.errorReply(`'${host}' is not a valid host.`);
          if (removing !== IPTools.residentialHosts.has(host)) {
            return this.errorReply(`'${host}' is ${removing ? "not" : "already"} in the list of residential hosts.`);
          }
        }
        if (removing) {
          void IPTools.removeResidentialHosts(hosts);
        } else {
          void IPTools.addResidentialHosts(hosts);
        }
        break;
      case "mobile":
        for (const host of hosts) {
          if (!IPTools.hostRegex.test(host))
            return this.errorReply(`'${host}' is not a valid host.`);
          if (removing !== IPTools.mobileHosts.has(host)) {
            return this.errorReply(`'${host}' is ${removing ? "not" : "already"} in the list of mobile hosts.`);
          }
        }
        if (removing) {
          void IPTools.removeMobileHosts(hosts);
        } else {
          void IPTools.addMobileHosts(hosts);
        }
        break;
      default:
        return this.errorReply(`'${type}' isn't one of 'openproxy', 'proxy', 'residential', or 'mobile'.`);
    }
    this.privateGlobalModAction(
      `${user.name} ${removing ? "removed" : "added"} ${hosts.length} hosts (${hosts.join(", ")}) ${removing ? "from" : "to"} the ${type} category`
    );
    this.globalModlog(removing ? "REMOVEHOSTS" : "ADDHOSTS", null, `${type}: ${hosts.join(", ")}`);
  },
  addhostshelp: [
    `/addhosts [category], host1, host2, ... - Adds hosts to the given category. Requires: hosts manager ~`,
    `/removehosts [category], host1, host2, ... - Removes hosts from the given category. Requires: hosts manager ~`,
    `Categories are: 'openproxy' (which takes IP addresses, not hosts), 'proxy', 'residential', and 'mobile'.`
  ],
  viewproxies(target, room, user) {
    checkCanPerform(this, user, "globalban");
    return this.parse("/join view-proxies");
  },
  viewproxieshelp: [
    `/viewproxies - View the list of proxies. Requires: hosts manager @ ~`
  ],
  markshared(target, room, user) {
    if (!target)
      return this.parse("/help markshared");
    checkCanPerform(this, user, "globalban");
    const [ip, note] = this.splitOne(target);
    if (!IPTools.ipRegex.test(ip)) {
      const pattern = IPTools.stringToRange(ip);
      if (!pattern) {
        return this.errorReply("Please enter a valid IP address.");
      }
      if (!user.can("rangeban")) {
        return this.errorReply("Only upper staff can markshare ranges.");
      }
      for (const range of Punishments.sharedRanges.keys()) {
        if (IPTools.rangeIntersects(range, pattern)) {
          return this.errorReply(
            `Range ${IPTools.rangeToString(pattern)} intersects with shared range ${IPTools.rangeToString(range)}`
          );
        }
      }
    }
    if (Punishments.isSharedIp(ip))
      return this.errorReply("This IP is already marked as shared.");
    if (Punishments.isBlacklistedSharedIp(ip)) {
      return this.errorReply(`This IP is blacklisted from being marked as shared.`);
    }
    if (!note) {
      this.errorReply(`You must specify who owns this shared IP.`);
      this.parse(`/help markshared`);
      return;
    }
    Punishments.addSharedIp(ip, note);
    this.privateGlobalModAction(`The IP '${ip}' was marked as shared by ${user.name}. (${note})`);
    this.globalModlog("SHAREDIP", null, note, ip);
  },
  marksharedhelp: [
    `/markshared [IP], [owner/organization of IP] - Marks an IP address as shared.`,
    `Note: the owner/organization (i.e., University of Minnesota) of the shared IP is required. Requires @ ~`
  ],
  unmarkshared(target, room, user) {
    if (!target)
      return this.parse("/help unmarkshared");
    checkCanPerform(this, user, "globalban");
    target = target.trim();
    const pattern = IPTools.stringToRange(target);
    if (!pattern)
      return this.errorReply("Please enter a valid IP address.");
    if (pattern.minIP !== pattern.maxIP && !user.can("rangeban")) {
      return this.errorReply(`Only administrators can unmarkshare ranges.`);
    }
    let shared = false;
    if (pattern.minIP !== pattern.maxIP) {
      for (const range of Punishments.sharedRanges.keys()) {
        shared = range.minIP === pattern.minIP && range.maxIP === pattern.maxIP;
        if (shared)
          break;
      }
    } else {
      shared = Punishments.sharedIps.has(target);
    }
    if (!shared)
      return this.errorReply(`That IP/range isn't marked as shared.`);
    Punishments.removeSharedIp(target);
    this.privateGlobalModAction(`The IP '${target}' was unmarked as shared by ${user.name}.`);
    this.globalModlog("UNSHAREDIP", null, null, target);
  },
  unmarksharedhelp: [`/unmarkshared [IP] - Unmarks a shared IP address. Requires @ ~`],
  marksharedblacklist: "nomarkshared",
  marksharedbl: "nomarkshared",
  nomarkshared: {
    add(target, room, user) {
      if (!target)
        return this.parse(`/help nomarkshared`);
      checkCanPerform(this, user, "globalban");
      const [ip, ...reasonArr] = target.split(",");
      if (!IPTools.ipRangeRegex.test(ip))
        return this.errorReply(`Please enter a valid IP address or range.`);
      if (!reasonArr?.length) {
        this.errorReply(`A reason is required.`);
        this.parse(`/help nomarkshared`);
        return;
      }
      if (Punishments.isBlacklistedSharedIp(ip)) {
        return this.errorReply(`This IP is already blacklisted from being marked as shared.`);
      }
      if (!IPTools.ipRegex.test(ip)) {
        if (!ip.endsWith("*")) {
          this.errorReply(`That looks like a range, but it is invalid.`);
          this.errorReply(`Append * to the end of the range and try again.`);
          return;
        }
        if (!user.can("bypassall")) {
          return this.errorReply(`Only Administrators can add ranges.`);
        }
        const range = IPTools.stringToRange(ip);
        if (!range)
          return this.errorReply(`Invalid IP range.`);
        for (const sharedIp of Punishments.sharedIps.keys()) {
          const ipNum = IPTools.ipToNumber(sharedIp);
          if (IPTools.checkPattern([range], ipNum)) {
            this.parse(`/unmarkshared ${sharedIp}`);
          }
        }
      } else {
        if (Punishments.isSharedIp(ip))
          this.parse(`/unmarkshared ${ip}`);
      }
      const reason = reasonArr.join(",");
      Punishments.addBlacklistedSharedIp(ip, reason);
      this.privateGlobalModAction(`The IP '${ip}' was blacklisted from being marked as shared by ${user.name}.`);
      this.globalModlog("SHAREDIP BLACKLIST", null, reason.trim(), ip);
    },
    remove(target, room, user) {
      if (!target)
        return this.parse(`/help nomarkshared`);
      checkCanPerform(this, user);
      if (!IPTools.ipRangeRegex.test(target))
        return this.errorReply(`Please enter a valid IP address or range.`);
      if (!Punishments.sharedIpBlacklist.has(target)) {
        return this.errorReply(`This IP is not blacklisted from being marked as shared.`);
      }
      Punishments.removeBlacklistedSharedIp(target);
      this.privateGlobalModAction(`The IP '${target}' was unblacklisted from being marked as shared by ${user.name}.`);
      this.globalModlog("SHAREDIP UNBLACKLIST", null, null, target);
    },
    view() {
      return this.parse(`/join view-sharedipblacklist`);
    },
    help: "",
    ""() {
      return this.parse(`/help nomarkshared`);
    }
  },
  nomarksharedhelp: [
    `/nomarkshared add [IP], [reason] - Prevents an IP from being marked as shared until it's removed from this list. Requires ~`,
    `Note: Reasons are required.`,
    `/nomarkshared remove [IP] - Removes an IP from the nomarkshared list. Requires ~`,
    `/nomarkshared view - Lists all IPs prevented from being marked as shared. Requires @ ~`
  ],
  sharedips: "viewsharedips",
  viewsharedips() {
    return this.parse("/join view-sharedips");
  },
  viewsharedipshelp: [
    `/viewsharedips \u2014 Lists IP addresses marked as shared. Requires: hosts manager @ ~`
  ]
};
//# sourceMappingURL=hosts.js.map