Участник:Js/whois.js

Материал из Википедии — свободной энциклопедии
Страница персонального оформления. У этого JS-кода есть документация: Участник:Js/whois.
После сохранения очистите кэш браузера.
//see [[user:js/whois]]

//PARAMETERS
// whoisStorageLimit  = // in bytes


if( window.localStorage ){

 var m, user = ''
 if( mw.config.get('wgCanonicalSpecialPageName') == 'Contributions' )
   user = $('input[name="target"]').val()
 else if( mw.config.get('wgCanonicalSpecialPageName') == 'Block' && !$('#mw-input-wpConfirm').length )
   user = document.URL.match(/\/([\d\.]+)$/)[1]
 else if( mw.config.get('wgAction') == 'rollback' || /:AbuseLog\//.test(mw.config.get('wgPageName')) ) {
   m = $('.mw-userlink').eq(0).attr('href').match(/:Contributions\/(.+)$/);
   user = m && m[1]
 } else if( mw.config.get('wgNamespaceNumber') == 2 || mw.config.get('wgNamespaceNumber') == 3 )
   user = mw.config.get('wgTitle')

 if( /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(user) )
   showWhois()

}



function showWhois(){

 var wsLimit = window.whoisStorageLimit || 200000 //bytes
 var ranges 
 
 $('<div style="margin-top: -5px;" />')
 .append(
   $('<a style="color:gray" '
    + 'href="http://toolserver.org/~overlordq/cgi-bin/whois.cgi?lookup='
    + user + '">whois:</a>').click(tools),
    '<span id=whois />'
    )
 .insertAfter('#contentSub')

 cache() || request()

 return


//---------------------------------


function cache(){
  loadCache()
  if( !ranges.length ){
    fetchCache()
    return false
  }
  var iphex = ip2hex(user)
  //quickly search in sorted array by checking the element in the middle
  var r1 = 0, r2 = ranges.length - 1, rr //r1 .... rr .... r2
  while( r1 < r2 ){
    rr = Math.floor( (r2 + r1)/2 ) + 1 //middle item
    if( iphex < ranges[rr].substring(0, 8) ) r2 = rr - 1 // ... is below this range
    else r1 = rr // ... is above or within this range
  }
  //check if ip is within this range
  var dat = ranges[r1].split('\t')
  var n1 = parseInt(dat[0].substring(0, 8), 16)
  var n2 = parseInt(dat[0].substring(8), 16) + n1
  if( n1 > parseInt(iphex, 16) || parseInt(iphex, 16) > n2 ) return false
  //display
  display(dat[1], dat[2], dat[3], ipDec(n1) + ' - ' + ipDec(n2) )
  $('#whois').append('<span style="color:gray; font-size:smaller">(cached)</span>')
  if( window.whoisStats ) stats()
  return true
}


function request(){
  $('#whois').html('<span style="color:gray"> requesting ...</span>')
  window.whois_cb = receive
  mw.loader.load(
 'https://stat.ripe.net/plugin/whois/data.json?callback=whois_cb&resource=' + user)
}


function receive(d){
  if(typeof d !== 'undefined')zd = d
  if( !d || !d.data ) return $('#whois').html('empty response')
  d = d.data
  if( d.records ) d = d.records[0]
  else return $('#whois').html( d.messages.toString() ) // a notice, happens...
  var w = {}, htm, key
  for (var i=0; i<d.length; i++){
    key=d[i][0]
    if( w[key] ) w[key] += ' / '
    else w[key] = ''
    w[key] += d[i][1]
  }
  //display
  display(w.country, w.netname, w.descr, w.inetnum)
  if( window.whoisDebug ){
    //temp display to make sure other info is useless
    htm = ''
    for (var i=0; i<d.length; i++)
       if( !/inetnum|netname|descr|country/.test(d[i][0]) )
          htm += d[i][0] + ':\t' + d[i][1] + '<br />'
    msg(htm, 'gray')
  }
  loadCache()
  if( !w.country || w.country.toLowerCase() == 'zz' ) return
  //save
  var rng = range2hex(w.inetnum)
  if( !rng ) return //could not parse range
  ranges.push( rng + '\t' + w.country + '\t' + w.netname + '\t' + w.descr.replace(/\t/g, ' ') )
  saveCache()
}



function display(country, netname, descr, ips){
  country = country ? country.toLowerCase() : null;
  if(!country) return;
  country = '<span '
   + ( country == 'zz' ? 'class=error>' : 'style="font-weight:bold2">' )
   + country + '</span>'
  $('#whois').html( ' ' + country + ' ' + netname + ' ' + descr
  + ' <span style="color:gray">' + ips + '</span> ')
}



function tools(e){
 e.preventDefault()
 if( $('#wh-tools').length ) return $('#wh-tools').remove()
 loadCache()
 $('<div id=wh-tools style="font-size:smaller" />')
  .append(
   $('<span style="cursor:pointer">[refresh IP]</span>').click(request),
   ' ',
   $('<span style="cursor:pointer">[edit cache]</span>').click(edit),
   ' ' + ranges.length + ' lines, '
   + Math.floor(ranges.join('\n').length / 1000)
   + ' KB (max ' + wsLimit / 1000 + ')&nbsp;&nbsp;'
 )
 .insertAfter('#whois')
}



function edit(){

 if( $('#wh-edit').length ) return  $('#wh-edit').remove()

 $('<div id=wh-edit>'
  + '<textarea rows=15 style="white-space:nowrap;overflow:scroll;" />'
  + '<input type=button value=Save />'
  + '</div'
  )
  .insertAfter('#wh-tools')

 loadCache()
 convertRanges()
 $('#wh-edit textarea').val( ranges.join('\n') )
 $('#wh-edit input').click(function(){
   ranges = $('#wh-edit textarea').val().split('\n')
   convertRanges(true)
   saveCache()
   edit() //to remove UI
 })

}


function fetchCache(){
 $.get('http://ru.wikipedia.org/wiki/Участник:Js/whois/cache?action=raw', function(s){
   ranges = s.split('\n')
   convertRanges(true)
   saveCache()
   if( ranges.length ){
      msg('Loaded initial cache: ' + ranges.length + ' lines')
   }else{
     msg('Unable to load initial cache', 'red') 
   }
 })
}


function stats(){ //log how many times range was requested to see the most often used ones
  if( mw.config.get('wgCanonicalSpecialPageName') != 'Contributions' ) return
  //console.log( 'stats for '  + user, dat[4])
  if( typeof dat[4] == 'undefined' ) dat.push(1)
  dat[4] = parseInt(dat[4]) + 1
  ranges[rangeIdx] = dat.join('\t')
  saveCache()
  $('#whois').append(' ', '<span style="color:gray">(' + dat[4] + ')')
}


// ------------- AUX functions --------------

function msg(txt, color){
 $('#whois').parent().append('<div style="color:' + color + '">' + txt + '</div>')
}


function loadCache(){
 ranges = localStorage.getItem('whois')
 ranges = ranges ? ranges.split('\n') : []
 //console.timeEnd('read cache')
}


function saveCache(){ //from ranges[]
 ranges.sort()
 //remove duplicates
 for( var i=0; i<ranges.length-2; i++ )
   if( ranges[i].split('\t')[0] == ranges[i+1].split('\t')[0] )
     ranges.splice(i--, 1)
 //save
 var txt = ranges.join('\n')
 if( txt.length > wsLimit )
    return msg('cannot save: cache too large now (' +  txt.length + ')', 'red' )
 try { localStorage.setItem( 'whois', txt ) }
 catch(e){ msg('cannot save: ' + e, 'red') }
}


function convertRanges(toHex){
 for( var i=0; i<ranges.length; i++){
   dat = ranges[i].split('\t')
   dat[1] = $.trim(dat[1])
   dat[2] = $.trim(dat[2])
   dat[3] = $.trim(dat[3])
   dat[0] = toHex ? range2hex(dat[0]) : hex2range(dat[0])
   if( dat[0] ) ranges[i] = dat.join('\t')
   else ranges.splice(i--, 1)
 }
}


function range2hex(s){
 s = s.replace(/ /g,'')
 var lowIP, rngLen
 //try x.x.x.x/yy
 var r = /^(\d+\.\d+\.\d+\.\d+)\/(\d\d)$/.exec(s)
 if( r ){
   lowIP = r[1]
   rngLen = Math.pow(2, 32 - r[2] ) - 1
 }else{ //x.x.x.x-y.y.y.y  
  r = s.split('-')
  if( r.length == 2 ){
    lowIP = r[0] 
    rngLen = ipNum(r[1]) - ipNum(r[0])
  }
 }
 //return
 if( lowIP ) return  ip2hex( lowIP ) + rngLen.toString(16)
 else        return // console.debug('bad range: ', s)  
 
}


function hex2range(hex){
 var ip1 = parseInt(hex.substring(0,8), 16)
 var ip2 = parseInt(hex.substring(8), 16) + ip1
 var s = ipDec(ip1) + '-' + ipDec(ip2)
 while( s.length < 25 )  s+= ' ' //pretiify for table output assuming tab = 8 spaces
 return s
}


function ipNum(ip){ // '1.2.3.255' -> 16909311
  ip = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/.exec(ip)
  if( ip ) return (+ip[1]<<24) + (+ip[2]<<16) + (+ip[3]<<8) + (+ip[4])
  else return null
}

function ipMask(i1, i2){
 var p = Math.log(ipNum(i2) - ipNum(i1) + 1) / Math.LN2
 if( Math.round(p) == p) return 32 - p
 else return ''
}



function ip2hex(s){ //'1.2.3.255' -> 010203ff'
 return s.replace(/\d+/g, function(s){
    t = parseInt(s, 10).toString(16)
    if( t.length == 1 ) t = '0' + t
    return t
  })
  .replace(/\./g, '');
}


function ipDec(n){ // 16909311 --> '1.2.3.255'
 var d = n % 256
 for( var i=0; i < 3; i++){
   n = Math.floor(n / 256)
   d = n % 256 + '.' + d
 }
 return d
}



}