<commit_before>'use strict';

const nodeColor = {
  RED : 0,
  BLACK : 1
}

/**
 * Node of the red black tree
 * constructor
 * param key : Number
 * param value : Object
 * param left : Node
 * param right : Node
 * param color : Number
 */
class Node {
  constructor(key, value, left, right, color, parent) {
    this.key = key;
    this.value = value;
    this.left = left;
    this.right = right;
    this.color = color;
    this.parent = parent;
  }

  /**
  * return Boolean
  */
  isRedNode() {
    return this.color === nodeColor.RED
  }

  /**
  * return Boolean
  */
  isBlackNode() {
    return this.color === nodeColor.BLACK
  }

  /**
  * get GrandParent of a given node
  */
  getGrandParent(node) {
    if ((node != null) && (node.parent != null)) {
      return node.parent.parent;
    } else {
      return null;
    }
  }

  /**
  * get uncle of a given node
  */
  getUncle(node) {
    let grandParent = getGrandParent(node);
    if (grandParent == null) {
      return null;
    }
    if (node.parent == node.left) {
      return grandParent.right;
    } else {
      return grandParent.left;
    }
  }
}

/**
 * constructor
 * Node of the red black tree
 * 1.Every node is either red or black
 * 2.Root and leaves are all black
 * 3.Every red node has black parent
 * 4.All simple paths from a node x to a descendant leaves of x has same black nodes
 */
class RbTree {
  constructor() {
    this.root = null;
  }

/**
  * Complexity: O(1).
  *
  * param Node node Node.
  * return Node a copy of original node
  */
  clone(node) {
    return new Node(node.key, node.value, node.left, node.right, node.color);
  }

/**
  * Complexity: O(1).
  *       y                   x
  *      / \                 / \
  *     x  Gamma   ====>   alpha y
  *   /  \                      / \
  * alpha beta               beta Gamma
  * method
  * param Node node Node.
  * return Node
  */
  rotateRight(node) {
    let y = node.right;
    node.left = y.right;
    if (y.right != null) {
      y.right.parent = node;
    }
    y.parent = node.parent;
    if (node.parent == null) {
      this.root = y;
    } elseif (node == node.parent.right) {
      node.parent.right = y
    } else {
      node.parent.left = y
    }
    y.right = node;
    node.parent = y;
  }

/**
  * Complexity: O(1).
  *       y                   x
  *      / \                 / \
  *     x  Gamma   <====   alpha y
  *   /  \                      / \
  * alpha beta               beta Gamma
  * method
  * param Node node Node.
  * return Node
  */
  rotateLeft(node) {
    let y = node.left;
    node.right = y.left;
    if (y.left != null) {
      y.left.parent = node;
    }
    y.parent = node.parent;
    if (node.parent == null) {
      this.root = y;
    } elseif (node == node.parent.left) {
      node.parent.left = y
    } else {
      node.parent.right = y
    }
    y.left = node;
    node.parent = y;
  }

/**
  * param Node node Node.
  * return Node
  */
  insert(node) {

  }
/**
  * method
  * param Node node Node.
  * return Node
  */
  remove(node) {

  }

}
<commit_msg>implemented find, rotate left and rotate right<commit_after>'use strict';

const nodeColor = {
  RED : 0,
  BLACK : 1
}

/**
 * Node of the red black tree
 * constructor
 * param key : Number
 * param value : Object
 * param left : Node
 * param right : Node
 * param color : Number
 */
class Node {
  constructor(key, value, left, right, color, parent) {
    this.key = key;
    this.value = value;
    this.left = left;
    this.right = right;
    this.color = color;
    this.parent = parent;
  }

  /**
  * return Boolean
  */
  isRedNode() {
    return this.color === nodeColor.RED
  }

  /**
  * return Boolean
  */
  isBlackNode() {
    return this.color === nodeColor.BLACK
  }

  /**
  * get GrandParent of a given node
  */
  getGrandParent(node) {
    if ((node != null) && (node.parent != null)) {
      return node.parent.parent;
    } else {
      return null;
    }
  }

  /**
  * get uncle of a given node
  */
  getUncle(node) {
    let grandParent = getGrandParent(node);
    if (grandParent == null) {
      return null;
    }
    if (node.parent == node.left) {
      return grandParent.right;
    } else {
      return grandParent.left;
    }
  }
}

/**
 * constructor
 * Node of the red black tree
 * 1.Every node is either red or black
 * 2.Root and leaves are all black
 * 3.Every red node has black parent
 * 4.All simple paths from a node x to a descendant leaves of x has same black nodes
 */
class RbTree {
  constructor() {
    this.root = null;
  }

/**
  * Complexity: O(1).
  *
  * param Node node Node.
  * return Node a copy of original node
  */
  clone(node) {
    return new Node(node.key, node.value, node.left, node.right, node.color);
  }

/**
 * find value by node key
 */
  find(key) {
    let node = root;
    while (node != null) {
      if (key < node.key) {
        node = node.left;
      } else if (key > node.key) {
        node = node.right;
      } else {
        return node.value
      }
    }
    return null
  }

/**
  * Complexity: O(1).
  *       y                   x
  *      / \                 / \
  *     x  Gamma   ====>   alpha y
  *   /  \                      / \
  * alpha beta               beta Gamma
  * method
  * param Node node Node.
  * return Node
  */
  rotateRight(node) {
    if (node.parent != null) {
      if (node == node.parent.left) {
        node.parent.left = node.left;
      } else {
        node.parent.right = node.left;
      }
      node.left.parent = node.parent;
      node.parent = node.left;
      if (node.left.right != null) {
        node.left.right.parent = node;
      }
      node.left = node.left.right;
      node.parent.right = node;
    } else {
      let left = this.root.left;
      this.root.left = this.root.left.right;
      left.right.parent = this.root;
      this.root.parent = left;
      left.right = this.root;
      left.parent = nil;
      this.root = left;
    }
  }

/**
  * Complexity: O(1).
  *       y                   x
  *      / \                 / \
  *     x  Gamma   <====   alpha y
  *   /  \                      / \
  * alpha beta               beta Gamma
  * method
  * param Node node Node.
  * return Node
  */
  rotateLeft(node) {
    if (node.parent != null) {
      if (node == node.parent.left) {
        node.parent.left = node.right;
      } else {
        node.parent.right = node.right;
      }
      node.right.parent = node.parent;
      node.parent = node.right;
      if (node.right.left != null) {
        node.right.left.parent = node;
      }
      node.right = node.right.left;
      node.parent.left = node;
    } else {
      let right = this.root.left;
      this.root.right = this.root.right.left;
      right.left.parent = this.root;
      this.root.parent = right;
      right.left = this.root;
      right.parent = nil;
      this.root = right;
    }
  }

/**
  * param Node node Node.
  * return Node
  */
  insert(node) {

  }
/**
  * method
  * param Node node Node.
  * return Node
  */
  remove(node) {

  }

}
<|endoftext|>


<commit_before>SC.initialize({
  client_id: "711c21de667ecd3ea4e91721e5a4fae1"
});

var debug = true;
var lastSound = null;
var $lastSpan = null;
var trackIsPlaying = false;

function log(str) {
  if (debug)
    console.log(str);
}

var LOAD_TIMEOUT = 4000; // ms
var loadStartedTime = null;

function play(track, $listElement) {
  var $s = $listElement.find('i');
  $s.removeClass("icon-block");
  //if (!$s.is($lastSpan)) { // not same track
  if (true) { // not same track
    $s.addClass("icon-spin3 animate-spin");
    $s.spinning = true;
  }

  // bind events to remove the loading icon once music is playing
  // and icon for sop when fnished playing
  var opts = (function(){
    var e = $s;
    return {
      whileplaying: function () {
        if (!e.spinning)
          return;

        if (this.position < 1) // once actually playing
          return;
        log("Music started to play.");
        e.removeClass("icon-spin3 animate-spin");
        e.spinning = false;
        if (this._timeout)
          clearTimeout(this._timeout);
      },
      onfinish: function () {
        log(" >>> ONFINISH CALLED");
        e.removeClass("icon-pause");
      }
    };
  })();

  var uri = track.uri || track;
  SC.stream(uri, opts, function (sound) {
    window.ss = sound;

    if (lastSound) {
      lastSound.stop();
      if (lastSound._timeout)
        clearTimeout(lastSound._timeout);
    }

    if ($lastSpan) {
      $lastSpan.removeClass("icon-pause");
      $lastSpan.removeClass("icon-spin3 animate-spin");
    }

    if ($s.is($lastSpan)) { // same track

      // pause/resume check
      if (trackIsPlaying) {
        var pp = lastSound.position;
        log("paused at " + pp);
        lastSound._pausePosition = pp;
        lastSound.pause();
        $s.removeClass("icon-pause");
        trackIsPlaying = false;
      } else {
        var pp = lastSound._pausePosition || 0;
        log("resumed at: " + pp);
        lastSound.setPosition(pp);
        lastSound.play();
        trackIsPlaying = true;
        $s.addClass("icon-pause");
      }

    } else { // selected new track

      if ($s) {
        sound.play();
        trackIsPlaying = true;
        $s.addClass("icon-pause");

        // retry playing sound if first attempt fails
        (function(){
          var mySound = sound;
          var $myElement = $listElement.find('i');
          log("setting up retry check timeout");
          mySound._timeout = setTimeout(function() {
            log("retry check timeout called");

            if (mySound.playState && mySound.position < 1 && trackIsPlaying) {
              // if still not playing - try again
              mySound.play();
              log(" -- retrying to play track");

              // set another timeout that tells the user
              // the music is broken if it still doesn't work
              mySound._timeout = setTimeout(function(){
                log('  final check called');
                if (mySound.playState && mySound.position < 1 && trackIsPlaying) {
                  $myElement
                    .removeClass("icon-spin3 animate-spin icon-paused")
                    .addClass("icon-block");
                  var str = "Oh noes :( that track seems to be broken.";
                  //showMessage(str, 'error');
                  showNotice(str, 'error');
                  mySound.stop();
                  log(" !! track seems to be broken, tell user and stop trying");
                  $lastSpan = null;
                } else {
                  log("    playState: " + mySound.playState);
                  log("    position: " + mySound.position);
                  log("    trackIsPlaying: " + trackIsPlaying);
                }
              }, LOAD_TIMEOUT * 1 + 500); // extend
            } else {
              log("element OK but check failed");
              log("  position is: " + mySound.position);
              log("  trackIsPlaying is: " + trackIsPlaying);
            }
          }, LOAD_TIMEOUT);
        })();
      }

      lastSound = sound;
      $lastSpan = $s;
    }
  });
}

