<commit_before>

function addTag() {

    var tagVal = $("#newTag").val();
    var addonid = $('#tags input[name="addonid"]').val();

    if($.trim(tagVal)=='' || $.trim(addonid)==''){
        return;
    }
    var post_data = $('#tagForm').serialize()+"&ajax=1";
    var add_ajax_url = $('#tagForm').attr('action');
    $.post(add_ajax_url, post_data, function(data) {
        $("#tags").html(data);
        $(".addtagform form")[0].reset();
        $("#tags .addon-tags").removeClass("nojs");
    });
};

 // PHP-compatible urlencode() for Javascript from http://us.php.net/manual/en/function.urlencode.php#85903
 function urlencode(s) {
  s = encodeURIComponent(s);
  return s.replace(/~/g,'%7E').replace(/%20/g,'+');
 };

function remTag(form_data){
    var remove_ajax_url = $('form#tags').attr('action');
    $.post(remove_ajax_url, form_data, function(data){
        $("#tags").html(data);
        $(".addtagform form")[0].reset();
        $("#tags .addon-tags").removeClass("nojs");
    });
};

$(document).ready(function(){
    //remove nojs classname so that css will hide the x's
    $("#tags .addon-tags").removeClass("nojs");
    //hide add tag form if you have js
    $(".addtagform ").addClass("hidden");

    $("#addtagbutton").click(function(e){
        addTag();
        e.preventDefault();
        e.stopPropagation();
    });

    $("form#tags .removetag").live("click",function(e){
        if (e.button != 0) return true; // no right-click
        var form = $("form#tags");
        form.find(":input[name='ajax']").val("1");

        var tagid = $(this).val();
        var form_data = form.serialize() + "&tagid=" + tagid;
        remTag(form_data);
        e.preventDefault();
        e.stopPropagation();
    });

    $("#tags .developertag, #tags .usertag")
        .live("mouseover",function(){
            $(this).addClass("hover");
            })
        .live("mouseout",function(){
            $(this).removeClass("hover");
            });

    $("#addatag").click(function(e){
        $(".addtagform")
            .removeClass("hidden")
            .attr("style","display:block;");
        $('#newTag').focus();
        e.preventDefault();
        e.stopPropagation();
    });

    $("#newTag").live("keypress",function(e){
        if($.trim($(this).val()) != '' &&  e.keyCode == 13) {
            $("#addtagbutton").click();
            e.preventDefault();
            e.stopPropagation();
        }

    });
})
<commit_msg>let there be tagging on all untagged add-ons (bug 568860)<commit_after>function addTag() {

    var tagVal = $("#newTag").val();
    var addonid = $('#tagForm input[name="addonid"]').val();

    if($.trim(tagVal)=='' || $.trim(addonid)==''){
        return;
    }
    var post_data = $('#tagForm').serialize()+"&ajax=1";
    var add_ajax_url = $('#tagForm').attr('action');
    $.post(add_ajax_url, post_data, function(data) {
        $("#tags").html(data);
        $(".addtagform form")[0].reset();
        $("#tags .addon-tags").removeClass("nojs");
    });
};

 // PHP-compatible urlencode() for Javascript from http://us.php.net/manual/en/function.urlencode.php#85903
 function urlencode(s) {
  s = encodeURIComponent(s);
  return s.replace(/~/g,'%7E').replace(/%20/g,'+');
 };

function remTag(form_data){
    var remove_ajax_url = $('form#tags').attr('action');
    $.post(remove_ajax_url, form_data, function(data){
        $("#tags").html(data);
        $(".addtagform form")[0].reset();
        $("#tags .addon-tags").removeClass("nojs");
    });
};

$(document).ready(function(){
    //remove nojs classname so that css will hide the x's
    $("#tags .addon-tags").removeClass("nojs");
    //hide add tag form if you have js
    $(".addtagform ").addClass("hidden");

    $("#addtagbutton").click(function(e){
        addTag();
        e.preventDefault();
        e.stopPropagation();
    });

    $("form#tags .removetag").live("click",function(e){
        if (e.button != 0) return true; // no right-click
        var form = $("form#tags");
        form.find(":input[name='ajax']").val("1");

        var tagid = $(this).val();
        var form_data = form.serialize() + "&tagid=" + tagid;
        remTag(form_data);
        e.preventDefault();
        e.stopPropagation();
    });

    $("#tags .developertag, #tags .usertag")
        .live("mouseover",function(){
            $(this).addClass("hover");
            })
        .live("mouseout",function(){
            $(this).removeClass("hover");
            });

    $("#addatag").click(function(e){
        $(".addtagform")
            .removeClass("hidden")
            .attr("style","display:block;");
        $('#newTag').focus();
        e.preventDefault();
        e.stopPropagation();
    });

    $("#newTag").live("keypress",function(e){
        if($.trim($(this).val()) != '' &&  e.keyCode == 13) {
            $("#addtagbutton").click();
            e.preventDefault();
            e.stopPropagation();
        }

    });
})
<|endoftext|>


<commit_before>var firstName = "Ada";

var secondLetterOfFirstName = firstName[1];

var lastName = "Lovelace";

var thirdLetterOfLastName = lastName[2];

// Use Bracket Notation to Find the Last Character in a String
var lastLetterOfLastName = lastName[lastName.length - 1];

// Use Bracket Notation to Find the NthtoLast Character in a String
var secondToLastLetterOfLastName = lastName[lastName.length - 2];

// Only change code above this line.
// We use this function to show you the value of your variable in your output box.
// You'll learn about functions soon.
(function(v){return v;})(thirdLetterOfLastName);<commit_msg>127. Add Two Numbers with JavaScript<commit_after>var sum = 10 + 10; //make this equal to 20 by changing the 0 into the appropriate number.
console.log(sum);

// Only change code above this line.
// We use this function to show you the value of your variable in your output box.
// You'll learn about functions soon.
(function(z){return 'sum='+z;})(sum);<|endoftext|>


<commit_before>// save the initial load hash so we can use it if set
app.hash = window.location.hash;
app.onResize = function(percent) {

  var height = $(window).height() * (percent || 0.825);
  // when fullscreen be odd?
  if (height) {
    $("#map").height(height);
    $("#map-wrapper").height(height);
    $(".tabs").height(height);
    $("#legend-wrapper").height(height - 20);
    $("#data-accordion").height(height - 92);
    app.map.render('map');
  }
};

$(window).on('resize', function() {
    app.onResize();
});

// add indexof for typeahead
if (!Array.prototype.indexOf) {

    Array.prototype.indexOf = function(obj, start) {
         for (var i = (start || 0), j = this.length; i < j; i++) {
             if (this[i] === obj) { return i; }
         }
         return -1;
    }
 }

// state of the app
app.state = {
  //list of active layer ids in order they appear on the map
  activeLayers: [],
  location: {}
};

// property to store the state of the map for restoring
app.restoreState = {};

ko.applyBindings(app.viewModel);
app.viewModel.loadLayersFromServer().done(function() {
  $('#fullscreen').show();
  $('#loading').hide();
  // app.map.updateSize();
  app.onResize();
  // if we have the hash state go ahead and load it now
  if (app.hash) {
    app.loadStateFromHash(app.hash);
  }
  // autocomplete for filter
  $('.search-box').typeahead({
    source: app.typeAheadSource
  });
});

