\n'
if (netSize > maxNetSize) {
// This is wrong. Need to figure out a way to get the number of children so you can set rowspan and the number
// of ancestors so you can set colspan.
// DONE: If the subnet address (without the mask) matches a larger subnet address
// in the heirarchy that is a signal to add more join buttons to that row, since they start at the top row and
// via rowspan extend downward.
let matchingNetworkList = get_matching_network_list(network, subnetMap).slice(1)
for (const i in matchingNetworkList) {
let matchingNetwork = matchingNetworkList[i]
let networkChildrenCount = count_network_children(matchingNetwork, subnetMap, [])
newRow += '
/' + matchingNetwork.split('/')[1] + '
\n'
}
}
newRow += '
';
$('#calcbody').append(newRow)
}
// Helper Functions
function ip2int(ip) {
return ip.split('.').reduce(function(ipInt, octet) { return (ipInt<<8) + parseInt(octet, 10)}, 0) >>> 0;
}
function int2ip (ipInt) {
return ( (ipInt>>>24) +'.' + (ipInt>>16 & 255) +'.' + (ipInt>>8 & 255) +'.' + (ipInt & 255) );
}
function subnet_last_address(subnet, netSize) {
return subnet + subnet_addresses(netSize) - 1;
}
function subnet_addresses(netSize) {
return 2**(32-netSize);
}
function get_dict_max_depth(dict, curDepth) {
let maxDepth = curDepth
for (let mapKey in dict) {
if (mapKey.startsWith('_')) { continue; }
let newDepth = get_dict_max_depth(dict[mapKey], curDepth + 1)
if (newDepth > maxDepth) { maxDepth = newDepth }
}
return maxDepth
}
function get_join_children(subnetTree, childCount) {
for (let mapKey in subnetTree) {
if (mapKey.startsWith('_')) { continue; }
if (has_network_sub_keys(subnetTree[mapKey])) {
childCount += get_join_children(subnetTree[mapKey])
} else {
return childCount
}
}
}
function has_network_sub_keys(dict) {
let allKeys = Object.keys(dict)
// Maybe an efficient way to do this with a Lambda?
for (let i in allKeys) {
if (!allKeys[i].startsWith('_')) {
return true
}
}
return false
}
function count_network_children(network, subnetTree, ancestryList) {
// TODO: This might be able to be optimized. Ultimately it needs to count the number of keys underneath
// the current key are unsplit networks (IE rows in the table, IE keys with a value of {}).
let childCount = 0
for (let mapKey in subnetTree) {
if (mapKey.startsWith('_')) { continue; }
if (has_network_sub_keys(subnetTree[mapKey])) {
childCount += count_network_children(network, subnetTree[mapKey], ancestryList.concat([mapKey]))
} else {
if (ancestryList.includes(network)) {
childCount += 1
}
}
}
return childCount
}
function get_network_children(network, subnetTree) {
// TODO: This might be able to be optimized. Ultimately it needs to count the number of keys underneath
// the current key are unsplit networks (IE rows in the table, IE keys with a value of {}).
let subnetList = []
for (let mapKey in subnetTree) {
if (mapKey.startsWith('_')) { continue; }
if (has_network_sub_keys(subnetTree[mapKey])) {
subnetList.push.apply(subnetList, get_network_children(network, subnetTree[mapKey]))
} else {
subnetList.push(mapKey)
}
}
return subnetList
}
function get_matching_network_list(network, subnetTree) {
let subnetList = []
for (let mapKey in subnetTree) {
if (mapKey.startsWith('_')) { continue; }
if (has_network_sub_keys(subnetTree[mapKey])) {
subnetList.push.apply(subnetList, get_matching_network_list(network, subnetTree[mapKey]))
}
if (mapKey.split('/')[0] === network) {
subnetList.push(mapKey)
}
}
return subnetList
}
function get_consolidated_property(subnetTree, property) {
let allValues = get_property_values(subnetTree, property)
// https://stackoverflow.com/questions/14832603/check-if-all-values-of-array-are-equal
let allValuesMatch = allValues.every( (val, i, arr) => val === arr[0] )
if (allValuesMatch) {
return allValues[0]
} else {
return ''
}
}
function get_property_values(subnetTree, property) {
let propValues = []
for (let mapKey in subnetTree) {
if (has_network_sub_keys(subnetTree[mapKey])) {
propValues.push.apply(propValues, get_property_values(subnetTree[mapKey], property))
} else {
// The "else" above is a bit different because it will start tracking values for subnets which are
// in the hierarchy, but not displayed. Those are always blank so it messes up the value list
propValues.push(subnetTree[mapKey][property] || '')
}
}
return propValues
}
function get_network(networkInput, netSize) {
let ipInt = ip2int(networkInput)
netSize = parseInt(netSize)
for (let i=31-netSize; i>=0; i--) {
ipInt &= ~ 1< searchParams.get(prop),
});
if (params['c'] !== null) {
// First character is the version of the URL string, in case the mechanism of encoding changes
let urlVersion = params['c'].substring(0, 1)
let urlData = params['c'].substring(1)
if (urlVersion === '1') {
let urlConfig = JSON.parse(LZString.decompressFromEncodedURIComponent(params['c'].substring(1)))
renameKey(urlConfig, 'v', 'config_version')
renameKey(urlConfig, 's', 'subnets')
expandKeys(urlConfig['subnets'])
let subnet_split = Object.keys(urlConfig['subnets'])[0].split('/')
$('#network').val(subnet_split[0])
$('#netsize').val(subnet_split[1])
importConfig(urlConfig)
return true
}
}
}
function shortenKeys(subnetTree) {
for (let mapKey in subnetTree) {
if (mapKey.startsWith('_')) {
continue;
}
if (has_network_sub_keys(subnetTree[mapKey])) {
shortenKeys(subnetTree[mapKey])
} else {
if (subnetTree[mapKey].hasOwnProperty('_note')) {
renameKey(subnetTree[mapKey], '_note', '_n')
}
if (subnetTree[mapKey].hasOwnProperty('_color')) {
renameKey(subnetTree[mapKey], '_color', '_c')
}
}
}
}
function expandKeys(subnetTree) {
for (let mapKey in subnetTree) {
if (mapKey.startsWith('_')) {
continue;
}
if (has_network_sub_keys(subnetTree[mapKey])) {
expandKeys(subnetTree[mapKey])
} else {
if (subnetTree[mapKey].hasOwnProperty('_n')) {
renameKey(subnetTree[mapKey], '_n', '_note')
}
if (subnetTree[mapKey].hasOwnProperty('_c')) {
renameKey(subnetTree[mapKey], '_c', '_color')
}
}
}
}
function renameKey(obj, oldKey, newKey) {
if (oldKey !== newKey) {
Object.defineProperty(obj, newKey,
Object.getOwnPropertyDescriptor(obj, oldKey));
delete obj[oldKey];
}
}
function importConfig(text) {
// TODO: Probably need error checking here
if (text['config_version'] === '1') {
subnetMap = text['subnets'];
renderTable()
}
}
const rgba2hex = (rgba) => `#${rgba.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+\.{0,1}\d*))?\)$/).slice(1).map((n, i) => (i === 3 ? Math.round(parseFloat(n) * 255) : parseFloat(n)).toString(16).padStart(2, '0').replace('NaN', '')).join('')}`