var $list = $('#list');

var lastTracks = null;
var currentTrackIndex = 0;

function addMoreTracks(amount, animation) {
  if (!lastTracks)
    return;

  var tracks = lastTracks;

  log("current: " + currentTrackIndex);
  log("tracks.length: " + tracks.length);

  if (currentTrackIndex >= tracks.length) {
    showMessage("Didn't find any more songs! Try a new search?", "error");
    $('#more-button').removeClass().html("No more songs found!");
    return;
  }

  var limit = amount + currentTrackIndex;
  for (var i = currentTrackIndex; i < limit; i++) {
    var t = tracks[i];

    var t_title = t.title.substring(0, 48);
    if (t.title.length > 48) {
      t_title += "...";
    }

    var ani = animation || 'fadeIn';
    var el = $(
      '
' +
        '' + t_title + '' +
      '
'
    );

    var ii = el.find('i');
    (function(){
      var e = el;
      ii.on('click', function () {
        log("click: " + e.trackUri);
        play(e.track, e);
        return false;
      })
    }());

    el.trackUri = t.uri;
    el.track = t;
    $list.append(el);
  }
  currentTrackIndex = limit;
}

var defaultLimit = 16;
var $text = $('#message-text');

function search(str) {
  // set spinning icon to signify loading
  showMessage(null, 'ok');
  $text.removeClass().html('').addClass('icon-spin3 animate-spin');

  var query = {
    q: str,
    limit: defaultLimit
  }

  SC.get("http://api.soundcloud.com/tracks", query, function (tracks) {
    currentTrackIndex = 0;
    lastTracks = tracks;
    $('#more-button').html("More results").removeClass().addClass('icon-plus');
    var track = tracks[0];

    if (tracks.length < 1) {
      log("No tracks found!");
      $list.empty();
      $('.results-footer').css("display", "none"); // hide more button
      showMessage("Didn't find any songs! Try a new search?", "error");
    } else {
      showMessage("Here are some results.", "ok");

      // clear list for new search
      $list.empty();

      // Initial amount of tracks to show after search
      addMoreTracks(4);
      $('.results-footer').css("display", "block"); // show more button
    }
  }); // eof SC.get
}

var inputWatermarkText = "Search for any song";
var input = $('.searchbar input');

// setup input watermark
var first = true;
input.val(inputWatermarkText);
input.on('focus', function () {
  input.val("");
});
input.on('blur', function () {
  if (input.val().length < 1)
    input.val(inputWatermarkText);
});

var timeout = null;
input.on('input', function () {

  if (timeout) {
    clearTimeout(timeout);
  }

  if (input.val().length <= 0)
    return; // do nothing

  timeout = setTimeout(function() {
    if (input.val().length < 2) {
      showMessage("How about we try searching for something real?", 'ok');
      return;
    }
    search(input.val());
  }, 400);
})

// seupt more button
$('#more-button').on('click', function() {
  addMoreTracks(2);
  return false;
});

var $text = $('#message-text');
var $message = $('#message-box');
function showMessage(message, type) {
  log("showMessage called");
  $text.removeClass();
  if (message)
    $text.html(message);

  $message.removeClass();
  $message.addClass("message info-ok info-" + type);
}

var $nText = $('#notice-text');
var $nMessage = $('#notice-box');
var nTimeout = null;
// show temporary notice message
function showNotice (message, type) {
  log("showNotice called");

  $nText.removeClass();
  if (message)
    $nText.html(message);

  $nMessage.removeClass();
  $nMessage.addClass("message bounce animated info-ok info-" + type);

  $nMessage.css('display', 'block');

  if (nTimeout)
    clearTimeout(nTimeout);

  nTimeout = setTimeout(function(){
    //$nMessage.css('display', 'none');
    $nMessage.addClass('fadeOut animated');
  }, LOAD_TIMEOUT * 1.8);
}

log("app loaded");
// default debug search result
search("melody circus");

