_ _    _ _____  ___   __                       
 __      _(_) | _(_)___ / ( _ ) / /_   ___ ___  _ __ ___  
 \ \ /\ / / | |/ / | |_ \ / _ \| '_ \ / __/ _ \| '_ ` _ \ 
  \ V  V /| |   <| |___) | (_) | (_) | (_| (_) | | | | | |
   \_/\_/ |_|_|\_\_|____/ \___/ \___(_)___\___/|_| |_| |_|

User:Lowellian/randomlink.js

In this article, we are going to deeply explore the topic of User:Lowellian/randomlink.js, a topic that has captured the attention of many people in recent years. User:Lowellian/randomlink.js has generated great interest and debate in different areas, from science to politics, including popular culture. Throughout this article, we will examine the different aspects of User:Lowellian/randomlink.js, from its origins and evolution, to its impact on today's society. Additionally, we will discuss the opinions and perspectives of experts on the topic, as well as the personal experiences of those who have been directly involved with User:Lowellian/randomlink.js. This article aims to provide readers with a broad understanding of User:Lowellian/randomlink.js and encourage critical reflection on this topic that is so relevant today.
//  2009-09-28 23:59 revision of ]
//  
//  Documentation at ]
//  and ]
//  
//  Travel to a random page linked in the article or listed on a special page.
//  See talk page for documentation.  Greg Ubben

//randomlink_start   = ;
//randomlink_hops    = 2;
//randomlink_exclude = /^List of/;
//randomlink_paged   = true;        // cats > 200 entries or multi-paged lists
randomlink_open    = true;        // if you want to open in new windows
//randomlink_debug   = true;        // set this, to debug
randomlink_maxfrom   = 20000000;    // 10-20% less than max page id
randomlink_maxoffset = 950;         // en.wikipedia is limited to 1000

function scrapeLinks( descend )
{
    var topnode = document.getElementById('bodyContent') || document;
    var node    = document.getElementById('mw-subcategories');
    var atags   = ;
    var links   = ;
    var nspat   = /^(Talk|User|Wik\w+|File|MediaWiki|Template|Help|Category|Portal)( talk)?:/i;

    var spec = getElementsByClassName(topnode, 'div', 'mw-spcontent');
    if (spec.length == 1)  topnode = spec;      // skip help links at top of specials

    if (node && descend)
        topnode = node;           // pick a sub-category
    else
        for (var id in {'mw-pages':0, 'mw-category-media':0 }) {
            node = document.getElementById( id );
            if (node) {
                var nodelist = node.getElementsByTagName('a');
                for (var i=0; i < nodelist.length; i++)
                    atags.push( nodelist );
            }
        }

    if (atags.length == 0)
        atags = topnode.getElementsByTagName('a');

  nextlink:
    for (var i=0; i < atags.length; i++) {
        var link  = atags;
        var href  = link.href;
        var title = link.title;

        if (!href)                                 // needed?
            continue;
        if (link.className.search(/^(mw-redirect|mw-userlink|Cat.*)?$/) == -1)
            continue;                              // external or image
        if (href.search(/\/Special:|\?(?!.*redirect=|.*from=.*to=)/) >= 0)
            continue;
        if (wgIsArticle && wgNamespaceNumber != 14 && title.search(/^(Category|File):|^$/) >= 0)
            continue;
        if (wgIsArticle && wgNamespaceNumber == 0 && title.search(nspat) >= 0)
            continue;
        if ((wgAction == "history") != (link.className == "mw-userlink"))
            continue;
        if (link.hostname != location.hostname)    // commons.wikimedia.org on images
            continue;
        if (link.parentNode.id == "coordinates")
            continue;                              // coords too common, or help link
        if (typeof randomlink_exclude != "undefined" && title.search(randomlink_exclude) >= 0)
            continue;

        //  Exclude message boxes and the Metadata section on Image pages.
        //  And also mw-usertool links and comments in page listings.
        //  And also top links on Recent changes and watchlists.
        //
        for (var n = link.parentNode; n != topnode; n = n.parentNode) {
            if (n.id.search(/^mw-watchlist-options|^recentchangestext/) >= 0)
                continue nextlink;
            if (n.className.search(/\b(usertool|summary|metadata|.mbox|comment)/) >= 0)
                continue nextlink;
        }
        links.push( link );
    }

    while (links.length && links.parentNode.id.search( /contentSub|jump-to|target/i ) >= 0)
        links.shift();                                  // breadcrumb links

    if (links.length && links.title == "Wikipedia:FAQ/Categories")
        links.shift();                                  // "learn more" link in cats

    return links;
}

function randomLink( links, hops )
{
    var continuing = (typeof links == "object" && links == null);

    if (typeof links == "undefined" && typeof randomlink_start != "undefined")
        links = randomlink_start;

    if (typeof hops == "undefined" && typeof randomlink_hops != "undefined")
        hops = randomlink_hops;

    if (typeof hops == "undefined")
        hops = 1;

    if (hops > 4)       // sanity check; 4 needed for Special:AllPages
        hops = 4;

    if (typeof links == "string" &&
        links.search(/^Special:(WhatLinksHere|RecentChangesLinked)$/i) >= 0)
    {
        links += "/" + wgPageName + "?limit=250";
        if (wgNamespaceNumber == 0)
            links += "&namespace=0";    // stay in article space if in it now
    }

    //  Random contrib: Toggles between user, page, user, page, ...
    //
    if (typeof links == "string" && links == "Special:Contributions")
        if (wgPageName.search(/^User:+$/) >= 0)
            links += "/" + wgPageName.slice(5) + "?namespace=0";
        else
            links = wgPageName + "?action=history";

    if (typeof links == "string")
        links = links.split("|");

    if (typeof links == "object" && links != null) {
        for (var i=0; i < links.length; i++)
            links = wgArticlePath.replace("$1", links).replace(/ /g, "_");
        hops++;
    }
    else {
        links = scrapeLinks( hops > 1 );
    }

    if (typeof randomlink_debug != "undefined" && randomlink_debug) {
        var msg = links.slice(0);
        if (msg.length > 36)
            msg.splice( 20, msg.length-35, "..." );
        alert( links.length + " links:\n   " + msg.join("\n   "));
    }

    if (links.length == 0)
        return alert("I am unable to comply.");

    var newpage = links.toString();

    if (typeof randomlink_paged != "undefined" && randomlink_paged)
        newpage = pagedUrl( newpage );

    if (wgCanonicalNamespace == "Category" && newpage.indexOf("/Category:") == -1)
        hops = 1;

    if (--hops > 0) {
        newpage += (newpage.indexOf("?") >= 0) ? "&" : "?";
        newpage += "random_hops=" + hops;
    }

    //  WikiProjects organize by talk pages, but let's end on the subject page.
    //
    if ((wgCanonicalNamespace == "Category" || wgCanonicalSpecialPageName == "Whatlinkshere")
             && continuing && hops <= 0)
        newpage = newpage.replace("/Talk:", "/").replace("_talk:", ":");

    if (typeof randomlink_open != "undefined" && randomlink_open && !continuing)
        window.open( newpage );
    else
        window.location = newpage;
}

function pagedUrl( url )
{
    var param = "";
    var value;
    var alphabet = "!abcdefghijklmnoprstuvwy~";

    if (url.indexOf("/Category:") >= 0) {
        value = alphabet.charAt(alphabet.length * Math.random()).toUpperCase()
              + alphabet.charAt(alphabet.length * Math.random());
        param = (value < "M" ? "from" : "until");
    }
    if (url.indexOf("Special:WhatLinksHere") >= 0) {
        param = "from";
        value = Math.floor( randomlink_maxfrom * Math.random() );
        // Clustering will hurt randomness, but better than nothing
    }
    if (url.search(/Special:\w+s\b/) >= 0) {
        param = "offset";
        value = Math.floor( randomlink_maxoffset * Math.random() );
    }
    if (param) {
        url += (url.indexOf("?") >= 0) ? "&" : "?";
        url += param + "=" + encodeURIComponent(value);
    }
    return url;
}

$( function()
{
    var hops = document.URL.match( /random_hops=(\d+)/ );
    if (hops)  randomLink( null, hops );

    var where = 'this page';
    if (typeof randomlink_start != 'undefined')
        where = randomlink_start.toString().slice(0,500);

    mw.util.addPortletLink('p-navigation', 'javascript:randomLink()', 'Random link',
                   'n-randomlink', 'Follow a randomly chosen link on ' + where, '@');
});