// initialize the map
app.init();
// Google.v3 uses EPSG:900913 as projection, so we have to
// transform our coordinates
app.map.setCenter(new OpenLayers.LonLat(-73.24, 38.93).transform(
new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913")), 7);

$(document).ready(function() {
  app.onResize();
  $(window).resize(app.onResize);

  //Do not display any warning for missing tiles
  OpenLayers.Util.onImageLoadError = function(){
    this.src='http://www.openlayers.org/api/img/blank.gif';
  };
  OpenLayers.Tile.Image.useBlankTile=false;

  // if we have the hash state go ahead and load it now
  if (app.hash) {
    app.loadStateFromHash(app.hash);
  }
  // handle coordinate indicator on pointer
  $('#map').bind('mouseleave mouseenter', function(e) {
    $('#pos').toggle();
  });
  $('#map').bind('mousemove', function(e) {
    $('#pos').css({
      left: e.pageX + 20,
      top: e.pageY + 20
    });
  });

  $('.icon-remove-sign').on('click', function(event) {
    $(event.target).prev('input').val('').focus();
  });

  // fullscreen stuff
  // for security reasons, this event listener must be bound directly
  if ( document.getElementById('btn-fullscreen').addEventListener ) {
      document.getElementById('btn-fullscreen').addEventListener('click', function() {
        if ( BigScreen.enabled ) {
          BigScreen.toggle(document.getElementById('fullscreen'));
          // You could also use .toggle(element)
        } else {
          // fallback for browsers that don't support full screen
          $('#fullscreen-error-overlay').show();
        }
      }, false);
  } else {
      $('#btn-fullscreen').on('click', function() {
        // fallback for browsers that don't support addEventListener
        $('#fullscreen-error-overlay').show();
      });
  }

  BigScreen.onenter = function() {
    // called when entering full screen
    app.viewModel.isFullScreen(true);
    // make map fullscreen
    app.onResize(.99);
    //app.map.updateSize();
    //app.map.render('map');
  };

  BigScreen.onexit = function() {
    // called when exiting full screen
    app.viewModel.isFullScreen(false);
    // return to normal size
    // Not exactly comfortable with the following 2 calls to resize,
    // but ff kept having problems when other strategies were tried...
    //for firefox
    setTimeout( app.onResize(), 300);
    //app.onResize();
    //for chrome
    setTimeout( app.onResize, 300);
    //app.onResize();
  };

  // Basemaps button and drop-down behavior
  //hide basemaps drop-down on mouseout
  $('#basemaps').mouseleave( function(e) {
    if ( $(e.toElement).hasClass('basey') ) { //handler for chrome and ie
        $('#basemaps').addClass('open');
    } else if ( $(e.relatedTarget).hasClass('basey') ) { //handler for ff
        $('#basemaps').addClass('open');
    } else {
        $('#SimpleLayerSwitcher_30').hide();
    }
  });

  //hide basemaps drop-down on mouseout
  $('#SimpleLayerSwitcher_30').mouseleave( function() {
    $('#SimpleLayerSwitcher_30').hide();
    $('#basemaps').removeClass('open');
  });

  //hide basemaps drop-down on mouseout
  $('#SimpleLayerSwitcher_30').mousedown( function() {
    $('#basemaps').removeClass('open');
  });

  //hide basemaps drop-down on mouseout
  $('#SimpleLayerSwitcher_30').mouseenter( function() {
    $('#basemaps').addClass('open');
  });

  /* testing mouseenter mouseleave
  $('div.sidebar-nav').mouseenter( function(e) {
    console.log('entering sidebar button');
  }).mouseleave( function(e) {
    console.log('exiting sidebar button');
  });
  */
  /*
  //Opacity popover behavior
  //hide opacity popover when mouse leaves popover or opacity button
  $('.opacity-button.active').mouseout( function() {
    console.log('exiting opacity button');
  });
  */
  $('#opacity-popover').mouseleave( function() {
    app.viewModel.hideOpacity();
  });

});

$('#bookmark-form').on('submit', function(event) {
  var inputs = {},
    $form = $(this);
  event.preventDefault();
  $(this).find('input, textarea').each(function(i, input) {
    var $input = $(input);
    inputs[$input.attr('name')] = $input.val();
  });
  $.post('/feedback/bookmark', inputs, function() {
    $form.closest('.modal').modal('hide');
  });
});

$('#feedback-form').on('submit', function (event) {
  var feedback = {}, $form = $(this);
  event.preventDefault();
   $(this).find('input, textarea').each(function (i, input) {
      var $input = $(input);
      feedback[$input.attr('name')] = $input.val();
   });
       feedback.url = window.location.href;
   $.post('/feedback/send', feedback, function () {
      $form.closest('.modal').modal('hide');
      //$('#thankyou-modal').modal('show');
   });
   $form.closest('.modal').modal('hide');
});

$(document).mousedown(function(e) {
  //removing bookmark popover from view
  if (e.target.id === "bookmarks-button") {} else if (!$(e.target).closest("#bookmark-popover").length) {
    $('#bookmark-popover').hide();
  }

  //ensure layer switcher is removed
  $('#SimpleLayerSwitcher_30').hide();

  //removing layer tooltip popover from view
  var layer_pvr_event = $(e.target).closest(".layer-popover").length;
  if (!layer_pvr_event) {
    $("#layer-popover").hide();
  }

  //removing opacity popover from view
  var op_pvr_event = $(e.target).closest("#opacity-popover").length;
  var op_btn_event = $(e.target).closest(".opacity-button").length;
  if (!op_pvr_event && !op_btn_event) {
    //$('#opacity-popover').hide();
    app.viewModel.hideOpacity();
  }
});<commit_msg>fixing issue in which bookmark button was not permitting bookmark popover to close<commit_after>// save the initial load hash so we can use it if set
app.hash = window.location.hash;
app.onResize = function(percent) {

  var height = $(window).height() * (percent || 0.825);
  // when fullscreen be odd?
  if (height) {
    $("#map").height(height);
    $("#map-wrapper").height(height);
    $(".tabs").height(height);
    $("#legend-wrapper").height(height - 20);
    $("#data-accordion").height(height - 92);
    app.map.render('map');
  }
};

$(window).on('resize', function() {
    app.onResize();
});

// add indexof for typeahead
if (!Array.prototype.indexOf) {

    Array.prototype.indexOf = function(obj, start) {
         for (var i = (start || 0), j = this.length; i < j; i++) {
             if (this[i] === obj) { return i; }
         }
         return -1;
    }
 }

// state of the app
app.state = {
  //list of active layer ids in order they appear on the map
  activeLayers: [],
  location: {}
};

// property to store the state of the map for restoring
app.restoreState = {};

ko.applyBindings(app.viewModel);
app.viewModel.loadLayersFromServer().done(function() {
  $('#fullscreen').show();
  $('#loading').hide();
  // app.map.updateSize();
  app.onResize();
  // if we have the hash state go ahead and load it now
  if (app.hash) {
    app.loadStateFromHash(app.hash);
  }
  // autocomplete for filter
  $('.search-box').typeahead({
    source: app.typeAheadSource
  });
});

// initialize the map
app.init();
// Google.v3 uses EPSG:900913 as projection, so we have to
// transform our coordinates
app.map.setCenter(new OpenLayers.LonLat(-73.24, 38.93).transform(
new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913")), 7);

$(document).ready(function() {
  app.onResize();
  $(window).resize(app.onResize);

  //Do not display any warning for missing tiles
  OpenLayers.Util.onImageLoadError = function(){
    this.src='http://www.openlayers.org/api/img/blank.gif';
  };
  OpenLayers.Tile.Image.useBlankTile=false;

  // if we have the hash state go ahead and load it now
  if (app.hash) {
    app.loadStateFromHash(app.hash);
  }
  // handle coordinate indicator on pointer
  $('#map').bind('mouseleave mouseenter', function(e) {
    $('#pos').toggle();
  });
  $('#map').bind('mousemove', function(e) {
    $('#pos').css({
      left: e.pageX + 20,
      top: e.pageY + 20
    });
  });

  $('.icon-remove-sign').on('click', function(event) {
    $(event.target).prev('input').val('').focus();
  });

  // fullscreen stuff
  // for security reasons, this event listener must be bound directly
  if ( document.getElementById('btn-fullscreen').addEventListener ) {
      document.getElementById('btn-fullscreen').addEventListener('click', function() {
        if ( BigScreen.enabled ) {
          BigScreen.toggle(document.getElementById('fullscreen'));
          // You could also use .toggle(element)
        } else {
          // fallback for browsers that don't support full screen
          $('#fullscreen-error-overlay').show();
        }
      }, false);
  } else {
      $('#btn-fullscreen').on('click', function() {
        // fallback for browsers that don't support addEventListener
        $('#fullscreen-error-overlay').show();
      });
  }

  BigScreen.onenter = function() {
    // called when entering full screen
    app.viewModel.isFullScreen(true);
    // make map fullscreen
    app.onResize(.99);
    //app.map.updateSize();
    //app.map.render('map');
  };

  BigScreen.onexit = function() {
    // called when exiting full screen
    app.viewModel.isFullScreen(false);
    // return to normal size
    // Not exactly comfortable with the following 2 calls to resize,
    // but ff kept having problems when other strategies were tried...
    //for firefox
    setTimeout( app.onResize(), 300);
    //app.onResize();
    //for chrome
    setTimeout( app.onResize, 300);
    //app.onResize();
  };

  // Basemaps button and drop-down behavior
  //hide basemaps drop-down on mouseout
  $('#basemaps').mouseleave( function(e) {
    if ( $(e.toElement).hasClass('basey') ) { //handler for chrome and ie
        $('#basemaps').addClass('open');
    } else if ( $(e.relatedTarget).hasClass('basey') ) { //handler for ff
        $('#basemaps').addClass('open');
    } else {
        $('#SimpleLayerSwitcher_30').hide();
    }
  });

  //hide basemaps drop-down on mouseout
  $('#SimpleLayerSwitcher_30').mouseleave( function() {
    $('#SimpleLayerSwitcher_30').hide();
    $('#basemaps').removeClass('open');
  });

  //hide basemaps drop-down on mouseout
  $('#SimpleLayerSwitcher_30').mousedown( function() {
    $('#basemaps').removeClass('open');
  });

  //hide basemaps drop-down on mouseout
  $('#SimpleLayerSwitcher_30').mouseenter( function() {
    $('#basemaps').addClass('open');
  });

  /* testing mouseenter mouseleave
  $('div.sidebar-nav').mouseenter( function(e) {
    console.log('entering sidebar button');
  }).mouseleave( function(e) {
    console.log('exiting sidebar button');
  });
  */
  /*
  //Opacity popover behavior
  //hide opacity popover when mouse leaves popover or opacity button
  $('.opacity-button.active').mouseout( function() {
    console.log('exiting opacity button');
  });
  */
  $('#opacity-popover').mouseleave( function() {
    app.viewModel.hideOpacity();
  });

});

$('#bookmark-form').on('submit', function(event) {
  var inputs = {},
    $form = $(this);
  event.preventDefault();
  $(this).find('input, textarea').each(function(i, input) {
    var $input = $(input);
    inputs[$input.attr('name')] = $input.val();
  });
  $.post('/feedback/bookmark', inputs, function() {
    $form.closest('.modal').modal('hide');
  });
});

$('#feedback-form').on('submit', function (event) {
  var feedback = {}, $form = $(this);
  event.preventDefault();
   $(this).find('input, textarea').each(function (i, input) {
      var $input = $(input);
      feedback[$input.attr('name')] = $input.val();
   });
       feedback.url = window.location.href;
   $.post('/feedback/send', feedback, function () {
      $form.closest('.modal').modal('hide');
      //$('#thankyou-modal').modal('show');
   });
   $form.closest('.modal').modal('hide');
});

$(document).mousedown(function(e) {
  //removing bookmark popover from view
  if ($(e.target).closest('a')[0].id === "bookmarks-button") {
    //do nothing as show/hide behavior is handled in viewModel
  } else if (!$(e.target).closest("#bookmark-popover").length) {
    $('#bookmark-popover').hide();
  }

  //ensure layer switcher is removed
  $('#SimpleLayerSwitcher_30').hide();

  //removing layer tooltip popover from view
  var layer_pvr_event = $(e.target).closest(".layer-popover").length;
  if (!layer_pvr_event) {
    $("#layer-popover").hide();
  }

  //removing opacity popover from view
  var op_pvr_event = $(e.target).closest("#opacity-popover").length;
  var op_btn_event = $(e.target).closest(".opacity-button").length;
  if (!op_pvr_event && !op_btn_event) {
    //$('#opacity-popover').hide();
    app.viewModel.hideOpacity();
  }
});<|endoftext|>


<commit_before>const BitlyClient = require('bitly').BitlyClient
const cheerio = require('cheerio')
const fs = require('fs')
const request = require('request')

var LOG = {}

var LOGFILE = __rootdir + '/data/ofn.json'
try {
  LOG = require(LOGFILE)
} catch (e) {
  //
}

var getTitle = function (url) {
  return new Promise(
    (resolve, reject) => {
      const maxSize = 1024
      var size = 0
      var response = ''
      var req = request(url)
      // Check the size of the downloaded data regularly
      req.on('data', chunk => {
        size += chunk.length
        response += chunk.toString()
        // After maxSize bytes, abort
        if (size > maxSize) {
          req.abort()
        }
      }).on('error', () => {
        // If there was an error, don't bother trying to get the title
        resolve(null)
      }).on('response', (response) => {
        if (response.statusCode !== 200) {
          resolve(null)
        }
      }).on('end', () => {
        // After aborting (or finishing), parse title
        const $ = cheerio.load(response)
        const title = $('title').text().trim().replace(/\s+/g, ' ').substring(0, 400) || null
        resolve(title)
      })
    })
}

let ofn = (number) => {
  if (number === 2) return ' (again)'
  if (number > 2) return ' (again ×' + (number - 1) + ')'
  return ''
}

var shorten = async function (bot, url) {
  try {
    const bitly = new BitlyClient(bot.config.get('bitly.accesstoken'), {})
    let result = await bitly.shorten(url)
    if (LOG[result.hash]) {
      LOG[result.hash]++
    } else {
      LOG[result.hash] = 1
    }

    fs.writeFileSync(LOGFILE, JSON.stringify(LOG, null, 4))

    return result.url + ofn(LOG[result.hash])
  } catch (e) {
    if (e.statusCode === 500) {
      if (e.message.includes('ALREADY_A_BITLY_LINK')) {
        // Don't bother shortening an already short URL
        return ofn(LOG[url.split('/').pop()])
      }
    }
    throw e
  }
}

module.exports = {
  events: {
    url: async function (bot, url, nick, to, text, msg) {
      // let shortenedUrl = await shorten(bot, url.href)
      // let urlTitle = await getTitle(url.href)

      // bot.shout(to, [shortenedUrl, urlTitle].filter(Boolean).join(' → '))
      //
      bot.shout(to,
        (await Promise.all([shorten(bot, url.href), getTitle(url.href)]))
          .filter(Boolean)
          .join(' → ')
      )
    }
  },
  commands: {
    randurl: {
      fireMessageEvent: true,
      help: 'Output a random URL from the channel history',
      command: function () {
        var keys = Object.keys(LOG)
        return 'https://bit.ly/' + keys[Math.floor(Math.random() * keys.length)]
      }
    },
    urlcount: {
      help: 'Count the number of URLs stored in channel history',
      command: function () {
        return Object.keys(LOG).length + ' URLs stored'
      }
    },
    shorten: {
      help: 'Shorten a URL',
      usage: [ 'url' ],
      command: async function (bot, msg) {
        let bitly = new BitlyClient(bot.config.get('bitly.accesstoken'))
        let res = await bitly.shorten(msg.args.url)
        if (res.url) {
          return res.url
        }
      }
    }
  }
}
<commit_msg>Add dirty un-homographing code for anon-ircd (#380)<commit_after>const BitlyClient = require('bitly').BitlyClient
const cheerio = require('cheerio')
const fs = require('fs')
const request = require('request')

var LOG = {}

var LOGFILE = __rootdir + '/data/ofn.json'
try {
  LOG = require(LOGFILE)
} catch (e) {
  //
}

var getTitle = function (url) {
  return new Promise(
    (resolve, reject) => {
      const maxSize = 1024
      var size = 0
      var response = ''
      var req = request(url)
      // Check the size of the downloaded data regularly
      req.on('data', chunk => {
        size += chunk.length
        response += chunk.toString()
        // After maxSize bytes, abort
        if (size > maxSize) {
          req.abort()
        }
      }).on('error', () => {
        // If there was an error, don't bother trying to get the title
        resolve(null)
      }).on('response', (response) => {
        if (response.statusCode !== 200) {
          resolve(null)
        }
      }).on('end', () => {
        // After aborting (or finishing), parse title
        const $ = cheerio.load(response)
        const title = $('title').text().trim().replace(/\s+/g, ' ').substring(0, 400) || null
        resolve(title)
      })
    })
}

let ofn = (number) => {
  if (number === 2) return ' (again)'
  if (number > 2) return ' (again ×' + (number - 1) + ')'
  return ''
}

var shorten = async function (bot, url) {
  try {
    const bitly = new BitlyClient(bot.config.get('bitly.accesstoken'), {})
    let result = await bitly.shorten(url)
    if (LOG[result.hash]) {
      LOG[result.hash]++
    } else {
      LOG[result.hash] = 1
    }

    fs.writeFileSync(LOGFILE, JSON.stringify(LOG, null, 4))

    return result.url + ofn(LOG[result.hash])
  } catch (e) {
    if (e.statusCode === 500) {
      if (e.message.includes('ALREADY_A_BITLY_LINK')) {
        // Don't bother shortening an already short URL
        return ofn(LOG[url.split('/').pop()])
      }
    }
    throw e
  }
}

module.exports = {
  events: {
    url: async function (bot, url, nick, to, text, msg) {
      if (process.env.NODE_ENV === 'kgz') {
        // dirty fix for bizarro IRC server github.com/kragniz/anon-ircd
        // which converts any mention of "You" to "You", but with cyrillc homoglyph
        //
        // url.href is already punycode normalised so being clever is complicated
        // so let's just hardcode to YouTube for now:
        url.href = url.href.replace('xn--yutube-wqf.com', 'youtube.com')
      }
      // let shortenedUrl = await shorten(bot, url.href)
      // let urlTitle = await getTitle(url.href)

      // bot.shout(to, [shortenedUrl, urlTitle].filter(Boolean).join(' → '))
      //
      bot.shout(to,
        (await Promise.all([shorten(bot, url.href), getTitle(url.href)]))
          .filter(Boolean)
          .join(' → ')
      )
    }
  },
  commands: {
    randurl: {
      fireMessageEvent: true,
      help: 'Output a random URL from the channel history',
      command: function () {
        var keys = Object.keys(LOG)
        return 'https://bit.ly/' + keys[Math.floor(Math.random() * keys.length)]
      }
    },
    urlcount: {
      help: 'Count the number of URLs stored in channel history',
      command: function () {
        return Object.keys(LOG).length + ' URLs stored'
      }
    },
    shorten: {
      help: 'Shorten a URL',
      usage: [ 'url' ],
      command: async function (bot, msg) {
        let bitly = new BitlyClient(bot.config.get('bitly.accesstoken'))
        let res = await bitly.shorten(msg.args.url)
        if (res.url) {
          return res.url
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>$(document).ready(function(){
	function redact() {
		$('.message').find('p').each(function(){
			// split each paragraph by newline
			var text = $(this).text().split('\n'),
			redacted = '';
			$(text).each(function(k, line){

				// loop through each line, split newlines by spaces
				// to create blocks of text
				var blocks = line.split(' ');
				$(blocks).each(function(k, block){

					// randomly choose if redacted or not
					if(Math.random() * 10 > 5) {
						redacted += ' ' + block + ' ';
					}
					else {
						redacted += block;
					}
				});
			});

			// update html
			$(this).html(redacted);
			return;
		});
		return;
	}
	$('#redactor').on('click', function(){
		redact();
		$(this).text('Redact it again.');
	});
});
<commit_msg>Prevnt removal of spaces<commit_after>$(document).ready(function(){
	function redact() {
		$('.message').find('p').each(function(){
			// split each paragraph by newline
			var text = $(this).text().split('\n'),
			redacted = '';
			$(text).each(function(k, line){

				// loop through each line, split newlines by spaces
				// to create blocks of text
				var blocks = line.split(' ');
				$(blocks).each(function(k, block){

					// randomly choose if redacted or not
					if(Math.random() * 10 > 5) {
						redacted += ' ' + block + ' ';
					}
					else {
						redacted += ( ' ' + block + ' ');
					}
				});
			});

			// update html
			$(this).html(redacted);
			return;
		});
		return;
	}
	$('#redactor').on('click', function(){
		redact();
		$(this).text('Redact it again.');
	});
});
<|endoftext|>


<commit_before>define([
    'dojo/_base/declare',
    'dijit/TitlePane',
    'dojo/on',
    'dojo/_base/lang',
    'dojo/dnd/Moveable',
    'dojo/aspect',
    'dojo/topic',
    'dojo/sniff',
    'dojo/_base/window',
    'dojo/window',
    'dojo/dom-geometry',
    'dojo/dom-style',
    'dojo/dom-construct',
    'dojo/dom-attr',
    'dojo/dom-class',
    'dojox/layout/ResizeHandle',
    'xstyle/css!dojox/layout/resources/ResizeHandle.css',
    'xstyle/css!./FloatingTitlePane/css/FloatingTitlePane.css'
], function (declare, TitlePane, on, lang, Moveable, aspect, topic, has, win, winUtils, domGeom, domStyle, domConstruct, domAttr, domClass, ResizeHandle) {

    return declare([TitlePane], {
        sidebarPosition: null,

        canFloat: false,
        isFloating: false,
        isDragging: false,
        dragDelay: 3,

        resizable: false,
        resizeOptions: {},
        isResizing: false,

        postCreate: function () {
            if (this.canFloat) {
                this.createDomNodes();
                this.own(on(window, 'resize', lang.hitch(this, '_endDrag')));
            }
            this.own(topic.subscribe('titlePane/event', lang.hitch(this, '_updateWidgetSidebarPosition')));
            this.own(aspect.after(this, 'toggle', lang.hitch(this, '_afterToggle')));
            this.inherited(arguments);
        },
        startup: function () {
            if (this.titleBarNode && this.canFloat) {
                if (has('edge') || has('trident')) {
                    this.dragDelay = 0;
                }
                this._moveable = new Moveable(this.domNode, {
                    handle: this.titleBarNode,
                    delay: this.dragDelay
                });
                this._titleBarHeight = domStyle.get(this.titleBarNode, 'height');
                aspect.after(this._moveable, 'onMove', lang.hitch(this, '_dragging'), true);
                aspect.after(this._moveable, 'onMoveStop', lang.hitch(this, '_endDrag'), true);
                aspect.after(this._moveable, 'onMoveStart', lang.hitch(this, '_startDrag'), true);

                // ensure that dragging the movable stops no matter
                // when/where the mouse is released or a touch is completed
                on(document, 'mouseup, touchend', lang.hitch(this, '_endDrag'));
            }
            this.inherited(arguments);
        },
        createDomNodes: function () {
            this.moveHandleNode = domConstruct.create('span', {
                title: 'Move widget',
                'class': 'floatingWidgetPopout'
            }, this.titleNode, 'after');

            this.dockHandleNode = domConstruct.create('span', {
                title: 'Dock widget',
                style: 'display:none',
                'class': 'floatingWidgetDock'
            }, this.titleNode, 'after');
            this.own(on(this.dockHandleNode, 'click', lang.hitch(this, function (evt) {
                this._dockWidget();
                evt.stopImmediatePropagation();
            })));

            if (this.resizable) {
                var resOptions = lang.mixin({
                    targetId: this.id,
                    activeResize: true,
                    intermediateChanges: true,
                    startTopic: this.id + '/resize/start',
                    endTopic: this.id + '/resize/end'
                }, this.resizeOptions);
                this._resizer = new ResizeHandle(resOptions).placeAt(this.id);
                domStyle.set(this._resizer.resizeHandle, 'display', 'none');
                on(this._resizer, 'resize', lang.hitch(this, '_resizing'), true);
                this.own(topic.subscribe(this.id + '/resize/start', lang.hitch(this, '_startResize')));
                this.own(topic.subscribe(this.id + '/resize/end', lang.hitch(this, '_endResize')));
            }
        },

        /* Methods related to Toggling the TitleBar */
        toggle: function () {
            if ((this.isFloating && this.isDragging) || this.resizing) {
                return;
            }
            this.inherited(arguments);
        },
        _afterToggle: function () {
            var evt = this.open ? 'open' : 'close';
            this._updateTopic(evt);
        },

        /* Methods for Dragging */
        _dragging: function () {
            this.isDragging = true;
            if (!this.titleCursor) {
                this.titleCursor = domStyle.get(this.titleBarNode, 'cursor');
            }
            domStyle.set(this.titleBarNode, 'cursor', 'move');
            if (!this.isFloating) {
                this._checkSidebarPosition();
                domStyle.set(this.dockHandleNode, 'display', 'inline');
                domStyle.set(this.moveHandleNode, 'display', 'none');
                domStyle.set(this.domNode, 'z-index', '40');
                var computedStyle = domStyle.getComputedStyle(this.containerNode);
                var width = parseInt(domStyle.getComputedStyle(this.sidebar.containerNode).width, 10);
                domGeom.setContentSize(this.domNode, {
                    w: (width - 2)
                }, computedStyle);
                this.isFloating = true;
                this.placeAt(win.body());
                domStyle.set(this.domNode, {
                    top: (this._moverBox.t - this._titleBarHeight) + 'px'
                });

                if (this.resizable && this._resizer && this._resizer.resizeHandle) {
                    domStyle.set(this._resizer.resizeHandle, 'display', 'block');
                }
                this._updateTopic('undock');
            }
        },
        _startDrag: function (mover) {
            this._moverBox = mover.marginBox;
        },
        _endDrag: function () {
            // summary:
            //      Called after dragging the Dialog. Saves the position of the dialog in the viewport,
            //      and also adjust position to be fully within the viewport, so user doesn't lose access to handle
            var nodePosition = domGeom.position(this.domNode);
            var viewport = winUtils.getBox(this.ownerDocument);
            nodePosition.y = Math.min(Math.max(nodePosition.y, 0), (viewport.h - nodePosition.h));
            nodePosition.x = Math.min(Math.max(nodePosition.x, 0), (viewport.w - nodePosition.w));
            this._relativePosition = nodePosition;
            this._position();
            domStyle.set(this.titleBarNode, 'cursor', this.titleCursor);

            //delayed slightly so the titlebar does not toggle
            window.setTimeout(lang.hitch(this, function () {
                this.isDragging = false;
            }), 50);
        },
        _position: function () {
            // summary:
            //      Position the dialog in the viewport.  If no relative offset
            //      in the viewport has been determined (by dragging, for instance),
            //      center the dialog.  Otherwise, use the Dialog's stored relative offset,
            //      adjusted by the viewport's scroll.
            if (!domClass.contains(this.ownerDocumentBody, 'dojoMove')) { // don't do anything if called during auto-scroll
                var node = this.domNode,
                    viewport = winUtils.getBox(this.ownerDocument),
                    p = this._relativePosition,
                    bb = p ? null : domGeom.position(node),
                    l = Math.floor(viewport.l + (p ? p.x : (viewport.w - bb.w) / 2)),
                    t = Math.floor(viewport.t + (p ? p.y : (viewport.h - bb.h) / 2));
                domStyle.set(node, {
                    left: l + 'px',
                    top: t + 'px'
                });
            }
        },

        /* Methods for Docking and Undocking */
        _dockWidget: function () {
            if (!this.isDragging) {
                domAttr.remove(this.domNode, 'style');
                domStyle.set(this.dockHandleNode, 'display', 'none');
                domStyle.set(this.moveHandleNode, 'display', 'inline');
                var dockedWidgets = this.sidebar.getChildren();
                if (this.sidebarPosition > dockedWidgets.length || this.sidebarPosition < 0) {
                    this.sidebarPosition = dockedWidgets.length;
                }
                this.placeAt(this.sidebar, this.sidebarPosition);
                this.isFloating = false;
                this._updateTopic('dock');
            }
            if (this.resizable && this._resizer && this._resizer.resizeHandle) {
                domStyle.set(this._resizer.resizeHandle, 'display', 'none');
                if (this._initialDimensions) {
                    topic.publish(this.id + '/resize/resize', this._initialDimensions);
                }
            }
        },
        _updateWidgetSidebarPosition: function (msg) {
            var id = msg.widgetID, pos = msg.sidebarPosition, action = msg.action;

            // do nothing if the topic is from the same widget
            // or this widget cannot float
            // or if the action is not dock/undock
            if (id === this.id || !this.canFloat || (action !== 'dock' && action !== 'undock')) {
                return;
            }

            this._checkSidebarPosition();

            // increment the position if the other widget is docked
            // above this widget's position
            if (action === 'dock') {
                var dockedWidgets = this.sidebar.getChildren();
                if (pos < this.sidebarPosition && this.sidebarPosition < dockedWidgets.length) {
                    this.sidebarPosition++;
                }

            // decrement the position if the other widget is undocked
            // above this widget's position
            } else if (action === 'undock') {
                if (pos < this.sidebarPosition && this.sidebarPosition > 0) {
                    this.sidebarPosition--;
                }
            }
        },
        _checkSidebarPosition: function () {
            // set the initial sidebar positions for all floating
            // widgets in this same sidebar. This is done
            // only once when the first widget is undocked.
            var dockedWidgets = this.sidebar.getChildren();
            if (this.sidebarPosition === null) {
                var k = 0, len = dockedWidgets.length;
                for (k = 0; k < len; k++) {
                    var widget = dockedWidgets[k];
                    if (widget.canFloat) {
                        widget.sidebarPosition = k;
                    }
                }
            }
        },

        /* Methods for Resizing */
        _resizing: function (evt) {
            this.isResizing = true;
            var newDim = this._resizer._getNewCoords(evt, this, 'margin');
            if (newDim) {
                topic.publish(this.id + '/resize/resize', {
                    h: this._resizeDimensions.h + (newDim.h - this._resizer.startSize.h),
                    w: this._resizeDimensions.w + (newDim.w - this._resizer.startSize.w)
                });
            }
        },
        _startResize: function () {
            this.isResizing = true;
            this._resizeDimensions = domGeom.getContentBox(this.containerNode);
            if (!this._initialDimensions) {
                this._initialDimensions = this._resizeDimensions;
            }
        },
        _endResize: function () {
            this.isResizing = false;
            domStyle.set(this.domNode, 'height', 'auto');
        },

        _updateTopic: function (msg) {
            topic.publish('titlePane/event', {
                category: 'Titlepane Event',
                action: msg,
                label: this.title,
                widgetID: this.id,
                sidebarPosition: this.sidebarPosition,
                value: msg
            });
        }
    });
});<commit_msg>fix issue in dojo mover class causing IE and now Chrome v 55 to not let go of the titlePane when mouse is released.<commit_after>define([
    'dojo/_base/declare',
    'dijit/TitlePane',
    'dojo/on',
    'dojo/_base/lang',
    'dojo/dnd/Moveable',
    'dojo/aspect',
    'dojo/topic',
    'dojo/sniff',
    'dojo/_base/window',
    'dojo/window',
    'dojo/dom-geometry',
    'dojo/dom-style',
    'dojo/dom-construct',
    'dojo/dom-attr',
    'dojo/dom-class',
    'dojox/layout/ResizeHandle',
    'xstyle/css!dojox/layout/resources/ResizeHandle.css',
    'xstyle/css!./FloatingTitlePane/css/FloatingTitlePane.css'
], function (declare, TitlePane, on, lang, Moveable, aspect, topic, has, win, winUtils, domGeom, domStyle, domConstruct, domAttr, domClass, ResizeHandle) {

    return declare([TitlePane], {
        sidebarPosition: null,

        canFloat: false,
        isFloating: false,
        isDragging: false,
        dragDelay: 3,

        resizable: false,
        resizeOptions: {},
        isResizing: false,

        postCreate: function () {
            if (this.canFloat) {
                this.createDomNodes();
                this.own(on(window, 'resize', lang.hitch(this, '_endDrag')));
            }
            this.own(topic.subscribe('titlePane/event', lang.hitch(this, '_updateWidgetSidebarPosition')));
            this.own(aspect.after(this, 'toggle', lang.hitch(this, '_afterToggle')));
            this.inherited(arguments);
        },
        startup: function () {
            if (this.titleBarNode && this.canFloat) {
                this._moveable = new Moveable(this.domNode, {
                    handle: this.titleBarNode,
                    delay: this.dragDelay
                });
                if (this.dragDelay > 0) {
                    this._moveable.mover.prototype.onMouseUp = function (e) {
                        this.destroy();
                        e.preventDefault();
                        e.stopPropagation();
                    };
                }
                this._titleBarHeight = domStyle.get(this.titleBarNode, 'height');
                aspect.after(this._moveable, 'onMove', lang.hitch(this, '_dragging'), true);
                aspect.after(this._moveable, 'onMoveStop', lang.hitch(this, '_endDrag'), true);
                aspect.after(this._moveable, 'onMoveStart', lang.hitch(this, '_startDrag'), true);

                // ensure that dragging the movable stops no matter
                // when/where the mouse is released or a touch is completed
                on(document, 'mouseup, touchend', lang.hitch(this, '_endDrag'));
            }
            this.inherited(arguments);
        },
        createDomNodes: function () {
            this.moveHandleNode = domConstruct.create('span', {
                title: 'Move widget',
                'class': 'floatingWidgetPopout'
            }, this.titleNode, 'after');

            this.dockHandleNode = domConstruct.create('span', {
                title: 'Dock widget',
                style: 'display:none',
                'class': 'floatingWidgetDock'
            }, this.titleNode, 'after');
            this.own(on(this.dockHandleNode, 'click', lang.hitch(this, function (evt) {
                this._dockWidget();
                evt.stopImmediatePropagation();
            })));

            if (this.resizable) {
                var resOptions = lang.mixin({
                    targetId: this.id,
                    activeResize: true,
                    intermediateChanges: true,
                    startTopic: this.id + '/resize/start',
                    endTopic: this.id + '/resize/end'
                }, this.resizeOptions);
                this._resizer = new ResizeHandle(resOptions).placeAt(this.id);
                domStyle.set(this._resizer.resizeHandle, 'display', 'none');
                on(this._resizer, 'resize', lang.hitch(this, '_resizing'), true);
                this.own(topic.subscribe(this.id + '/resize/start', lang.hitch(this, '_startResize')));
                this.own(topic.subscribe(this.id + '/resize/end', lang.hitch(this, '_endResize')));
            }
        },

        /* Methods related to Toggling the TitleBar */
        toggle: function () {
            if ((this.isFloating && this.isDragging) || this.resizing) {
                return;
            }
            this.inherited(arguments);
        },
        _afterToggle: function () {
            var evt = this.open ? 'open' : 'close';
            this._updateTopic(evt);
        },

        /* Methods for Dragging */
        _dragging: function () {
            this.isDragging = true;
            if (!this.titleCursor) {
                this.titleCursor = domStyle.get(this.titleBarNode, 'cursor');
            }
            domStyle.set(this.titleBarNode, 'cursor', 'move');
            if (!this.isFloating) {
                this._checkSidebarPosition();
                domStyle.set(this.dockHandleNode, 'display', 'inline');
                domStyle.set(this.moveHandleNode, 'display', 'none');
                domStyle.set(this.domNode, 'z-index', '40');
                var computedStyle = domStyle.getComputedStyle(this.containerNode);
                var width = parseInt(domStyle.getComputedStyle(this.sidebar.containerNode).width, 10);
                domGeom.setContentSize(this.domNode, {
                    w: (width - 2)
                }, computedStyle);
                this.isFloating = true;
                this.placeAt(win.body());
                domStyle.set(this.domNode, {
                    top: (this._moverBox.t - this._titleBarHeight) + 'px'
                });

                if (this.resizable && this._resizer && this._resizer.resizeHandle) {
                    domStyle.set(this._resizer.resizeHandle, 'display', 'block');
                }
                this._updateTopic('undock');
            }
        },
        _startDrag: function (mover) {
            this._moverBox = mover.marginBox;
        },
        _endDrag: function () {
            // summary:
            //      Called after dragging the Dialog. Saves the position of the dialog in the viewport,
            //      and also adjust position to be fully within the viewport, so user doesn't lose access to handle
            var nodePosition = domGeom.position(this.domNode);
            var viewport = winUtils.getBox(this.ownerDocument);
            nodePosition.y = Math.min(Math.max(nodePosition.y, 0), (viewport.h - nodePosition.h));
            nodePosition.x = Math.min(Math.max(nodePosition.x, 0), (viewport.w - nodePosition.w));
            this._relativePosition = nodePosition;
            this._position();
            domStyle.set(this.titleBarNode, 'cursor', this.titleCursor);

            //delayed slightly so the titlebar does not toggle
            window.setTimeout(lang.hitch(this, function () {
                this.isDragging = false;
            }), 50);
        },
        _position: function () {
            // summary:
            //      Position the dialog in the viewport.  If no relative offset
            //      in the viewport has been determined (by dragging, for instance),
            //      center the dialog.  Otherwise, use the Dialog's stored relative offset,
            //      adjusted by the viewport's scroll.
            if (!domClass.contains(this.ownerDocumentBody, 'dojoMove')) { // don't do anything if called during auto-scroll
                var node = this.domNode,
                    viewport = winUtils.getBox(this.ownerDocument),
                    p = this._relativePosition,
                    bb = p ? null : domGeom.position(node),
                    l = Math.floor(viewport.l + (p ? p.x : (viewport.w - bb.w) / 2)),
                    t = Math.floor(viewport.t + (p ? p.y : (viewport.h - bb.h) / 2));
                domStyle.set(node, {
                    left: l + 'px',
                    top: t + 'px'
                });
            }
        },

        /* Methods for Docking and Undocking */
        _dockWidget: function () {
            if (!this.isDragging) {
                domAttr.remove(this.domNode, 'style');
                domStyle.set(this.dockHandleNode, 'display', 'none');
                domStyle.set(this.moveHandleNode, 'display', 'inline');
                var dockedWidgets = this.sidebar.getChildren();
                if (this.sidebarPosition > dockedWidgets.length || this.sidebarPosition < 0) {
                    this.sidebarPosition = dockedWidgets.length;
                }
                this.placeAt(this.sidebar, this.sidebarPosition);
                this.isFloating = false;
                this._updateTopic('dock');
            }
            if (this.resizable && this._resizer && this._resizer.resizeHandle) {
                domStyle.set(this._resizer.resizeHandle, 'display', 'none');
                if (this._initialDimensions) {
                    topic.publish(this.id + '/resize/resize', this._initialDimensions);
                }
            }
        },
        _updateWidgetSidebarPosition: function (msg) {
            var id = msg.widgetID, pos = msg.sidebarPosition, action = msg.action;

            // do nothing if the topic is from the same widget
            // or this widget cannot float
            // or if the action is not dock/undock
            if (id === this.id || !this.canFloat || (action !== 'dock' && action !== 'undock')) {
                return;
            }

            this._checkSidebarPosition();

            // increment the position if the other widget is docked
            // above this widget's position
            if (action === 'dock') {
                var dockedWidgets = this.sidebar.getChildren();
                if (pos < this.sidebarPosition && this.sidebarPosition < dockedWidgets.length) {
                    this.sidebarPosition++;
                }

            // decrement the position if the other widget is undocked
            // above this widget's position
            } else if (action === 'undock') {
                if (pos < this.sidebarPosition && this.sidebarPosition > 0) {
                    this.sidebarPosition--;
                }
            }
        },
        _checkSidebarPosition: function () {
            // set the initial sidebar positions for all floating
            // widgets in this same sidebar. This is done
            // only once when the first widget is undocked.
            var dockedWidgets = this.sidebar.getChildren();
            if (this.sidebarPosition === null) {
                var k = 0, len = dockedWidgets.length;
                for (k = 0; k < len; k++) {
                    var widget = dockedWidgets[k];
                    if (widget.canFloat) {
                        widget.sidebarPosition = k;
                    }
                }
            }
        },

        /* Methods for Resizing */
        _resizing: function (evt) {
            this.isResizing = true;
            var newDim = this._resizer._getNewCoords(evt, this, 'margin');
            if (newDim) {
                topic.publish(this.id + '/resize/resize', {
                    h: this._resizeDimensions.h + (newDim.h - this._resizer.startSize.h),
                    w: this._resizeDimensions.w + (newDim.w - this._resizer.startSize.w)
                });
            }
        },
        _startResize: function () {
            this.isResizing = true;
            this._resizeDimensions = domGeom.getContentBox(this.containerNode);
            if (!this._initialDimensions) {
                this._initialDimensions = this._resizeDimensions;
            }
        },
        _endResize: function () {
            this.isResizing = false;
            domStyle.set(this.domNode, 'height', 'auto');
        },

        _updateTopic: function (msg) {
            topic.publish('titlePane/event', {
                category: 'Titlepane Event',
                action: msg,
                label: this.title,
                widgetID: this.id,
                sidebarPosition: this.sidebarPosition,
                value: msg
            });
        }
    });
});<|endoftext|>


<commit_before>/** @babel */

import {CompositeDisposable, Emitter} from 'atom'
import FileDiff from './file-diff'
import GitService from './git-service'
import EventTransactor from './event-transactor'

// FileList contains a collection of FileDiff objects
export default class FileList {
  constructor (files, {stageOnChange} = {}) {
    // TODO: Rather than this `stageOnChange` bool, there should probably be a
    // new object that just handles the connection to nodegit. Cause there are
    // several of these objects in the system, but only one of them handles
    // writing to the index.
    this.gitService = GitService.instance()
    this.emitter = new Emitter()
    this.transactor = new EventTransactor(this.emitter, {fileList: this})
    this.fileCache = {}
    this.setFiles(files || [])
    if (stageOnChange) {
      this.onDidChange(this.handleDidChange.bind(this))
    }
  }

  onDidChange (callback) {
    return this.emitter.on('did-change', callback)
  }

  didChange (event) {
    this.transactor.didChange(event)
  }

  onDidUserChange (callback) {
    return this.emitter.on('did-user-change', callback)
  }

  didUserChange () {
    this.emitter.emit('did-user-change')
  }

  async handleDidChange (event) {
    if (!(event && event.events && event.fileList === this)) return
    if (this.isSyncingState()) return

    console.log('staging?', event)

    let stagableLinesPerHunk = {}

    for (let fileEvent of event.events) {
      if (!fileEvent) continue

      for (let hunkEvent of fileEvent.events) {
        if (!hunkEvent) continue

        const hunk = hunkEvent.hunk
        if (!stagableLinesPerHunk[hunk]) {
          stagableLinesPerHunk[hunk] = {
            linesToStage: [],
            linesToUnstage: []
          }
        }
        const stagableLines = stagableLinesPerHunk[hunk]
        for (let lineEvent of hunkEvent.events) {
          if (lineEvent.line && lineEvent.property === 'isStaged') {
            if (lineEvent.line.isStaged()) {
              stagableLines.linesToStage.push(lineEvent.line)
            } else {
              stagableLines.linesToUnstage.push(lineEvent.line)
            }
          }
        }
      }
    }

    let patchInfoByFile = {}
    for (let hunkString in stagableLinesPerHunk) {
      const {linesToStage, linesToUnstage} = stagableLinesPerHunk[hunkString]
      console.log('lines to stage:', linesToStage.length, '; unstage:', linesToUnstage.length)
      const hunk = linesToStage.length > 0 ? linesToStage[0].hunk : linesToUnstage[0].hunk
      const file = hunk.diff
      let info = patchInfoByFile[file]
      if (!info) {
        info = {promises: [], file, stage: linesToStage.length > 0}
        patchInfoByFile[file] = info
      }

      let promise = null
      if (linesToStage.length) {
        promise = this.gitService.calculatePatchText(hunk, linesToStage, true)
      } else if (linesToUnstage.length) {
        promise = this.gitService.calculatePatchText(hunk, linesToUnstage, false)
      }

      info.promises.push(promise)
    }

    // TODO: All this shit should be parallel.
    for (let file in patchInfoByFile) {
      const info = patchInfoByFile[file]
      const patches = await Promise.all(info.promises)
      await this.stagePatches(info.file, patches, info.stage)
    }

    this.didUserChange()
  }

  openFileDiffAtIndex (index) {
    return this.files[index].openDiff()
  }

  setFiles (files) {
    if (this.fileSubscriptions) {
      this.fileSubscriptions.dispose()
    }
    this.fileSubscriptions = new CompositeDisposable()
    this.files = files
    for (const file of files) {
      this.fileSubscriptions.add(file.onDidChange(this.didChange.bind(this)))
      this.addFileToCache(file)
    }
    this.didChange()
  }

  getFiles () {
    return this.files
  }

  // position = [0, 2] will get you the third hunk in the first file.
  // position = [0, 2, 1] will get you the 2nd line in the third hunk in the first file.
  getObjectAtPosition (position) {
    const [fileIndex, hunkIndex, lineIndex] = position

    const file = this.getFiles()[fileIndex]
    const hunk = file.getHunks()[hunkIndex]
    if (lineIndex != null) {
      return hunk.getLines()[lineIndex]
    } else {
      return hunk
    }
  }

  // The file cache should allow all UI elements usage of the same FileDiff
  // models. Sometimes it's a bit of a chicken and egg problem, and it happens
  // when a tab is deserialized.
  //
  // * Let's say there is a Diff tab being deserialized for `config.js`.
  // * The deserializer runs before nodegit knows the state of things, but the
  // tab needs a model. The tab will use `getOrCreateFileFromPathName` to get
  // the model.
  // * Then and the FileDiff::loadFromGitUtils is called and there are changes
  // in `config.js`
  // * `loadFromGitUtils` will use
  // `getOrCreateFileFromPathName('config.js')`, which will grab the same model
  // that the Diff tab is using.
  // * The model will be updated from the nodegit state and the Diff tab will
  // update properly.
  addFileToCache (file) {
    if (file.getOldPathName() !== file.getNewPathName() && this.fileCache[file.getOldPathName()]) {
      delete this.fileCache[file.getOldPathName()]
    }
    this.fileCache[file.getNewPathName()] = file
  }

  getFileFromPathName (pathName) {
    return this.fileCache[pathName]
  }

  getOrCreateFileFromPathName (pathName) {
    let file = this.getFileFromPathName(pathName)
    if (!file) {
      file = new FileDiff({newPathName: pathName, oldPathName: pathName})
      this.addFileToCache(file)
    }
    return file
  }

  isSyncingState () {
    if (this.isSyncing) {
      return true
    }

    for (let file of this.files) {
      if (file.isSyncingState()) {
        return true
      }
    }

    return false
  }

  toString () {
    return this.files.map((file) => { return file.toString() }).join('\n')
  }

  async stagePatches (fileDiff, patches, stage) {
    const patchText = patches.join('\n')
    if (stage) {
      return this.gitService.stagePatch(fileDiff, patchText)
    } else {
      return this.gitService.unstagePatch(fileDiff, patchText)
    }
  }

  async loadFromGitUtils () {
    let files = []
    this.isSyncing = true

    // FIXME: for now, we need to get the stati for the diff stuff to work. :/
    this.gitService.getStatuses()
    let unifiedDiffs = await this.gitService.getDiffs('all')
    // TODO: It's a bummer these lines happen sequentially
    const stagedDiffs = await this.gitService.getDiffs('staged')
    const unstagedDiffs = await this.gitService.getDiffs('unstaged')

    const stagedDiffsByName = {}
    for (const diff of stagedDiffs) {
      // TODO: Old path is probably not always right.
      stagedDiffsByName[diff.oldFile().path()] = diff
    }

    const unstagedDiffsByName = {}
    for (const diff of unstagedDiffs) {
      // TODO: Old path is probably not always right.
      unstagedDiffsByName[diff.oldFile().path()] = diff
    }

    for (let diff of unifiedDiffs) {
      let fileDiff = this.getOrCreateFileFromPathName(diff.newFile().path())
      const stagedDiff = stagedDiffsByName[diff.newFile().path()]
      const unstagedDiff = unstagedDiffsByName[diff.newFile().path()]
      await fileDiff.fromGitUtilsObject({diff, stagedDiff, unstagedDiff})
      files.push(fileDiff)
    }

    this.transactor.transact(() => {
      this.setFiles(files)
    })
    this.isSyncing = false
  }
}
<commit_msg>Extract these into their own methods.<commit_after>/** @babel */

import {CompositeDisposable, Emitter} from 'atom'
import FileDiff from './file-diff'
import GitService from './git-service'
import EventTransactor from './event-transactor'

// FileList contains a collection of FileDiff objects
export default class FileList {
  constructor (files, {stageOnChange} = {}) {
    // TODO: Rather than this `stageOnChange` bool, there should probably be a
    // new object that just handles the connection to nodegit. Cause there are
    // several of these objects in the system, but only one of them handles
    // writing to the index.
    this.gitService = GitService.instance()
    this.emitter = new Emitter()
    this.transactor = new EventTransactor(this.emitter, {fileList: this})
    this.fileCache = {}
    this.setFiles(files || [])
    if (stageOnChange) {
      this.onDidChange(this.handleDidChange.bind(this))
    }
  }

  onDidChange (callback) {
    return this.emitter.on('did-change', callback)
  }

  didChange (event) {
    this.transactor.didChange(event)
  }

  onDidUserChange (callback) {
    return this.emitter.on('did-user-change', callback)
  }

  didUserChange () {
    this.emitter.emit('did-user-change')
  }

  async handleDidChange (event) {
    if (!(event && event.events && event.fileList === this)) return
    if (this.isSyncingState()) return

    console.log('staging?', event)

    const stagableLinesPerHunk = this.extractLinesFromEventByHunk(event)
    await this.stageLines(stagableLinesPerHunk)
    this.didUserChange()
  }

  async stageLines (stagableLinesPerHunk) {
    let patchInfoByFile = {}
    for (let hunkString in stagableLinesPerHunk) {
      const {linesToStage, linesToUnstage} = stagableLinesPerHunk[hunkString]
      console.log('lines to stage:', linesToStage.length, '; unstage:', linesToUnstage.length)
      const hunk = linesToStage.length > 0 ? linesToStage[0].hunk : linesToUnstage[0].hunk
      const file = hunk.diff
      let info = patchInfoByFile[file]
      if (!info) {
        info = {promises: [], file, stage: linesToStage.length > 0}
        patchInfoByFile[file] = info
      }

      let promise = null
      if (linesToStage.length) {
        promise = this.gitService.calculatePatchText(hunk, linesToStage, true)
      } else if (linesToUnstage.length) {
        promise = this.gitService.calculatePatchText(hunk, linesToUnstage, false)
      }

      info.promises.push(promise)
    }

    // TODO: All this shit should be parallel.
    for (let file in patchInfoByFile) {
      const info = patchInfoByFile[file]
      const patches = await Promise.all(info.promises)
      await this.stagePatches(info.file, patches, info.stage)
    }
  }

  extractLinesFromEventByHunk (event) {
    let stagableLinesPerHunk = {}

    for (let fileEvent of event.events) {
      if (!fileEvent) continue

      for (let hunkEvent of fileEvent.events) {
        if (!hunkEvent) continue

        const hunk = hunkEvent.hunk
        if (!stagableLinesPerHunk[hunk]) {
          stagableLinesPerHunk[hunk] = {
            linesToStage: [],
            linesToUnstage: []
          }
        }
        const stagableLines = stagableLinesPerHunk[hunk]
        for (let lineEvent of hunkEvent.events) {
          if (lineEvent.line && lineEvent.property === 'isStaged') {
            if (lineEvent.line.isStaged()) {
              stagableLines.linesToStage.push(lineEvent.line)
            } else {
              stagableLines.linesToUnstage.push(lineEvent.line)
            }
          }
        }
      }
    }

    return stagableLinesPerHunk
  }

  openFileDiffAtIndex (index) {
    return this.files[index].openDiff()
  }

  setFiles (files) {
    if (this.fileSubscriptions) {
      this.fileSubscriptions.dispose()
    }
    this.fileSubscriptions = new CompositeDisposable()
    this.files = files
    for (const file of files) {
      this.fileSubscriptions.add(file.onDidChange(this.didChange.bind(this)))
      this.addFileToCache(file)
    }
    this.didChange()
  }

  getFiles () {
    return this.files
  }

  // position = [0, 2] will get you the third hunk in the first file.
  // position = [0, 2, 1] will get you the 2nd line in the third hunk in the first file.
  getObjectAtPosition (position) {
    const [fileIndex, hunkIndex, lineIndex] = position

    const file = this.getFiles()[fileIndex]
    const hunk = file.getHunks()[hunkIndex]
    if (lineIndex != null) {
      return hunk.getLines()[lineIndex]
    } else {
      return hunk
    }
  }

  // The file cache should allow all UI elements usage of the same FileDiff
  // models. Sometimes it's a bit of a chicken and egg problem, and it happens
  // when a tab is deserialized.
  //
  // * Let's say there is a Diff tab being deserialized for `config.js`.
  // * The deserializer runs before nodegit knows the state of things, but the
  // tab needs a model. The tab will use `getOrCreateFileFromPathName` to get
  // the model.
  // * Then and the FileDiff::loadFromGitUtils is called and there are changes
  // in `config.js`
  // * `loadFromGitUtils` will use
  // `getOrCreateFileFromPathName('config.js')`, which will grab the same model
  // that the Diff tab is using.
  // * The model will be updated from the nodegit state and the Diff tab will
  // update properly.
  addFileToCache (file) {
    if (file.getOldPathName() !== file.getNewPathName() && this.fileCache[file.getOldPathName()]) {
      delete this.fileCache[file.getOldPathName()]
    }
    this.fileCache[file.getNewPathName()] = file
  }

  getFileFromPathName (pathName) {
    return this.fileCache[pathName]
  }

  getOrCreateFileFromPathName (pathName) {
    let file = this.getFileFromPathName(pathName)
    if (!file) {
      file = new FileDiff({newPathName: pathName, oldPathName: pathName})
      this.addFileToCache(file)
    }
    return file
  }

  isSyncingState () {
    if (this.isSyncing) {
      return true
    }

    for (let file of this.files) {
      if (file.isSyncingState()) {
        return true
      }
    }

    return false
  }

  toString () {
    return this.files.map((file) => { return file.toString() }).join('\n')
  }

  async stagePatches (fileDiff, patches, stage) {
    const patchText = patches.join('\n')
    if (stage) {
      return this.gitService.stagePatch(fileDiff, patchText)
    } else {
      return this.gitService.unstagePatch(fileDiff, patchText)
    }
  }

  async loadFromGitUtils () {
    let files = []
    this.isSyncing = true

    // FIXME: for now, we need to get the stati for the diff stuff to work. :/
    this.gitService.getStatuses()
    let unifiedDiffs = await this.gitService.getDiffs('all')
    // TODO: It's a bummer these lines happen sequentially
    const stagedDiffs = await this.gitService.getDiffs('staged')
    const unstagedDiffs = await this.gitService.getDiffs('unstaged')

    const stagedDiffsByName = {}
    for (const diff of stagedDiffs) {
      // TODO: Old path is probably not always right.
      stagedDiffsByName[diff.oldFile().path()] = diff
    }

    const unstagedDiffsByName = {}
    for (const diff of unstagedDiffs) {
      // TODO: Old path is probably not always right.
      unstagedDiffsByName[diff.oldFile().path()] = diff
    }

    for (let diff of unifiedDiffs) {
      let fileDiff = this.getOrCreateFileFromPathName(diff.newFile().path())
      const stagedDiff = stagedDiffsByName[diff.newFile().path()]
      const unstagedDiff = unstagedDiffsByName[diff.newFile().path()]
      await fileDiff.fromGitUtilsObject({diff, stagedDiff, unstagedDiff})
      files.push(fileDiff)
    }

    this.transactor.transact(() => {
      this.setFiles(files)
    })
    this.isSyncing = false
  }
}
<|endoftext|>


<commit_before>function format(fmt) {
  var args = Array.slice(arguments, 1);
  return fmt.replace(/%(([a-zA-Z]\w*)|(\d+)|\{([a-zA-Z]\w*)\}|\{(\d+)\})\b/g, function(all, key, name, index, name2, index2) {
    name = name || name2;
    index = index || index2;
    if (index !== undefined)
      return args[parseInt(index, 10)];
    for (var i = 0; i < args.length; i++)
      if (args[i].hasOwnProperty(name))
        return args[i][name];
    return '';
  });
}

function Formatter(options) {
  console.log(options);
  for (var key in options)
    if (key in this && options[key] !== undefined)
      this[key] = options[key];
}
$declare(Formatter, {

  header: undefined,
  footer: undefined,

  defaultGateway: true,

  groupGateway: false,
  groupHeader: undefined,
  groupFooter: undefined,

  gateway: {},
  groupName: {},

  filterRule: function(rule) {
    return this.defaultGateway || rule.prefix !== '0.0.0.0' || rule.length > 0;
  },

  groupRules: function(rules) {
    var groups = {};
    for (var i = 0; i < rules.length; i++) {
      var rule = rules[i];
      if (!groups[rule.gateway])
        groups[rule.gateway] = [];
      groups[rule.gateway].push(rule);
    }
    return groups;
  },

  formatRule: function(rule) {
    return format(this.ruleFormat, {
      prefix: rule.prefix,
      mask: rule.mask,
      length: rule.length,
      gw: this.gateway[rule.gateway] || rule.gateway
    });
  },

  format: function(rules) {
    var output = [];

    rules = rules.filter(this.filterRule.bind(this));

    if (this.header)
      output.push(this.header);

    if (this.groupGateway) {
      var groups = this.groupRules(rules);
      for (var gateway in groups) {
        if (this.groupHeader)
          output.push(format(this.groupHeader, {
            name: this.groupName[gateway] || gateway
          }));
        rules = groups[gateway];
        for (var i = 0; i < rules.length; i++)
          output.push(this.formatRule(rules[i]));
        if (this.groupFooter)
          output.push(format(this.groupFooter, {
            name: this.groupName[gateway] || gateway
          }));
      }
    } else {
      for (var i = 0; i < rules.length; i++)
        output.push(this.formatRule(rules[i]));
    }

    if (this.footer)
      output.push(this.footer);

    return output.join('');
  }
});

module.exports = Formatter;

<commit_msg>Fix custom formatter<commit_after>function format(fmt) {
  var args = Array.slice(arguments, 1);
  return fmt.replace(/%(([a-zA-Z]\w*)|(\d+)|\{([a-zA-Z]\w*)\}|\{(\d+)\})\b/g, function(all, key, name, index, name2, index2) {
    name = name || name2;
    index = index || index2;
    if (index !== undefined)
      return args[parseInt(index, 10)];
    for (var i = 0; i < args.length; i++)
      if (args[i].hasOwnProperty(name))
        return args[i][name];
    return '';
  });
}

function Formatter(options) {
  for (var key in options)
    if (key in this && options[key] !== undefined)
      this[key] = options[key];
}
$declare(Formatter, {

  header: undefined,
  footer: undefined,
  ruleFormat: null,
  defaultGateway: true,
  groupGateway: false,
  groupHeader: undefined,
  groupFooter: undefined,
  gateway: {},
  groupName: {},

  filterRule: function(rule) {
    return this.defaultGateway || rule.prefix !== '0.0.0.0' || rule.length > 0;
  },

  groupRules: function(rules) {
    var groups = {};
    for (var i = 0; i < rules.length; i++) {
      var rule = rules[i];
      if (!groups[rule.gateway])
        groups[rule.gateway] = [];
      groups[rule.gateway].push(rule);
    }
    return groups;
  },

  formatRule: function(rule) {
    return format(this.ruleFormat, {
      prefix: rule.prefix,
      mask: rule.mask,
      length: rule.length,
      gw: this.gateway[rule.gateway] || rule.gateway
    });
  },

  format: function(rules) {
    var output = [];

    rules = rules.filter(this.filterRule.bind(this));

    if (this.header)
      output.push(this.header);

    if (this.groupGateway) {
      var groups = this.groupRules(rules);
      for (var gateway in groups) {
        if (this.groupHeader)
          output.push(format(this.groupHeader, {
            name: this.groupName[gateway] || gateway
          }));
        rules = groups[gateway];
        for (var i = 0; i < rules.length; i++)
          output.push(this.formatRule(rules[i]));
        if (this.groupFooter)
          output.push(format(this.groupFooter, {
            name: this.groupName[gateway] || gateway
          }));
      }
    } else {
      for (var i = 0; i < rules.length; i++)
        output.push(this.formatRule(rules[i]));
    }

    if (this.footer)
      output.push(this.footer);

    return output.join('');
  }
});

module.exports = Formatter;

<|endoftext|>


<commit_before>//utils Test
var utils = require('../controllerUtils.js')
var assert = require('assert');

//email tests
//invalid email returns false
var badEmail = "ojh12345@gmail"
var goodEmail = "ojh12345@yahoo.com"
//if(utils.verifyEmail(badEmail)==false){
//    console.log('Test Passed')
//}
//else{
//    console.log('Test failed')
//}
assert.equal(utils.validEmail(badEmail), false, ['invalid email'])
assert.equal(utils.validEmail(goodEmail), true, ['valid email'])

//password test
//invalid password return false, needs to be 8-16 characters
var badPass = "1234"
var goodPass = "1234567890"
assert.equal(utils.validPassword(badPass), false, ['invalid password'])
assert.equal(utils.validPassword(goodPass), true, ['valid password'])

//token test
//invalid token returns false, needs to be 36 characters
var badToken = "1245720983"
var goodToken = "123456789012345678901234567890123456"
assert.equal(utils.validToken(badToken), false, ['invalid token'])
assert.equal(utils.validToken(goodToken), true, ["valid token"])
<commit_msg>Update utilsTest.js<commit_after>//utils Test
var utils = require('../controllerUtils.js');
var assert = require('assert');

//email tests
//invalid email returns false
var badEmail = "ojh12345@gmail";
var goodEmail = "ojh12345@yahoo.com";
//if(utils.verifyEmail(badEmail)==false){
//    console.log('Test Passed')
//}
//else{
//    console.log('Test failed')
//}
assert.equal(utils.validEmail(badEmail), false, ['invalid email']);
assert.equal(utils.validEmail(goodEmail), true, ['valid email']);

//password test
//invalid password return false, needs to be 8-16 characters
var badPass = "1234";
var goodPass = "1234567890";
assert.equal(utils.validPassword(badPass), false, ['invalid password']);
assert.equal(utils.validPassword(goodPass), true, ['valid password']);

//token test
//invalid token returns false, needs to be 36 characters
var badToken = "1245720983";
var goodToken = "123456789012345678901234567890123456";
assert.equal(utils.validToken(badToken), false, ['invalid token']);
assert.equal(utils.validToken(goodToken), true, ["valid token"]);
<|endoftext|>


<commit_before>
/**
  CoreJS

  Configures the framework, and is in charge of assembling all the applications together.
  Provides the master server that handles and routes all of the virtual host requests.

  Available globally as framework.
 */

var _ = require('underscore'),
    events = require('events'),
    net = require('net'),
    child_process = require('child_process'),
    cluster = require('cluster'),
    os = require('os'),
    http = require('http'),
    util = require('util'),
    pathModule = require('path'),
    EventEmitter = events.EventEmitter;

// Allow console to print & inspect data, then exit
console.exit = function(msg) {
  if (typeof msg == 'string') console.log(msg);
  else console.dir(msg);
  process.exit();
}

function CoreJS(noserver) {

  var self = this;

  // Initialize `framework` global
  global.framework = this;

  // Inherit from constructor
  _.extend(this, this.constructor);

  // Cluster configuration
  this.clusterConfig = {
    listenPort: null,
    multiProcess: 0,
    masterProcess: 'node [master]',
    singleProcess: 'node [single process]',
    workerProcess: 'node worker'
  };

  this.extend = _.extend;

  this.Multi = require('multi');

  // Internals
  this.drivers = {};
  this.engines = {};
  this.storages = {};
  this.lib = {};

  // Regular expressions
  this.regex = require('./regex');

  // Instance properties
  this.apps = {};
  this.vhosts = {};
  this.path = pathModule.resolve(__dirname, '../');
  this.className = this.constructor.name;
  this.environment = this.config.environment || 'GENERIC';

  // Server options, provided by environment
  this.serverOptions = null;

  // Preload Utility
  var Utility = require('./utility'),
      skipFromLibDir = ['request.js', 'response.js', 'framework.js', 'addons', 'drivers', 'engines', 'storages'];

  this.util = new Utility();

  // Lib
  this.util.getFiles(this.path + '/lib', function(file) {
    var key = file.replace(self.regex.jsFile, '');
    if (skipFromLibDir.indexOf(file) >= 0) return;
    self.lib[key] = require(self.path + '/lib/' + file);
  });

  // Storage
  this.util.getFiles(this.path + '/lib/storages/' , function(file) {
    var key = file.replace(self.regex.jsFile, '');
    self.storages[key] = require(self.path + '/lib/storages/' + file);
  });

  // Database drivers
  this.util.getFiles(this.path + '/lib/drivers', function(file) {
    var key = file.replace(self.regex.jsFile, '');
    self.drivers[key] = require(self.path + '/lib/drivers/' + file);
  });

  // Template engine prototype
  this.engineProto = new this.lib.engine();

  // Template Engines
  this.util.getFiles(this.path + '/lib/engines', function(file) {
    var key = file.replace(self.regex.jsFile, '');
    self.engines[key] = require(self.path + '/lib/engines/' + file);
  });

  // Enhance request/response
  require('./response');
  require('./request');

  // Initialization event, used by environments
  this.emit('init');

  // Allow using framework standalone
  if (noserver) return;

  // Start the debugger if on DEBUG environment
  if (this.config.environment == 'debug') this.checkInspectorStatus();

  // Launch application server
  this.launchApplication();

  // Only set important properties enumerable
  this.util.onlySetEnumerable(this, ['version', 'className', 'environment', 'path', 'config', 'vhosts', 'apps',
    'drivers', 'engines', 'storages']);

  // console.exit(this);
}

// CoreJS version
CoreJS.version = '0.0.0'

// Stores the configuration settings for the framework
CoreJS.config = {
  autoCurl: true
};

// Save the Framework's MasterPath, for future reference
CoreJS.path = pathModule.resolve(__dirname, '../');

// Inherit from events.EventEmitter
_.extend(CoreJS, new EventEmitter());

/**
  Developers Note: the static properties of the CoreJS constructor are passed
  to the framework instance on construction. This means, the methods and properties
  available in the CoreJS constructor will also be available in the instance.
 */

/**
  Bootstraps an application

  @param {string} dir
  @param {object} config
  @static
 */

CoreJS.bootstrap = function(dir, config) {

  if (typeof config == 'undefined') {
    throw new Error('Configuration parameter missing');
  }

  var appEnv, envFunc, vhosts = {};

  // Run application as standalone (from command line)
  appEnv = process.env.NODE_ENV || config.environment || 'development';

  // Start node debugger, if on `debug` environment
  if (appEnv == 'debug') {
    console.log('');
    require('child_process').spawn('kill', ['-s', 'SIGUSR1', process.pid]);
    CoreJS.configure('inspector_port', config.inspector_port || 3000);
  }

  // Configure vhosts
  CoreJS.configure('environment', appEnv);
  CoreJS.configure('hostname', config.host || 'localhost');
  CoreJS.configure('appPath', dir);

  // Configure server
  CoreJS.configure('server', {
    listenPort: config.port || 8080,
    multiProcess: config.multiProcess || false,
    stayUp: config.stayUp || false,
  });

  // Run environment script on `app_init` event
  CoreJS.on('app_init', function(app) {
    var envFunc = app.require('config/env/' + appEnv);
    envFunc(app);
  });

  // Framework singleton
  return new CoreJS();

}

/**
  Configures the framework.

  @param {string} context
  @param {string|object} value
  @returns {self} for chaining
  @static
 */

CoreJS.configure = function(context, value) {
  this.config[context] = value;
  return this;
}

/**
  Requires a module relative to the framework's path

  @param {string} module
  @param {boolean} reload
  @returns {object}
  @public
 */

CoreJS.prototype.require = function(module, reload) {
  var Module, oldCache, outModule,
      modulePath = '../' + module;

  if (reload) {
    // Get node's Module
    Module = require('module').Module;

    // Backup original cache
    oldCache = Module._cache;

    // Temporarily empty cache
    Module._cache = {};

    // Get the reloaded module
    try { outModule = require(modulePath); }
    catch(e) { outModule = require(module); }

    // Restore the module cache
    Module._cache = oldCache;

    return outModule;
  } else {
    try { return require(modulePath); }
    catch(e) { return require(module); }
  }
}

/**
  Notifies the application that an asynchronous event has been triggered
 */

CoreJS.prototype.async = function(app) {
  app.asyncQueue.push(1);
}

/**
  Notifies the application that an asynchronous event has finalized

 */

CoreJS.prototype.done = function(app) {
  app.asyncQueue.pop();
  if (app.asyncQueue.length === 0) {
    // Application is initialized on the next tick of event loop,
    // To prevent access errors on objects
    process.nextTick(function() {
      app.initialize();
    });
  }
}

/**
  Shortcut for util.inherits

  @param {function} base
  @param {function} parent
  @public
 */

CoreJS.prototype.inherits = function(base, parent) {
  util.inherits(base, this.lib[parent]);
}

/**
  Initializes applications, and configures virtual hosts

  @param {object} servers
  @private
 */

CoreJS.prototype.launchApplication = function(servers) {
  var Application, app, appInit, data, host, initFunction, path, controllerProto;
  var enumerable = ['className', 'domain', 'path', 'debugMode', 'viewCaching',
      'storage', 'lib','models', 'helpers', 'controllers', 'engines', 'session'];

  host = this.config.hostname;
  path = pathModule.resolve(this.path, this.config.appPath);

  // Enable inheritance within Application
  Application = require(path + '/app');

  // Initialize app routes
  this.lib.controller.prototype.queuedRoutes[host] = [];

  // Provide new app prototype
  app = new this.lib.application(host, path);
  app._super = app;

  // Construct new app
  _.extend(app, new Application(host, path));

  // Set app pseudo-singleton
  this.app = app;

  // Only set important properties enumerable
  this.util.onlySetEnumerable(app, enumerable);

  // Start the server
  this.startServer();
}

/**
  Starts the application server

  @private
 */

CoreJS.prototype.startServer = function() {

  /*jshint loopfunc:true */

  var app = this.app,
      interProcess = this,
      options = this.config.server,
      allCPUS = os.cpus();

  // Merge config with this.clusterConfig
  options = this.serverOptions = _.extend(this.clusterConfig, options);

  if (typeof options.multiProcess == 'number') {
    allCPUS = (options.multiProcess || 1);
    options.multiProcess = true;
    options.allCPUS = allCPUS;
  } else allCPUS = os.cpus().length;

  // Convenience function, to avoid repetition
  function commonStartupOperations() {
    if (options.stayUp) {
      process.on('uncaughtException', app.log); // prints stack trace
    }
    startupMessage.call(this, options);
    app.emit('init');
  }

  if (options.multiProcess && cluster.isMaster) {

    // Master

    process.title = options.masterProcess;

    for (var worker, i=0; i < allCPUS; i++) {
      worker = cluster.fork();
      worker.on('message', function(data) {
        if (data.cmd != null) interProcess.emit('worker_message', data);
        if (data.response != null) worker.send({response: data.response});
      });
    }

    cluster.on('death', function(worker) {
      app.log('Worker process ' + worker.pid + ' died. Restarting...');
      cluster.fork();
    });

    commonStartupOperations.call(this);
    app.log('Master running...');

  } else {

    // Worker
    app.server = http.createServer(function(req, res) {
      app.routeRequest(req, res); // Needs to run in the app's context
    });
    app.server.listen(options.listenPort);

    if (options.multiProcess) {
      process.title = options.workerProcess;
      app.log('Worker running...');
    } else {
      process.title = options.singleProcess;
      commonStartupOperations.call(this);
      autoCurlRequest();
    }

  }
}

/**
  Checks the status of the node inspector

  @private
 */

CoreJS.prototype.checkInspectorStatus = function() {
  var port = this.config.inspector_port || 3000;

  this.util.checkPort(port, function(err) {
    if (err) {
      console.log('Node Inspector is not running.\n\nStart it with `./tools/run-inspector`\n');
      process.exit();
    } else {
      console.log('Node Inspector running on http://0.0.0.0:' + port);
    }
  });

}

/**
  Prints the startup message

  @param {object} options
  @private
 */

function startupMessage(options) {
  var app = this.app;
  if (process.argv.length >= 3 && !options.multiProcess) return; // Disable startup message on curl requests
  app.log(util.format('Server running on %s', app.baseUrl));
  if (options.multiProcess) app.log(util.format('Running a cluster of %d workers', options.allCPUS));
}

/**
  Handles automatic curl requests on environments, by passing its command line options for a new request.

  If a relative path is used, the default application's (the first you have defined on the environment) url
  will be used, and the path attached to it.

  An URL can also be used.

  @private
 */

function autoCurlRequest() {
  if (process.argv.length >= 3 && framework.config.autoCurl) {
    var app = framework.app,
        config = framework.config,
        args = process.argv.slice(2),
        url = args[args.length - 1],
        exec = require('child_process').exec,
        portStr = config.server.listenPort !== 80 ? ":" + config.server.listenPort : '';

    if (framework.regex.startsWithSlash.test(url)) {
      url = "http://" + app.domain + portStr + url;
    }

    var switches = args.slice(0, (args.length - 1)).join(' ');

    exec('curl ' + switches + ' ' + url, function(err, stdout, stderr) {
      console.log(err ? stderr : stdout);
      process.exit();
    });
  }
}

module.exports = CoreJS;
<commit_msg>Application's now only listens in its own domain.<commit_after>
/**
  CoreJS

  Configures the framework, and is in charge of assembling all the applications together.
  Provides the master server that handles and routes all of the virtual host requests.

  Available globally as framework.
 */

var _ = require('underscore'),
    events = require('events'),
    net = require('net'),
    child_process = require('child_process'),
    cluster = require('cluster'),
    os = require('os'),
    http = require('http'),
    util = require('util'),
    pathModule = require('path'),
    EventEmitter = events.EventEmitter;

// Allow console to print & inspect data, then exit
console.exit = function(msg) {
  if (typeof msg == 'string') console.log(msg);
  else console.dir(msg);
  process.exit();
}

function CoreJS(noserver) {

  var self = this;

  // Initialize `framework` global
  global.framework = this;

  // Inherit from constructor
  _.extend(this, this.constructor);

  // Cluster configuration
  this.clusterConfig = {
    listenPort: null,
    multiProcess: 0,
    masterProcess: 'node [master]',
    singleProcess: 'node [single process]',
    workerProcess: 'node worker'
  };

  this.extend = _.extend;

  this.Multi = require('multi');

  // Internals
  this.drivers = {};
  this.engines = {};
  this.storages = {};
  this.lib = {};

  // Regular expressions
  this.regex = require('./regex');

  // Instance properties
  this.apps = {};
  this.vhosts = {};
  this.path = pathModule.resolve(__dirname, '../');
  this.className = this.constructor.name;
  this.environment = this.config.environment || 'GENERIC';

  // Server options, provided by environment
  this.serverOptions = null;

  // Preload Utility
  var Utility = require('./utility'),
      skipFromLibDir = ['request.js', 'response.js', 'framework.js', 'addons', 'drivers', 'engines', 'storages'];

  this.util = new Utility();

  // Lib
  this.util.getFiles(this.path + '/lib', function(file) {
    var key = file.replace(self.regex.jsFile, '');
    if (skipFromLibDir.indexOf(file) >= 0) return;
    self.lib[key] = require(self.path + '/lib/' + file);
  });

  // Storage
  this.util.getFiles(this.path + '/lib/storages/' , function(file) {
    var key = file.replace(self.regex.jsFile, '');
    self.storages[key] = require(self.path + '/lib/storages/' + file);
  });

  // Database drivers
  this.util.getFiles(this.path + '/lib/drivers', function(file) {
    var key = file.replace(self.regex.jsFile, '');
    self.drivers[key] = require(self.path + '/lib/drivers/' + file);
  });

  // Template engine prototype
  this.engineProto = new this.lib.engine();

  // Template Engines
  this.util.getFiles(this.path + '/lib/engines', function(file) {
    var key = file.replace(self.regex.jsFile, '');
    self.engines[key] = require(self.path + '/lib/engines/' + file);
  });

  // Enhance request/response
  require('./response');
  require('./request');

  // Initialization event, used by environments
  this.emit('init');

  // Allow using framework standalone
  if (noserver) return;

  // Start the debugger if on DEBUG environment
  if (this.config.environment == 'debug') this.checkInspectorStatus();

  // Launch application server
  this.launchApplication();

  // Only set important properties enumerable
  this.util.onlySetEnumerable(this, ['version', 'className', 'environment', 'path', 'config', 'vhosts', 'apps',
    'drivers', 'engines', 'storages']);

  // console.exit(this);
}

// CoreJS version
CoreJS.version = '0.0.0'

// Stores the configuration settings for the framework
CoreJS.config = {
  autoCurl: true
};

// Save the Framework's MasterPath, for future reference
CoreJS.path = pathModule.resolve(__dirname, '../');

// Inherit from events.EventEmitter
_.extend(CoreJS, new EventEmitter());

/**
  Developers Note: the static properties of the CoreJS constructor are passed
  to the framework instance on construction. This means, the methods and properties
  available in the CoreJS constructor will also be available in the instance.
 */

/**
  Bootstraps an application

  @param {string} dir
  @param {object} config
  @static
 */

CoreJS.bootstrap = function(dir, config) {

  if (typeof config == 'undefined') {
    throw new Error('Configuration parameter missing');
  }

  var appEnv, envFunc, vhosts = {};

  // Run application as standalone (from command line)
  appEnv = process.env.NODE_ENV || config.environment || 'development';

  // Start node debugger, if on `debug` environment
  if (appEnv == 'debug') {
    console.log('');
    require('child_process').spawn('kill', ['-s', 'SIGUSR1', process.pid]);
    CoreJS.configure('inspector_port', config.inspector_port || 3000);
  }

  // Configure vhosts
  CoreJS.configure('environment', appEnv);
  CoreJS.configure('hostname', config.host || 'localhost');
  CoreJS.configure('appPath', dir);

  // Configure server
  CoreJS.configure('server', {
    listenPort: config.port || 8080,
    multiProcess: config.multiProcess || false,
    stayUp: config.stayUp || false,
  });

  // Run environment script on `app_init` event
  CoreJS.on('app_init', function(app) {
    var envFunc = app.require('config/env/' + appEnv);
    envFunc(app);
  });

  // Framework singleton
  return new CoreJS();

}

/**
  Configures the framework.

  @param {string} context
  @param {string|object} value
  @returns {self} for chaining
  @static
 */

CoreJS.configure = function(context, value) {
  this.config[context] = value;
  return this;
}

/**
  Requires a module relative to the framework's path

  @param {string} module
  @param {boolean} reload
  @returns {object}
  @public
 */

CoreJS.prototype.require = function(module, reload) {
  var Module, oldCache, outModule,
      modulePath = '../' + module;

  if (reload) {
    // Get node's Module
    Module = require('module').Module;

    // Backup original cache
    oldCache = Module._cache;

    // Temporarily empty cache
    Module._cache = {};

    // Get the reloaded module
    try { outModule = require(modulePath); }
    catch(e) { outModule = require(module); }

    // Restore the module cache
    Module._cache = oldCache;

    return outModule;
  } else {
    try { return require(modulePath); }
    catch(e) { return require(module); }
  }
}

/**
  Notifies the application that an asynchronous event has been triggered
 */

CoreJS.prototype.async = function(app) {
  app.asyncQueue.push(1);
}

/**
  Notifies the application that an asynchronous event has finalized

 */

CoreJS.prototype.done = function(app) {
  app.asyncQueue.pop();
  if (app.asyncQueue.length === 0) {
    // Application is initialized on the next tick of event loop,
    // To prevent access errors on objects
    process.nextTick(function() {
      app.initialize();
    });
  }
}

/**
  Shortcut for util.inherits

  @param {function} base
  @param {function} parent
  @public
 */

CoreJS.prototype.inherits = function(base, parent) {
  util.inherits(base, this.lib[parent]);
}

/**
  Initializes applications, and configures virtual hosts

  @param {object} servers
  @private
 */

CoreJS.prototype.launchApplication = function(servers) {
  var Application, app, appInit, data, host, initFunction, path, controllerProto;
  var enumerable = ['className', 'domain', 'path', 'debugMode', 'viewCaching',
      'storage', 'lib','models', 'helpers', 'controllers', 'engines', 'session'];

  host = this.config.hostname;
  path = pathModule.resolve(this.path, this.config.appPath);

  // Enable inheritance within Application
  Application = require(path + '/app');

  // Initialize app routes
  this.lib.controller.prototype.queuedRoutes[host] = [];

  // Provide new app prototype
  app = new this.lib.application(host, path);
  app._super = app;

  // Construct new app
  _.extend(app, new Application(host, path));

  // Set app pseudo-singleton
  this.app = app;

  // Only set important properties enumerable
  this.util.onlySetEnumerable(app, enumerable);

  // Start the server
  this.startServer();
}

/**
  Starts the application server

  @private
 */

CoreJS.prototype.startServer = function() {

  /*jshint loopfunc:true */

  var app = this.app,
      interProcess = this,
      options = this.config.server,
      allCPUS = os.cpus();

  // Merge config with this.clusterConfig
  options = this.serverOptions = _.extend(this.clusterConfig, options);

  if (typeof options.multiProcess == 'number') {
    allCPUS = (options.multiProcess || 1);
    options.multiProcess = true;
    options.allCPUS = allCPUS;
  } else allCPUS = os.cpus().length;

  // Convenience function, to avoid repetition
  function commonStartupOperations() {
    if (options.stayUp) {
      process.on('uncaughtException', app.log); // prints stack trace
    }
    startupMessage.call(this, options);
    app.emit('init');
  }

  if (options.multiProcess && cluster.isMaster) {

    // Master

    process.title = options.masterProcess;

    for (var worker, i=0; i < allCPUS; i++) {
      worker = cluster.fork();
      worker.on('message', function(data) {
        if (data.cmd != null) interProcess.emit('worker_message', data);
        if (data.response != null) worker.send({response: data.response});
      });
    }

    cluster.on('death', function(worker) {
      app.log('Worker process ' + worker.pid + ' died. Restarting...');
      cluster.fork();
    });

    commonStartupOperations.call(this);
    app.log('Master running...');

  } else {

    // Worker

    app.server = http.createServer(function(req, res) {
      app.routeRequest(req, res); // Needs to run in the app's context
    });

    app.server.listen(options.listenPort, app.domain);

    if (options.multiProcess) {
      process.title = options.workerProcess;
      app.log('Worker running...');
    } else {
      process.title = options.singleProcess;
      commonStartupOperations.call(this);
      autoCurlRequest();
    }

  }
}

/**
  Checks the status of the node inspector

  @private
 */

CoreJS.prototype.checkInspectorStatus = function() {
  var port = this.config.inspector_port || 3000;

  this.util.checkPort(port, function(err) {
    if (err) {
      console.log('Node Inspector is not running.\n\nStart it with `./tools/run-inspector`\n');
      process.exit();
    } else {
      console.log('Node Inspector running on http://0.0.0.0:' + port);
    }
  });

}

/**
  Prints the startup message

  @param {object} options
  @private
 */

function startupMessage(options) {
  var app = this.app;
  if (process.argv.length >= 3 && !options.multiProcess) return; // Disable startup message on curl requests
  app.log(util.format('Server running on %s', app.baseUrl));
  if (options.multiProcess) app.log(util.format('Running a cluster of %d workers', options.allCPUS));
}

/**
  Handles automatic curl requests on environments, by passing its command line options for a new request.

  If a relative path is used, the default application's (the first you have defined on the environment) url
  will be used, and the path attached to it.

  An URL can also be used.

  @private
 */

function autoCurlRequest() {
  if (process.argv.length >= 3 && framework.config.autoCurl) {
    var app = framework.app,
        config = framework.config,
        args = process.argv.slice(2),
        url = args[args.length - 1],
        exec = require('child_process').exec,
        portStr = config.server.listenPort !== 80 ? ":" + config.server.listenPort : '';

    if (framework.regex.startsWithSlash.test(url)) {
      url = "http://" + app.domain + portStr + url;
    }

    var switches = args.slice(0, (args.length - 1)).join(' ');

    exec('curl ' + switches + ' ' + url, function(err, stdout, stderr) {
      console.log(err ? stderr : stdout);
      process.exit();
    });
  }
}

module.exports = CoreJS;
<|endoftext|>