document.body.addEventListener('touchstart', function () {
  var o = new Audio();
  alert("Audio: " + o);
  document.body.removeEventListener('touchstart);
}, false);
<commit_msg>typo fix<commit_after>SC.initialize({
  client_id: "711c21de667ecd3ea4e91721e5a4fae1"
});

var debug = true;
var lastSound = null;
var $lastSpan = null;
var trackIsPlaying = false;

function log(str) {
  if (debug)
    console.log(str);
}

var LOAD_TIMEOUT = 4000; // ms
var loadStartedTime = null;

function play(track, $listElement) {
  var $s = $listElement.find('i');
  $s.removeClass("icon-block");
  //if (!$s.is($lastSpan)) { // not same track
  if (true) { // not same track
    $s.addClass("icon-spin3 animate-spin");
    $s.spinning = true;
  }

  // bind events to remove the loading icon once music is playing
  // and icon for sop when fnished playing
  var opts = (function(){
    var e = $s;
    return {
      whileplaying: function () {
        if (!e.spinning)
          return;

        if (this.position < 1) // once actually playing
          return;
        log("Music started to play.");
        e.removeClass("icon-spin3 animate-spin");
        e.spinning = false;
        if (this._timeout)
          clearTimeout(this._timeout);
      },
      onfinish: function () {
        log(" >>> ONFINISH CALLED");
        e.removeClass("icon-pause");
      }
    };
  })();

  var uri = track.uri || track;
  SC.stream(uri, opts, function (sound) {
    window.ss = sound;

    if (lastSound) {
      lastSound.stop();
      if (lastSound._timeout)
        clearTimeout(lastSound._timeout);
    }

    if ($lastSpan) {
      $lastSpan.removeClass("icon-pause");
      $lastSpan.removeClass("icon-spin3 animate-spin");
    }

    if ($s.is($lastSpan)) { // same track

      // pause/resume check
      if (trackIsPlaying) {
        var pp = lastSound.position;
        log("paused at " + pp);
        lastSound._pausePosition = pp;
        lastSound.pause();
        $s.removeClass("icon-pause");
        trackIsPlaying = false;
      } else {
        var pp = lastSound._pausePosition || 0;
        log("resumed at: " + pp);
        lastSound.setPosition(pp);
        lastSound.play();
        trackIsPlaying = true;
        $s.addClass("icon-pause");
      }

    } else { // selected new track

      if ($s) {
        sound.play();
        trackIsPlaying = true;
        $s.addClass("icon-pause");

        // retry playing sound if first attempt fails
        (function(){
          var mySound = sound;
          var $myElement = $listElement.find('i');
          log("setting up retry check timeout");
          mySound._timeout = setTimeout(function() {
            log("retry check timeout called");

            if (mySound.playState && mySound.position < 1 && trackIsPlaying) {
              // if still not playing - try again
              mySound.play();
              log(" -- retrying to play track");

              // set another timeout that tells the user
              // the music is broken if it still doesn't work
              mySound._timeout = setTimeout(function(){
                log('  final check called');
                if (mySound.playState && mySound.position < 1 && trackIsPlaying) {
                  $myElement
                    .removeClass("icon-spin3 animate-spin icon-paused")
                    .addClass("icon-block");
                  var str = "Oh noes :( that track seems to be broken.";
                  //showMessage(str, 'error');
                  showNotice(str, 'error');
                  mySound.stop();
                  log(" !! track seems to be broken, tell user and stop trying");
                  $lastSpan = null;
                } else {
                  log("    playState: " + mySound.playState);
                  log("    position: " + mySound.position);
                  log("    trackIsPlaying: " + trackIsPlaying);
                }
              }, LOAD_TIMEOUT * 1 + 500); // extend
            } else {
              log("element OK but check failed");
              log("  position is: " + mySound.position);
              log("  trackIsPlaying is: " + trackIsPlaying);
            }
          }, LOAD_TIMEOUT);
        })();
      }

      lastSound = sound;
      $lastSpan = $s;
    }
  });
}

var $list = $('#list');

var lastTracks = null;
var currentTrackIndex = 0;

function addMoreTracks(amount, animation) {
  if (!lastTracks)
    return;

  var tracks = lastTracks;

  log("current: " + currentTrackIndex);
  log("tracks.length: " + tracks.length);

  if (currentTrackIndex >= tracks.length) {
    showMessage("Didn't find any more songs! Try a new search?", "error");
    $('#more-button').removeClass().html("No more songs found!");
    return;
  }

  var limit = amount + currentTrackIndex;
  for (var i = currentTrackIndex; i < limit; i++) {
    var t = tracks[i];

    var t_title = t.title.substring(0, 48);
    if (t.title.length > 48) {
      t_title += "...";
    }

    var ani = animation || 'fadeIn';
    var el = $(
      '
' +
        '' + t_title + '' +
      '
'
    );

    var ii = el.find('i');
    (function(){
      var e = el;
      ii.on('click', function () {
        log("click: " + e.trackUri);
        play(e.track, e);
        return false;
      })
    }());

    el.trackUri = t.uri;
    el.track = t;
    $list.append(el);
  }
  currentTrackIndex = limit;
}

var defaultLimit = 16;
var $text = $('#message-text');

function search(str) {
  // set spinning icon to signify loading
  showMessage(null, 'ok');
  $text.removeClass().html('').addClass('icon-spin3 animate-spin');

  var query = {
    q: str,
    limit: defaultLimit
  }

  SC.get("http://api.soundcloud.com/tracks", query, function (tracks) {
    currentTrackIndex = 0;
    lastTracks = tracks;
    $('#more-button').html("More results").removeClass().addClass('icon-plus');
    var track = tracks[0];

    if (tracks.length < 1) {
      log("No tracks found!");
      $list.empty();
      $('.results-footer').css("display", "none"); // hide more button
      showMessage("Didn't find any songs! Try a new search?", "error");
    } else {
      showMessage("Here are some results.", "ok");

      // clear list for new search
      $list.empty();

      // Initial amount of tracks to show after search
      addMoreTracks(4);
      $('.results-footer').css("display", "block"); // show more button
    }
  }); // eof SC.get
}

var inputWatermarkText = "Search for any song";
var input = $('.searchbar input');

// setup input watermark
var first = true;
input.val(inputWatermarkText);
input.on('focus', function () {
  input.val("");
});
input.on('blur', function () {
  if (input.val().length < 1)
    input.val(inputWatermarkText);
});

var timeout = null;
input.on('input', function () {

  if (timeout) {
    clearTimeout(timeout);
  }

  if (input.val().length <= 0)
    return; // do nothing

  timeout = setTimeout(function() {
    if (input.val().length < 2) {
      showMessage("How about we try searching for something real?", 'ok');
      return;
    }
    search(input.val());
  }, 400);
})

// seupt more button
$('#more-button').on('click', function() {
  addMoreTracks(2);
  return false;
});

var $text = $('#message-text');
var $message = $('#message-box');
function showMessage(message, type) {
  log("showMessage called");
  $text.removeClass();
  if (message)
    $text.html(message);

  $message.removeClass();
  $message.addClass("message info-ok info-" + type);
}

var $nText = $('#notice-text');
var $nMessage = $('#notice-box');
var nTimeout = null;
// show temporary notice message
function showNotice (message, type) {
  log("showNotice called");

  $nText.removeClass();
  if (message)
    $nText.html(message);

  $nMessage.removeClass();
  $nMessage.addClass("message bounce animated info-ok info-" + type);

  $nMessage.css('display', 'block');

  if (nTimeout)
    clearTimeout(nTimeout);

  nTimeout = setTimeout(function(){
    //$nMessage.css('display', 'none');
    $nMessage.addClass('fadeOut animated');
  }, LOAD_TIMEOUT * 1.8);
}

log("app loaded");
// default debug search result
search("melody circus");

document.body.addEventListener('touchstart', function () {
  var o = new Audio();
  alert("Audio: " + o);
  document.body.removeEventListener('touchstart');
}, false);
<|endoftext|>


<commit_before>Package.describe({
    summary: "Send e-mails with attachments.",
    version: "1.0.11",
    git: "www.github.com/priyadarshy/email-att"
});

Npm.depends({
    "simplesmtp": "0.3.10",
    "stream-buffers": "0.2.5",
    "mailcomposer": "0.1.15"
});

Package.on_use(function(api) {
    api.versionsFrom('METEOR@0.9.2.1');
    api.addFiles('ashutosh:email-att.js', ['server']);
});

Package.on_test(function(api) {
    api.use('tinytest');
    api.use('ashutosh:email-att');
    api.addFiles('ashutosh:email-att-tests.js', ['server']);
});

<commit_msg>Bump version number.<commit_after>Package.describe({
    summary: "Send e-mails with attachments.",
    version: "1.0.12",
    git: "www.github.com/priyadarshy/email-att"
});

Npm.depends({
    "simplesmtp": "0.3.10",
    "stream-buffers": "0.2.5",
    "mailcomposer": "0.1.15"
});

Package.on_use(function(api) {
    api.versionsFrom('METEOR@0.9.2.1');
    api.addFiles('ashutosh:email-att.js', ['server']);
});

Package.on_test(function(api) {
    api.use('tinytest');
    api.use('ashutosh:email-att');
    api.addFiles('ashutosh:email-att-tests.js', ['server']);
});

<|endoftext|>


<commit_before>import Notifications from '../lib/collections/notifications/collection.js';
import Messages from '../lib/collections/messages/collection.js';
import Conversations from '../lib/collections/conversations/collection.js';

import Localgroups from '../lib/collections/localgroups/collection.js';
import Users from 'meteor/vulcan:users';
import { Posts } from '../lib/collections/posts';
import { Comments } from '../lib/collections/comments'
import { renderAndSendEmail, reasonUserCantReceiveEmails } from './emails/renderEmail.js';
import './emailComponents/EmailWrapper.jsx';
import './emailComponents/NewPostEmail.jsx';
import './emailComponents/PrivateMessagesEmail.jsx';
import { EventDebouncer } from './debouncer.js';
import { UnsubscribeAllToken } from './emails/emailTokens.js';

import { Components, addCallback, newMutation } from 'meteor/vulcan:core';

import React from 'react';
import keyBy from 'lodash/keyBy';

const createNotifications = async (userIds, notificationType, documentType, documentId) => {
  return Promise.all(
    userIds.map(async userId => {
      let user = Users.findOne({ _id:userId });

      let notificationData = {
        userId: userId,
        documentId: documentId,
        documentType: documentType,
        message: notificationMessage(notificationType, documentType, documentId),
        type: notificationType,
        link: getLink(notificationType, documentType, documentId),
      }

      await newMutation({
        action: 'notifications.new',
        collection: Notifications,
        document: notificationData,
        currentUser: user,
        validate: false
      });
    })
  );
}

const sendPostByEmail = async (users, postId, reason) => {
  let post = await Posts.findOne(postId);

  for(let user of users) {
    if(!reasonUserCantReceiveEmails(user)) {
      const unsubscribeAllLink = await UnsubscribeAllToken.generateLink(user._id);
      await renderAndSendEmail({
        user,
        subject: post.title,
        bodyComponent: <Components.EmailWrapper
          user={user}
          unsubscribeAllLink={unsubscribeAllLink}
        >
          <Components.NewPostEmail documentId={post._id} reason={reason}/>
        </Components.EmailWrapper>
      });
    } else {
      //eslint-disable-next-line no-console
      console.log(`Skipping user ${user.username} when emailing: ${reasonUserCantReceiveEmails(user)}`);
    }
  }
}

const getLink = (notificationType, documentType, documentId) => {
  let document = getDocument(documentType, documentId);

  switch(notificationType) {
    case "emailVerificationRequired":
      return "/resendVerificationEmail";
    default:
      // Fall through to based on document-type
      break;
  }

  switch(documentType) {
    case "post":
      return Posts.getPageUrl(document);
    case "comment":
      return Comments.getPageUrl(document);
    case "user":
      return Users.getProfileUrl(document);
    case "message":
      return Messages.getLink(document);
    default:
      //eslint-disable-next-line no-console
      console.error("Invalid notification type");
  }
}

const notificationMessage = (notificationType, documentType, documentId) => {
  let document = getDocument(documentType, documentId);
  let group = {}
  if (documentType == "post" && document.groupId) {
    group = Localgroups.findOne(document.groupId);
  }

  switch(notificationType) {
    case "newPost":
      return Posts.getAuthorName(document) + ' has created a new post: ' + document.title;
    case "newPendingPost":
      return Posts.getAuthorName(document) + ' has a new post pending approval ' + document.title;
    case "postApproved":
      return 'Your post "' + document.title + '" has been approved';
    case "newEvent":
        return Posts.getAuthorName(document) + ' has created a new event in the group "' + group.name + '"';
    case "newGroupPost":
        return Posts.getAuthorName(document) + ' has created a new post in the group "' + group.name + '"';
    case "newComment":
      return Comments.getAuthorName(document) + ' left a new comment on "' + Posts.findOne(document.postId).title + '"';
    case "newReply":
      return Comments.getAuthorName(document) + ' replied to a comment on "' + Posts.findOne(document.postId).title + '"';
    case "newReplyToYou":
        return Comments.getAuthorName(document) + ' replied to your comment on "' + Posts.findOne(document.postId).title + '"';
    case "newUser":
      return document.displayName + ' just signed up!';
    case "newMessage":
      let conversation = Conversations.findOne(document.conversationId);
      return Users.findOne(document.userId).displayName + ' sent you a new message' + (conversation.title ? (' in the conversation ' + conversation.title) : "") + '!';
    case "emailVerificationRequired":
      return "Verify your email address to activate email subscriptions.";
    default:
      //eslint-disable-next-line no-console
      console.error("Invalid notification type");
  }
}

const getDocument = (documentType, documentId) => {
  if (!documentId) return null;

  switch(documentType) {
    case "post":
      return Posts.findOne(documentId);
    case "comment":
      return Comments.findOne(documentId);
    case "user":
      return Users.findOne(documentId);
    case "message":
      return Messages.findOne(documentId);
    default:
      //eslint-disable-next-line no-console
      console.error(`Invalid documentType type: ${documentType}`);
  }
}

/**
 * @summary Add notification callback when a post is approved
 */
function PostsApprovedNotification(post) {
  createNotifications([post.userId], 'postApproved', 'post', post._id);
}
addCallback("posts.approve.async", PostsApprovedNotification);

function PostsUndraftNotification(post) {
  //eslint-disable-next-line no-console
  console.info("Post undrafted, creating notifications");

  postsNewNotifications(post);
}
addCallback("posts.undraft.async", PostsUndraftNotification);

// Add new post notification callback on post submit
function postsNewNotifications (post) {
  if (!post.draft && post.status === Posts.config.STATUS_APPROVED) {
    // Removed because this was useless. Will be reintroduced in a different
    // form (with advanced filters and emailing.)
    //let usersToNotify = _.pluck(Users.find({'notifications_posts': true}, {fields: {_id:1}}).fetch(), '_id');
    let usersToNotify = [];

    // add users who are subscribed to this post's author
    const postAuthor = Users.findOne(post.userId);
    if (!!postAuthor.subscribers) {
      usersToNotify = _.union(usersToNotify, postAuthor.subscribers);
    }

    // add users who are subscribed to this post's groups
    if (post.groupId) {
      const group = Localgroups.findOne(post.groupId);
      if (group.subscribers) {
        usersToNotify = _.union(usersToNotify, group.subscribers);
      }
    }
    // remove this post's author
    usersToNotify = _.without(usersToNotify, post.userId);

    if (post.groupId && post.isEvent) {
      createNotifications(usersToNotify, 'newEvent', 'post', post._id);
    } else if (post.groupId && !post.isEvent) {
      createNotifications(usersToNotify, 'newGroupPost', 'post', post._id);
    } else {
      createNotifications(usersToNotify, 'newPost', 'post', post._id);
    }

  }
}
addCallback("posts.new.async", postsNewNotifications);

function findUsersToEmail(filter) {
  let usersMatchingFilter = Users.find(filter).fetch();

  let usersToEmail = usersMatchingFilter.filter(u => {
    if (u.email && u.emails && u.emails.length) {
      let primaryAddress = u.email;

      for(let i=0; i<u.emails.length; i++)
      {
        if(u.emails[i].address === primaryAddress && u.emails[i].verified)
          return true;
      }
      return false;
    } else {
      return false;
    }
  });
  return usersToEmail
}

const curationEmailDelay = new EventDebouncer({
  name: "curationEmail",
  delayMinutes: 20,
  callback: async (postId) => {
    const post = await Posts.findOne(postId);

    // Still curated? If it was un-curated during the 20 minute delay, don't
    // send emails.
    if (post.curatedDate) {
      let usersToEmail = findUsersToEmail({'emailSubscribedToCurated': true});
      sendPostByEmail(usersToEmail, postId, "you have the \"Email me new posts in Curated\" option enabled");
    } else {
      //eslint-disable-next-line no-console
      console.log(`Not sending curation notice for ${post.title} because it was un-curated during the delay period.`);
    }
  }
});

function PostsCurateNotification (post, oldPost) {
  if(post.curatedDate && !oldPost.curatedDate) {
    curationEmailDelay.recordEvent({
      key: post._id,
      data: null,
      af: false
    });
  }
}
addCallback("posts.edit.async", PostsCurateNotification);

// add new comment notification callback on comment submit
async function CommentsNewNotifications(comment) {
  // note: dummy content has disableNotifications set to true
  if(Meteor.isServer && !comment.disableNotifications) {

    const post = await Posts.findOne(comment.postId);

    // keep track of whom we've notified (so that we don't notify the same user twice for one comment,
    // if e.g. they're both the author of the post and the author of a comment being replied to)
    let notifiedUsers = [];

    // 1. Notify users who are subscribed to the parent comment
    if (!!comment.parentCommentId) {
      const parentComment = Comments.findOne(comment.parentCommentId);

      if (!!parentComment.subscribers && !!parentComment.subscribers.length) {
        // remove userIds of users that have already been notified
        // and of comment and parentComment author (they could be replying in a thread they're subscribed to)
        let parentCommentSubscribersToNotify = _.difference(parentComment.subscribers, notifiedUsers, [comment.userId, parentComment.userId]);
        createNotifications(parentCommentSubscribersToNotify, 'newReply', 'comment', comment._id);
        notifiedUsers = [...notifiedUsers, ...parentCommentSubscribersToNotify];

        // Separately notify author of comment with different notification, if they are subscribed, and are NOT the author of the comment
        if (parentComment.subscribers.includes(parentComment.userId) && parentComment.userId !== comment.userId) {
          createNotifications([parentComment.userId], 'newReplyToYou', 'comment', comment._id);
          notifiedUsers = [...notifiedUsers, parentComment.userId];
        }
      }
    }

    // 2. Notify users who are subscribed to the post (which may or may not include the post's author)
    if (post && post.subscribers && post.subscribers.length) {
      // remove userIds of users that have already been notified
      // and of comment author (they could be replying in a thread they're subscribed to)
      let postSubscribersToNotify = _.difference(post.subscribers, notifiedUsers, [comment.userId]);
      createNotifications(postSubscribersToNotify, 'newComment', 'comment', comment._id);
    }
  }
}
addCallback("comments.new.async", CommentsNewNotifications);

async function sendPrivateMessagesEmail(conversationId, messageIds) {
  const conversation = await Conversations.findOne(conversationId);
  const participants = await Users.find({_id: {$in: conversation.participantIds}}).fetch();
  const participantsById = keyBy(participants, u=>u._id);
  const messages = await Messages.find(
    {_id: {$in: messageIds}},
    { sort: {createdAt:1} })
    .fetch();

  for (const recipientUser of participants)
  {
    // TODO: Gradual rollout--only email admins with this. Remove later when
    // this is more tested.
    if (!Users.isAdmin(recipientUser))
      continue;

    // If this user is responsible for every message that would be in the
    // email, don't send it to them (you only want emails that contain at
    // least one message that's not your own; your own messages are optional
    // context).
    if (!_.some(messages, message=>message.userId !== recipientUser._id))
      continue;

    const otherParticipants = _.filter(participants, u=>u._id != recipientUser._id);
    const subject = `Private message conversation with ${otherParticipants.map(u=>u.displayName).join(', ')}`;

    if(!reasonUserCantReceiveEmails(recipientUser)) {
      const unsubscribeAllLink = await UnsubscribeAllToken.generateLink(recipientUser._id);
      await renderAndSendEmail({
        user: recipientUser,
        subject: subject,
        bodyComponent: <Components.EmailWrapper
          user={recipientUser}
          unsubscribeAllLink={unsubscribeAllLink}
        >
          <Components.PrivateMessagesEmail
            conversation={conversation}
            messages={messages}
            participantsById={participantsById}
          />
        </Components.EmailWrapper>
      });
    } else {
      //eslint-disable-next-line no-console
      console.log(`Skipping user ${recipientUser.username} when emailing: ${reasonUserCantReceiveEmails(recipientUser)}`);
    }
  }
}

const privateMessagesDebouncer = new EventDebouncer({
  name: "privateMessage",
  delayMinutes: 15,
  maxDelayMinutes: 30,
  callback: sendPrivateMessagesEmail
});

function messageNewNotification(message) {
  const conversationId = message.conversationId;
  const conversation = Conversations.findOne(conversationId);

  // For on-site notifications, notify everyone except the sender of the
  // message. For email notifications, notify everyone including the sender
  // (since if there's a back-and-forth in the grouped notifications, you want
  // to see your own messages.)
  const recipients = conversation.participantIds.filter((id) => (id !== message.userId));

  // Create on-site notification
  createNotifications(recipients, 'newMessage', 'message', message._id);

  // Generate debounced email notifications
  privateMessagesDebouncer.recordEvent({
    key: conversationId,
    data: message._id,
    af: conversation.af,
  });
}
addCallback("messages.new.async", messageNewNotification);

export async function bellNotifyEmailVerificationRequired (user) {
  await createNotifications([user._id], 'emailVerificationRequired', null, null);
}
<commit_msg>notify users who are shared on a draft<commit_after>import Notifications from '../lib/collections/notifications/collection.js';
import Messages from '../lib/collections/messages/collection.js';
import Conversations from '../lib/collections/conversations/collection.js';

import Localgroups from '../lib/collections/localgroups/collection.js';
import Users from 'meteor/vulcan:users';
import { Posts } from '../lib/collections/posts';
import { Comments } from '../lib/collections/comments'
import { renderAndSendEmail, reasonUserCantReceiveEmails } from './emails/renderEmail.js';
import './emailComponents/EmailWrapper.jsx';
import './emailComponents/NewPostEmail.jsx';
import './emailComponents/PrivateMessagesEmail.jsx';
import { EventDebouncer } from './debouncer.js';
import { UnsubscribeAllToken } from './emails/emailTokens.js';

import { Components, addCallback, newMutation } from 'meteor/vulcan:core';

import React from 'react';
import keyBy from 'lodash/keyBy';

const createNotifications = async (userIds, notificationType, documentType, documentId) => {
  return Promise.all(
    userIds.map(async userId => {
      let user = Users.findOne({ _id:userId });

      let notificationData = {
        userId: userId,
        documentId: documentId,
        documentType: documentType,
        message: notificationMessage(notificationType, documentType, documentId),
        type: notificationType,
        link: getLink(notificationType, documentType, documentId),
      }

      await newMutation({
        action: 'notifications.new',
        collection: Notifications,
        document: notificationData,
        currentUser: user,
        validate: false
      });
    })
  );
}

const sendPostByEmail = async (users, postId, reason) => {
  let post = await Posts.findOne(postId);

  for(let user of users) {
    if(!reasonUserCantReceiveEmails(user)) {
      const unsubscribeAllLink = await UnsubscribeAllToken.generateLink(user._id);
      await renderAndSendEmail({
        user,
        subject: post.title,
        bodyComponent: <Components.EmailWrapper
          user={user}
          unsubscribeAllLink={unsubscribeAllLink}
        >
          <Components.NewPostEmail documentId={post._id} reason={reason}/>
        </Components.EmailWrapper>
      });
    } else {
      //eslint-disable-next-line no-console
      console.log(`Skipping user ${user.username} when emailing: ${reasonUserCantReceiveEmails(user)}`);
    }
  }
}

const getLink = (notificationType, documentType, documentId) => {
  let document = getDocument(documentType, documentId);

  switch(notificationType) {
    case "emailVerificationRequired":
      return "/resendVerificationEmail";
    default:
      // Fall through to based on document-type
      break;
  }

  switch(documentType) {
    case "post":
      return Posts.getPageUrl(document);
    case "comment":
      return Comments.getPageUrl(document);
    case "user":
      return Users.getProfileUrl(document);
    case "message":
      return Messages.getLink(document);
    default:
      //eslint-disable-next-line no-console
      console.error("Invalid notification type");
  }
}

const notificationMessage = (notificationType, documentType, documentId) => {
  let document = getDocument(documentType, documentId);
  let group = {}
  if (documentType == "post" && document.groupId) {
    group = Localgroups.findOne(document.groupId);
  }

  switch(notificationType) {
    case "newPost":
      return Posts.getAuthorName(document) + ' has created a new post: ' + document.title;
    case "newPendingPost":
      return Posts.getAuthorName(document) + ' has a new post pending approval ' + document.title;
    case "postApproved":
      return 'Your post "' + document.title + '" has been approved';
    case "newEvent":
        return Posts.getAuthorName(document) + ' has created a new event in the group "' + group.name + '"';
    case "newGroupPost":
        return Posts.getAuthorName(document) + ' has created a new post in the group "' + group.name + '"';
    case "newComment":
      return Comments.getAuthorName(document) + ' left a new comment on "' + Posts.findOne(document.postId).title + '"';
    case "newReply":
      return Comments.getAuthorName(document) + ' replied to a comment on "' + Posts.findOne(document.postId).title + '"';
    case "newReplyToYou":
        return Comments.getAuthorName(document) + ' replied to your comment on "' + Posts.findOne(document.postId).title + '"';
    case "newUser":
      return document.displayName + ' just signed up!';
    case "newMessage":
      let conversation = Conversations.findOne(document.conversationId);
      return Users.findOne(document.userId).displayName + ' sent you a new message' + (conversation.title ? (' in the conversation ' + conversation.title) : "") + '!';
    case "emailVerificationRequired":
      return "Verify your email address to activate email subscriptions.";
    case "postSharedWithUser":
      return `You have been shared on the ${document.draft ? "draft" : "post"} ${document.title}`
    default:
      //eslint-disable-next-line no-console
      console.error("Invalid notification type");
  }
}

const getDocument = (documentType, documentId) => {
  if (!documentId) return null;

  switch(documentType) {
    case "post":
      return Posts.findOne(documentId);
    case "comment":
      return Comments.findOne(documentId);
    case "user":
      return Users.findOne(documentId);
    case "message":
      return Messages.findOne(documentId);
    default:
      //eslint-disable-next-line no-console
      console.error(`Invalid documentType type: ${documentType}`);
  }
}

/**
 * @summary Add notification callback when a post is approved
 */
function PostsApprovedNotification(post) {
  createNotifications([post.userId], 'postApproved', 'post', post._id);
}
addCallback("posts.approve.async", PostsApprovedNotification);

function PostsUndraftNotification(post) {
  //eslint-disable-next-line no-console
  console.info("Post undrafted, creating notifications");

  postsNewNotifications(post);
}
addCallback("posts.undraft.async", PostsUndraftNotification);

// Add new post notification callback on post submit
function postsNewNotifications (post) {
  if (!post.draft && post.status === Posts.config.STATUS_APPROVED) {
    // Removed because this was useless. Will be reintroduced in a different
    // form (with advanced filters and emailing.)
    //let usersToNotify = _.pluck(Users.find({'notifications_posts': true}, {fields: {_id:1}}).fetch(), '_id');
    let usersToNotify = [];

    // add users who are subscribed to this post's author
    const postAuthor = Users.findOne(post.userId);
    if (!!postAuthor.subscribers) {
      usersToNotify = _.union(usersToNotify, postAuthor.subscribers);
    }

    // add users who are subscribed to this post's groups
    if (post.groupId) {
      const group = Localgroups.findOne(post.groupId);
      if (group.subscribers) {
        usersToNotify = _.union(usersToNotify, group.subscribers);
      }
    }
    // remove this post's author
    usersToNotify = _.without(usersToNotify, post.userId);

    if (post.groupId && post.isEvent) {
      createNotifications(usersToNotify, 'newEvent', 'post', post._id);
    } else if (post.groupId && !post.isEvent) {
      createNotifications(usersToNotify, 'newGroupPost', 'post', post._id);
    } else {
      createNotifications(usersToNotify, 'newPost', 'post', post._id);
    }

  }
}
addCallback("posts.new.async", postsNewNotifications);

function findUsersToEmail(filter) {
  let usersMatchingFilter = Users.find(filter).fetch();

  let usersToEmail = usersMatchingFilter.filter(u => {
    if (u.email && u.emails && u.emails.length) {
      let primaryAddress = u.email;

      for(let i=0; i<u.emails.length; i++)
      {
        if(u.emails[i].address === primaryAddress && u.emails[i].verified)
          return true;
      }
      return false;
    } else {
      return false;
    }
  });
  return usersToEmail
}

const curationEmailDelay = new EventDebouncer({
  name: "curationEmail",
  delayMinutes: 20,
  callback: async (postId) => {
    const post = await Posts.findOne(postId);

    // Still curated? If it was un-curated during the 20 minute delay, don't
    // send emails.
    if (post.curatedDate) {
      let usersToEmail = findUsersToEmail({'emailSubscribedToCurated': true});
      sendPostByEmail(usersToEmail, postId, "you have the \"Email me new posts in Curated\" option enabled");
    } else {
      //eslint-disable-next-line no-console
      console.log(`Not sending curation notice for ${post.title} because it was un-curated during the delay period.`);
    }
  }
});

function PostsCurateNotification (post, oldPost) {
  if(post.curatedDate && !oldPost.curatedDate) {
    curationEmailDelay.recordEvent({
      key: post._id,
      data: null,
      af: false
    });
  }
}
addCallback("posts.edit.async", PostsCurateNotification);

// add new comment notification callback on comment submit
async function CommentsNewNotifications(comment) {
  // note: dummy content has disableNotifications set to true
  if(Meteor.isServer && !comment.disableNotifications) {

    const post = await Posts.findOne(comment.postId);

    // keep track of whom we've notified (so that we don't notify the same user twice for one comment,
    // if e.g. they're both the author of the post and the author of a comment being replied to)
    let notifiedUsers = [];

    // 1. Notify users who are subscribed to the parent comment
    if (!!comment.parentCommentId) {
      const parentComment = Comments.findOne(comment.parentCommentId);

      if (!!parentComment.subscribers && !!parentComment.subscribers.length) {
        // remove userIds of users that have already been notified
        // and of comment and parentComment author (they could be replying in a thread they're subscribed to)
        let parentCommentSubscribersToNotify = _.difference(parentComment.subscribers, notifiedUsers, [comment.userId, parentComment.userId]);
        createNotifications(parentCommentSubscribersToNotify, 'newReply', 'comment', comment._id);
        notifiedUsers = [...notifiedUsers, ...parentCommentSubscribersToNotify];

        // Separately notify author of comment with different notification, if they are subscribed, and are NOT the author of the comment
        if (parentComment.subscribers.includes(parentComment.userId) && parentComment.userId !== comment.userId) {
          createNotifications([parentComment.userId], 'newReplyToYou', 'comment', comment._id);
          notifiedUsers = [...notifiedUsers, parentComment.userId];
        }
      }
    }

    // 2. Notify users who are subscribed to the post (which may or may not include the post's author)
    if (post && post.subscribers && post.subscribers.length) {
      // remove userIds of users that have already been notified
      // and of comment author (they could be replying in a thread they're subscribed to)
      let postSubscribersToNotify = _.difference(post.subscribers, notifiedUsers, [comment.userId]);
      createNotifications(postSubscribersToNotify, 'newComment', 'comment', comment._id);
    }
  }
}
addCallback("comments.new.async", CommentsNewNotifications);

async function sendPrivateMessagesEmail(conversationId, messageIds) {
  const conversation = await Conversations.findOne(conversationId);
  const participants = await Users.find({_id: {$in: conversation.participantIds}}).fetch();
  const participantsById = keyBy(participants, u=>u._id);
  const messages = await Messages.find(
    {_id: {$in: messageIds}},
    { sort: {createdAt:1} })
    .fetch();

  for (const recipientUser of participants)
  {
    // TODO: Gradual rollout--only email admins with this. Remove later when
    // this is more tested.
    if (!Users.isAdmin(recipientUser))
      continue;

    // If this user is responsible for every message that would be in the
    // email, don't send it to them (you only want emails that contain at
    // least one message that's not your own; your own messages are optional
    // context).
    if (!_.some(messages, message=>message.userId !== recipientUser._id))
      continue;

    const otherParticipants = _.filter(participants, u=>u._id != recipientUser._id);
    const subject = `Private message conversation with ${otherParticipants.map(u=>u.displayName).join(', ')}`;

    if(!reasonUserCantReceiveEmails(recipientUser)) {
      const unsubscribeAllLink = await UnsubscribeAllToken.generateLink(recipientUser._id);
      await renderAndSendEmail({
        user: recipientUser,
        subject: subject,
        bodyComponent: <Components.EmailWrapper
          user={recipientUser}
          unsubscribeAllLink={unsubscribeAllLink}
        >
          <Components.PrivateMessagesEmail
            conversation={conversation}
            messages={messages}
            participantsById={participantsById}
          />
        </Components.EmailWrapper>
      });
    } else {
      //eslint-disable-next-line no-console
      console.log(`Skipping user ${recipientUser.username} when emailing: ${reasonUserCantReceiveEmails(recipientUser)}`);
    }
  }
}

const privateMessagesDebouncer = new EventDebouncer({
  name: "privateMessage",
  delayMinutes: 15,
  maxDelayMinutes: 30,
  callback: sendPrivateMessagesEmail
});

function messageNewNotification(message) {
  const conversationId = message.conversationId;
  const conversation = Conversations.findOne(conversationId);

  // For on-site notifications, notify everyone except the sender of the
  // message. For email notifications, notify everyone including the sender
  // (since if there's a back-and-forth in the grouped notifications, you want
  // to see your own messages.)
  const recipients = conversation.participantIds.filter((id) => (id !== message.userId));

  // Create on-site notification
  createNotifications(recipients, 'newMessage', 'message', message._id);

  // Generate debounced email notifications
  privateMessagesDebouncer.recordEvent({
    key: conversationId,
    data: message._id,
    af: conversation.af,
  });
}
addCallback("messages.new.async", messageNewNotification);

export async function bellNotifyEmailVerificationRequired (user) {
  await createNotifications([user._id], 'emailVerificationRequired', null, null);
}

async function PostsEditNotifyUsersSharedOnPost (newPost, oldPost) {
  if (!_.isEqual(newPost.shareWithUsers, oldPost.shareWithUsers)) {
    // Right now this only creates notifications when users are shared (and not when they are "unshared")
    // because currently notifications are hidden from you if you don't have view-access to a post.
    // TODO: probably fix that, such that users can see when they've lost access to post. [but, eh, I'm not sure this matters that much]
    const sharedUsers = _.difference(newPost.shareWithUsers || [], oldPost.shareWithUsers || [])
    createNotifications(sharedUsers, "postSharedWithUser", "post", newPost._id)
  }
}
addCallback("posts.edit.async", PostsEditNotifyUsersSharedOnPost);

async function PostsNewNotifyUsersSharedOnPost (post) {
  if (post.shareWithUsers?.length) {
    createNotifications(post.shareWithUsers, "postSharedWithUser", "post", post._id)
  }
}
addCallback("posts.new.async", PostsNewNotifyUsersSharedOnPost);<|endoftext|>


<commit_before>'use strict';
define(['jquery'], function ($) {
    var initializedModules = {};
    return {
        init: function (config) {
            var loadTempl;
            var injectBeacon;

            loadTempl = function (template, wrapper, params, self, cb, isMobile) {
                var callbackInit, templateSuffix, cssSuffix, initMethod, moduleJs, loadMethod;

                if (!initializedModules[template]) {
                    templateSuffix = isMobile ? '.mobi.html' : '.html';
                    cssSuffix = isMobile ? '.mobi.css' : '.css';
                    initMethod = isMobile ? 'initMobile' : 'init';
                    var requiredArray = ['../' + template, 'text!../../' + template + templateSuffix];
                    requiredArray.push('css!../../css/' + template + cssSuffix);

                    window.require(requiredArray, function (module, html) {
                        if (module === undefined) return;

                        wrapper.html(html);

                        // Create objects or Initicialize objects and store
                        if (module.type === 'Class') {
                            initializedModules[template] = new module(wrapper, self, params, isMobile, cb);
                        } else {
                            module[initMethod].call(module, wrapper, self, params, cb);
                            initializedModules[template] = module;
                        }
                    });
                } else {
                    moduleJs = initializedModules[template];
                    if (typeof moduleJs.load !== 'function') return;

                    loadMethod = isMobile ? 'loadMobile' : 'load';

                    if (moduleJs.type === 'Class') {
                        moduleJs.load(moduleJs, params, isMobile, cb);
                    } else {
                        moduleJs[loadMethod].call(moduleJs, params, cb);
                    }
                }
                injectBeacon(template);
            };
            // Beacon injection
            injectBeacon = function (template) {
                var beaconUrl = window.parent['personaBarSettings'] !== undefined ? window.parent['personaBarSettings']['beaconUrl'] : undefined;
                if (beaconUrl != undefined && beaconUrl !== "" && template !== "tasks") {
                    (new Image()).src = beaconUrl + "&f=" + encodeURI(template);
                }
            };

            return {
                loadTemplate: function (template, wrapper, params, cb) {
                    var self = this;
                    loadTempl(template, wrapper, params, self, cb, false);
                },

                loadMobileTemplate: function (template, wrapper, params, cb) {
                    var self = this;
                    loadTempl(template, wrapper, params, self, cb, true);
                },

                loadInContextAnalytics: function (template, wrapper, cb) {
                    var self = this;
                    var params = { moduleName: config.socialModule, showEngageStats: config.socialModule && config.isCommunityManager };
                    loadTempl(template, wrapper, params, self, cb, false);
                },

                loadResx: function (cb) {
                    var self = this;

                    self.sf.moduleRoot = 'personaBar';
                    self.sf.controller = 'localization';
                    self.sf.getsilence('gettable', { culture: config.culture }, function (d) {
                        self.resx = d;
                        if (typeof cb === 'function') cb();
                    });
                },

                getResx: function (moduleName, key) {
                    if (this.resx[moduleName] && this.resx[moduleName].hasOwnProperty(key)) {
                        return this.resx[moduleName][key];
                    }

                    return key;
                },

                getModuleNameByParams: function (params) {
                    return params ? (params.moduleName || '') : '';
                },

                getIdentifierByParams: function (params) {
                    return params ? (params.identifier || '') : '';
                },

                asyncParallel: function (deferreds, callback) {
                    var i = deferreds.length;
                    if (i === 0) callback();
                    var call = function () {
                        i--;
                        if (i === 0) {
                            callback();
                        }
                    };

                    $.each(deferreds, function (ii, d) {
                        d(call);
                    });
                },

                asyncWaterfall: function (deferreds, callback) {
                    var call = function () {
                        var deferred = deferreds.shift();
                        if (!deferred) {
                            callback();
                            return;
                        }
                        deferred(call);
                    };
                    call();
                },

                confirm: function (text, confirmBtn, cancelBtn, confirmHandler, cancelHandler) {
                    $('#confirmation-dialog > p').html(text);
                    $('#confirmation-dialog a#confirmbtn').html(confirmBtn).unbind('click').bind('click', function () {
                        if (typeof confirmHandler === 'function') confirmHandler.apply();
                        $('#confirmation-dialog').fadeOut(200, 'linear', function () { $('#mask').hide(); });
                    });
                    $('#confirmation-dialog a#cancelbtn').html(cancelBtn).unbind('click').bind('click', function () {
                        if (typeof cancelHandler === 'function') cancelHandler.apply();
                        $('#confirmation-dialog').fadeOut(200, 'linear', function () { $('#mask').hide(); });
                    });
                    $('#mask').show();
                    $('#confirmation-dialog').fadeIn(200, 'linear');

                    $(window).off('keydown.confirmDialog').on('keydown.confirmDialog', function (evt) {

                        if (evt.keyCode === 27) {
                            $(window).off('keydown.confirmDialog');
                            $('#confirmation-dialog a#cancelbtn').trigger('click');
                        }
                    });
                },

                notify: function (text, timeout) {
                    timeout = timeout || 2000;
                    $('#notification-dialog > p').removeClass().html(text);
                    $('#notification-dialog').fadeIn(200, 'linear', function () {
                        setTimeout(function () {
                            $('#notification-dialog').fadeOut(200, 'linear');
                        }, timeout);
                    });
                },

                notifyError: function (text, timeout) {
                    timeout = timeout || 2000;
                    $('#notification-dialog > p').removeClass().addClass('errorMessage').html(text);
                    $('#notification-dialog').fadeIn(200, 'linear', function () {
                        setTimeout(function () {
                            $('#notification-dialog').fadeOut(200, 'linear');
                        }, timeout);
                    });
                },

                localizeErrMessages: function (validator) {
                    var self = this;
                    validator.errorMessages = {
                        'required': self.resx.PersonaBar.err_Required,
                        'minLength': self.resx.PersonaBar.err_Minimum,
                        'number': self.resx.PersonaBar.err_Number,
                        'nonNegativeNumber': self.resx.PersonaBar.err_NonNegativeNumber,
                        'positiveNumber': self.resx.PersonaBar.err_PositiveNumber,
                        'nonDecimalNumber': self.resx.PersonaBar.err_NonDecimalNumber,
                        'email': self.resx.PersonaBar.err_Email
                    };
                },

                trimContentToFit: function (content, width) {
                    if (!content || !width) return '';
                    var charWidth = 8.5;
                    var max = Math.floor(width / charWidth);

                    var arr = content.split(' ');
                    var trimmed = '', count = 0;
                    $.each(arr, function (i, v) {
                        count += v.length;
                        if (count < max) {
                            if (trimmed) trimmed += ' ';
                            trimmed += v;
                            count++;
                        } else {
                            trimmed += '...';
                            return false;
                        }
                    });
                    return trimmed;
                },

                deserializeCustomDate: function (str) {
                    if (this.moment) {
                        return this.moment(str, 'YYYY-MM-DD').toDate();
                    }
                },

                serializeCustomDate: function (dateObj) {
                    if (this.moment) {
                        return this.moment(dateObj).format('YYYY-MM-DD');
                    }
                },

                getObjectCopy: function (object) {
                    if (typeof object === "object") {
                        return JSON.parse(JSON.stringify(object));
                    } else {
                        throw new Error("The object " + object + " passed in is not an object.");
                    }
                },

                throttleExecution: function (callback) {
                    if (typeof callback === "function") {
                        setTimeout(callback, 0);
                    }
                },

                ONE_THOUSAND: 1000,
                ONE_MILLION: 1000000,

                formatAbbreviateBigNumbers: function (number) {
                    var size = number;
                    var suffix;

                    if (size >= this.ONE_MILLION) {
                        size = size / this.ONE_MILLION;
                        suffix = this.resx.PersonaBar.label_OneMillionSufix;
                    } else if (size >= this.ONE_THOUSAND) {
                        size = size / this.ONE_THOUSAND;
                        suffix = this.resx.PersonaBar.label_OneThousandSufix;
                    } else {
                        return this.formatCommaSeparate(size);
                    }

                    return this.formatCommaSeparate(size.toFixed(1)) + ' ' + suffix;
                },
                getCulture(){
                    return config.culture;
                },
                getNumbersSeparatorByLocale: function () {
                    var numberWithSeparator = (1000).toLocaleString(config.culture);
                    return numberWithSeparator.indexOf(",") > 0 ? "," : ".";
                },
                formatCommaSeparate: function (number) {
                    var numbersSeparatorByLocale = this.getNumbersSeparatorByLocale();
                    while (/(\d+)(\d{3})/.test(number.toString())) {
                        number = number.toString().replace(/(\d+)(\d{3})/, '$1' + numbersSeparatorByLocale + '$2');
                    }
                    return number;
                },
                secondsFormatter: function (seconds) {
                    var oneHour = 3600;
                    var format = seconds >= oneHour ? "H:mm:ss" : "mm:ss";
                    return moment().startOf('day').add(seconds, 'seconds').format(format);
                },
                getApplicationRootPath: function getApplicationRootPath() {
                    var rootPath = location.protocol + '//' + location.host + (location.port ? (':' + location.port) : '');
                    if (rootPath.substr(rootPath.length - 1, 1) === '/') {
                        rootPath = rootPath.substr(0, rootPath.length - 1);
                    }
                    return rootPath;
                },
                getPanelIdFromPath: function getPanelIdFromPath(path) {
                    return path + '-panel';
                },
                parseQueryParameter: function (item) {
                    item.Query = '';
                    var pathInfo;
                    if (typeof item.Path !== "undefined" && item.Path.indexOf("?") > -1) {
                        pathInfo = item.Path.split('?');
                        item.Path = pathInfo[0];
                        item.Query = pathInfo[1];
                    } else if (typeof item.path !== "undefined" && item.path.indexOf("?") > -1) {
                        pathInfo = item.path.split('?');
                        item.path = pathInfo[0];
                        item.query = pathInfo[1];
                    }
                },

                /**
                * Builds the view model that will be used to
                * create the DOM structure for the Persona Bar menu
                *
                * @method buildMenuViewModel
                * @param {Object} menuStructure the menu structured stored in config object
                * @param {Boolean} isMobile flag that tell you if you are in mobile version of the Persona Bar
                * @return {Object} view model that will be used to build the HTML DOM of the menu
                */
                buildMenuViewModel: function buildMenuViewModel(menuStructure, isMobile) {

                    var menu = {
                        menuItems: []
                    };

                    var util = this;
                    menuStructure.MenuItems.forEach(function (menuItem) {
                        if (isMobile && !menuItem.MobileSupport) {
                            return;
                        }
                        util.parseQueryParameter(menuItem);
                        var topMenuItem = {
                            id: menuItem.Identifier,
                            resourceKey: menuItem.ResourceKey,
                            moduleName: menuItem.ModuleName,
                            path: menuItem.Path,
                            query: menuItem.Query,
                            link: menuItem.Link,
                            css: menuItem.CssClass,
                            displayName: menuItem.DisplayName,
                            settings: menuItem.Settings,
                            menuItems: []
                        }
                        if (menuItem.Children) {
                            menuItem.Children.forEach(function (menuItem) {
                                if (isMobile && !menuItem.MobileSupport) {
                                    return;
                                }

                                util.parseQueryParameter(menuItem);
                                var subMenuItem = {
                                    id: menuItem.Identifier,
                                    resourceKey: menuItem.ResourceKey,
                                    moduleName: menuItem.ModuleName,
                                    path: menuItem.Path,
                                    query: menuItem.Query,
                                    link: menuItem.Link,
                                    css: menuItem.CssClass,
                                    displayName: menuItem.DisplayName,
                                    settings: menuItem.Settings
                                }
                                topMenuItem.menuItems.push(subMenuItem);
                            });
                        }

                        //parse menu items into columns
                        var firstColumn, secondColumn;
                        if (topMenuItem.menuItems.length === 0) {
                            topMenuItem.menuItems = [];
                        } else if (topMenuItem.menuItems.length < 9) {
                            topMenuItem.menuItems = [topMenuItem.menuItems];
                        } else if (topMenuItem.menuItems.length <= 18) {
                            var count = topMenuItem.menuItems.length / 2;
                            if (topMenuItem.menuItems.length % 2 !== 0) {
                                count++;
                            }
                            firstColumn = topMenuItem.menuItems.splice(0, count);
                            topMenuItem.menuItems = [firstColumn, topMenuItem.menuItems];
                            topMenuItem.css += " two-columns-menu";
                        } else {
                            firstColumn = topMenuItem.menuItems.splice(0, 7);
                            secondColumn = topMenuItem.menuItems.splice(0, 7);
                            topMenuItem.menuItems = [firstColumn, secondColumn, topMenuItem.menuItems];
                            topMenuItem.css += " three-columns-menu";
                        }

                        menu.menuItems.push(topMenuItem);
                    });

                    return {
                        menu: menu
                    };
                },

                /**
                * Gets the path defined by the first menu item with a
                * given module name
                *
                * @method getPathByModuleName
                * @param {Object} menuStructure the menu structured stored in config object
                * @param {String} moduleName moduleName
                * @return {String} path
                */
                getPathByModuleName: function getPathByModuleName(menuStructure, moduleName) {
                    var path = null;
                    menuStructure.MenuItems.forEach(function (menuItem) {
                        if (menuItem.ModuleName === moduleName) {
                            path = menuItem.Path;
                            return;
                        }

                        if (menuItem.Children) {
                            menuItem.Children.forEach(function (menuItem) {
                                if (menuItem.ModuleName === moduleName) {
                                    path = menuItem.Path;
                                    return;
                                }
                            });
                        }
                    });
                    return path;
                }
            };
        }
    };
});

define('css', {
    load: function (name, require, load, config) {
        function inject(filename) {
            var head = document.getElementsByTagName('head')[0];
            var link = document.createElement('link');
            link.href = filename;
            link.rel = 'stylesheet';
            link.type = 'text/css';
            head.appendChild(link);
        }

        var path = name;
        for (var i in config.paths) {
            if (path.indexOf(i) === 0) {
                path = path.replace(i, config.paths[i]);
                break;
            }
        }

        if (path.indexOf('://') === -1) {
            path = config.baseUrl + path;
        }

        inject(path + '?' + config.urlArgs);
        load(true);
    },
    pluginBuilder: './css-build'
});;
<commit_msg>AP-391 - Fix ecma6 sintax. Not supported by IE<commit_after>'use strict';
define(['jquery'], function ($) {
    var initializedModules = {};
    return {
        init: function (config) {
            var loadTempl;
            var injectBeacon;

            loadTempl = function (template, wrapper, params, self, cb, isMobile) {
                var callbackInit, templateSuffix, cssSuffix, initMethod, moduleJs, loadMethod;

                if (!initializedModules[template]) {
                    templateSuffix = isMobile ? '.mobi.html' : '.html';
                    cssSuffix = isMobile ? '.mobi.css' : '.css';
                    initMethod = isMobile ? 'initMobile' : 'init';
                    var requiredArray = ['../' + template, 'text!../../' + template + templateSuffix];
                    requiredArray.push('css!../../css/' + template + cssSuffix);

                    window.require(requiredArray, function (module, html) {
                        if (module === undefined) return;

                        wrapper.html(html);

                        // Create objects or Initicialize objects and store
                        if (module.type === 'Class') {
                            initializedModules[template] = new module(wrapper, self, params, isMobile, cb);
                        } else {
                            module[initMethod].call(module, wrapper, self, params, cb);
                            initializedModules[template] = module;
                        }
                    });
                } else {
                    moduleJs = initializedModules[template];
                    if (typeof moduleJs.load !== 'function') return;

                    loadMethod = isMobile ? 'loadMobile' : 'load';

                    if (moduleJs.type === 'Class') {
                        moduleJs.load(moduleJs, params, isMobile, cb);
                    } else {
                        moduleJs[loadMethod].call(moduleJs, params, cb);
                    }
                }
                injectBeacon(template);
            };
            // Beacon injection
            injectBeacon = function (template) {
                var beaconUrl = window.parent['personaBarSettings'] !== undefined ? window.parent['personaBarSettings']['beaconUrl'] : undefined;
                if (beaconUrl != undefined && beaconUrl !== "" && template !== "tasks") {
                    (new Image()).src = beaconUrl + "&f=" + encodeURI(template);
                }
            };

            return {
                loadTemplate: function (template, wrapper, params, cb) {
                    var self = this;
                    loadTempl(template, wrapper, params, self, cb, false);
                },

                loadMobileTemplate: function (template, wrapper, params, cb) {
                    var self = this;
                    loadTempl(template, wrapper, params, self, cb, true);
                },

                loadInContextAnalytics: function (template, wrapper, cb) {
                    var self = this;
                    var params = { moduleName: config.socialModule, showEngageStats: config.socialModule && config.isCommunityManager };
                    loadTempl(template, wrapper, params, self, cb, false);
                },

                loadResx: function (cb) {
                    var self = this;

                    self.sf.moduleRoot = 'personaBar';
                    self.sf.controller = 'localization';
                    self.sf.getsilence('gettable', { culture: config.culture }, function (d) {
                        self.resx = d;
                        if (typeof cb === 'function') cb();
                    });
                },

                getResx: function (moduleName, key) {
                    if (this.resx[moduleName] && this.resx[moduleName].hasOwnProperty(key)) {
                        return this.resx[moduleName][key];
                    }

                    return key;
                },

                getModuleNameByParams: function (params) {
                    return params ? (params.moduleName || '') : '';
                },

                getIdentifierByParams: function (params) {
                    return params ? (params.identifier || '') : '';
                },

                asyncParallel: function (deferreds, callback) {
                    var i = deferreds.length;
                    if (i === 0) callback();
                    var call = function () {
                        i--;
                        if (i === 0) {
                            callback();
                        }
                    };

                    $.each(deferreds, function (ii, d) {
                        d(call);
                    });
                },

                asyncWaterfall: function (deferreds, callback) {
                    var call = function () {
                        var deferred = deferreds.shift();
                        if (!deferred) {
                            callback();
                            return;
                        }
                        deferred(call);
                    };
                    call();
                },

                confirm: function (text, confirmBtn, cancelBtn, confirmHandler, cancelHandler) {
                    $('#confirmation-dialog > p').html(text);
                    $('#confirmation-dialog a#confirmbtn').html(confirmBtn).unbind('click').bind('click', function () {
                        if (typeof confirmHandler === 'function') confirmHandler.apply();
                        $('#confirmation-dialog').fadeOut(200, 'linear', function () { $('#mask').hide(); });
                    });
                    $('#confirmation-dialog a#cancelbtn').html(cancelBtn).unbind('click').bind('click', function () {
                        if (typeof cancelHandler === 'function') cancelHandler.apply();
                        $('#confirmation-dialog').fadeOut(200, 'linear', function () { $('#mask').hide(); });
                    });
                    $('#mask').show();
                    $('#confirmation-dialog').fadeIn(200, 'linear');

                    $(window).off('keydown.confirmDialog').on('keydown.confirmDialog', function (evt) {

                        if (evt.keyCode === 27) {
                            $(window).off('keydown.confirmDialog');
                            $('#confirmation-dialog a#cancelbtn').trigger('click');
                        }
                    });
                },

                notify: function (text, timeout) {
                    timeout = timeout || 2000;
                    $('#notification-dialog > p').removeClass().html(text);
                    $('#notification-dialog').fadeIn(200, 'linear', function () {
                        setTimeout(function () {
                            $('#notification-dialog').fadeOut(200, 'linear');
                        }, timeout);
                    });
                },

                notifyError: function (text, timeout) {
                    timeout = timeout || 2000;
                    $('#notification-dialog > p').removeClass().addClass('errorMessage').html(text);
                    $('#notification-dialog').fadeIn(200, 'linear', function () {
                        setTimeout(function () {
                            $('#notification-dialog').fadeOut(200, 'linear');
                        }, timeout);
                    });
                },

                localizeErrMessages: function (validator) {
                    var self = this;
                    validator.errorMessages = {
                        'required': self.resx.PersonaBar.err_Required,
                        'minLength': self.resx.PersonaBar.err_Minimum,
                        'number': self.resx.PersonaBar.err_Number,
                        'nonNegativeNumber': self.resx.PersonaBar.err_NonNegativeNumber,
                        'positiveNumber': self.resx.PersonaBar.err_PositiveNumber,
                        'nonDecimalNumber': self.resx.PersonaBar.err_NonDecimalNumber,
                        'email': self.resx.PersonaBar.err_Email
                    };
                },

                trimContentToFit: function (content, width) {
                    if (!content || !width) return '';
                    var charWidth = 8.5;
                    var max = Math.floor(width / charWidth);

                    var arr = content.split(' ');
                    var trimmed = '', count = 0;
                    $.each(arr, function (i, v) {
                        count += v.length;
                        if (count < max) {
                            if (trimmed) trimmed += ' ';
                            trimmed += v;
                            count++;
                        } else {
                            trimmed += '...';
                            return false;
                        }
                    });
                    return trimmed;
                },

                deserializeCustomDate: function (str) {
                    if (this.moment) {
                        return this.moment(str, 'YYYY-MM-DD').toDate();
                    }
                },

                serializeCustomDate: function (dateObj) {
                    if (this.moment) {
                        return this.moment(dateObj).format('YYYY-MM-DD');
                    }
                },

                getObjectCopy: function (object) {
                    if (typeof object === "object") {
                        return JSON.parse(JSON.stringify(object));
                    } else {
                        throw new Error("The object " + object + " passed in is not an object.");
                    }
                },

                throttleExecution: function (callback) {
                    if (typeof callback === "function") {
                        setTimeout(callback, 0);
                    }
                },

                ONE_THOUSAND: 1000,
                ONE_MILLION: 1000000,

                formatAbbreviateBigNumbers: function (number) {
                    var size = number;
                    var suffix;

                    if (size >= this.ONE_MILLION) {
                        size = size / this.ONE_MILLION;
                        suffix = this.resx.PersonaBar.label_OneMillionSufix;
                    } else if (size >= this.ONE_THOUSAND) {
                        size = size / this.ONE_THOUSAND;
                        suffix = this.resx.PersonaBar.label_OneThousandSufix;
                    } else {
                        return this.formatCommaSeparate(size);
                    }

                    return this.formatCommaSeparate(size.toFixed(1)) + ' ' + suffix;
                },
				getCulture: function () {
                    return config.culture;
                },
                getNumbersSeparatorByLocale: function () {
                    var numberWithSeparator = (1000).toLocaleString(config.culture);
                    return numberWithSeparator.indexOf(",") > 0 ? "," : ".";
                },
                formatCommaSeparate: function (number) {
                    var numbersSeparatorByLocale = this.getNumbersSeparatorByLocale();
                    while (/(\d+)(\d{3})/.test(number.toString())) {
                        number = number.toString().replace(/(\d+)(\d{3})/, '$1' + numbersSeparatorByLocale + '$2');
                    }
                    return number;
                },
                secondsFormatter: function (seconds) {
                    var oneHour = 3600;
                    var format = seconds >= oneHour ? "H:mm:ss" : "mm:ss";
                    return moment().startOf('day').add(seconds, 'seconds').format(format);
                },
                getApplicationRootPath: function getApplicationRootPath() {
                    var rootPath = location.protocol + '//' + location.host + (location.port ? (':' + location.port) : '');
                    if (rootPath.substr(rootPath.length - 1, 1) === '/') {
                        rootPath = rootPath.substr(0, rootPath.length - 1);
                    }
                    return rootPath;
                },
                getPanelIdFromPath: function getPanelIdFromPath(path) {
                    return path + '-panel';
                },
                parseQueryParameter: function (item) {
                    item.Query = '';
                    var pathInfo;
                    if (typeof item.Path !== "undefined" && item.Path.indexOf("?") > -1) {
                        pathInfo = item.Path.split('?');
                        item.Path = pathInfo[0];
                        item.Query = pathInfo[1];
                    } else if (typeof item.path !== "undefined" && item.path.indexOf("?") > -1) {
                        pathInfo = item.path.split('?');
                        item.path = pathInfo[0];
                        item.query = pathInfo[1];
                    }
                },

                /**
                * Builds the view model that will be used to
                * create the DOM structure for the Persona Bar menu
                *
                * @method buildMenuViewModel
                * @param {Object} menuStructure the menu structured stored in config object
                * @param {Boolean} isMobile flag that tell you if you are in mobile version of the Persona Bar
                * @return {Object} view model that will be used to build the HTML DOM of the menu
                */
                buildMenuViewModel: function buildMenuViewModel(menuStructure, isMobile) {

                    var menu = {
                        menuItems: []
                    };

                    var util = this;
                    menuStructure.MenuItems.forEach(function (menuItem) {
                        if (isMobile && !menuItem.MobileSupport) {
                            return;
                        }
                        util.parseQueryParameter(menuItem);
                        var topMenuItem = {
                            id: menuItem.Identifier,
                            resourceKey: menuItem.ResourceKey,
                            moduleName: menuItem.ModuleName,
                            path: menuItem.Path,
                            query: menuItem.Query,
                            link: menuItem.Link,
                            css: menuItem.CssClass,
                            displayName: menuItem.DisplayName,
                            settings: menuItem.Settings,
                            menuItems: []
                        }
                        if (menuItem.Children) {
                            menuItem.Children.forEach(function (menuItem) {
                                if (isMobile && !menuItem.MobileSupport) {
                                    return;
                                }

                                util.parseQueryParameter(menuItem);
                                var subMenuItem = {
                                    id: menuItem.Identifier,
                                    resourceKey: menuItem.ResourceKey,
                                    moduleName: menuItem.ModuleName,
                                    path: menuItem.Path,
                                    query: menuItem.Query,
                                    link: menuItem.Link,
                                    css: menuItem.CssClass,
                                    displayName: menuItem.DisplayName,
                                    settings: menuItem.Settings
                                }
                                topMenuItem.menuItems.push(subMenuItem);
                            });
                        }

                        //parse menu items into columns
                        var firstColumn, secondColumn;
                        if (topMenuItem.menuItems.length === 0) {
                            topMenuItem.menuItems = [];
                        } else if (topMenuItem.menuItems.length < 9) {
                            topMenuItem.menuItems = [topMenuItem.menuItems];
                        } else if (topMenuItem.menuItems.length <= 18) {
                            var count = topMenuItem.menuItems.length / 2;
                            if (topMenuItem.menuItems.length % 2 !== 0) {
                                count++;
                            }
                            firstColumn = topMenuItem.menuItems.splice(0, count);
                            topMenuItem.menuItems = [firstColumn, topMenuItem.menuItems];
                            topMenuItem.css += " two-columns-menu";
                        } else {
                            firstColumn = topMenuItem.menuItems.splice(0, 7);
                            secondColumn = topMenuItem.menuItems.splice(0, 7);
                            topMenuItem.menuItems = [firstColumn, secondColumn, topMenuItem.menuItems];
                            topMenuItem.css += " three-columns-menu";
                        }

                        menu.menuItems.push(topMenuItem);
                    });

                    return {
                        menu: menu
                    };
                },

                /**
                * Gets the path defined by the first menu item with a
                * given module name
                *
                * @method getPathByModuleName
                * @param {Object} menuStructure the menu structured stored in config object
                * @param {String} moduleName moduleName
                * @return {String} path
                */
                getPathByModuleName: function getPathByModuleName(menuStructure, moduleName) {
                    var path = null;
                    menuStructure.MenuItems.forEach(function (menuItem) {
                        if (menuItem.ModuleName === moduleName) {
                            path = menuItem.Path;
                            return;
                        }

                        if (menuItem.Children) {
                            menuItem.Children.forEach(function (menuItem) {
                                if (menuItem.ModuleName === moduleName) {
                                    path = menuItem.Path;
                                    return;
                                }
                            });
                        }
                    });
                    return path;
                }
            };
        }
    };
});

define('css', {
    load: function (name, require, load, config) {
        function inject(filename) {
            var head = document.getElementsByTagName('head')[0];
            var link = document.createElement('link');
            link.href = filename;
            link.rel = 'stylesheet';
            link.type = 'text/css';
            head.appendChild(link);
        }

        var path = name;
        for (var i in config.paths) {
            if (path.indexOf(i) === 0) {
                path = path.replace(i, config.paths[i]);
                break;
            }
        }

        if (path.indexOf('://') === -1) {
            path = config.baseUrl + path;
        }

        inject(path + '?' + config.urlArgs);
        load(true);
    },
    pluginBuilder: './css-build'
});;
<|endoftext|>


<commit_before>var ZBaseMainMenu = function() {
  var render = function(elem, path) {
    var tpl = $.getTemplate(
        "widgets/zbase-main-menu",
        "zbase_main_menu_tpl");

    setActiveMenuItem(tpl, "/a/sql");

    elem.appendChild(tpl);
  };

  var setActiveMenuItem = function(tpl, path) {
    var items = tpl.querySelectorAll("a");
    var active_path_length = 0;
    var active_item;

    for (var i = 0; i < items.length; i++) {
      var current_path = items[i].getAttribute("href");
      if (path.indexOf(current_path) == 0 &&
          current_path.length > active_path_length) {
              active_item = items[i];
              active_path_length = current_path.length;
      }
    }

    active_item.setAttribute("data-active", "active");
  };

  return {
    render: render
  }
};
<commit_msg>main_menu: set active item only if path matches item link<commit_after>var ZBaseMainMenu = function() {
  var render = function(elem, path) {
    var tpl = $.getTemplate(
        "widgets/zbase-main-menu",
        "zbase_main_menu_tpl");

    setActiveMenuItem(tpl, path);
    $.replaceContent(elem, tpl);
  };

  var setActiveMenuItem = function(tpl, path) {
    var items = tpl.querySelectorAll("a");
    var active_path_length = 0;
    var active_item;

    for (var i = 0; i < items.length; i++) {
      var current_path = items[i].getAttribute("href");
      if (path.indexOf(current_path) == 0 &&
          current_path.length > active_path_length) {
              active_item = items[i];
              active_path_length = current_path.length;
      }
    }

    if (active_item) {
      active_item.setAttribute("data-active", "active");
    }
  };

  return {
    render: render
  }
};
<|endoftext|>


<commit_before>Package.describe({
  name: 'ostrio:files',
  version: '1.3.9',
  summary: 'Upload, Store and Stream (Video & Audio streaming) files to/from file system (FS) via DDP and HTTP',
  git: 'https://github.com/VeliovGroup/Meteor-Files',
  documentation: 'README.md'
});

Package.onUse(function(api) {
  api.versionsFrom('1.1');
  api.addFiles('files.coffee');
  api.use(['templating', 'reactive-var', 'tracker'], 'client');
  api.use(['underscore', 'check', 'sha', 'ostrio:cookies@2.0.0', 'random', 'coffeescript', 'iron:router@1.0.12', 'aldeed:collection2@2.5.0'], ['client', 'server']);
});

Npm.depends({
  'fs-extra': '0.22.1',
  'file-type': '2.10.2',
  'request': '2.58.0'
});<commit_msg>v1.3.10<commit_after>Package.describe({
  name: 'ostrio:files',
  version: '1.3.10',
  summary: 'Upload, Store and Stream (Video & Audio streaming) files to/from file system (FS) via DDP and HTTP',
  git: 'https://github.com/VeliovGroup/Meteor-Files',
  documentation: 'README.md'
});

Package.onUse(function(api) {
  api.versionsFrom('1.1');
  api.addFiles('files.coffee');
  api.use(['templating', 'reactive-var', 'tracker'], 'client');
  api.use(['underscore', 'check', 'sha', 'ostrio:cookies@2.0.1', 'random', 'coffeescript', 'iron:router@1.0.12', 'aldeed:collection2@2.5.0'], ['client', 'server']);
});

Npm.depends({
  'fs-extra': '0.22.1',
  'file-type': '2.10.2',
  'request': '2.58.0'
});<|endoftext|>