TrexBoot

var TREX_VERSION="1.09";
// Dependencies
  include("http://outliner.smallpicture.com/strings.js");
  include("http://static.smallpicture.com/pagedown/Markdown.Converter.js");
  include("http://static.smallpicture.com/js/sha1.js");
  include("http://static.smallpicture.com/js/oauth.js");
  include("http://static.smallpicture.com/js/strftime.js");
  // string helpers and String object extensions
    var string = {};
    string.patternmatch = function(pattern, str){
      return str.indexOf(pattern);
      };
    string.insert = function(source,dest,ix){
      var s1 = dest.substr(0,ix);
      var s2 = dest.substr(ix,dest.length-ix);
      return s1 + source + s2;
      };
    string.nthfield = function(s,chdelim,n){
      var splits = s.split(chdelim);
      if(splits.length >= n){
        return splits[n-1];
        }
      return null;
      };
    string.delete = function(s, ix, ct){
      var start = ix-1;
      var end = (ix+ct)-1;
      var s1 = s.substr(0, start);
      var s2 = s.substr(end);
      return s1+s2;
      };
    string.lower = function(s){
      return s.toLowerCase();
      };
    string.empty = function(s){
      if(s==undefined){
        return true;
        }
      if(s==null){
        return true;
        }
      if(s==""){
        return true;
        }
      return false;
      };
    string.padwithzeros = function(num, places){
      var s = num.toString();
      var padding = "";
      for(var i = 0; i < (places-s.length); i++){
        padding += "0";
        }
      return padding+s;
      };
    string.multiplereplaceall = function(s, adrTable, flCaseSensitive, startCharacters, endCharacters){
      if(flCaseSensitive===undefined){
        flCaseSensitive = false;
        }
      if(startCharacters===undefined){
        startCharacters="";
        }
      if(endCharacters===undefined){
        endCharacters="";
        }
      for( var item in adrTable){
        var replacementValue = adrTable[item];
        var regularExpressionModifier = "g";
        if(!flCaseSensitive){
          regularExpressionModifier = "gi";
          }
        var regularExpressionString = (startCharacters+item+endCharacters).replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
        var regularExpression = new RegExp(regularExpressionString, regularExpressionModifier);
        s = s.replace(regularExpression, replacementValue);
        }
      return s;
      };
    string.mid = function(s, ix, len){
      return s.substr(ix-1,len);
      };
    String.prototype.beginswith = function(startsWithStr){
      if(this.match(new RegExp("^"+startsWithStr))){
        return true;
        }
      return false;
      };
    String.prototype.endswith = function(startsWithStr){
      if(this.match(new RegExp(startsWithStr+"$"))){
        return true;
        }
      return false;
      };
  // misc helpers
    var infinity = Number.MAX_VALUE;
    function defined(ref){
      return (ref !== undefined);
      }
    function boolean(val){
      if(val===true){
        return true;
        }
      if(val=="true"){
        return true;
        }
      return false;
      }
    function randomNumber(start, end){
      return Math.floor((Math.random()*(end-start))+start);
      }
    function camelCase(str) { // 5/29/13 by KS
      str = str.replace("-", " ");
      return str.replace(/(?:^\w|[A-Z]|\b\w)/g, function(letter, index) {
        return index == 0 ? letter.toLowerCase() : letter.toUpperCase();
        }).replace(/\s+/g, '');
      }
    function getCommentHtml (pagetable, groupname, flHidable) { //6/7/13 by DW
      var id = "", hidingCode, visibleStyle;
      if (pagetable.macros.opmlUrl != undefined) {
        id += pagetable.macros.opmlUrl ;
        }
      if (pagetable.macros.created != undefined) {
        id += pagetable.macros.created ;
        }
      //set hidingCode -- 7/4/13 by DW
        if (pagetable.macros.type == "thread") {
          if (flHidable == undefined) {
            flHidable = false;
            }
          }
        else {
          if (pagetable.macros.flCommentsHidable != undefined) {
            if (pagetable.macros.flCommentsHidable == "true") {
              flHidable = true;
              }
            else {
              flHidable = false;
              }
            }
          else {
            if (flHidable == undefined) {
              flHidable = true;
              }
            }
          }
        if (flHidable) {
          var initialState = "visible";
          hidingCode = "";
          if (pagetable.macros.flCommentsVisible != undefined) {
            if (pagetable.macros.flCommentsVisible == "false") {
              initialState = "hidden";
              }
            }
          visibleStyle = " style=\"visibility: " + initialState + ";\" ";
          }
        else {
          hidingCode = "";
          visibleStyle = "";
          }
      if (id.length > 0) {
        id = "var disqus_identifier = '" + id + "';"
        }

      return (id + hidingCode + "

      ");

      }
    Date.prototype.strftime_f.e = function(d){
      return d.getDate() + '';
      };
    Date.prototype.strftime_f.N = function(d){
      return (d.getMonth()+1) + '';
      };
    function getDate(datevalue, timeZoneOffset){
      try {
        if(!defined(timeZoneOffset)){
          return new Date(datevalue);
          }
        var offset = new Number(timeZoneOffset);
        var d = new Date(datevalue);
        var localTime = d.getTime();
        var localOffset = d.getTimezoneOffset() * 60000;
        var utc = localTime + localOffset;
        var newTime = utc + (3600000*offset);
        return new Date(newTime);
        }
      catch (tryerror){
        return new Date(datevalue);
        }
      }
    Number.prototype.toRoman= function(){
      var n= Math.floor(this),val,s= '',limit= 3999,i= 0;
      v= [1000,900,500,400,100,90,50,40,10,9,5,4,1],
      r= ['M','CM','D','CD','C','XC','L','XL','X','IX','V','IV','I'];
      if(n< 1 || n> limit) return '';
      while(i<13){
        val= v[i];
        while(n>= val){
          n-= val;
          s+= r[i];
        }
        if(n== 0) return s;
        ++i;
      }
      return '';
      }
// World Outline
  var worldOutline = {};
  worldOutline.macros = {
    includeHTTP: function(url){
      var r = http.get(url);
      if(r.code==200){
        return r.body;
        }
      return "";
      },
    square: function(i){
      return i*i;
      },
    icon: function(name){
      return '';
      },
    version: function () { //8/21/13 by DW
      return (TREX_VERSION);
      },
    slogan: function () {
      var now = new Date (), slogans = [
        "Good for the environment.",
        "All baking done on premises.",
        "Still diggin!",
        "It's even worse than it appears.",
        "Ask not what the Internet can do for you...",
        "You should never argue with a crazy man.",
        "Welcome back my friends to the show that never ends.",
        "People come back to places that send them away.",
        "Greetings, citizen of Planet Earth. We are your overlords. :-)",
        "We don't need no stinkin rock stars.",
        "This aggression will not stand.",
        "Pay no attention to the man behind the curtain.",
        "Only steal from the best.",
        "Reallll soooon now...",
        "What a long strange trip it's been.",
        "Ask not what the Internet can do for you.",
        "When in doubt, blog."
        ];
      return ("" + slogans [now.getMinutes () % slogans.length] + "");
      },
    disqusComments: function (groupname) {
      return (getCommentHtml (this.pagetable, groupname, false));
      },
    reader: function (opmlurl, font, fontSize, lineHeight) { //8/6/13 by DW
      var s = "";
      opmlurl = opmlurl.replace ("dl.dropbox.com", "dl.dropboxusercontent.com"); //8/7/13 by DW
      opmlurl = opmlurl.replace ("www.dropbox.com", "dl.dropboxusercontent.com"); //8/7/13 by DW
      if (font == undefined) {
        font = "Arial";
        }
      if (fontSize == undefined) {
        fontSize = "16";
        }
      if (lineHeight == undefined) {
        lineHeight = "24";
        }
      if (defined (this.pagetable.glossary ["<%outlineEmbedCode%>"])) {
        s = this.pagetable.glossary ["<%outlineEmbedCode%>"];
        s = s.replace ("<%opmlUrl%>", opmlurl);
        s = s.replace ("<%font%>", font);
        s = s.replace ("<%fontSize%>", fontSize);
        s = s.replace ("<%lineHeight%>", lineHeight);
        }
      return (s);
      },
    googleAnalytics: function (account) {
      var s =
        "var _gaq = _gaq || []; _gaq.push(['_setAccount', '%%account%%']); _gaq.push(['_setDomainName', '%%domain%%']); _gaq.push(['_trackPageview']); (function() {var ga = document.createElement('script'); ga.type = ";
        s += "'text/javascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); })();";
      if (account == undefined) { //6/30/13 by DW
        account = this.pagetable.macros.googleAnalyticsID;
        if (account == undefined) {
          return ("");
          }
        }
      s = s.replace ("%%account%%", account);
      s = s.replace ("%%domain%%", this.pagetable.request.headers ["Host"]);
      return ("" + s + "");
      },
    scriptingCounter: function (groupname) {
      if (groupname == undefined) { //8/8/13 by DW
        groupname = this.pagetable.macros.counterGroupName;
        if (groupname == undefined) {
          return ("");
          }
        }
      var referer = this.pagetable.request.headers ["Referer"];
      var imageUrl = "http://counters.scripting.com/counters/count.gif?group=" + groupname + "&referer=" + escape (referer);
      var imageTag = "";
      return (imageTag);
      },
    rssLink: function () {
      if (this.pagetable.macros.opmlFeed != undefined) {
        return ("");
        }
      else {
        return ("");
        }
      },
    prevNextLinks: function (iconPrev, iconNext) {
      var prevLink, nextLink;
      if (iconPrev == undefined) {
        iconPrev = "arrow-left";
        }
      if (iconNext == undefined) {
        iconNext = "arrow-right";
        }
      if (this.pagetable.macros.urlPrev.length > 0) {
        prevLink = "";
        }
      else {
        prevLink = "";
        }
      if (this.pagetable.macros.urlNext.length > 0) {
        nextLink = "";
        }
      else {
        nextLink = "";
        }

      return ("
      " + prevLink + " " + nextLink + "
      ");

      }
    };
  worldOutline.methods = {
    bloghome: function(adrobject, adrxstruct, template, glossary, atts){
      var homeOutline = new libxml.Document("1.0");
      homeOutline.node("opml").node("body");
      var homeBody = homeOutline.get("/opml/body");
      var counter = 0;
      var bloghomeItemsToShow = 10000;
      if(defined(atts.bloghomeItemCount) && (atts.bloghomeItemCount!="") && (this.pagetable.request.uri=="/")){
        var parsedCount = parseInt(atts.bloghomeItemCount);
        if(parsedCount!=NaN){
          bloghomeItemsToShow = parsedCount;
          }
        }
      var pathNames = [];
      var relpath = this.pagetable.request.uri;
      if(!relpath.endswith("/")){
        relpath=relpath+"/";
        }
      var pagetable = this.pagetable;
      var isdirective = function(adr){
        if(adr.attr("text")!=null){
          return adr.attr("text").value().beginswith("#");
          }
        return false;
        };
      var iscomment = function(adr){
        if(adr.attr("isComment")!=null){
          return (adr.attr("isComment").value()=="true");
          }
        return false;
        };
      var dolevel = function(adr){
        for(var i in adr.childNodes()){
          var adrchild =adr.childNodes()[i];
          if(adrchild.name().endswith("outline") && (adrchild.attr("text")!=null) && !isdirective(adrchild) && !iscomment(adrchild)){
            var name = getCanonicalName(adrchild.attr("text").value());
            if(adrchild.attr("name")!=null){
              name = adrchild.attr("name").value();
              }
            pathNames.push(name);
            if((adrchild.attr("type")!=null) && (adrchild.attr("type").value()!="index") && (adrchild.attr("type").value()!="redirect")){
              if(counter < bloghomeItemsToShow){
                var childUrl = relpath+pathNames.join("/");
                var newText = ""+adrchild.attr("text").value()+"";
                var method = undefined;
                if(adrchild.attr("method")!=null){
                method = adrchild.attr("method").value().toLowerCase();
                }
                else if (adrchild.attr("type")!=null){
                if(adrchild.attr("type").value().toLowerCase()=="markdown"){
                method = "markdown";
                }
                }
                for(var j in adrchild.attrs()){
                var childatt = adrchild.attrs()[j];
                if(childatt.name()=="type"){
                childatt.value("");
                }
                else if (childatt.name()=="text"){
                childatt.value(newText);
                }
                }
                if(adrchild.attr("created")!=null){
                var d = getDate(adrchild.attr("created").value(), pagetable.macros.siteTimeZone);
                var dateText = " " + d.strftime("%N/%e/%Y; %l:%M:%S %p") + "";
                if(defined(method) && (method=="markdown")){
                adrchild.node("outline").attr({"text" : ""});
                }
                adrchild.node("outline").attr({"text" : dateText});
                }
                homeBody.addChild(adrchild);
                counter++;
                }
              else {
                break;
                }
              }
            else {
              dolevel(adrchild);
              }
            pathNames.pop();
            }
          }
        };
      dolevel(adrxstruct);
      var rulesText = "";
      if(defined(template)){
        rulesText = template.rulesText
        }
      return viewOutline(homeBody, rulesText, relpath, glossary, atts);
      },
    presentation: function(adrpost){
      var slides = "";
      var indentlevel = 0;
      var add = function(s){
        slides = slides + (filledString ("\t", indentlevel-1) + s + "\r\n");
        };
      var iscomment = function(adr){
        return (adr.attributes["isComment"]=="true");
        };
      var textatt = function(adr){
        return adr.attributes["text"];
        };
      var hassubs = function(adr){
        return (adr.children.length>0);
        };
      var isdirective = function(adr){
        return (adr.attributes["text"].beginswith("#"));
        };
      for(var i in adrpost.children){
        var adrslide = adrpost.children[i];
        if (adrslide.name.endswith("outline")) {
          if(isdirective(adrslide)){
            continue;
            }
          if(!iscomment(adrslide)){
            var dolevel = function (adrlevel){

              add ("
              "); indentlevel++;

              for (var j in adrlevel.children) {
                var adr = adrlevel.children[j];
                if(!iscomment (adr)){

                add ("
                " + textatt (adr) + "
                ");

                if (hassubs (adr)){
                dolevel (adr);
                }
                }
                }

              add ("
              "); indentlevel--;

              };

            add ("
            "); indentlevel++;

            add ("
            " + textatt (adrslide) + "
            ");

            dolevel (adrslide);

            add ("
            "); indentlevel--;

            }
          }
        }
      if(!defined(this.pagetable.macros.theme)){
        this.pagetable.macros.theme = "default";
        }
      if(!defined(this.pagetable.macros.transition)){
        this.pagetable.macros.transition = "default";
        }
      return slides;
      }
    };
  worldOutline.firstFilter = function(pagetable){
    // called before rendering
    // pagetable.macros is where the atts are stored and can be read/modfiied
    // byline
      var createdWithTimeZone = "";
      if(pagetable.macros.created!=""){
        createdWithTimeZone = getDate(pagetable.macros.created, pagetable.macros.siteTimeZone).toGMTString();
        }
      var url = pagetable.macros.opmlOwnerProfile;
      if (url.length == 0) {
        url = pagetable.macros.opmlLink;
        }
      if (url.length == 0) {
        pagetable.macros.byline = pagetable.macros.opmlOwnerName;
        }
      else {
        pagetable.macros.byline = "" + pagetable.macros.opmlOwnerName + "";
        }
    // menus
      pagetable.macros.menu = "";
      if(defined(pagetable.macros.menuName) && defined(pagetable.macros.menusStruct)){
        var menuStruct = undefined;
        for(var i in pagetable.macros.menusStruct.children){
          var menuChild = pagetable.macros.menusStruct["children"][i];
          if(menuChild.attributes["text"] == pagetable.macros.menuName){
            menuStruct = menuChild;
            break;
            }
          }
        if(menuStruct){
          var macroReplace = function(s){
            return string.multiplereplaceall(s, pagetable.macros, false, "<%", "%>");
            };
          if(menuStruct.children.length>0){
            var menu = menuStruct.children[0];
            if(defined(menu)){
              var menuTitle = macroReplace(menu.attributes["text"]);
              var menuItems = menu.children;

              var menuHtml = "

              ";

              menuHtml += ""+menuTitle+"";

              menuHtml += "
              ";

              for(var i in menuItems){
                var item = menuItems[i];
                var addMenuItem = function(_item, _parent){
                if(_item.attributes["type"] && (_item.children.length>0)){
                var parentPrefix = "";
                if(defined(_parent)){
                var parentName = getCanonicalName(_parent.attributes["text"]);
                if(defined(_parent.attributes["name"])){
                parentName = _parent.attributes["name"];
                }
                parentPrefix = parentName + "/";
                }
                var name = getCanonicalName(_item.attributes["text"]);
                if(defined(_item.attributes["name"])){
                name = _item.attributes["name"];
                }

                menuHtml += "
                "+macroReplace(_item.attributes["text"])+"
                ";

                }
                else if (_item.attributes["text"]=="-"){

                menuHtml += "

                ";

                }
                else if (_item.attributes["url"]){

                menuHtml += "
                "+macroReplace(_item.attributes["text"])+"
                ";

                }
                else {

                menuHtml += "
                "+macroReplace(_item.attributes["text"])+"
                ";

                }
                };
                if(!defined(item.attributes["text"])){
                continue;
                }
                if(item.attributes["type"]=="archive"){
                item.attributes["type"] = undefined;
                for(var i in pagetable.opml.get("/opml/body").childNodes()){
                var year = pagetable.opml.get("/opml/body").childNodes()[i];
                if(year.name().endswith("outline")){
                if((year.attr("text")!=null) && (year.attr("name")!=null)){
                if(year.attr("name").value().match(/^\d{4}$/)){
                if(year.childNodes().length>0){
                for(var j in year.childNodes()){
                var yearChild = year.childNodes()[j];
                if(yearChild.name().endswith("outline")){
                if((yearChild.attr("text")!=null) && (yearChild.attr("name")!=null)){
                if(yearChild.attr("name").value().match(/^\d{2}$/)){
                if(yearChild.childNodes().length > 0){
                var monthUrl = "/" + year.attr("name").value() + "/" + yearChild.attr("name").value();
                var monthText = yearChild.attr("text").value();
                item.children.push({name: "outline", attributes: {url: monthUrl, text: monthText}, children: []});
                }
                }
                }
                }
                }
                }
                }
                }
                }
                }
                }
                if(item.children.length > 0){
                if(defined(item.attributes["type"])){
                addMenuItem(item);
                }
                else {

                menuHtml += "
                "+item.attributes["text"]+" ";

                menuHtml += "
                ";

                for(var j in item.children){
                var dropdownItem = item.children[j];
                if(!defined(dropdownItem.attributes["text"])){
                continue;
                }
                addMenuItem(dropdownItem, item);
                }

                menuHtml += "

                ";

                }
                }
                else {
                addMenuItem(item);
                }
                }

              menuHtml += "

              ";

              pagetable.macros.menu = menuHtml;
              }
            }
          }
        }
    //comments att
      var groupname = "smallpict"; //6/29/13 by DW
      if (pagetable.macros.disqusGroupName != undefined) {
        groupname = pagetable.macros.disqusGroupName;
        }
      if ((pagetable.macros.flDisqusComments != undefined) && (pagetable.macros.flDisqusComments.toLowerCase () != "true")) {
        pagetable.macros.comments = "";
        }
      else { //7/4/13 by DW
        pagetable.macros.comments = getCommentHtml (pagetable, groupname);
        }
    // bootstrapTheme
      if(defined(pagetable.macros.bootstrapTheme)){
        if(defined(pagetable.glossary["<%useBootstrap%>"])){
          var bootstrapThemeUrl = pagetable.macros.bootstrapTheme;
          var bootstrapMatches = bootstrapThemeUrl.match(/^(\w+)$/);
          if(bootstrapMatches!=null){
            bootstrapThemeUrl = "http://bootswatch.com/"+bootstrapMatches[1].toLowerCase()+"/bootstrap.min.css"
            }
          bootstrapThemeUrl = bootstrapThemeUrl.replace ("/bootswatch.com/", "/static.smallpicture.com/bootswatch/"); //8/5/13 by DW
          pagetable.glossary["<%useBootstrap%>"] = pagetable.glossary["<%useBootstrap%>"].replace("http://static.smallpicture.com/bootstrap/css/bootstrap.css", bootstrapThemeUrl);
          }
        }
    };
  worldOutline.finalFilter = function(pagetable){
    // called after rendering
    // pagetable.response.code is the HTTP code (200 for success. 500 on error.)
    // pagetable.response.body is the html text string that is about to be rendered back to the user
    };
  function processMethod(methodName, adrmethods, env, adrnode, template, glossary, atts){
    var hassubs = function(adrx){
      return (adrx.childNodes().length > 0);
      };
    var dolevel = function(adrlevel){
      var adrchildren = adrlevel.childNodes();
      for(var i in adrchildren){
        var adr = adrchildren[i];
        if(adr.name()=="outline"){
          if(defined(adr.attr("isComment")) && (adr.attr("isComment")!=null) && (adr.attr("isComment").value()=="true")){
            continue;
            }
          var text = null;
          if(adr.attr("text")!=null){
            text = adr.attr("text").value();
            }
          else{
            continue;
            }
          // process #directives
            var directiveMatch = text.match(/^#(\w+)\s+"(.+)"$/);
            if(directiveMatch != null){
              var directiveName = directiveMatch[1];
              var directiveValue = directiveMatch[2];
              atts[directiveName] = directiveValue;
              continue;
              }
          if(hassubs(adr)){
            dolevel (adr);
            }
          }
        }
      }
    dolevel(adrnode);
    var xmlstruct = xmlNodeToStruct(adrnode);
    return adrmethods[methodName].apply(env, [xmlstruct, adrnode, template, glossary, atts]);
    }
  function xmlNodeToStruct(adrnode){
    var includestack = [];
    var elementToStruct = function(adrelement){
      var element = new Object();
      element.name = adrelement.name();
      element.text = adrelement.text();
      element.attributes = new InsensitiveObject();
      element.children = [];
      for(var ai in adrelement.attrs()){
        var att = adrelement.attrs()[ai];
        element.attributes[att.name()]=att.value();
        }
      if(!defined(element.attributes["text"])){
        return undefined;
        }
      if((adrelement.childNodes().length==0) && defined(element.attributes["type"]) && (element.attributes["type"] == "include") && defined(element.attributes["url"])){
        try {
          var url = element.attributes["url"];
          if(includestack.indexOf(url) == -1){
            var includeOpml = op.getNetOutline(url);
            var includeBody = includeOpml.get("/opml/body");
            for(var z in includeBody.childNodes()){
              var includeBodyChild = includeBody.childNodes()[z];
              adrelement.addChild(includeBodyChild);
              }
            includestack.push(url);
            }
          }
        catch(err){
          console.log(err);
          }
        }
      var adrchildren = adrelement.childNodes();
      for(var i in adrchildren){
        var adr = adrchildren[i];
        if(defined(adr.attr("isComment")) && (adr.attr("isComment")!=null) && (adr.attr("isComment").value()=="true")){
          continue;
          }
        var childElement = elementToStruct(adr);
        if(defined(childElement)){
          element.children.push(childElement);
          }
        }
      return element;
      };
    var struct = elementToStruct(adrnode);
    return struct;
    }
  function pathWalk(adrnode, path, adrAtts){
    if(!defined(adrAtts)){
      adrAtts = {};
      }
    var originalnode = adrnode;
    var origpath = path;
    var pathNames = [];
    var isdirective = function(adr){
      if(adr.attr("text")!=null){
        return adr.attr("text").value().beginswith("#");
        }
      return false;
      };
    var iscomment = function(adr){
      if(adr.attr("isComment")!=null){
        return (adr.attr("isComment").value()=="true");
        }
      return false;
      };
    var setAtts = function(adr){
      for(var k in adr.attrs()){
        var att = adr.attrs()[k];
        if(defined(att.value())){
          if(att.name().toLowerCase() && (att.value().toLowerCase()!="include")){
            adrAtts[att.name()] = att.value();
            }
          }
        }
      };
    var processDirectives = function(adrparent){
      var type = adrparent.attr("type");
      var url = adrparent.attr("url");
      if((type!=null) && (url!=null) && (type.value()=="include") && (adrparent.childNodes().length==0)){
        var includeOpml = op.getNetOutline (url.value());
        var includeBody = includeOpml.get("/opml/body");
        for(var i in includeBody.childNodes()){
          var includeChild = includeBody.childNodes()[i];
          adrparent.addChild(includeChild);
          }
        }
      for(var i in adrparent.childNodes()){
        var adr = adrparent.childNodes()[i];
        if(adr.name().endswith("outline")){
          if(adr.attr("text")){
            var text = adr.attr("text").value();
            var directiveMatch = text.match(/^#(\w+)\s+"(.+)"$/);
            if(directiveMatch != null){
              var directiveName = directiveMatch[1];
              var directiveValue = directiveMatch[2];
              adrAtts[directiveName] = directiveValue;
              }
            }
          }
        }
      };
    var addIncludedContent = function(adrinclude){
      if((adrinclude.attr("type").value()!="include") || (adrinclude.attr("url")==null)){
        return;
        }
      var url = adrinclude.attr("url").value();
      if(adrinclude.childNodes().length==0){
        var includeOpml = op.getNetOutline (url);
        var includeBody = includeOpml.get("/opml/body");
        for(var i in includeBody.childNodes()){
          var includeChild = includeBody.childNodes()[i];
          adrinclude.addChild(includeChild);
          }
        }
      };
    var findsubof = function(adrparent, name){
      var type = adrparent.attr("type");
      if((type!=null) && (type.value()=="include")){
        addIncludedContent(adrparent);
        }
      var lowername = string.lower(name);
      // process #directives
        processDirectives(adrparent);
      for(var i in adrparent.childNodes()){
        var adr = adrparent.childNodes()[i];
        if(adr.name().endswith("outline") && !isdirective(adr) && !iscomment(adr)){
          if(adr.attr("name")){
            if(string.lower(adr.attr("name").value()) == lowername){
              return adr;
              }
            }
          }
        }
      for(var i in adrparent.childNodes()){
        var adr = adrparent.childNodes()[i];
        if(adr.name().endswith("outline") && !isdirective(adr) && !iscomment(adr)){
          var lowertext = string.lower(adr.attr("text").value());
          if(lowertext==lowername){
            return adr;
            }
          if(string.lower(getCanonicalName(lowertext)) == lowername) {
            return adr;
            }
          }
        }
      return null;
      };
    var setNextPrev = function(){
      var linearnodes = adrnode.find("//outline[@type]");
      var lastNode = null;
      var prevNode = null;
      var nextNode = null;
      var foundNode = null;
      var hasparentcomment = function(adr){
        if((adr.parent()!=null) && (adr.parent().name().endswith("outline"))){
          if( iscomment(adr.parent()) ){
            return true;
            }
          else {
            return hasparentcomment(adr.parent());
            }
          }
        return false;
        };
      for(var z in linearnodes){
        var node = linearnodes[z];
        if(node.attr("type")==null){
          continue;
          }
        if(iscomment(node) || isdirective(node) || hasparentcomment(node)){
          continue;
          }
        var nodeType = node.attr("type").value();
        if((nodeType=="index") || (nodeType=="bloghome") || (nodeType=="link") || (nodeType=="redirect")){
          continue;
          }
        if(node === adrnode){
          foundNode = node;
          if(lastNode!=null){
            if(lastNode.attr("type").value()=="include"){
              for(var j = z-2; z >= 0; j--){
                var lastLinearNode = linearnodes[j];
                var lastLinearType = lastLinearNode.attr("type").value().toLowerCase();
                if((lastLinearType!="include") && (lastLinearType!="index") && (lastLinearType!="bloghome")){
                prevNode = lastLinearNode;
                break;
                }
                }
              }
            else{
              prevNode = lastNode;
              }
            }
          }
        else {
          if(foundNode != null){
            nextNode = node;
            break;
            }
          else {
            lastNode = node;
            }
          }
        }
      var getpathfornode = function(adr){
        var paths = [];
        do {
          if(!adr.name().endswith("outline")){
            break;
            }
          if(adr.attr("domain")!=null){
            break;
            }
          var name = undefined;
          if(adr.attr("text")!=null){
            name = getCanonicalName(adr.attr("text").value());
            }
          else {
            return undefined;
            }
          if(adr.attr("name")!=null){
            name = adr.attr("name").value();
            }
          if(!defined(name)){
            return undefined;
            }
          if(adr.attr("text").value().beginswith("#")){
            return undefined;
            }
          paths.push(name);
          adr = adr.parent();
          } while(adr!=null);
        if(paths.length==0){
          return undefined;
          }
        return "/"+ paths.reverse().join("/");
        };
      if(prevNode!=null){
        var prevPath = getpathfornode(prevNode);
        if(defined(prevPath)){
          adrAtts.urlPrev = prevPath;
          }
        }
      if(nextNode!=null){
        if(nextNode.attr("type").value()=="include"){
          addIncludedContent(nextNode);
          for(var i = 0; i < nextNode.childNodes().length; i++){
            var includedTypeNode = nextNode.childNodes()[i];
            if(includedTypeNode.attr("type")==null){
              continue;
              }
            var includedTypeNodeType = includedTypeNode.attr("type").value().toLowerCase();
            if((includedTypeNodeType=="index") || (includedTypeNodeType=="bloghome") || (includedTypeNodeType=="link") || (includedTypeNodeType=="redirect")){
              continue;
              }
            nextNode = includedTypeNode;
            break;
            }
          }
        var nextPath = getpathfornode(nextNode);
        if(defined(nextPath)){
          adrAtts.urlNext = nextPath;
          }
        }
      };
    setAtts(adrnode);
    // process #directives
      processDirectives(adrnode);
    do {
      if(path.beginswith("/")){
        path = string.delete(path,1,1);
        }
      if(path.length==0){
        return adrnode;
        }
      name = string.nthfield(path, "/", 1);
      adrnode = findsubof(adrnode, name);
      if(defined(adrAtts["text"]) && defined(adrAtts.breadcrumbsArray)){
        var text = adrAtts["text"];
        var crumblink = ""+text+"";
        adrAtts.breadcrumbsArray.push(crumblink);
        }
      pathNames.push(name);
      if(adrnode==null){
        return null;
        }
      setAtts(adrnode);
      path = string.delete (path, 1, name.length + 1);
      } while(path.length>0);
    setNextPrev();
    return adrnode;
    }
  function getRawHtml(adrhtmlnode, macros){
    var htmltext = "";
    var indentlevel=0;
    var directives = {};
    var includestack = [];
    var add = function(s){
      if(s!=null){
        htmltext = htmltext + filledString("\t", indentlevel-1) + s + "\r\n";
        }
      };
    var hassubs = function(adrx){
      return (adrx.childNodes().length > 0);
      };
    var dolevel = function(adrlevel, fljavascript){
      if(fljavascript==undefined){
        fljavascript=false;
        }
      if((adrlevel.attr("type") != null) && (adrlevel.attr("type").value()=="javascript")){
        fljavascript=true;
        }
      var adrchildren = adrlevel.childNodes();
      for(var i in adrchildren){
        var adr = adrchildren[i];
        if(adr.name()=="outline"){
          if(defined(adr.attr("isComment")) && (adr.attr("isComment")!=null) && (adr.attr("isComment").value()=="true")){
            continue;
            }
          var text = null;
          if(adr.attr("text")!=null){
            text = adr.attr("text").value();
            }
          else{
            continue;
            }
          // process #directives
            var directiveMatch = text.match(/^#(\w+)\s+"(.+)"$/);
            if(directiveMatch != null){
              if(defined(macros)){
                var directiveName = directiveMatch[1];
                var directiveValue = directiveMatch[2];
                macros[directiveName] = directiveValue;
                }
              continue;
              }
          if(!hassubs(adr) && defined(adr.attr("type")) && (adr.attr("type")!=null) && (adr.attr("type").value()=="include") && defined(adr.attr("url"))){
            // dive into include node
              try {
                var url = adr.attr("url").value();
                if(includestack.indexOf(url) == -1){
                var includeOpml = op.getNetOutline(url);
                var includeBody = includeOpml.get("/opml/body");
                for(var z in includeBody.childNodes()){
                var includeBodyChild = includeBody.childNodes()[z];
                adr.addChild(includeBodyChild);
                }
                includestack.push(url);
                }
                }
              catch(err){
                console.log(err);
                }
            }
          if(hassubs(adr)){
            if(fljavascript){
              var ix = text.indexOf("//");
              if(ix > 0){
                text = string.insert(" { ", text, ix);
                }
              else{
                text = text + " { ";
                }
              }
            add(text);
            indentlevel++;
            dolevel (adr, fljavascript);
            if(fljavascript){
              add("}");
              }
            indentlevel--;
            }
          else{
            var semicolon = "";
            if(fljavascript){
              semicolon = ";";
              }
            add(text + semicolon);
            }
          }
        }
      };
    dolevel(adrhtmlnode);
    return htmltext;
    }
  function processMacros(s, adrmacros, env){
    if(adrmacros===undefined){
      adrmacros = worldOutline.macros;
      }
    var processMacro = function(macrotext){
      var macroFunctionNames = [];
      for(var key in adrmacros){
        macroFunctionNames.push(key);
        }
      var matches = macrotext.match(new RegExp("^\\s*("+macroFunctionNames.join("|")+")\\s*\\((.*)\\)\\s*$"));
      if(matches){
        try {
          var macroName = matches[1];
          var macroArguments = [];
          if(matches[2]!=""){
            macroArguments = JSON.parse("["+matches[2]+"]");
            }
          return adrmacros[macroName].apply(env, macroArguments);
          }
        catch (tryerror){
          return ("" + tryerror + "")
          }
        }
      else{
        return "<%"+macrotext+"%>";
        }
      };
    var i = 0;
    while( i < s.length){
      if (s[i] == "<") {
        if (s[i+1] == "%"){
          var flfound = false;
          for(var j = i+2; j < (s.length-1); j++){
            if ((s[j] == "%") && (s[j+1] == ">")){
              var macrotext = s.substr(i+2,j-i-2);
              macrotext = processMacro(macrotext) + "";
              s = string.delete(s, i+1, j-i+2);
              s = string.insert(macrotext, s, i);
              i = i + macrotext.length;
              flfound = true;
              break;
              }
            }
          if(!flfound){
            break;
            }
          }
        else {
          i = i+2;
          }
        }
      else {
        i++;
        }
      }
    return s;
    }
  function getNetOutlineWithIncludes(opmlUrl, includeCallback){
    var xstruct = op.getNetOutline(opmlUrl);
    var visit = function(adrx, visitedUrls){
      if(defined(includeCallback)){
        if(!includeCallback(adrx)){
          return;
          }
        }
      if(visitedUrls===undefined){
        visitedUrls=[];
        }
      if(adrx.attr("type") && (adrx.attr("type").value()=="include") && adrx.attr("url") && (adrx.childNodes().length==0) && (visitedUrls.indexOf(adrx.attr("url").value()) == -1) ){
        var includeUrl = adrx.attr("url").value();
        visitedUrls.push(includeUrl);
        try {
          var includeOpml = op.getNetOutline(includeUrl);
          var includeBody = includeOpml.get("//body");
          for(var i in includeBody.childNodes()){
            var includeChild = includeBody.childNodes()[i];
            var el = adrx.addChild(includeChild);
            visit(el.child(el.childNodes().length-1), visitedUrls);
            }
          }
        catch(err){
          console.log(err);
          }
        }
      for(var i in adrx.childNodes()){
        visit(adrx.childNodes()[i], visitedUrls);
        }
      };
    var body = xstruct.get("//body");
    for(var i in body.childNodes()){
      var child = body.childNodes()[i];
      visit(child, [opmlUrl]);
      }
    return xstruct;
    }
  function compileRules(text, rulesTable){
    try{ //7/3/13 by KS -- eat bad rules declarations
      if(!defined(text)){
        return;
        }
      if(text.length==0){
        return;
        }
      var doc = xml.parse(text);
      if(!defined(doc)){
        return;
        }
      var root = doc.get("/rules");
      if(!defined(root)){
        return;
        }
      for(var i in root.childNodes()){
        var ruleContainer = root.childNodes()[i];
        if(ruleContainer.name().endswith("rule")){
          var startlevel = 1;
          var endlevel = infinity;
          if(ruleContainer.attr("level")){
            startlevel = ruleContainer.attr("level").value();
            }
          if(ruleContainer.attr("to")){
            if(ruleContainer.attr("to").value()!="infinity"){
              endlevel = ruleContainer.attr("to").value();
              }
            }
          for(var j in ruleContainer.childNodes()){
            var rule = ruleContainer.childNodes()[j];
            if(rule.name()!="text"){
              rulesTable.push({"name": rule.name(), "value": rule.text(), "startlevel": startlevel, "endlevel": endlevel});
              }
            }
          }
        }
      }
    catch(tryerror){
      console.log(tryerror);
      }
    }
  function viewOutline(adrParent, adrInitialRulesText, relpath, glossary, macros){
    // Variable defaults
      var adrbody = adrParent;
      var htmltext = "\r";
      var indentlevel = 0;
      var level = 0;
      var oplevel = 0;
      var rules = [];
      var permalinkimg="";
      var fonts = {};
      var includestack = [];
      var t = {};
      var directives = {};
      var showClassName = "show";
      var flSuppressComments = true;
      var flHtmlCache = true;
      var flrulessuppliedbycaller = defined(adrInitialRulesText);
      var flfirstpush=true;
      var pathIntoOutline = null;
      var adrLineLevelCallback = null;
      var myrules = undefined;
      var harvardOutlineTypeStack = [];
    // setup rules
      if( defined(adrInitialRulesText) ){
        var r = [];
        compileRules(adrInitialRulesText, r);
        rules.push(r);
        }
      else {
        rules.push([]);
        }
    // images
      var wedgeBlankUrl = "http://i.opml.org/bw.gif";
      var wedgeRightUrl = "http://i.opml.org/rw.gif";
      var wedgeDownUrl = "http://i.opml.org/dw.gif";
      var wedgeblank = "";
      var docicon = "";
    // icons
      var wedgeRightIcon = "caret-right";
      var wedgeDownIcon = "caret-down";
    var add = function(s){
      htmltext = htmltext + filledString("\t", indentlevel) + s + "\r\n";
      };
    var hassubs = function(adrx){
      for(var i in adrx.childNodes()){
        var adr = adrx.childNodes()[i];
        if(adr.name().endswith("outline")){
          return true;
          }
        }
      return false;
      };
    var isinclude = function(adratts){
      return (adratts.type && (string.lower(adratts.type)=="include") && (adratts.url) && (adratts.url!="http://smallpicture.com/userDirectory.opml"));
      };
    var getExpandCollapseIcon = function (id, flInitiallyExpanded, showClassName, iconName) {
      if(!defined(flInitiallyExpanded)){
        flInitiallyExpanded = true;
        }
      if(!defined(showClassName)){
        showClassName = "show";
        }
      if(!defined(iconName)){
        iconName=null;
        }
      if (defined (myrules["no-icons"]) ) {
        if(myrules["no-icons"]=="true"){
          return "";
          }
        }
      var iconExpand;
      var iconCollapse;
      var iconStyle="";
      if(defined(myrules["font-size"])){
        iconStyle = " style=\"font-size: "+myrules["font-size"]+";\"";
        }
      //set iconExpand, iconCollapse
        if (defined (myrules["icon-expand"]) ) {
          iconExpand = myrules["icon-expand"];
          }
        else {
          iconExpand = wedgeRightIcon;
          }
        if ( defined (myrules["icon-collapse"]) ) {
          iconCollapse = myrules["icon-collapse"];
          }
        else {
          iconCollapse = wedgeDownIcon;
          }
      if (iconName == null) {
        if (flInitiallyExpanded) {
          iconName = iconCollapse;
          }
        else {
          iconName = iconExpand;
          }
        }
      else {
        iconExpand = iconName;
        iconCollapse = iconName;
        }
      var cssClasses = "ec ecIcon";
      if(flInitiallyExpanded){
        cssClasses += " expanded";
        }
      else{
        cssClasses += " collapsed";
        }
      var iconExpandHtml = "";
      if(iconExpand.beginswith("http://")){
        iconExpandHtml = "";
        }
      else {
        iconExpandHtml = "";
        }
      var iconCollapseHtml = "";
      if(iconCollapse.beginswith("http://")){
        iconCollapseHtml = "";
        }
      else {
        iconCollapseHtml = "";
        }
      var linkStyle = "";
      if(defined(myrules["font-size"])){
        linkStyle = " style=\"width: "+myrules["font-size"]+"; margin-left: -"+myrules["font-size"]+";\"";
        }
      return (""+iconExpandHtml+iconCollapseHtml+"");
      };
    var textToId = function (text) {
      var s = "";
      for(var i = 0; i < text.length; i++) {
        ch = text [i];
        if (isNumeric(ch) || isAlpha(ch)) {
          s = s + ch;
          }
        else {
          s = s + " ";
          }
        }
      s = getCanonicalName (s);
      if (s.length > 20) {
        s = string.mid (s, 1, 20);
        }
      return (s + randomNumber(1, 100000));
      };
    var notdocnode = function (adr){
      if(adr.attr("type") && (adr.attr("type")!=null) && (adr.attr("type").value()!="")){
        if(adr.attr("type").value()=="tweet"){
          return true;
          }
        else {
          return false;
          }
        }
      return true;
      };
    var pushruleslevel = function () {
      if (flfirstpush && flrulessuppliedbycaller) { //(adrInitialRules != nil)
        flfirstpush = false;
        return (rules [0]);
        }
      else {
        rules.push([]);
        return rules[rules.length-1];
        }
      };
    var popruleslevel = function (){
      rules.pop();
      };
    var getmyrules = function(){
      var _myrules = {};
      for(var i = 0; i < rules.length; i++){
        var relativeLevel = rules.length-(i+1)+1;
        var levelRules = rules[i];
        for(var j in levelRules){
          var rule = levelRules[j];
          if((relativeLevel >= rule.startlevel) && (relativeLevel <= rule.endlevel)){
            var val = rule.value;
            if(val=="infinity"){
              val = infinity;
              }
            _myrules[rule.name] = val;
            }
          }
        }
      return _myrules;
      };
    var nonstylerule = function (name) { //rules that don't get added to style attributes
      switch(string.lower (name)) {
        case "expanded":
        case "icon-expand":
        case "icon-collapse":
        case "no-icons":
        case "list-space":
        case "permalink":
        case "outline-indent":
        case "outline-space-before":
        case "outline-space":
          return true;
          break;
        }
      return false;
      };
    var getxmltext = function(adrtable, xmllevel){
      var _xmltext = filledString ("\t", xmllevel) + adrtable.attr("text").value() + "\r";
      xmllevel++;
      for(var i in adrtable.childNodes()){
        var child = adrtable.childNodes()[i];
        if(child.name().endswith("outline")){
          _xmltext = _xmltext + getxmltext(child, xmllevel);
          }
        }
      xmllevel--;
      return _xmltext;
      };
    var compilerules = function(adr, adrlocalrules){
      var xmltext = getxmltext(adr, 0);
      compileRules(xmltext, adrlocalrules);
      };
    var styletext = function (s, adrrules, flexpandable, adrnodeatts) { //apply rules to text
      var style = "";
      var classadd="";
      if(!defined(flexpandable)){
        flexpandable = false;
        }
      if(!defined(adrnodeatts)){
        adrnodeatts = null;
        }
      if (flexpandable) {
        classadd = " spanExpandableText";
        }
      if (defined(adrrules)) {
        for(var name in adrrules) {
          var value = adrrules[name];
          if (!nonstylerule (name)) {
            if (name == "font-family") {
              //fonts[adrrule] = true;
              }
            if(name == "new-item-color") {
              if (adrnodeatts != null) {
                if (defined (adrnodeatts.created)) {
                if (adrnodeatts.created > ((new Date()) - 3600)) {
                style = style + "color: " + adrrule.value + "; ";
                }
                }
                }
              continue;
              }
            style = style + name + ": " +value + "; ";
            }
          }
        if (style.length > 0) {
          style = " style=\"" + string.delete (style, style.length, 1) + "\"";
          }
        }
      s = "" + s + "";
      return (s);
      };
    var pushharvardoutlinetype = function(){
      if(myrules && myrules["numbering"] && (myrules["numbering"].toLowerCase()=="harvard")){
        var lastType = "";
        var outlineType = "";
        if(harvardOutlineTypeStack.length>0){
          lastType = harvardOutlineTypeStack[harvardOutlineTypeStack.length-1];
          }
        switch(lastType.toLowerCase()){
          case "romanuppercase":
            outlineType = "alphauppercase";
            break;
          case "alphauppercase":
            outlineType = "decimal";
            break;
          case "decimal":
            outlineType = "alphalowercase";
            break;
          case "alphalowercase":
            outlineType = "decimal";
            break;
          default:
            outlineType = "romanuppercase";
          }
        harvardOutlineTypeStack.push(outlineType);
        }
      else {
        harvardOutlineTypeStack=[];
        }
      };
    var popharvardoutlinetype = function(){
      harvardOutlineTypeStack.pop();
      };
    var addlevel = function(adrlevel, pathIntoOutline, relpath){
      if(relpath===undefined){
        relpath="";
        }
      if(relpath===null){
        relpath="";
        }
      var listitemstyle="";
      var itemnum = 0;
      var levelIndex = 1;
      var flpopincludestack = false;
      var adrlocalrules = pushruleslevel();
      var harvardOutlineType = pushharvardoutlinetype();
      myrules = getmyrules();
      if(pathIntoOutline != null){
        if(pathIntoOutline.beginswith("/")){
          pathIntoOutline = string.delete (pathIntoOutline, 1, 1);
          }
        var firstpathelement = string.nthfield (pathIntoOutline, "/", 1);
        pathIntoOutline = string.delete (pathIntoOutline, 1, firstpathelement.length);
        }
      // dive into include node
        var adratts = {};
        for(var j in adrlevel.attrs()){
          var att = adrlevel.attrs()[j];
          adratts[att.name()] = att.value();
          }
        if(isinclude(adratts)){
          if(includestack.indexOf(adratts.url) >= 0){
            popruleslevel();
            return;
            }
          try {
            var includeOpml = op.getNetOutline(adratts.url);
            adrlevel = includeOpml.get("/opml/body");
            includestack.push(adratts.url);
            flpopincludestack = true;
            }
          catch(err){
            console.log(err);
            popruleslevel();
            return;
            }
          }
      var style = "";
      if(myrules["outline-indent"]){
        style = style + "padding-left: "+myrules["outline-indent"] + "; ";
        }
      if(myrules["list-space"]){
        style = style + "padding-bottom: "+myrules["list-space"] + "; ";
        }
      if(style.length>0){
        style = " style=\"" + string.delete (style, style.length, 1) + "\"";
        }

      add ("
      "); indentlevel++; oplevel++;

      var processChildren = true;
      // markdown
        if(adrlevel.attr("method")!=null){
          if(adrlevel.attr("method").value().toLowerCase()=="markdown"){
            if( hassubs (adrlevel) ){
              var style = "";
              for(var name in myrules) {
                var value = myrules[name];
                if (!nonstylerule (name)) {
                style = style + name + ": " +value + "; ";
                }
                }
              if (style.length > 0) {
                style = " style=\"" + string.delete (style, style.length, 1) + "\"";
                }
              processChildren = false;
              var plaintext = getRawHtml(adrlevel, macros);
              plaintext = string.multiplereplaceall(plaintext, macros, false, "<%", "%>");
              plaintext = string.multiplereplaceall(plaintext, glossary, false);
              plaintext = processMacros(plaintext, worldOutline.macros, {pagetable: {macros: macros}});
              var converter = new Markdown.Converter ();
              var markdownText = converter.makeHtml (plaintext);
              var markdownLines = markdownText.split(/\n/);

              add ("
              "); indentlevel++;

              for(var m in markdownLines){
                add(markdownLines[m]);
                }

              add ("
              "); indentlevel--;

              }
            }
          }
      if(processChildren){
        for( var l in adrlevel.childNodes()){
          var adr = adrlevel.childNodes()[l];
          if(adr.name().endswith("outline")){
            // set adratts
              var adratts = {};
              for(var ai in adr.attrs()){
                var att = adr.attrs()[ai];
                adratts[att.name()]=att.value();
                }
            var text = "";
            if(adr.attr("text")!=null){
              text = adr.attr("text").value();
              }
            var lowertext = string.lower(text);
            var permalink = undefined;
            var iditem="";
            var icon = "";
            var ecId = "";
            var getOutlineNumber = function(){
              if(myrules["numbering"]){
                var outlineNumber = undefined;
                var outlineType = myrules["numbering"];
                if(outlineType.toLowerCase()=="harvard"){
                if(harvardOutlineTypeStack.length==0){
                harvardOutlineType = pushharvardoutlinetype();
                }
                outlineType = harvardOutlineTypeStack[harvardOutlineTypeStack.length-1];
                }
                switch(outlineType.toLowerCase()){
                case "decimal":
                outlineNumber = "" + levelIndex;
                break;
                case "romanuppercase":
                outlineNumber = "" + levelIndex.toRoman();
                break;
                case "romanlowercase":
                outlineNumber = "" + levelIndex.toRoman().toLowerCase();
                break;
                case "alphauppercase":
                outlineNumber = "" + String.fromCharCode(64+levelIndex).toUpperCase();
                break;
                case "alphalowercase":
                outlineNumber = "" + String.fromCharCode(64+levelIndex).toLowerCase();
                break;
                }
                if(defined(outlineNumber)){
                levelIndex++;
                return "" + outlineNumber + ". ";
                }
                }
              return "";
              };
            var addoutlineitem = function () {
              var id = "", img = "";
              if (iditem.length > 0) {
                id = " id=\"" + iditem + "\"";
                }
              if(ecId.length > 0){
                ecId = " ec-id=\""+ecId+"\"";
                }
              if (defined (adratts.img)) { //7/28/13 by DW
                img = "";
                if (defined (adratts.url)) { //8/5/13 by DW
                img = "" + img + "";
                }
                }

              add (callbacktext + "
              " + icon + img + text + permalink + "
              ");

              };
            // ignore comments
              if(adr.attr("isComment")!=null){
                if(adr.attr("isComment").value().toLowerCase()=="true"){
                continue;
                }
                }
            // ignore nodes with invisible att defined and true -- 8/22/13 by DW
              if (adr.attr ("invisible") != null) {
                if (adr.attr ("invisible").value ().toLowerCase () == "true") {
                continue;
                }
                }
            // process #directives
              var directiveMatch = text.match(/^#(\w+)\s+"(.+)"$/);
              if(directiveMatch != null){
                if(defined(macros)){
                var directiveName = directiveMatch[1];
                var directiveValue = directiveMatch[2];
                macros[directiveName] = directiveValue;
                }
                continue;
                }
            // ignore lines that start with # if at top level
              if(text.beginswith("#") && (level == 0)){
                continue;
                }
            // get < rules>
              if(text == ""){
                compilerules(adr, adrlocalrules);
                continue;
                }
              else {
                if(text.match(/^$/)){
                if(defined(glossary[text])){
                compileRules(glossary[text], adrlocalrules);
                continue;
                }
                }
                }
            // pass , through without processing
              if((lowertext=="") || (lowertext=="")){
                var xmltext = getxmltext(adr, level);
                add(xmltext);
                continue;
                }
            myrules = getmyrules();
            var canonicalname = getCanonicalName(text);
            if(adr.attr("name")!=null){
              canonicalname = adr.attr("name").value();
              }
            itemnum++;
            // set flexpanded
              flexpanded = false
              if(canonicalname == firstpathelement){
                flexpanded = true;
                text = ""+text+"";
                }
                else {
                if( defined(myrules.expanded) ){
                flexpanded = boolean (myrules.expanded);
                }
                }
                if(adr.attr("collapse")){
                flexpanded = !(adr.attr("collapse").value()=="true");
                }
            // set listiemstyle
              var style = "";
              if(myrules["outline-space"]){
                style = style + "padding-bottom: "+myrules["outline-space"] + "; ";
                }
              if(myrules["outline-space-before"]){
                style = style + "padding-top: "+myrules["outline-space-before"] + "; ";
                }
              if (style.length > 0) {
                style = " style=\"" + string.delete (style, style.length, 1) + "\"";
                }
              listitemstyle = style;
            // set permalink
              var flpermalink = false;
              if ( defined(myrules.permalink) ) {
                flpermalink = boolean (myrules.permalink);
                }
              if (flpermalink) {
                permalink = " #";
                }
              else {
                permalink = "";
                }
            //set idItem
              if ( defined (adr.attr("pgfnum")) && (adr.attr("pgfnum")!=null)) {
                iditem = "i" + adr.attr("pgfnum").value();
                }
              else {
                iditem = "";
                }
            //set callbacktext
              if (adrLineLevelCallback != null) {
                callbacktext = adrLineLevelCallback (adr, idItem);
                }
              else {
                callbacktext = "";
                }
            //set outline number
              text = getOutlineNumber() + text;
            if ((hassubs (adr) && notdocnode (adr)) || isinclude (adratts)) {
              var id = textToId(text);
              ecId = id;
              var flcontainsnolink = (lowertext.indexOf("</a")==-1);
              icon = getExpandCollapseIcon (id, flexpanded, showClassName, adratts["icon"]);
              text = styletext (text, myrules, flcontainsnolink, adratts);
              //click in text to expand/collapse
                if (flcontainsnolink) { //don't hot-up if there's one or more links in the text
                text = "" + text + "";
                }
              addoutlineitem ();

              //add the text in a special
              that makes it expandable

                var classname = "hide";
                if (flexpanded) {
                classname = "show";
                }

                add ("
                "); indentlevel++;

                level++;
                addlevel (adr, pathIntoOutline, relpath + canonicalname + "/");
                level--;

                add ("
                "); indentlevel--;

              }
            else {
              var docicon = "";
              //if type att is present, link to a doc
                if (defined (adratts.type) && (adratts.type!="")) {
                var linktodoc = function (iconname, url) {
                var iconname="file";
                var path = "";
                if (url != null) {
                path = url;
                }
                else {
                if ( defined (adratts.domain) ) {
                path = "http://" + adratts.domain + "/";
                }
                else {
                var name;
                if (defined (adratts.name)) {
                name = adratts.name;
                }
                else {
                name = getCanonicalName (text);
                }
                path = relpath + name;
                }
                }
                docicon =" ";
                text = "" + text + "";
                };
                switch ( string.lower (adratts.type) ) {
                case "link":
                linktodoc ("bookmark", adratts.url);
                break;
                case "thumblist":
                linktodoc ("th");
                break;
                case "photo":
                linktodoc ("camera");
                break;
                case "outline":
                linktodoc ("list-alt");
                break;
                case "rss":
                linktodoc ("signal");
                break;
                case "redirect":
                linktodoc ("refresh");
                break;
                case "tweet":
                break;
                default:
                linktodoc();
                }
                }
              // if icon att is present, display it.
                if(defined(adratts.icon)){
                var iconStyle="";
                if(defined(myrules["font-size"])){
                iconStyle = " style=\"font-size: "+myrules["font-size"]+";\"";
                }
                var linkStyle = "";
                if(defined(myrules["font-size"])){
                linkStyle = " style=\"width: "+myrules["font-size"]+"; margin-left: -"+myrules["font-size"]+";\"";
                }
                icon = "";
                }
              text = styletext (text, myrules, false, adratts);
              addoutlineitem ();
              }
            }
          }
        }

      add ("
      "); indentlevel--; oplevel--;

      popruleslevel();
      popharvardoutlinetype();
      if (flpopincludestack) {
        includestack.pop();
        }
      };

    add ("
    "); indentlevel++;

    addlevel(adrbody, pathIntoOutline, relpath);

    add ("
    "); indentlevel--;

    return htmltext;
    }
  function getOutlineUrlForNamedUser(directoryOutline, name){
    var namedOutline = undefined;
    for(var i in directoryOutline.childNodes()){
      var el = directoryOutline.childNodes()[i];
      if(el.attr("text") && (el.attr("text").value()==name)){
        namedOutline = el;
        break;
        }
      }
    var namedOutlineUser = undefined;
    if(namedOutline){
      var type = namedOutline.attr("type");
      var url = namedOutline.attr("url");
      if( type && (type.value() == "include") && url && (url.value() != "") ){
        namedOutlineUser = url.value();
        }
      }
    return namedOutlineUser;
    }
  function getNetOutlineText(urlOutline){
    var doc = op.getNetOutline(urlOutline);
    if(!defined(doc)){
      return undefined;
      }
    var dbOutlineKey = "system.temp.op.netOutlines.["+urlOutline+"]";
    var adrtable = db.get(dbOutlineKey);
    if(defined(adrtable)){
      return adrtable.xmltext;
      }
    return undefined;
    }
  function findDomainsForNamedUser(name, adrnode){
    var findDomainsForOutline = function(adrOutline, adrParent){
      var domains = adrOutline.find("//outline[@domain]");
      var directiveDomains = adrOutline.find("//outline[starts-with(@text, '#domain ')]");
      var parentPaths = [];
      var addToPaths = function(domainNode, pathsArray){
        if(domainNode.name().endswith("outline")){
          var n = undefined;
          if(domainNode.attr("text")){
            n = domainNode.attr("text").value();
            }
          if(domainNode.attr("name")){
            n = domainNode.attr("name").value();
            }
          if(defined(n)){
            pathsArray.push(n);
            addToPaths(domainNode.parent(), pathsArray);
            }
          }
        };
      if(defined(adrParent)){
        addToPaths(adrParent, parentPaths);
        }
      for(var i in domains){
        var d = domains[i];
        var domainAttribute = d.attr("domain").value();
        if(domainAttribute!=""){
          expireCacheForDomain(domainAttribute);
          var pathsToDomain = [];
          addToPaths(d, pathsToDomain);
          var domainDbKey = 'domainsToNames.["'+domainAttribute+'"]';
          var existingDomain = db.get(domainDbKey);
          if((!defined(existingDomain) || (defined(existingDomain) && (existingDomain.name==name))) && (pathsToDomain.length>0)){
            var finalPathArray = parentPaths.reverse().concat(pathsToDomain.reverse());
            db.put(domainDbKey, {name: name, path: "/"+finalPathArray.join("/")});
            }
          }
        }
      for(var j in directiveDomains){
        var d = directiveDomains[j];
        var directiveMatch = d.attr("text").value().match("^#domain \"(.+)\"$");
        if(directiveMatch!=null){
          var domainAttribute = directiveMatch[1];
          if(domainAttribute!=""){
            expireCacheForDomain(domainAttribute);
            var pathsToDomain = [];
            addToPaths(d.parent(), pathsToDomain);
            var domainDbKey = 'domainsToNames.["'+domainAttribute+'"]';
            var existingDomain = db.get(domainDbKey);
            if((!defined(existingDomain) || (defined(existingDomain) && (existingDomain.name==name)))){
              var finalPathArray = parentPaths.reverse().concat(pathsToDomain.reverse());
              db.put(domainDbKey, {name: name, path: "/"+finalPathArray.join("/")});
              }
            }
          }
        }
      };
    findDomainsForOutline (adrnode);
    var includes = adrnode.find("//outline[@type='include']");
    for(var i in includes){
      try{
        var include = includes[i];
        var url = include.attr("url");
        if(url && url.value()){
          var includeOpml = op.getNetOutline (url.value());
          var includeBody = includeOpml.get("/opml/body");
          findDomainsForOutline (includeBody, include);
          }
        }
      catch(tryerror){
        //no-op
        }
      }
    }
  function getNetOutlineEtag(urlOutline){
    var dbOutlineKey = "system.temp.op.netOutlines.["+urlOutline+"]";
    var adrtable = db.get(dbOutlineKey);
    if(defined(adrtable)){
      return adrtable.etag;
      }
    return undefined;
    }
  function expireCacheForDomain(domain){
    try{
      http.request("BAN", "http://localhost:9080", {"Ban-Host" : domain});
      }
    catch(tryerror){
      // Eat tryerror
      }
    }
// Responders
  // Twitter
    server.addResponder("twitter", function(pagetable){
      var host = pagetable.request.headers["Host"];
      if(defined(host) && host.endswith(".fargo.io")){
        pagetable.response.headers["Server"] = "Trex/"+TREX_VERSION;
        pagetable.response.headers["Access-Control-Allow-Origin"] = "*";
        var twitterConsumerKey = "vcqCKoFOYPTf6R7Dh8zRzQ";
        var twitterConsumerSecret = "SmqQNgibJKFgRZuGukugZwJUx9UXh67MCHkaJXu0rGQ";
        var twitterRequestTokenURL = "https://api.twitter.com/oauth/request_token";
        var twitterAuthorizeURL = "https://api.twitter.com/oauth/authorize";
        var twitterAccessTokenURL = "https://api.twitter.com/oauth/access_token";
        var twitterStatusUpdateURL = "https://api.twitter.com/1.1/statuses/update.json";
        var twitterStatusMentionsURL = "https://api.twitter.com/1.1/statuses/mentions_timeline.json";
        var twitterUserTimelineURL = "https://api.twitter.com/1.1/statuses/user_timeline.json";
        if(pagetable.request.uri.match(/^\/twitter\/connect$/)){
          var host = pagetable.request.headers["Host"];
          var accessor = { consumerSecret: twitterConsumerSecret,
            tokenSecret: ""};
          var message = { action: twitterRequestTokenURL
            , method: "POST"
            , parameters: []
            };
          var callbackUrl = "http://"+host+"/twitter/callback";
          if(defined(pagetable.request.params["redirect_url"])){
            callbackUrl += "?redirect_url="+encodeURIComponent(pagetable.request.params["redirect_url"]);
            }
          message.parameters.push(["oauth_callback", callbackUrl]);
          message.parameters.push(["oauth_consumer_key", twitterConsumerKey]);
          message.parameters.push(["oauth_version", "1.0"]);
          OAuth.setTimestampAndNonce(message);
          OAuth.SignatureMethod.sign(message, accessor);
          var parameterMap = OAuth.getParameterMap(message.parameters);
          var authorizationString = OAuth.getAuthorizationHeader("api.twitter.com", parameterMap);
          var requestTokenHeaders = {"Authorization" : authorizationString};
          var requestTokenResponse = http.post(twitterRequestTokenURL, "", requestTokenHeaders);
          if(requestTokenResponse.code==200){
            var responseParameters = OAuth.getParameterMap(requestTokenResponse.body);
            pagetable.response.code = 302;
            pagetable.response.headers["Location"] = twitterAuthorizeURL + "?oauth_token="+encodeURIComponent(responseParameters["oauth_token"]);
            }
          else {
            pagetable.response.code = requestTokenResponse.code;
            pagetable.response.body = requestTokenResponse.body;
            }
          return true;
          }
        if(pagetable.request.uri.match(/^\/twitter\/callback$/)){
          var accessor = { consumerSecret: twitterConsumerSecret,
            tokenSecret: ""};
          var message = { action: twitterAccessTokenURL
            , method: "POST"
            , parameters: []
            };
          message.parameters.push(["oauth_consumer_key", twitterConsumerKey]);
          message.parameters.push(["oauth_token", pagetable.request.params["oauth_token"]]);
          message.parameters.push(["oauth_version", "1.0"]);
          OAuth.setTimestampAndNonce(message);
          OAuth.SignatureMethod.sign(message, accessor);
          var parameterMap = OAuth.getParameterMap(message.parameters);
          var authorizationString = OAuth.getAuthorizationHeader("api.twitter.com", parameterMap);
          var requestTokenHeaders = {"Authorization" : authorizationString};
          var requestTokenResponse = http.post(twitterAccessTokenURL, "oauth_verifier="+OAuth.percentEncode(pagetable.request.params["oauth_verifier"]), requestTokenHeaders);
          if(requestTokenResponse.code==200){
            if(pagetable.request.params["redirect_url"]){
              var decodedForm = OAuth.getParameterMap(OAuth.decodeForm(requestTokenResponse.body));
              pagetable.response.code = 302;
              pagetable.response.headers["Location"] = pagetable.request.params["redirect_url"]+"?oauth_token="+encodeURIComponent(decodedForm["oauth_token"])+"&oauth_token_secret="+encodeURIComponent(decodedForm["oauth_token_secret"])+"&user_id="+encodeURIComponent(decodedForm["user_id"])+"&screen_name="+encodeURIComponent(decodedForm["screen_name"]);
              }
            else {
              pagetable.response.headers["Content-Type"] = requestTokenResponse.headers["Content-Type"];
              pagetable.response.body = requestTokenResponse.body;
              }
            }
          else {
            pagetable.response.code = requestTokenResponse.code;
            pagetable.response.body = requestTokenResponse.body;
            }
          return true;
          }
        if((pagetable.request.method=="POST") && (pagetable.request.uri.match(/^\/twitter\/tweet$/))){
          var formData = OAuth.getParameterMap(OAuth.decodeForm(pagetable.request.body));
          var oauthToken = formData["oauth_token"];
          var oauthTokenSecret = formData["oauth_token_secret"];
          var twitterStatus = formData["status"];
          var inReplyToStatusId = formData["in_reply_to_status_id"];
          var accessor = { consumerKey: twitterConsumerKey, consumerSecret: twitterConsumerSecret,
            token: oauthToken,
            tokenSecret: oauthTokenSecret};
          var message = { action: twitterStatusUpdateURL
            , method: "POST"
            , parameters: []
            };
          var queryString = "?status="+OAuth.percentEncode(twitterStatus);
          message.parameters.push(["oauth_consumer_key", twitterConsumerKey]);
          message.parameters.push(["oauth_version", "1.0"]);
          message.parameters.push(["status", twitterStatus]);
          if(defined(inReplyToStatusId)){
            if(inReplyToStatusId!="0"){
              message.parameters.push(["in_reply_to_status_id", inReplyToStatusId]);
              queryString += "&in_reply_to_status_id="+OAuth.percentEncode(inReplyToStatusId);
              }
            }
          OAuth.completeRequest(message, accessor);
          var parameterMap = OAuth.getParameterMap(message.parameters);
          var authorizationString = OAuth.getAuthorizationHeader("api.twitter.com", parameterMap);
          var requestTokenHeaders = {"Authorization" : authorizationString};
          var requestTokenResponse = http.post(twitterStatusUpdateURL+queryString, "", requestTokenHeaders);
          if(requestTokenResponse.code==200){
            pagetable.response.headers["Content-Type"] = requestTokenResponse.headers["Content-Type"];
            pagetable.response.body = requestTokenResponse.body;
            }
          else {
            pagetable.response.code = requestTokenResponse.code;
            pagetable.response.body = requestTokenResponse.body;
            }
          return true;
          }
        if(pagetable.request.uri.match(/^\/twitter\/mentions$/)){
          var oauthToken = pagetable.request.params["oauth_token"];
          var oauthTokenSecret = pagetable.request.params["oauth_token_secret"];
          var since_id = pagetable.request.params["since_id"];
          var count = pagetable.request.params["count"];
          if(!defined(count)){
            count = "200";
            }
          var queryString = "?count="+count;
          var accessor = { consumerKey: twitterConsumerKey, consumerSecret: twitterConsumerSecret,
            token: oauthToken,
            tokenSecret: oauthTokenSecret};
          var message = { action: twitterStatusMentionsURL
            , method: "GET"
            , parameters: []
            };
          message.parameters.push(["oauth_consumer_key", twitterConsumerKey]);
          message.parameters.push(["oauth_version", "1.0"]);
          message.parameters.push(["count", count]);
          if(defined(since_id)){
            queryString+="&since_id="+since_id;
            message.parameters.push(["since_id", since_id]);
            }
          OAuth.completeRequest(message, accessor);
          var parameterMap = OAuth.getParameterMap(message.parameters);
          var authorizationString = OAuth.getAuthorizationHeader("api.twitter.com", parameterMap);
          var requestTokenHeaders = {"Authorization" : authorizationString};
          var requestTokenResponse = http.get(twitterStatusMentionsURL+queryString, requestTokenHeaders);
          if(requestTokenResponse.code==200){
            pagetable.response.headers["Content-Type"] = requestTokenResponse.headers["Content-Type"];
            pagetable.response.body = requestTokenResponse.body;
            }
          else {
            pagetable.response.code = requestTokenResponse.code;
            pagetable.response.body = requestTokenResponse.body;
            }
          return true;
          }
        if(pagetable.request.uri.match(/^\/twitter\/timeline$/)){
          var oauthToken = pagetable.request.params["oauth_token"];
          var oauthTokenSecret = pagetable.request.params["oauth_token_secret"];
          var since_id = pagetable.request.params["since_id"];
          var count = pagetable.request.params["count"];
          if(!defined(count)){
            count = "200";
            }
          var queryString = "?include_rts=false&count="+count;
          var accessor = { consumerKey: twitterConsumerKey, consumerSecret: twitterConsumerSecret,
            token: oauthToken,
            tokenSecret: oauthTokenSecret};
          var message = { action: twitterUserTimelineURL
            , method: "GET"
            , parameters: []
            };
          message.parameters.push(["oauth_consumer_key", twitterConsumerKey]);
          message.parameters.push(["oauth_version", "1.0"]);
          message.parameters.push(["count", count]);
          message.parameters.push(["include_rts", "false"]);
          if(defined(since_id)){
            queryString+="&since_id="+since_id;
            message.parameters.push(["since_id", since_id]);
            }
          OAuth.completeRequest(message, accessor);
          var parameterMap = OAuth.getParameterMap(message.parameters);
          var authorizationString = OAuth.getAuthorizationHeader("api.twitter.com", parameterMap);
          var requestTokenHeaders = {"Authorization" : authorizationString};
          var requestTokenResponse = http.get(twitterUserTimelineURL+queryString, requestTokenHeaders);
          if(requestTokenResponse.code==200){
            pagetable.response.headers["Content-Type"] = requestTokenResponse.headers["Content-Type"];
            pagetable.response.body = requestTokenResponse.body;
            }
          else {
            pagetable.response.code = requestTokenResponse.code;
            pagetable.response.body = requestTokenResponse.body;
            }
          return true;
          }
        }
      return false;
      });
  // Trex
    server.addResponder("trex", function(pagetable){
      // Constants
        var glossaryId = "#glossary";
        var templatesId = "#templates";
        var menusId = "#menus";
        var defaultMenuName = "default";
        var defaultRenderMethod = "outline";
        var defaultDateFormat = "%A, %B %e, %Y at %l:%M %p";
        var defaultSiteTimeZone = "-4";
      if(pagetable.request.uri=="/favicon.ico"){
        return false;
        }
      pagetable.response.headers["Server"] = "Trex/"+TREX_VERSION;
      pagetable.response.headers["Access-Control-Allow-Origin"] = "*";
      try {
        // Our single World Outline file named "TrexWorldOutline" on Tacoma.
        var opmlUrl = "http://static.smallpicture.com/tacoma/wo/admin/2013/05/08/archive019.opml";
        var domain = pagetable.request.headers["Host"];
        if(opmlUrl && domain){
          var opml = getNetOutlineWithIncludes(opmlUrl, function(adrx){
            if(adrx.attr("type") && (adrx.attr("type").value()=="include") && adrx.parent().attr("text") && (adrx.parent().attr("text").value()=="userDirectory")){
              return false;
              }
            return true;
            });
          if(opml){
            var domainPath = pagetable.request.uri;
            // Global Glossary
              var glossary = {};
              var processGlossary = function(glossaryOutline){
                if(defined(glossaryOutline)){
                for(var i in glossaryOutline.childNodes()){
                var glossaryDef = glossaryOutline.childNodes()[i];
                if(glossaryDef.attr("text") && (glossaryDef.attr("text").value()!="")){
                var glossaryName = glossaryDef.attr("text").value();
                var glossaryText = "";
                var level = 0;
                var getxmltext = function(adrtable){
                var _xmltext = filledString ("\t", level-1) + adrtable.attr("text").value() + "\r\n";
                level++;
                for(var i in adrtable.childNodes()){
                var child = adrtable.childNodes()[i];
                if(child.name().endswith("outline")){
                _xmltext = _xmltext + getxmltext(child);
                }
                }
                level--;
                return _xmltext;
                };
                for(var j in glossaryDef.childNodes()){
                var child = glossaryDef.childNodes()[j];
                if(child.name().endswith("outline")){
                glossaryText = glossaryText + getxmltext(child);
                }
                }
                if(glossaryText.match(/^(.+)\r\n$/)!=null){
                glossaryText = glossaryText.match(/^(.+)\r\n$/)[1];
                }
                glossary[glossaryName] = glossaryText;
                }
                }
                }
                };
              processGlossary(opml.get("/opml/body/outline[@text='"+glossaryId+"']"));
            // Global Templates
              var templates = {};
              var processTemplate = function(templateOutline){
                if(defined(templateOutline)){
                for(var i in templateOutline.childNodes()){
                var template = templateOutline.childNodes()[i];
                if(template.attr("text") && (template.attr("text").value()!="")){
                var templateName = template.attr("text").value();
                var templateObj = {templateText: "", rulesText: undefined};
                var level = 0;
                var getxmltext = function(adrtable){
                var _xmltext = filledString ("\t", level-1) + adrtable.attr("text").value() + "\r\n";
                level++;
                for(var i in adrtable.childNodes()){
                var child = adrtable.childNodes()[i];
                if((child.attr("isComment")!=null) && (child.attr("isComment").value().toLowerCase()=="true")){
                continue;
                }
                if(child.name().endswith("outline")){
                _xmltext = _xmltext + getxmltext(child);
                }
                }
                level--;
                return _xmltext;
                };
                for(var i in template.childNodes()){
                var child = template.childNodes()[i];
                if(child.name().endswith("outline")){
                if((child.attr("isComment")!=null) && (child.attr("isComment").value().toLowerCase()=="true")){
                continue;
                }
                if(child.attr("text").value()==""){
                templateObj.rulesText = getxmltext(child);
                level = 0;
                continue;
                }
                else{
                templateObj.templateText = templateObj.templateText + getxmltext(child);
                }
                }
                }
                templates[templateName] = templateObj;
                }
                }
                }
                };
              processTemplate(opml.get("/opml/body/outline[@text='"+templatesId+"']"));
            // Global Menus
              var globalMenus = opml.get("/opml/body/outline[@text='"+menusId+"']");
            // Look for domain in TrexWorldOutline file
              var domainOutline = opml.get("//outline[@domain='"+domain+"']");
            // Find user directory
              var directoryOutline = opml.get("/opml/body/outline[@text='userDirectory']");
            // Track ETag
              var etag = undefined;
            // Setup parentOutline
              var parentOutline = opml;
            // Try to find a named user in the directory
              var namedMenus = undefined;
              if(!defined(domainOutline) && defined(directoryOutline)){
                var name = domain.split(".")[0];
                var existingDomainKey = 'domainsToNames.["'+domain+'"]';
                var existingDomainEntry = db.get(existingDomainKey);
                if(existingDomainEntry){
                name = existingDomainEntry.name;
                }
                var namedOutlineUrl = getOutlineUrlForNamedUser(directoryOutline, name);
                if(namedOutlineUrl){
                if((pagetable.request.method=="POST") && (pagetable.request.uri=="/") ){
                // PING
                var namedOutline = op.getNetOutline (namedOutlineUrl, true, true, 0);
                var name = domain.split(".")[0];
                findDomainsForNamedUser (name, namedOutline);
                pagetable.response.body = "";
                expireCacheForDomain(domain);
                return true;
                }
                else if(!defined(existingDomainEntry) && (pagetable.request.uri=="/") && ((pagetable.request.headers["Accept"] == "text/x-opml") || (pagetable.request.params["format"]=="opml")) ){
                var namedOpmlText = getNetOutlineText(namedOutlineUrl);
                if(namedOpmlText){
                pagetable.response.body = namedOpmlText;
                pagetable.response.headers["Content-Type"]="text/xml; charset=utf-8";
                return true;
                }
                else {
                pagetable.response.code = 404;
                return true;
                }
                var adrNamedOutline = db.get("system.temp.op.netOutlines.["+namedOutlineUrl+"]");
                if(defined(adrNamedOutline)){
                etag = adrNamedOutline.etag;
                }
                }
                else {
                var namedOutline = op.getNetOutline (namedOutlineUrl);
                var namedOutlineBody = namedOutline.get("/opml/body");
                if(defined(namedOutlineBody) && (pagetable.request.uri=="/")){
                if(!defined(existingDomainEntry) || (defined(existingDomainEntry) && domain.endswith(".smallpict.com")) ){
                for(var i in namedOutlineBody.childNodes()){
                var namedOutlineBodyChild = namedOutlineBody.childNodes()[i];
                if((namedOutlineBodyChild.attr("text")!=null) && ((namedOutlineBodyChild.attr("text").value().toLowerCase()=="profile") || (namedOutlineBodyChild.attr("text").value().toLowerCase()=="#profile") || (namedOutlineBodyChild.attr("text").value().toLowerCase()=="index"))){
                domainPath = "/"+namedOutlineBodyChild.attr("text").value().toLowerCase();
                break;
                }
                }
                }
                }
                parentOutline = namedOutline;
                opmlUrl = namedOutlineUrl;
                var adrNamedOutline = db.get("system.temp.op.netOutlines.["+namedOutlineUrl+"]");
                if(defined(adrNamedOutline)){
                etag = adrNamedOutline.etag;
                }
                if(existingDomainEntry){
                domainOutline = pathWalk(namedOutline.get("/opml/body"), existingDomainEntry.path);
                if((domainOutline==null) && domain.endswith(".smallpict.com")){
                var domainDirectiveNamedOutline = namedOutline.get("/opml/body/outline[starts-with(@text, '#domain ')]");
                if(domainDirectiveNamedOutline!=null){
                var domainDirectiveNamedOutlineMatch = domainDirectiveNamedOutline.attr("text").value().match("^#domain \"(.+)\"$");
                if(domainDirectiveNamedOutlineMatch!=null){
                var directiveDomain = domainDirectiveNamedOutlineMatch[1];
                if(domain!=directiveDomain){
                pagetable.response.code = 302;
                pagetable.response.headers["Location"] = "http://"+directiveDomain+pagetable.request.uri;
                return true;
                }
                }
                }
                domainOutline = namedOutline.get("/opml/body");
                }
                }
                else {
                var domainDirectiveNamedOutline = namedOutline.get("/opml/body/outline[starts-with(@text, '#domain ')]");
                if(domainDirectiveNamedOutline!=null){
                var domainDirectiveNamedOutlineMatch = domainDirectiveNamedOutline.attr("text").value().match("^#domain \"(.+)\"$");
                if(domainDirectiveNamedOutlineMatch!=null){
                var directiveDomain = domainDirectiveNamedOutlineMatch[1];
                if(domain!=directiveDomain){
                pagetable.response.code = 302;
                pagetable.response.headers["Location"] = "http://"+directiveDomain+pagetable.request.uri;
                return true;
                }
                }
                }
                domainOutline = namedOutline.get("/opml/body");
                }
                var namedTemplates = namedOutline.get("/opml/body/outline[@text='"+templatesId+"']");
                if(defined(namedTemplates)){
                processTemplate(namedTemplates);
                }
                var namedGlossary = namedOutline.get("/opml/body/outline[@text='"+glossaryId+"']");
                if(defined(namedGlossary)){
                processGlossary(namedGlossary);
                }
                namedMenus = namedOutline.get("/opml/body/outline[@text='"+menusId+"']");
                }
                }
                }
            // Render outline
              if(domainOutline){
                // Setup atts
                var atts = new InsensitiveObject();
                atts.trexVersion = TREX_VERSION;
                atts.type = "bloghome"; //7/3/13 by KS
                atts.text = "";
                atts.created = "";
                atts.breadcrumbs = "";
                atts.breadcrumbsArray = [];
                atts.urlPrev = "";
                atts.urlNext = "";
                atts.siteTimeZone = defaultSiteTimeZone;
                atts.menuName = defaultMenuName;
                atts.bootstrapTheme = "readable"; //7/3/13 by DW
                atts.bloghomeItemCount = "10"; //7/3/13 by KS -- only applies to homepage now
                if(defined(namedMenus) && (namedMenus!=null)){
                var _menusStruct = xmlNodeToStruct(namedMenus);
                if (defined(globalMenus) && (globalMenus!=null)){
                var menuExists = function(_menu){
                for(var i in _menusStruct.children){
                var _menuStructMenu = _menusStruct.children[i];
                if(_menuStructMenu.attributes["text"] == _menu.attributes["text"]){
                return true;
                }
                }
                return false;
                };
                var _globalMenusStruct = xmlNodeToStruct(globalMenus);
                for(var i in _globalMenusStruct.children){
                var _globalMenu = _globalMenusStruct.children[i];
                if(!menuExists(_globalMenu)){
                _menusStruct.children.push(_globalMenu);
                }
                }
                }
                atts.menusStruct = _menusStruct;
                }
                else if (defined(globalMenus) && (globalMenus!=null)){ //7/3/13 by KS
                atts.menusStruct = xmlNodeToStruct(globalMenus);
                }
                // OPML attributes
                atts.opmlUrl = opmlUrl;
                atts.opmlTitle = "";
                atts.opmlLongTitle = "";
                atts.opmlLink = "";
                atts.opmlDescription = "";
                atts.opmlDateCreated = "";
                atts.opmlDateModified = "";
                atts.opmlOwnerName = "";
                atts.opmlOwnerEmail = "";
                atts.opmlOwnerId = "";
                atts.opmlOwnerProfile = ""; //9/3/13 by DW
                if(parentOutline.get("/opml/head")){
                var parentHead = parentOutline.get("/opml/head");
                for(var i in parentHead.childNodes()){
                var parentHeadElement = parentHead.childNodes()[i];
                if(parentHeadElement.name()!="text"){
                var canonicalHeadName = camelCase("opml " + parentHeadElement.name());
                atts[canonicalHeadName] = parentHeadElement.text();
                }
                }
                }
                // HTTP attributes
                atts.httpPath = pagetable.request.uri;
                for(var headerName in pagetable.request.headers){
                var canonicalHttpName = camelCase("http " + headerName);
                atts[canonicalHttpName] = pagetable.request.headers[headerName];
                }
                // opmlFeed
                var parentFeed = parentOutline.get("/opml/head/feed");
                if(defined(parentFeed) && (parentFeed!=null)){
                var opmlFeed = parentFeed.text();
                atts.opmlFeed = "http://"+domain+"/rss.xml";
                if(domainPath=="/rss.xml"){
                var feedResponse = http.get(opmlFeed);
                if(feedResponse.code == 200){
                pagetable.response.headers["Content-Type"]="text/xml; charset=utf-8";
                pagetable.response.body = feedResponse.body;
                return true;
                }
                }
                }
                // set menuTitle 7/3/13 by KS
                if ((atts.opmlLongTitle != undefined) && (atts.opmlLongTitle != "")) { //7/4/13 by DW
                atts.menuTitle = atts.opmlLongTitle;
                atts.text = atts.opmlLongTitle;
                }
                else {
                atts.menuTitle = atts.opmlOwnerName;
                atts.text = atts.opmlOwnerName;
                }
                //set blogHomeTitle -- 7/4/13 by DW
                if (atts.blogHomeTitle == undefined) {
                if ((atts.opmlLongTitle != undefined) && (atts.opmlLongTitle != "")) {
                atts.blogHomeTitle = atts.opmlLongTitle;
                }
                else {
                if (atts.text != undefined) {
                atts.blogHomeTitle = atts.text;
                }
                else {
                atts.blogHomeTitle = "";
                }
                }
                }
                //set blogHomeDescription -- 7/4/13 by DW
                if (atts.blogHomeDescription == undefined) {
                if ((atts.opmlDescription != undefined) && (atts.opmlDescription != "")) {
                atts.blogHomeDescription = atts.opmlDescription;
                }
                else {
                atts.blogHomeDescription = "";
                }
                }
                var adrnode = pathWalk(domainOutline, domainPath, atts);
                if(adrnode){
                // Menu story
                if(defined(namedMenus) && (namedMenus!=null)){
                if(atts.menuName && pagetable.request.params["story"]){
                var nameMenu = namedMenus.get("outline[@text='"+atts.menuName+"']");
                if(nameMenu!=null){
                for(var nc in nameMenu.childNodes()){
                var nameMenuChild = nameMenu.childNodes()[nc];
                if(nameMenuChild.name().endswith("outline")){
                var storyNode = pathWalk(nameMenuChild, pagetable.request.params["story"], atts);
                if(storyNode!=null){
                adrnode=storyNode;
                atts.breadcrumbsArray = [];
                atts.urlNext = "";
                atts.urlPrev = "";
                }
                break;
                }
                }
                }
                }
                }
                // ?format=opml
                if(defined(pagetable.request.params["format"]) && (pagetable.request.params["format"]=="opml")){
                // create new xml document
                var doc = new libxml.Document("1.0");
                doc.node('opml').attr({"version" : "2.0"}).node("head");
                // set head section
                var addToHead = function(name,val){
                if(val!=""){
                doc.get("/opml/head").node(name, val);
                }
                };
                addToHead("title", atts.opmlTitle);
                addToHead("longTitle", atts.opmlLongTitle);
                addToHead("link", atts.opmlLink);
                addToHead("description", atts.opmlDescription);
                addToHead("dateCreated", atts.opmlDateCreated);
                addToHead("dateModified", atts.opmlDateModified);
                addToHead("ownerName", atts.opmlOwnerName);
                addToHead("ownerEmail", atts.opmlOwnerEmail);
                addToHead("ownerId", atts.opmlOwnerId);
                // set body
                if(adrnode.name().endswith("body")){
                doc.get("/opml").addChild(adrnode);
                }
                else {
                doc.get("/opml").node("body");
                doc.get("/opml/body").addChild(adrnode);
                }
                pagetable.response.headers["Content-Type"]="text/xml; charset=utf-8";
                pagetable.response.body = doc.toString();
                return true;
                }
                // Set breadcrumbs macro
                if(atts.breadcrumbsArray.length>0){

                var crumbs = "
                ";

                atts.breadcrumbsArray [0] = "Home"; //8/24/13 by DW
                for(var c in atts.breadcrumbsArray){
                var crumb = atts.breadcrumbsArray[c];

                crumbs += "
                ";

                crumbs += crumb;
                if(c < (atts.breadcrumbsArray.length-1)){
                crumbs += "/";
                }

                crumbs += "
                ";

                }

                crumbs += "
                ";

                atts.breadcrumbs = crumbs;
                }
                pagetable.macros = atts;
                pagetable.glossary = glossary;
                pagetable.opml = parentOutline;
                worldOutline.firstFilter(pagetable);
                // Now
                atts.now = getDate(new Date(), atts.siteTimeZone).strftime(defaultDateFormat);
                // Dates
                if(defined(atts.opmlDateCreated) && (atts.opmlDateCreated!="")){
                atts.opmlDateCreated = getDate(atts.opmlDateCreated, atts.siteTimeZone).strftime(defaultDateFormat);
                }
                if(defined(atts.opmlDateModified) && (atts.opmlDateModified!="")){
                atts.opmlDateModified = getDate(atts.opmlDateModified, atts.siteTimeZone).strftime(defaultDateFormat);
                }
                if(defined(atts.created) && (atts.created!="")){
                atts.created = getDate(atts.created, atts.siteTimeZone).strftime(defaultDateFormat);
                }
                var htmltext = undefined;
                var renderMethod = defaultRenderMethod;
                var nodetype = atts.type;
                if(nodetype=="redirect"){
                var redirectUrl = atts["url"];
                if(defined(redirectUrl)){
                pagetable.response.code = 302;
                pagetable.response.headers["Location"] = redirectUrl;
                return true;
                }
                }
                if(defined(atts["method"])){
                renderMethod = atts["method"].toLowerCase();
                }
                else {
                switch(nodetype){
                case "html":
                renderMethod = nodetype;
                break;
                case "outline":
                renderMethod = nodetype;
                break;
                case "markdown":
                renderMethod = nodetype;
                break;
                case "index":
                renderMethod = "outline";
                break;
                default:
                if(defined(worldOutline.methods[nodetype])){
                renderMethod = nodetype;
                }
                }
                }
                var template = templates[nodetype];
                if(renderMethod=="html"){
                if(defined(template)){
                atts.bodytext = string.multiplereplaceall(getRawHtml(adrnode, atts), atts, false, "<%", "%>");
                htmltext = string.multiplereplaceall(template.templateText, atts, false, "<%", "%>");
                }
                else{
                htmltext = string.multiplereplaceall(getRawHtml(adrnode, atts), atts, false, "<%", "%>");
                }
                htmltext = string.multiplereplaceall(htmltext, glossary, false);
                htmltext = processMacros(htmltext, worldOutline.macros, {pagetable: pagetable});
                }
                else if(renderMethod=="markdown"){
                var plaintext = getRawHtml(adrnode, atts);
                plaintext = string.multiplereplaceall(plaintext, atts, false, "<%", "%>");
                plaintext = string.multiplereplaceall(plaintext, glossary, false);
                plaintext = processMacros(plaintext, worldOutline.macros, {pagetable: pagetable});
                var converter = new Markdown.Converter ();
                atts.bodytext = converter.makeHtml (plaintext);
                if(defined(template)){
                htmltext = string.multiplereplaceall(template.templateText, atts, false, "<%", "%>");
                htmltext = string.multiplereplaceall(htmltext, glossary, false);
                htmltext = processMacros(htmltext, worldOutline.macros, {pagetable: pagetable});
                }
                else{
                htmltext = atts.bodytext;
                }
                }
                else if (renderMethod=="outline") {
                var relpath = pagetable.request.uri;
                if(defined(atts.relpath)){
                relpath = atts.relpath;
                }
                if(!relpath.endswith("/")){
                relpath=relpath+"/";
                }
                if(defined(template)){
                atts.bodytext = string.multiplereplaceall(viewOutline(adrnode, template.rulesText, relpath, glossary, atts), atts, false, "<%", "%>");
                htmltext = string.multiplereplaceall(template.templateText, atts, false, "<%", "%>");
                }
                else {
                htmltext = string.multiplereplaceall(viewOutline(adrnode, "", relpath, glossary, atts), atts, false, "<%", "%>");
                }
                htmltext = string.multiplereplaceall(htmltext, glossary, false);
                htmltext = processMacros(htmltext, worldOutline.macros, {pagetable: pagetable});
                }
                else if (defined(worldOutline.methods[renderMethod])) {
                var methodHtml = processMethod(renderMethod, worldOutline.methods, {pagetable: pagetable}, adrnode, template, glossary, atts);
                if(defined(template)){
                atts.bodytext = string.multiplereplaceall(methodHtml, atts, false, "<%", "%>");
                htmltext = string.multiplereplaceall(template.templateText, atts, false, "<%", "%>");
                }
                else {
                htmltext = string.multiplereplaceall(methodHtml, atts, false, "<%", "%>");
                }
                htmltext = string.multiplereplaceall(htmltext, glossary, false);
                htmltext = processMacros(htmltext, worldOutline.macros, {pagetable: pagetable});
                }
                if(defined(atts["content-type"])){
                pagetable.response.headers["Content-Type"]=atts["content-type"];
                }
                else {
                pagetable.response.headers["Content-Type"]="text/html; charset=utf-8";
                }
                if(defined(htmltext)){
                pagetable.response.body = htmltext;
                }
                else {
                pagetable.response.code = 500;

                pagetable.response.body="Unknown
                Unknown type

                Can't render page because type "+nodetype+" is not defined.
                ";

                }
                worldOutline.finalFilter(pagetable);
                return true;
                }
                else {
                pagetable.response.code = 404;

                pagetable.response.body="Not Found
                Not Found

                Can't render page because path "+atts.httpPath+" could not be found within the outline.
                ";

                return true;
                }
                }
              else {
                pagetable.response.code = 404;

                pagetable.response.body="Not Found
                Not Found

                Can't render page because the domain "+pagetable.request.headers["Host"]+" is not associated with an outline.
                ";

                return true;
                }
            }
          }
        return false;
        }
      catch(tryerror){
        pagetable.response.code = 500;

        pagetable.response.body="Error
        Error

        Trex couldn't complete your request because an exception was thrown.
        " + tryerror + "";

        return true;
        }
      });
  // Not found
    server.addResponder("notFound", function(pagetable){
      pagetable.response.code = 404;

      pagetable.response.body="Not Found
      Not Found

      Can't render page because no outline was found.
      ";

      return true;
      });