<commit_before>!function () {

  // Action overflow
  var checkActionOverflow = function () {

    var actionBars = document.querySelectorAll('.action-bar'),
        a = actionBars.length,
        cleanUp = document.querySelectorAll('.action-overflow'),
        c = cleanUp.length;

    // Clean up the existing action overflows
    while (cleanUp && c--) cleanUp[c].parentNode.removeChild(cleanUp[c]);

    // Do this only when the screen width is below or equal to 480 pixels
    if (window.innerWidth <= 480) {

      // Iterate over all action bars
      while (a--) {
        var actionButtons = actionBars[a].querySelectorAll('.actions .action');

        if (actionButtons.length > 2) {

          // Maintain the first item then replace the rest with an action overflow
          var first = actionButtons[0],
              i = actionButtons.length,
              overflowList = document.createElement('ol'), // This goes inside overflowListItem
              overflowListItem = document.createElement('li'),
              overflowButton = document.createElement('a'),
              overflowIcon = document.createElement('i');

          // Reverse the list since we're iterating it backwards
          overflowList.setAttribute('reversed', 'reversed');

          overflowList.classList.add('action-overflow-list');
          overflowList.classList.add('spinner');

          // Hide the overflow
          while(i-- > 1) {
            actionButtons[i].parentNode.classList.add('action-overflow-hidden');

            var li = document.createElement('li'),
                anchor = document.createElement('a');

            anchor.innerHTML = actionButtons[i].getAttribute('title');
            anchor.setAttribute('href', actionButtons[i].getAttribute('href'));

            // Copy over all stack-related data attributes
            anchor.setAttribute('data-transition', actionButtons[i].getAttribute('data-transition'));
            anchor.setAttribute('data-timeout', actionButtons[i].getAttribute('data-timeout'));
            anchor.setAttribute('data-ignore', actionButtons[i].getAttribute('data-ignore'));

            li.classList.add('spinner-item');
            li.appendChild(anchor);
            overflowList.appendChild(li);
          }

          // Add the action overflow button
          overflowButton.classList.add('action');
          overflowButton.classList.add('action-overflow-icon');
          overflowButton.classList.add('toggle-spinner');
          overflowButton.appendChild(overflowIcon);

          overflowListItem.classList.add('action-overflow');
          overflowListItem.appendChild(overflowButton);
          overflowListItem.appendChild(overflowList);

          actionBars[a].querySelector('.actions').appendChild(overflowListItem);
        }
      }

    }
    else {
      // Iterate over all action bars
      while (a--) {
        var actionButtons = actionBars[a].querySelectorAll('.actions .action')
            i = actionButtons.length;

        // Un-overflow the action buttons
        while (i--) {
          actionButtons[i].parentNode.classList.remove('action-overflow-hidden');
        }
      }
    }
  }

  // Attach the event handlers
  window.addEventListener('load', checkActionOverflow, false);
  window.addEventListener('resize', checkActionOverflow, false);
  window.addEventListener('popstate', checkActionOverflow, false);

}();<commit_msg>Add option to disable action overflow on an action bar<commit_after>!function () {

  // Action overflow
  var checkActionOverflow = function () {

    var actionBars = document.querySelectorAll('.action-bar'),
        a = actionBars.length,
        cleanUp = document.querySelectorAll('.action-overflow'),
        c = cleanUp.length;

    // Clean up the existing action overflows
    while (cleanUp && c--) cleanUp[c].parentNode.removeChild(cleanUp[c]);

    // Do this only when the screen width is below or equal to 480 pixels
    if (window.innerWidth <= 480) {

      // Iterate over all action bars
      while (a--) {
        var actions = actionBars[a].querySelector('.actions'),
            actionButtons = actionBars[a].querySelectorAll('.actions .action');

        if (actionButtons.length > 2 && actions.getAttribute('data-overflow') !== "false") {

          // Maintain the first item then replace the rest with an action overflow
          var first = actionButtons[0],
              i = actionButtons.length,
              overflowList = document.createElement('ol'), // This goes inside overflowListItem
              overflowListItem = document.createElement('li'),
              overflowButton = document.createElement('a'),
              overflowIcon = document.createElement('i');

          // Reverse the list since we're iterating it backwards
          overflowList.setAttribute('reversed', 'reversed');

          overflowList.classList.add('action-overflow-list');
          overflowList.classList.add('spinner');

          // Hide the overflow
          while(i-- > 1) {
            actionButtons[i].parentNode.classList.add('action-overflow-hidden');

            var li = document.createElement('li'),
                anchor = document.createElement('a');

            anchor.innerHTML = actionButtons[i].getAttribute('title');
            anchor.setAttribute('href', actionButtons[i].getAttribute('href'));

            // Copy over all stack-related data attributes
            anchor.setAttribute('data-transition', actionButtons[i].getAttribute('data-transition'));
            anchor.setAttribute('data-timeout', actionButtons[i].getAttribute('data-timeout'));
            anchor.setAttribute('data-ignore', actionButtons[i].getAttribute('data-ignore'));

            li.classList.add('spinner-item');
            li.appendChild(anchor);
            overflowList.appendChild(li);
          }

          // Add the action overflow button
          overflowButton.classList.add('action');
          overflowButton.classList.add('action-overflow-icon');
          overflowButton.classList.add('toggle-spinner');
          overflowButton.appendChild(overflowIcon);

          overflowListItem.classList.add('action-overflow');
          overflowListItem.appendChild(overflowButton);
          overflowListItem.appendChild(overflowList);

          actionBars[a].querySelector('.actions').appendChild(overflowListItem);
        }
      }

    }
    else {
      // Iterate over all action bars
      while (a--) {
        var actionButtons = actionBars[a].querySelectorAll('.actions .action')
            i = actionButtons.length;

        // Un-overflow the action buttons
        while (i--) {
          actionButtons[i].parentNode.classList.remove('action-overflow-hidden');
        }
      }
    }
  }

  // Attach the event handlers
  window.addEventListener('load', checkActionOverflow, false);
  window.addEventListener('resize', checkActionOverflow, false);
  window.addEventListener('popstate', checkActionOverflow, false);

}();<|endoftext|>


<commit_before>(function Calcite () {

var calcite = {
  version: '0.0.9'
};

// ┌───────────────┐
// │ DOM Utilities │
// └───────────────┘

calcite.dom = {};

// ┌──────────────────────┐
// │ DOM Event Management │
// └──────────────────────┘

// returns standard interaction event, later will add touch support
calcite.dom.event = function () {
  return 'click';
};

// add a callback function to an event on a DOM node
calcite.dom.addEvent = function (domNode, event, fn) {
  if (domNode.addEventListener) {
    return domNode.addEventListener(event, fn, false);
  }
  if (domNode.attachEvent) {
    return domNode.attachEvent('on' + event, fn);
  }
};

// remove a specific function binding from a DOM node event
calcite.dom.removeEvent = function (domNode, event, fn) {
  if (domNode.removeEventListener) {
    return domNode.removeEventListener(event, fn, false);
  }
  if (domNode.detachEvent) {
    return domNode.detachEvent('on' + event,  fn);
  }
};

// get the target element of an event
calcite.dom.eventTarget = function (event) {
  if (!event.target) {
    return event.srcElement;
  }
  if (event.target) {
    return event.target;
  }
};

// prevent default behavior of an event
calcite.dom.preventDefault = function (event) {
  if (event.preventDefault) {
    return event.preventDefault();
  }
  if (event.returnValue) {
    event.returnValue = false;
  }
};

// stop and event from bubbling up the DOM tree
calcite.dom.stopPropagation = function (event) {
  event = event || window.event;
  if (event.stopPropagation) {
    return event.stopPropagation();
  }
  if (event.cancelBubble) {
    event.cancelBubble = true;
  }
};

// ┌────────────────────┐
// │ Class Manipulation │
// └────────────────────┘

// check if an element has a specific class
calcite.dom.hasClass = function (domNode, className) {
  var exp = new RegExp(' ' + className + ' ');
  if (exp.test(' ' + domNode.className + ' ')) {
    return true;
  }

  return false;
};

// add one or more classes to an element
calcite.dom.addClass = function (domNode, classes) {
  classes = classes.split(' ');

  for (var i = 0; i < classes.length; i++) {
    if (!calcite.dom.hasClass(domNode, classes[i])) {
      domNode.className += ' ' + classes[i];
    }
  }
};

// remove one or more classes from an element
calcite.dom.removeClass = function (domNode, classes) {
  classes = classes.split(' ');

  for (var i = 0; i < classes.length; i++) {
    var newClass = ' ' + domNode.className.replace( /[\t\r\n]/g, ' ') + ' ';

    if (calcite.dom.hasClass(domNode, classes[i])) {
      while (newClass.indexOf(' ' + classes[i] + ' ') >= 0) {
        newClass = newClass.replace(' ' + classes[i] + ' ', ' ');
      }

      domNode.className = newClass.replace(/^\s+|\s+$/g, '');
    }
  }
};

// ┌───────────────┐
// │ DOM Traversal │
// └───────────────┘

// returns closest element up the DOM tree matching a given class
calcite.dom.closest = function (className, context) {
  var result, current;
  for (current = context; current; current = current.parentNode) {
    if (current.nodeType === 1 && calcite.dom.hasClass(current, className)) {
      result = current;
      break;
    }
  }
  return current;
};

// get an attribute for an element
calcite.dom.getAttr = function(domNode, attr) {
  if (domNode.getAttribute) {
    return domNode.getAttribute(attr);
  }

  var result;
  var attrs = domNode.attributes;

  for (var i = 0; i < attrs.length; i++) {
    if (attrs[i].nodeName === attr) {
      result = attrs[i].nodeValue;
    }
  }

  return result;
};

// ┌───────────────────┐
// │ Object Conversion │
// └───────────────────┘

// turn a domNodeList into an array
calcite.dom.nodeListToArray = function (domNodeList) {
  var array = [];
  for (var i = 0; i < domNodeList.length; i++) {
    array.push(domNodeList[i]);
  }
  return array;
};

// ┌────────────────────┐
// │ Array Manipulation │
// └────────────────────┘

calcite.arr = {};

// return the index of an object in an array with optional offset
calcite.arr.indexOf = function (obj, arr, offset) {
  var i = offset || 0;

  if (arr.indexOf) {
    return arr.indexOf(obj, i);
  }

  for (i; i < arr.length; i++) {
    if (arr[i] === obj) {
      return i;
    }
  }

  return -1;
};

// ┌───────────────────────────┐
// │ Browser Feature Detection │
// └───────────────────────────┘
// detect features like touch, ie, etc.

calcite.browser = {};

// detect touch, could be improved for more coverage
calcite.browser.isTouch = function () {
  if (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0)) {
    return true;
  }
  return false;
};

// ┌─────────────┐
// │ JS Patterns │
// └─────────────┘
// javascript logic for ui patterns

function findElements (className) {
  var elements = document.querySelectorAll(className);
  if (elements.length) {
    return calcite.dom.nodeListToArray(elements);
  } else {
    return false;
  }
}

// remove 'is-active' class from every element in an array
function removeActive (array) {
  if (typeof array == 'object') {
    array = calcite.dom.nodeListToArray(array);
  }
  array.forEach(function (item) {
    calcite.dom.removeClass(item, 'is-active');
  });
}

// remove 'is-active' from array, add to element
function toggleActive (array, el) {
  var isActive = calcite.dom.hasClass(el, 'is-active');
  if (isActive) {
    calcite.dom.removeClass(el, 'is-active');
  } else {
    removeActive(array);
    calcite.dom.addClass(el, 'is-active');
  }
}

// ┌───────────┐
// │ Accordion │
// └───────────┘
// collapsible accordion list

calcite.accordion = function () {
  var accordions = findElements('.js-accordion');

  if (!accordions) {
    return;
  }

  for (var i = 0; i < accordions.length; i++) {
    var children = accordions[i].children;
    for (var j = 0; j < children.length; j++) {
      calcite.dom.addEvent(children[j], calcite.dom.event(), toggleAccordion);
    }
  }

  function toggleAccordion (event) {
    var parent = calcite.dom.closest('accordion-section', calcite.dom.eventTarget(event));
    if (calcite.dom.hasClass(parent, 'is-active')) {
      calcite.dom.removeClass(parent, 'is-active');
    } else {
      calcite.dom.addClass(parent, 'is-active');
    }
  }

};

// ┌──────────┐
// │ Carousel │
// └──────────┘
// show carousel with any number of slides

calcite.carousel = function () {

  var carousels = findElements('.js-carousel');

  if (!carousels) {
    return;
  }

  for (var i = 0; i < carousels.length; i++) {

    var carousel = carousels[i];
    var wrapper = carousel.querySelectorAll('.carousel-slides')[0];
    var slides = carousel.querySelectorAll('.carousel-slide');
    var toggles = calcite.dom.nodeListToArray(carousel.querySelectorAll('.js-carousel-link'));

    wrapper.style.width = slides.length * 100 + '%';

    calcite.dom.addClass(slides[0], 'is-active');
    calcite.dom.addClass(carousel, 'is-first-slide');

    for (var k = 0; k < slides.length; k++) {
      slides[k].style.width = 100 / slides.length + '%';
    }

    for (var j = 0; j < toggles.length; j++) {
      calcite.dom.addEvent(toggles[j], calcite.dom.event(), toggleSlide);
    }

  }

  function toggleSlide (e) {
    calcite.dom.preventDefault(e);
    var link = calcite.dom.eventTarget(e);
    var index = calcite.dom.getAttr(link, 'data-slide');
    var carousel = calcite.dom.closest('carousel', link);
    var current = carousel.querySelectorAll('.carousel-slide.is-active')[0];
    var slides = carousel.querySelectorAll('.carousel-slide');
    var wrapper = carousel.querySelectorAll('.carousel-slides')[0];

    if (index == 'prev') {
      index = calcite.arr.indexOf(current, slides);
      if (index === 0) { index = 1; }
    } else if (index == 'next') {
      index = calcite.arr.indexOf(current, slides) + 2;
      if (index > slides.length) { index = slides.length; }
    }

    calcite.dom.removeClass(carousel, 'is-first-slide is-last-slide');

    if (index == slides.length) { calcite.dom.addClass(carousel, 'is-last-slide');}
    if (index == 1) { calcite.dom.addClass(carousel, 'is-first-slide');}

    removeActive(slides);
    calcite.dom.addClass(slides[index - 1], 'is-active');
    var offset = (index - 1)/slides.length * -100 + '%';
    wrapper.style.transform= 'translate3d(' + offset + ',0,0)';
  }

};

// ┌──────────┐
// │ Dropdown │
// └──────────┘
// show and hide dropdown menus

calcite.dropdown = function () {
  var toggles = findElements('.js-dropdown-toggle');
  var dropdowns = findElements('.js-dropdown');
  if (!dropdowns) {
    return;
  }

  function closeAllDropdowns () {
    for (var i = 0; i < dropdowns.length; i++) {
      calcite.dom.removeClass(dropdowns[i], 'is-active');
    }
  }

  function toggleDropdown (dropdown) {
    var isActive = calcite.dom.hasClass(dropdown, 'is-active');
    if (isActive) {
      calcite.dom.removeClass(dropdown, 'is-active');
    } else {
      closeAllDropdowns();
      calcite.dom.addClass(dropdown, 'is-active');
      calcite.dom.addEvent(document.body, calcite.dom.event(), function(event) {
        closeAllDropdowns();
      });
    }
  }

  function bindDropdown (toggle) {
    calcite.dom.addEvent(toggle, calcite.dom.event(), function(event) {
      calcite.dom.preventDefault(event);
      calcite.dom.stopPropagation(event);
      var dropdown = calcite.dom.closest('js-dropdown', toggle);
      toggleDropdown(dropdown);
    });
  }

  for (var i = 0; i < toggles.length; i++) {
    bindDropdown(toggles[i]);
  }
};

// ┌────────┐
// │ Drawer │
// └────────┘
// show and hide drawers
calcite.drawer = function () {

  var toggles = findElements('.js-drawer-toggle');
  var drawers = findElements('.js-drawer');

  if (!drawers) {
    return;
  }

  function bindToggle (toggle) {
    calcite.dom.addEvent(toggle, calcite.dom.event(), function(event) {
      calcite.dom.preventDefault(event);
      var target = calcite.dom.getAttr(toggle, 'data-drawer');
      for (var i = 0; i < drawers.length; i++) {
        var drawer = drawers[i];
        var isTarget = calcite.dom.getAttr(drawers[i], 'data-drawer');
        if (target == isTarget) {
          toggleActive(drawers, drawer);
        }
      }
    });
  }

  function bindDrawer (drawer) {
    calcite.dom.addEvent(drawer, calcite.dom.event(), function(event) {
      if (calcite.dom.hasClass(event.target, 'drawer')) {
        toggleActive(drawers, drawer);
      }
    });
  }

  for (var i = 0; i < toggles.length; i++) {
    bindToggle(toggles[i]);
  }
  for (var j = 0; j < drawers.length; j++) {
    bindDrawer(drawers[j]);
  }
};

// ┌───────────────┐
// │ Expanding Nav │
// └───────────────┘
// show and hide exanding nav located under topnav
calcite.expandingNav = function () {
  var toggles = findElements('.js-expanding-toggle');
  var expanders = findElements('.js-expanding');

  if (!expanders) {
    return;
  }

  function bindToggle (toggle) {
    calcite.dom.addEvent(toggle, calcite.dom.event(), function(event) {
      calcite.dom.preventDefault(event);

      var sectionName = calcite.dom.getAttr(toggle, 'data-expanding-nav');
      var sections = document.querySelectorAll('.js-expanding-nav');
      var section = document.querySelectorAll('.js-expanding-nav[data-expanding-nav="' + sectionName + '"]')[0];
      var expander = calcite.dom.closest('js-expanding', section);
      var isOpen = calcite.dom.hasClass(expander, 'is-active');
      var shouldClose = calcite.dom.hasClass(section, 'is-active');

      if (isOpen) {
        if (shouldClose) {
          calcite.dom.removeClass(expander, 'is-active');
        }
        toggleActive(sections, section);
      } else {
        toggleActive(sections, section);
        calcite.dom.addClass(expander, 'is-active');
      }

    });
  }

  for (var i = 0; i < toggles.length; i++) {
    bindToggle(toggles[i]);
  }
};

// ┌───────┐
// │ Modal │
// └───────┘
// show and hide modal dialogues

calcite.modal = function () {

  var toggles = findElements('.js-modal-toggle');
  var modals = findElements('.js-modal');

  if (!modals) {
    return;
  }

  function bindToggle (toggle) {
    calcite.dom.addEvent(toggle, calcite.dom.event(), function(event) {
      calcite.dom.preventDefault(event);
      var target = calcite.dom.getAttr(toggle, 'data-modal');
      for (var i = 0; i < modals.length; i++) {
        var modal = modals[i];
        var isTarget = calcite.dom.getAttr(modals[i], 'data-modal');
        if (target == isTarget) {
         toggleActive(modals, modal);
        }
      }
    });
  }

  function bindModal (modal) {
    calcite.dom.addEvent(modal, calcite.dom.event(), function(event) {
      calcite.dom.preventDefault(event);
      toggleActive(modals, modal);
    });
  }

  for (var i = 0; i < toggles.length; i++) {
    bindToggle(toggles[i]);
  }
  for (var j = 0; j < modals.length; j++) {
    bindModal(modals[j]);
  }
};

// ┌──────┐
// │ Tabs │
// └──────┘
// tabbed content pane

calcite.tabs = function () {
  var tabs = findElements('.js-tab');
  var tabGroups = findElements('.js-tab-group');

  if (!tabs) {
    return;
  }

  // set max width for each tab
  for (var j = 0; j < tabGroups.length; j++) {
    var tabsInGroup = tabGroups[j].querySelectorAll('.js-tab');
    var percent = 100 / tabsInGroup.length;
    for (var k = 0; k < tabsInGroup.length; k++){
      tabsInGroup[k].style.maxWidth = percent + '%';
    }
  }

  function switchTab (event) {
    calcite.dom.preventDefault(event);

    var tab = calcite.dom.closest('js-tab', calcite.dom.eventTarget(event));
    var tabGroup = calcite.dom.closest('js-tab-group', tab);
    var tabs = tabGroup.querySelectorAll('.js-tab');
    var contents = tabGroup.querySelectorAll('.js-tab-section');
    var index = calcite.arr.indexOf(tab, tabs);

    removeActive(tabs);
    removeActive(contents);

    calcite.dom.addClass(tab, 'is-active');
    calcite.dom.addClass(contents[index], 'is-active');
  }

  // attach the switchTab event to all tabs
  for (var i = 0; i < tabs.length; i++) {
    calcite.dom.addEvent(tabs[i], calcite.dom.event(), switchTab);
  }

};

// ┌────────┐
// │ Sticky │
// └────────┘
// sticks things to the window

calcite.sticky = function () {
  var elements = findElements('.js-sticky');

  if (!elements) {
    return;
  }

  var stickies = [];

  for (var i = 0; i < elements.length; i++) {
    var el = elements[i];
    var top = el.offsetTop;
    var dataTop = calcite.dom.getAttr(el, 'data-top');

    if (dataTop) {
      top = top - parseInt(dataTop, 0);
    }

    stickies.push({
      active: false,
      top: top,
      shim: el.cloneNode('deep'),
      element: el
    });
  }

  function handleScroll(item, offset) {
    var elem = item.element;
    var parent = elem.parentNode;
    var distance = item.top - offset;
    var dataTop = calcite.dom.getAttr(el, 'data-top');

    if (distance < 1 && !item.active) {
      item.shim.style.visiblity = 'hidden';
      parent.insertBefore(item.shim, elem);
      calcite.dom.addClass(elem, 'is-sticky');
      item.active = true;
      elem.style.top = dataTop + 'px';
    } else if (item.active && offset < item.top){
      parent.removeChild(item.shim);
      calcite.dom.removeClass(elem, 'is-sticky');
      elem.style.top = null;
      item.active = false;
    }
  }

  calcite.dom.addEvent(window, 'scroll', function() {
    var offset = window.pageYOffset;
    for (var i = 0; i < stickies.length; i++) {
      handleScroll(stickies[i], offset);
    }
  });

};

// ┌────────────────────┐
// │ Initialize Calcite │
// └────────────────────┘
// start up Calcite and attach all the patterns
// optionally pass an array of patterns you'd like to watch

calcite.init = function (patterns) {
  if (patterns) {
    for (var i = 0; i < patterns.length; i++) {
      calcite[patterns[i]]();
    }
  } else {
    calcite.modal();
    calcite.dropdown();
    calcite.drawer();
    calcite.expandingNav();
    calcite.tabs();
    calcite.accordion();
    calcite.carousel();
    calcite.sticky();
  }

  // add a touch class to the body
  if ( calcite.browser.isTouch() ) {
    calcite.dom.addClass(document.body, 'calcite-touch');
  }
};

// ┌───────────────────┐
// │ Expose Calcite.js │
// └───────────────────┘
// implementation borrowed from Leaflet

// define calcite as a global variable, saving the original to restore later if needed
function expose () {
  var oldCalcite = window.calcite;

  calcite.noConflict = function () {
    window.calcite = oldCalcite;
    return this;
  };

  window.calcite = calcite;
}

// no NPM/AMD for now because it just causes issues
// @TODO: bust them into AMD & NPM distros

// // define Calcite for CommonJS module pattern loaders (NPM, Browserify)
// if (typeof module === 'object' && typeof module.exports === 'object') {
//   module.exports = calcite;
// }

// // define Calcite as an AMD module
// else if (typeof define === 'function' && define.amd) {
//   define(calcite);
// }

expose();

})();
<commit_msg>refactor calcite-web.js<commit_after>(function Calcite () {

  // ┌────────────┐
  // │ Public API │
  // └────────────┘
  // define all public api methods (excluding patterns)
  var calcite = {
    version: 'v0.2.2',
    event: event,
    addEvent: addEvent,
    removeEvent: removeEvent,
    eventTarget: eventTarget,
    preventDefault: preventDefault,
    stopPropagation: stopPropagation,
    hasClass: hasClass,
    addClass: addClass,
    removeClass: removeClass,
    closest: closest,
    getAttr: getAttr,
    nodeListToArray: nodeListToArray,
    patterns: {},
    init: init
  };

  // ┌──────────────────────┐
  // │ DOM Event Management │
  // └──────────────────────┘

  // returns standard interaction event, later will add touch support
  function event () {
    return 'click';
  }

  // add a callback function to an event on a DOM node
  function addEvent (domNode, event, fn) {
    if (domNode.addEventListener) {
      return domNode.addEventListener(event, fn, false);
    } else if (domNode.attachEvent) {
      return domNode.attachEvent('on' + event, fn);
    }
  }

  // remove a specific function binding from a DOM node event
  function removeEvent (domNode, event, fn) {
    if (domNode.removeEventListener) {
      return domNode.removeEventListener(event, fn, false);
    } else if (domNode.detachEvent) {
      return domNode.detachEvent('on' + event,  fn);
    }
  }

  // get the target element of an event
  function eventTarget (event) {
    return event.target || event.srcElement;
  }

  // prevent default behavior of an event
  function preventDefault (event) {
    if (event.preventDefault) {
      return event.preventDefault();
    } else if (event.returnValue) {
      event.returnValue = false;
    }
  }

  // stop and event from bubbling up the DOM tree
  function stopPropagation (event) {
    event = event || window.event;
    if (event.stopPropagation) {
      return event.stopPropagation();
    }
    if (event.cancelBubble) {
      event.cancelBubble = true;
    }
  }

  // ┌────────────────────┐
  // │ Class Manipulation │
  // └────────────────────┘

  // check if an element has a specific class
  function hasClass (domNode, className) {
    var elementClass = ' ' + domNode.className + ' ';
    return elementClass.indexOf(' ' + className + ' ') !== -1;
  }

  // add one or more classes to an element
  function addClass (domNode, classes) {
    classes.split(' ').forEach(function (c) {
      if (!hasClass(domNode, c)) {
        domNode.className += ' ' + c;
      }
    });
  }

  // remove one or more classes from an element
  function removeClass (domNode, classes) {
    var elementClass = ' ' + domNode.className + ' ';
    classes.split(' ').forEach(function (c) {
      elementClass = elementClass.replace(' ' + c + ' ', ' ');
    });
    domNode.className = elementClass.trim();
  }

  // if domNode has the class, remove it, else add it
  function toggleClass (domNode, className) {
    if (hasClass(domNode, className)) {
      removeClass(domNode, className);
    } else {
      addClass(domNode, className);
    }
  }

  // ┌─────┐
  // │ DOM │
  // └─────┘

  // returns closest element up the DOM tree matching a given class
  function closest (className, context) {
    var result, current;
    for (current = context; current; current = current.parentNode) {
      if (current.nodeType === 1 && hasClass(current, className)) {
        result = current;
        break;
      }
    }
    return current;
  }

  // get an attribute for an element
  function getAttr (domNode, attr) {
    if (domNode.getAttribute) {
      return domNode.getAttribute(attr);
    }

    var result;
    var attrs = domNode.attributes;

    for (var i = 0; i < attrs.length; i++) {
      if (attrs[i].nodeName === attr) {
        result = attrs[i].nodeValue;
      }
    }

    return result;
  }

  // turn a domNodeList into an array
  function nodeListToArray (domNodeList) {
    var array = [];
    for (var i = 0; i < domNodeList.length; i++) {
      array.push(domNodeList[i]);
    }
    return array;
  }

  // ┌─────────────┐
  // │ JS Patterns │
  // └─────────────┘
  // helper functions for ui patterns

  // return an array of elements matching a query
  function findElements (query) {
    var elements = document.querySelectorAll(query);
    return nodeListToArray(elements);
  }

  // remove 'is-active' class from every element in an array
  function removeActive (array) {
    if (typeof array == 'object') {
      array = nodeListToArray(array);
    }
    array.forEach(function (item) {
      removeClass(item, 'is-active');
    });
  }

  // remove 'is-active' from array, add to element
  function toggleActive (array, el) {
    var isActive = hasClass(el, 'is-active');
    if (isActive) {
      removeClass(el, 'is-active');
    } else {
      removeActive(array);
      addClass(el, 'is-active');
    }
  }

  // ┌───────────┐
  // │ Accordion │
  // └───────────┘
  // collapsible accordion list
  calcite.patterns.accordion = function () {
    findElements('.js-accordion').forEach(function (accordion) {
      nodeListToArray(accordion.children).forEach(function (child) {
        addEvent(child, event(), toggleAccordion);
      });
    });

    function toggleAccordion (event) {
      var parent = closest('accordion-section', eventTarget(event));
      toggleClass(parent, 'is-active');
    }
  };

  // ┌──────────┐
  // │ Dropdown │
  // └──────────┘
  // show and hide dropdown menus
  calcite.patterns.dropdown = function () {
    var toggles = findElements('.js-dropdown-toggle');
    var dropdowns = findElements('.js-dropdown');

    function closeAllDropdowns () {
      removeEvent(document.body, event(), closeAllDropdowns);
      dropdowns.forEach(function (dropdown) {
        removeClass(dropdown, 'is-active');
      });
    }

    function bindToggle (toggle) {
      addEvent(toggle, event(), function (event) {
        preventDefault(event);
        stopPropagation(event);
        var dropdown = closest('js-dropdown', toggle);
        closeAllDropdowns();
        addClass(dropdown, 'is-active');
        addEvent(document.body, event(), closeAllDropdowns);
      });
    }

    toggles.forEach(bindToggle);
  };

  // ┌────────┐
  // │ Drawer │
  // └────────┘
  // show and hide drawers
  calcite.patterns.drawer = function () {
    var toggles = findElements('.js-drawer-toggle');
    var drawers = findElements('.js-drawer');

    toggles.forEach(function (toggle) {
      addEvent(toggle, event(), function (event) {
        preventDefault(event);
        var drawerId = getAttr(toggle, 'data-drawer');
        var drawer = document.querySelector('.js-drawer[data-drawer="' + drawerId + '"');
        toggleActive(drawers, drawer);
      });
    });

    drawers.forEach(function (drawer) {
      addEvent(drawer, event(), function (event) {
        if (hasClass(event.target, 'drawer')) {
          toggleActive(drawers, drawer);
        }
      });
    });
  };

  // ┌───────────────┐
  // │ Expanding Nav │
  // └───────────────┘
  // show and hide exanding nav located under topnav
  calcite.patterns.expandingNav = function () {
    var toggles = findElements('.js-expanding-toggle');
    var expanders = findElements('.js-expanding');
    var sections = document.querySelectorAll('.js-expanding-nav');

    toggles.forEach(function (toggle) {
      addEvent(toggle, event(), function (event) {
        preventDefault(event);

        var sectionId = getAttr(toggle, 'data-expanding-nav');
        var section = document.querySelector('.js-expanding-nav[data-expanding-nav="' + sectionId + '"]');
        var expander = closest('js-expanding', section);
        var isOpen = hasClass(expander, 'is-active');
        var shouldClose = hasClass(section, 'is-active');

        toggleActive(sections, section);

        if (isOpen && shouldClose) {
          removeClass(expander, 'is-active');
        } else {
          addClass(expander, 'is-active');
        }
      });
    });
  };

  // ┌───────┐
  // │ Modal │
  // └───────┘
  // show and hide modal dialogues
  calcite.patterns.modal = function () {
    var toggles = findElements('.js-modal-toggle');
    var modals = findElements('.js-modal');

    toggles.forEach(function (toggle) {
      addEvent(toggle, event(), function(event) {
        preventDefault(event);
        var modal;
        var modalId = getAttr(toggle, 'data-modal');
        if (modalId) {
          modal = document.querySelector('.js-modal[data-modal="' + modalId + '"');
        } else {
          modal = closest('js-modal', toggle);
        }
        toggleActive(modals, modal);
      });
    });

    modals.forEach(function (modal) {
      addEvent(modal, event(), function(event) {
        stopPropagation(event);
        if (eventTarget(event) === modal) {
          toggleActive(modals, modal);
        }
      });
    });
  };

  // ┌──────┐
  // │ Tabs │
  // └──────┘
  // tabbed content pane
  calcite.patterns.tabs = function () {
    var tabs = findElements('.js-tab');
    var tabGroups = findElements('.js-tab-group');

    // set max width for each tab
    tabGroups.forEach(function (tab) {
      var tabsInGroup = tab.querySelectorAll('.js-tab');
      var percent = 100 / tabsInGroup.length;
      for (var i = 0; i < tabsInGroup.length; i++) {
        tabsInGroup[i].style.maxWidth = percent + '%';
      }
    });

    function switchTab (event) {
      preventDefault(event);

      var tab = closest('js-tab', eventTarget(event));
      var tabGroup = closest('js-tab-group', tab);
      var tabs = tabGroup.querySelectorAll('.js-tab');
      var contents = tabGroup.querySelectorAll('.js-tab-section');
      var index = nodeListToArray(tabs).indexOf(tab);

      removeActive(tabs);
      removeActive(contents);

      addClass(tab, 'is-active');
      addClass(contents[index], 'is-active');
    }

    tabs.forEach(function (tab) {
      addEvent(tab, event(), switchTab);
    });
  };

  // ┌────────┐
  // │ Sticky │
  // └────────┘
  // sticks things to the window
  calcite.patterns.sticky = function () {
    var elements = findElements('.js-sticky');
    var stickies = elements.map(function (el) {
      var offset = el.offsetTop;
      var dataTop = getAttr(el, 'data-top') || 0;
      return {
        active: false,
        top: offset - parseInt(dataTop, 0),
        shim: el.cloneNode('deep'),
        element: el
      };
    });

    function handleScroll(item, offset) {
      var el = item.element;
      var parent = el.parentNode;
      var distance = item.top - offset;
      var dataTop = getAttr(el, 'data-top');

      if (distance < 1 && !item.active) {
        item.shim.style.visiblity = 'hidden';
        parent.insertBefore(item.shim, el);
        addClass(el, 'is-sticky');
        item.active = true;
        el.style.top = dataTop + 'px';
      } else if (item.active && offset < item.top) {
        parent.removeChild(item.shim);
        removeClass(el, 'is-sticky');
        el.style.top = null;
        item.active = false;
      }
    }

    addEvent(window, 'scroll', function () {
      var offset = window.pageYOffset;
      stickies.forEach(function (sticky) {
        handleScroll(sticky, offset);
      });
    });

  };

  // ┌────────────────────┐
  // │ Initialize Calcite │
  // └────────────────────┘
  // start up Calcite and attach all the patterns
  // optionally pass an array of patterns you'd like to watch

  function init (patterns) {
    patterns = patterns || Object.keys(calcite.patterns);
    patterns.forEach(function (pattern) {
      calcite.patterns[pattern]();
    });
  }

  // ┌────────────────┐
  // │ Expose Calcite │
  // └────────────────┘

  if (typeof define === 'function' && define.amd) {
    define(function () { return calcite; });
  } else if (typeof exports === 'object') {
    module.exports = calcite;
  } else {
    window.calcite = calcite;
  }

})();
<|endoftext|>


<commit_before>module.exports = jsFlowTracker

var debug = require('debug')('bittorrent-tracker:websocket-tracker')
var EventEmitter = require('events').EventEmitter
var hat = require('hat')
var inherits = require('inherits')
var jsFlow = require('./jsFlow')
var Peer = require('simple-peer')
//var Peer = require('jsflow-peer') // No changes yet.. :)

function jsFlowTracker (client, announceUrl, opts) {
  console.log('jsFlowTracker constructor is now running')
	var self=this
	EventEmitter.call(self)

  self.client=client
  self._opts = opts
  self._announceUrl = announceUrl
  self._peers = {} // peers (peer id -> peer)
  self._intervalMs = self.client._intervalMs // use client interval initially
  self._interval = null

  console.log(self);

  jsFlow.onRecievedUserId = function(userId) {
    console.log('userId', userId);
    self._peerID = userId;
  };

  // Starts jsFlow and handles the user ID
  jsFlow.run("31bc728296d8da7e14e132k",{sessionAuthURL: 'http://corslabs.com/jsflow',
                  debugMsg: true});

  jsFlow.addHandler('list', self._onData.bind(self)) // These messages are only sent by the TRACKER

  //Handlers for peer-2-peer WebRTC signalling using jsFlow
  jsFlow.addHandler('webrtc_offer', self._onWebRtcOffer.bind(self)) // only sent from other PEERS
  jsFlow.addHandler('webrtc_answer', self._onWebRtcAnswer.bind(self)) // only sent from other PEERS
  jsFlow.addHandler('webrtc_ice', self._onWebRtcIce.bind(self)) // only sent from other PEERS
}

jsFlowTracker.prototype.announce = function(opts){
  var self=this
  opts.info_hash = self.client._infoHash.toString('base64')
  opts.peer_id = self._peerId
  opts.trackerid = 'tracker'

  self._sendAnnounce(opts)
}

jsFlowTracker.prototype.setInterval= function (intervalMs) {
  var self = this
  clearInterval(self._interval)

  self._intervalMs = intervalMs
  if (intervalMs) {
    // HACK
    var update = self.announce.bind(self, self.client._defaultAnnounceOpts())
    self._interval = setInterval(update, self._intervalMs)
  }
}

jsFlowTracker.prototype._onData = function (payload, from) {
  console.log('Got Data from Tracker!!', payload, from);

  var self = this
  if (!(typeof payload === 'object' && payload !== null)) {
    return self.client.emit('warning', new Error('Invalid tracker response'))
  }

  if (payload.info_hash !== self.client._infoHash.toString('base64')) {
    return self.client.emit('warning', new Error('Invalid tracker response'))
  }

  var failure = payload['failure reason']
  if (failure) return self.client.emit('warning', new Error(failure))

  var warning = payload['warning message']
  if (warning) self.client.emit('warning', new Error(warning))

  var interval = payload.interval || payload['min interval']
  if (interval && !self._opts.interval && self._intervalMs !== 0) { //TODO: Fix so tracker can set interval (now defaults to 30 min)
  //if(interval) { // ALWAYS use the interval recommended by tracker
    self.setInterval(interval)
  }

  var trackerId = payload['tracker id']
  if (trackerId) {
    // If absent, do not discard previous trackerId value
    self._trackerId = trackerId
  }

  if (payload.complete) {
    self.client.emit('update', {
    announce: self._announceUrl,
    complete: payload.complete,
    incomplete: payload.incomplete
    })
  }

  // Handle received peers
  if (Array.isArray(payload.peers)) {
    payload.peers.forEach(function (peerInfo) { //For all peers we receive - Open a WebRTC peer connection

      console.log('Will handle connection for peer: ', peerInfo.peerId);

      var peer = self._peers[peerId] = new Peer({
        initiator: true,
        trickle: true,
        config: self.client._rtcConfig,
        wrtc: self.client._wrtc
      })
      peer.id = peerInfo.peerId

      peer.on('signal', function (signalObject) {
        console.log('GOT SIGNAL, expecting offer/ice', signalObject);
        if(signalObject.candidate) { // The signalling is for ICE
          var params = {
            info_hash: self.client._infoHash.toString('base64'),
            peer_id: self._peerID,
            candidate: candidate
          }

          jsFlow.messageUser(peerId, params, 'webrtc_ice');
        }
        else { // The signalling is for an OFFER
          offer = signalObject;
          var params = {
            info_hash: self.client._infoHash.toString('base64'),
            peer_id: self._peerID,
            offer: offer
          }

          jsFlow.messageUser(peerId, params, 'webrtc_offer');
        }
      })
    })
  };
}

jsFlowTracker.prototype._onWebRtcOffer = function (payload, from) {
  if(!self._peers[from]) { //Verify we haven't already received an offer from this user
    var peer = self._peers[from] = new Peer({
      trickle: true,
      config: self.client._rtcConfig,
      wrtc: self.client._wrtc
    })
    peer.id = from

    peer.on('signal', function (signalObject) {
        console.log('GOT SIGNAL, expecting offer/ice', signalObject);
      if(signalObject.candidate) { // The signalling is for ICE
        var params = {
          info_hash: self.client._infoHash.toString('base64'),
          peer_id: self._peerID,
          candidate: candidate
        }

        jsFlow.messageUser(from, params, 'webrtc_ice');
      }
      else { // The signalling is for an ANSWER
        answer = signalObject;
        var params = {
          info_hash: self.client._infoHash.toString('base64'),
          peer_id: self._peerID,
          answer: answer
        }

        jsFlow.messageUser(from, params, 'webrtc_answer');
      }
    })

    peer.signal(payload.offer)

    self.client.emit('peer', peer)
  }
  else {
    console.error('Already have peer connection with user: ' + from);
  }
}

jsFlowTracker.prototype._onWebRtcAnswer = function (payload, from) {
  peer = self._peers[from]
  if(peer) {
    peer.id = from
    peer.signal(payload.answer)
    self.client.emit('peer', peer)
  }
  else {
    console.error('Got answer on peer connection that does not exist, from user: ' + from);
  }
}

jsFlowTracker.prototype._onWebRtcIce = function (payload, from) {
  //TODO: Buffer ICE ?
  console.log('WILL ADD ICE CANDIDATE!!!');
  peer.signal(payload.candidate)
}

jsFlowTracker.prototype._sendAnnounce = function (params) {
  var self = this
  jsFlow.messageUser(params.trackerid, params, 'announce')
}
<commit_msg>Minor fix<commit_after>module.exports = jsFlowTracker

var debug = require('debug')('bittorrent-tracker:websocket-tracker')
var EventEmitter = require('events').EventEmitter
var hat = require('hat')
var inherits = require('inherits')
var jsFlow = require('./jsFlow')
var Peer = require('simple-peer')
//var Peer = require('jsflow-peer') // No changes yet.. :)

function jsFlowTracker (client, announceUrl, opts) {
  console.log('jsFlowTracker constructor is now running')
	var self=this
	EventEmitter.call(self)

  self.client=client
  self._opts = opts
  self._announceUrl = announceUrl
  self._peers = {} // peers (peer id -> peer)
  self._intervalMs = self.client._intervalMs // use client interval initially
  self._interval = null

  console.log(self);

  jsFlow.onRecievedUserId = function(userId) {
    console.log('userId', userId);
    self._peerID = userId;
  };

  // Starts jsFlow and handles the user ID
  jsFlow.run("31bc728296d8da7e14e132k",{sessionAuthURL: 'http://corslabs.com/jsflow',
                  debugMsg: true});

  jsFlow.addHandler('list', self._onData.bind(self)) // These messages are only sent by the TRACKER

  //Handlers for peer-2-peer WebRTC signalling using jsFlow
  jsFlow.addHandler('webrtc_offer', self._onWebRtcOffer.bind(self)) // only sent from other PEERS
  jsFlow.addHandler('webrtc_answer', self._onWebRtcAnswer.bind(self)) // only sent from other PEERS
  jsFlow.addHandler('webrtc_ice', self._onWebRtcIce.bind(self)) // only sent from other PEERS
}

jsFlowTracker.prototype.announce = function(opts){
  var self=this
  opts.info_hash = self.client._infoHash.toString('base64')
  opts.peer_id = self._peerId
  opts.trackerid = 'tracker'

  self._sendAnnounce(opts)
}

jsFlowTracker.prototype.setInterval= function (intervalMs) {
  var self = this
  clearInterval(self._interval)

  self._intervalMs = intervalMs
  if (intervalMs) {
    // HACK
    var update = self.announce.bind(self, self.client._defaultAnnounceOpts())
    self._interval = setInterval(update, self._intervalMs)
  }
}

jsFlowTracker.prototype._onData = function (payload, from) {
  console.log('Got Data from Tracker!!', payload, from);

  var self = this
  if (!(typeof payload === 'object' && payload !== null)) {
    return self.client.emit('warning', new Error('Invalid tracker response'))
  }

  if (payload.info_hash !== self.client._infoHash.toString('base64')) {
    return self.client.emit('warning', new Error('Invalid tracker response'))
  }

  var failure = payload['failure reason']
  if (failure) return self.client.emit('warning', new Error(failure))

  var warning = payload['warning message']
  if (warning) self.client.emit('warning', new Error(warning))

  var interval = payload.interval || payload['min interval']
  if (interval && !self._opts.interval && self._intervalMs !== 0) { //TODO: Fix so tracker can set interval (now defaults to 30 min)
  //if(interval) { // ALWAYS use the interval recommended by tracker
    self.setInterval(interval)
  }

  var trackerId = payload['tracker id']
  if (trackerId) {
    // If absent, do not discard previous trackerId value
    self._trackerId = trackerId
  }

  if (payload.complete) {
    self.client.emit('update', {
    announce: self._announceUrl,
    complete: payload.complete,
    incomplete: payload.incomplete
    })
  }

  // Handle received peers
  if (Array.isArray(payload.peers)) {
    payload.peers.forEach(function (peerInfo) { //For all peers we receive - Open a WebRTC peer connection

      console.log('Will handle connection for peer: ', peerInfo.peerId);

      var peer = self._peers[peerId] = new Peer({
        initiator: true,
        trickle: true,
        config: self.client._rtcConfig,
        wrtc: self.client._wrtc
      })
      peer.id = peerInfo.peerId

      peer.on('signal', function (signalObject) {
        console.log('GOT SIGNAL, expecting offer/ice', signalObject);
        if(signalObject.candidate) { // The signalling is for ICE
          var params = {
            info_hash: self.client._infoHash.toString('base64'),
            peer_id: self._peerID,
            candidate: signalObject.candidate
          }

          jsFlow.messageUser(peerId, params, 'webrtc_ice');
        }
        else { // The signalling is for an OFFER
          offer = signalObject;
          var params = {
            info_hash: self.client._infoHash.toString('base64'),
            peer_id: self._peerID,
            offer: offer
          }

          jsFlow.messageUser(peerId, params, 'webrtc_offer');
        }
      })
    })
  };
}

jsFlowTracker.prototype._onWebRtcOffer = function (payload, from) {
  if(!self._peers[from]) { //Verify we haven't already received an offer from this user
    var peer = self._peers[from] = new Peer({
      trickle: true,
      config: self.client._rtcConfig,
      wrtc: self.client._wrtc
    })
    peer.id = from

    peer.on('signal', function (signalObject) {
        console.log('GOT SIGNAL, expecting offer/ice', signalObject);
      if(signalObject.candidate) { // The signalling is for ICE
        var params = {
          info_hash: self.client._infoHash.toString('base64'),
          peer_id: self._peerID,
          candidate: signalObject.candidate
        }

        jsFlow.messageUser(from, params, 'webrtc_ice');
      }
      else { // The signalling is for an ANSWER
        answer = signalObject;
        var params = {
          info_hash: self.client._infoHash.toString('base64'),
          peer_id: self._peerID,
          answer: answer
        }

        jsFlow.messageUser(from, params, 'webrtc_answer');
      }
    })

    peer.signal(payload.offer)

    self.client.emit('peer', peer)
  }
  else {
    console.error('Already have peer connection with user: ' + from);
  }
}

jsFlowTracker.prototype._onWebRtcAnswer = function (payload, from) {
  peer = self._peers[from]
  if(peer) {
    peer.id = from
    peer.signal(payload.answer)
    self.client.emit('peer', peer)
  }
  else {
    console.error('Got answer on peer connection that does not exist, from user: ' + from);
  }
}

jsFlowTracker.prototype._onWebRtcIce = function (payload, from) {
  //TODO: Buffer ICE ?
  console.log('WILL ADD ICE CANDIDATE!!!');
  peer.signal(payload.candidate)
}

jsFlowTracker.prototype._sendAnnounce = function (params) {
  var self = this
  jsFlow.messageUser(params.trackerid, params, 'announce')
}
<|endoftext|>


<commit_before>var debug = require('debug')('bindings');

var events = require('events');
var util = require('util');

var HciBle = require('./hci-ble');
var L2capBle = require('./l2cap-ble');

var NobleBindings = function() {
  this._addresses = {};
  this._addresseTypes = {};

  this._hciBle = new HciBle();
  this._l2capBle = {};
};

util.inherits(NobleBindings, events.EventEmitter);

var nobleBindings = new NobleBindings();

nobleBindings.init = function() {
  this._hciBle.on('stateChange', this.onStateChange.bind(this));
  this._hciBle.on('scanStart', this.onScanStart.bind(this));
  this._hciBle.on('scanStop', this.onScanStop.bind(this));
  this._hciBle.on('discover', this.onDiscover.bind(this));
};

nobleBindings.onStateChange = function(state) {
  this.emit('stateChange', state);
};

nobleBindings.startScanning = function(serviceUuids, allowDuplicates) {
  this._scanServiceUuids = serviceUuids || [];

  this._hciBle.startScanning(allowDuplicates);
};

nobleBindings.onScanStart = function() {
  this.emit('scanStart');
};

nobleBindings.stopScanning = function() {
  this._hciBle.stopScanning();
};

nobleBindings.onScanStop = function() {
  this.emit('scanStop');
};

nobleBindings.onDiscover = function(address, addressType, advertisement, rssi) {
  var serviceUuids = advertisement.serviceUuids;
  var hasScanServiceUuids = (this._scanServiceUuids.length === 0);

  if (!hasScanServiceUuids) {
    for (var i in serviceUuids) {
      hasScanServiceUuids = (this._scanServiceUuids.indexOf(serviceUuids[i]) !== -1);

      if (hasScanServiceUuids) {
        break;
      }
    }
  }

  if (hasScanServiceUuids) {
    var uuid = address.split(':').join('').toLowerCase();
    this._addresses[uuid] = address;
    this._addresseTypes[uuid] = addressType;

    this.emit('discover', uuid, advertisement, rssi);
  }
};

nobleBindings.connect = function(peripheralUuid) {
  var address = this._addresses[peripheralUuid];
  var addressType = this._addresseTypes[peripheralUuid];

  this._l2capBle[address] = new L2capBle(address, addressType);
  this._l2capBle[address].on('connect', this.onConnect.bind(this));
  this._l2capBle[address].on('disconnect', this.onDisconnect.bind(this));
  this._l2capBle[address].on('mtu', this.onMtu.bind(this));
  this._l2capBle[address].on('rssi', this.onRssi.bind(this));
  this._l2capBle[address].on('servicesDiscover', this.onServicesDiscovered.bind(this));
  this._l2capBle[address].on('includedServicesDiscover', this.onIncludedServicesDiscovered.bind(this));
  this._l2capBle[address].on('characteristicsDiscover', this.onCharacteristicsDiscovered.bind(this));
  this._l2capBle[address].on('read', this.onRead.bind(this));
  this._l2capBle[address].on('write', this.onWrite.bind(this));
  this._l2capBle[address].on('broadcast', this.onBroadcast.bind(this));
  this._l2capBle[address].on('notify', this.onNotify.bind(this));
  this._l2capBle[address].on('notification', this.onNotification.bind(this));
  this._l2capBle[address].on('descriptorsDiscover', this.onDescriptorsDiscovered.bind(this));
  this._l2capBle[address].on('valueRead', this.onValueRead.bind(this));
  this._l2capBle[address].on('valueWrite', this.onValueWrite.bind(this));
  this._l2capBle[address].on('handleRead', this.onHandleRead.bind(this));
  this._l2capBle[address].on('handleWrite', this.onHandleWrite.bind(this));

  this._l2capBle[address].connect();
};

nobleBindings.onConnect = function(address) {
  var uuid = address.split(':').join('').toLowerCase();

  this.exchangeMtu(uuid, 256); // delay connect event until MTU is exchanged
};

nobleBindings.disconnect = function(peripheralUuid) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].disconnect();
};

nobleBindings.onDisconnect = function(address) {
  var uuid = address.split(':').join('').toLowerCase();

  this._l2capBle[address].kill();

  this._l2capBle[address].removeAllListeners();

  delete this._l2capBle[address];

  this.emit('disconnect', uuid);
};

nobleBindings.exchangeMtu = function(peripheralUuid, mtu) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].exchangeMtu(mtu);
};

nobleBindings.onMtu = function(address, mtu) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('connect', uuid);
};

nobleBindings.updateRssi = function(peripheralUuid) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].updateRssi();
};

nobleBindings.onRssi = function(address, rssi) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('rssiUpdate', uuid, rssi);
};

nobleBindings.discoverServices = function(peripheralUuid, uuids) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].discoverServices(uuids || []);
};

nobleBindings.onServicesDiscovered = function(address, serviceUuids) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('servicesDiscover', uuid, serviceUuids);
};

nobleBindings.discoverIncludedServices = function(peripheralUuid, serviceUuid, serviceUuids) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].discoverIncludedServices(serviceUuid, serviceUuids || []);
};

nobleBindings.onIncludedServicesDiscovered = function(address, serviceUuid, includedServiceUuids) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('includedServicesDiscover', uuid, serviceUuid, includedServiceUuids);
};

nobleBindings.discoverCharacteristics = function(peripheralUuid, serviceUuid, characteristicUuids) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].discoverCharacteristics(serviceUuid, characteristicUuids || []);
};

nobleBindings.onCharacteristicsDiscovered = function(address, serviceUuid, characteristics) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('characteristicsDiscover', uuid, serviceUuid, characteristics);
};

nobleBindings.read = function(peripheralUuid, serviceUuid, characteristicUuid) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].read(serviceUuid, characteristicUuid);
};

nobleBindings.onRead = function(address, serviceUuid, characteristicUuid, data) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('read', uuid, serviceUuid, characteristicUuid, data, false);
};

nobleBindings.write = function(peripheralUuid, serviceUuid, characteristicUuid, data, withoutResponse) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].write(serviceUuid, characteristicUuid, data, withoutResponse);
};

nobleBindings.onWrite = function(address, serviceUuid, characteristicUuid) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('write', uuid, serviceUuid, characteristicUuid);
};

nobleBindings.broadcast = function(peripheralUuid, serviceUuid, characteristicUuid, broadcast) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].broadcast(serviceUuid, characteristicUuid, broadcast);
};

nobleBindings.onBroadcast = function(address, serviceUuid, characteristicUuid, state) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('broadcast', uuid, serviceUuid, characteristicUuid, state);
};

nobleBindings.notify = function(peripheralUuid, serviceUuid, characteristicUuid, notify) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].notify(serviceUuid, characteristicUuid, notify);
};

nobleBindings.onNotify = function(address, serviceUuid, characteristicUuid, state) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('notify', uuid, serviceUuid, characteristicUuid, state);
};

nobleBindings.onNotification = function(address, serviceUuid, characteristicUuid, data) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('read', uuid, serviceUuid, characteristicUuid, data, true);
};

nobleBindings.discoverDescriptors = function(peripheralUuid, serviceUuid, characteristicUuid) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].discoverDescriptors(serviceUuid, characteristicUuid);
};

nobleBindings.onDescriptorsDiscovered = function(address, serviceUuid, characteristicUuid, descriptorUuids) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('descriptorsDiscover', uuid, serviceUuid, characteristicUuid, descriptorUuids);
};

nobleBindings.readValue = function(peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].readValue(serviceUuid, characteristicUuid, descriptorUuid);
};

nobleBindings.onValueRead = function(address, serviceUuid, characteristicUuid, descriptorUuid, data) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('valueRead', uuid, serviceUuid, characteristicUuid, descriptorUuid, data);
};

nobleBindings.writeValue = function(peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid, data) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].writeValue(serviceUuid, characteristicUuid, descriptorUuid, data);
};

nobleBindings.onValueWrite = function(address, serviceUuid, characteristicUuid, descriptorUuid) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('valueWrite', uuid, serviceUuid, characteristicUuid, descriptorUuid);
};

nobleBindings.readHandle = function(peripheralUuid, handle) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].readHandle(handle);
};

nobleBindings.onHandleRead = function(address, handle, data) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('handleRead', uuid, handle, data);
};

nobleBindings.writeHandle = function(peripheralUuid, handle, data, withoutResponse) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].writeHandle(handle, data, withoutResponse);
};

nobleBindings.onHandleWrite = function(address, handle) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('handleWrite', uuid, handle);
};

nobleBindings.init();

module.exports = nobleBindings;
<commit_msg>- send MTU exchange request and then emit connect, potential fix for issue #39<commit_after>var debug = require('debug')('bindings');

var events = require('events');
var util = require('util');

var HciBle = require('./hci-ble');
var L2capBle = require('./l2cap-ble');

var NobleBindings = function() {
  this._addresses = {};
  this._addresseTypes = {};

  this._hciBle = new HciBle();
  this._l2capBle = {};
};

util.inherits(NobleBindings, events.EventEmitter);

var nobleBindings = new NobleBindings();

nobleBindings.init = function() {
  this._hciBle.on('stateChange', this.onStateChange.bind(this));
  this._hciBle.on('scanStart', this.onScanStart.bind(this));
  this._hciBle.on('scanStop', this.onScanStop.bind(this));
  this._hciBle.on('discover', this.onDiscover.bind(this));
};

nobleBindings.onStateChange = function(state) {
  this.emit('stateChange', state);
};

nobleBindings.startScanning = function(serviceUuids, allowDuplicates) {
  this._scanServiceUuids = serviceUuids || [];

  this._hciBle.startScanning(allowDuplicates);
};

nobleBindings.onScanStart = function() {
  this.emit('scanStart');
};

nobleBindings.stopScanning = function() {
  this._hciBle.stopScanning();
};

nobleBindings.onScanStop = function() {
  this.emit('scanStop');
};

nobleBindings.onDiscover = function(address, addressType, advertisement, rssi) {
  var serviceUuids = advertisement.serviceUuids;
  var hasScanServiceUuids = (this._scanServiceUuids.length === 0);

  if (!hasScanServiceUuids) {
    for (var i in serviceUuids) {
      hasScanServiceUuids = (this._scanServiceUuids.indexOf(serviceUuids[i]) !== -1);

      if (hasScanServiceUuids) {
        break;
      }
    }
  }

  if (hasScanServiceUuids) {
    var uuid = address.split(':').join('').toLowerCase();
    this._addresses[uuid] = address;
    this._addresseTypes[uuid] = addressType;

    this.emit('discover', uuid, advertisement, rssi);
  }
};

nobleBindings.connect = function(peripheralUuid) {
  var address = this._addresses[peripheralUuid];
  var addressType = this._addresseTypes[peripheralUuid];

  this._l2capBle[address] = new L2capBle(address, addressType);
  this._l2capBle[address].on('connect', this.onConnect.bind(this));
  this._l2capBle[address].on('disconnect', this.onDisconnect.bind(this));
  this._l2capBle[address].on('mtu', this.onMtu.bind(this));
  this._l2capBle[address].on('rssi', this.onRssi.bind(this));
  this._l2capBle[address].on('servicesDiscover', this.onServicesDiscovered.bind(this));
  this._l2capBle[address].on('includedServicesDiscover', this.onIncludedServicesDiscovered.bind(this));
  this._l2capBle[address].on('characteristicsDiscover', this.onCharacteristicsDiscovered.bind(this));
  this._l2capBle[address].on('read', this.onRead.bind(this));
  this._l2capBle[address].on('write', this.onWrite.bind(this));
  this._l2capBle[address].on('broadcast', this.onBroadcast.bind(this));
  this._l2capBle[address].on('notify', this.onNotify.bind(this));
  this._l2capBle[address].on('notification', this.onNotification.bind(this));
  this._l2capBle[address].on('descriptorsDiscover', this.onDescriptorsDiscovered.bind(this));
  this._l2capBle[address].on('valueRead', this.onValueRead.bind(this));
  this._l2capBle[address].on('valueWrite', this.onValueWrite.bind(this));
  this._l2capBle[address].on('handleRead', this.onHandleRead.bind(this));
  this._l2capBle[address].on('handleWrite', this.onHandleWrite.bind(this));

  this._l2capBle[address].connect();
};

nobleBindings.onConnect = function(address) {
  var uuid = address.split(':').join('').toLowerCase();

  this._l2capBle[address].exchangeMtu(256);

  this.emit('connect', uuid);
};

nobleBindings.disconnect = function(peripheralUuid) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].disconnect();
};

nobleBindings.onDisconnect = function(address) {
  var uuid = address.split(':').join('').toLowerCase();

  this._l2capBle[address].kill();

  this._l2capBle[address].removeAllListeners();

  delete this._l2capBle[address];

  this.emit('disconnect', uuid);
};

nobleBindings.exchangeMtu = function(peripheralUuid, mtu) {
};

nobleBindings.onMtu = function(address, mtu) {

};

nobleBindings.updateRssi = function(peripheralUuid) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].updateRssi();
};

nobleBindings.onRssi = function(address, rssi) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('rssiUpdate', uuid, rssi);
};

nobleBindings.discoverServices = function(peripheralUuid, uuids) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].discoverServices(uuids || []);
};

nobleBindings.onServicesDiscovered = function(address, serviceUuids) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('servicesDiscover', uuid, serviceUuids);
};

nobleBindings.discoverIncludedServices = function(peripheralUuid, serviceUuid, serviceUuids) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].discoverIncludedServices(serviceUuid, serviceUuids || []);
};

nobleBindings.onIncludedServicesDiscovered = function(address, serviceUuid, includedServiceUuids) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('includedServicesDiscover', uuid, serviceUuid, includedServiceUuids);
};

nobleBindings.discoverCharacteristics = function(peripheralUuid, serviceUuid, characteristicUuids) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].discoverCharacteristics(serviceUuid, characteristicUuids || []);
};

nobleBindings.onCharacteristicsDiscovered = function(address, serviceUuid, characteristics) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('characteristicsDiscover', uuid, serviceUuid, characteristics);
};

nobleBindings.read = function(peripheralUuid, serviceUuid, characteristicUuid) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].read(serviceUuid, characteristicUuid);
};

nobleBindings.onRead = function(address, serviceUuid, characteristicUuid, data) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('read', uuid, serviceUuid, characteristicUuid, data, false);
};

nobleBindings.write = function(peripheralUuid, serviceUuid, characteristicUuid, data, withoutResponse) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].write(serviceUuid, characteristicUuid, data, withoutResponse);
};

nobleBindings.onWrite = function(address, serviceUuid, characteristicUuid) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('write', uuid, serviceUuid, characteristicUuid);
};

nobleBindings.broadcast = function(peripheralUuid, serviceUuid, characteristicUuid, broadcast) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].broadcast(serviceUuid, characteristicUuid, broadcast);
};

nobleBindings.onBroadcast = function(address, serviceUuid, characteristicUuid, state) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('broadcast', uuid, serviceUuid, characteristicUuid, state);
};

nobleBindings.notify = function(peripheralUuid, serviceUuid, characteristicUuid, notify) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].notify(serviceUuid, characteristicUuid, notify);
};

nobleBindings.onNotify = function(address, serviceUuid, characteristicUuid, state) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('notify', uuid, serviceUuid, characteristicUuid, state);
};

nobleBindings.onNotification = function(address, serviceUuid, characteristicUuid, data) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('read', uuid, serviceUuid, characteristicUuid, data, true);
};

nobleBindings.discoverDescriptors = function(peripheralUuid, serviceUuid, characteristicUuid) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].discoverDescriptors(serviceUuid, characteristicUuid);
};

nobleBindings.onDescriptorsDiscovered = function(address, serviceUuid, characteristicUuid, descriptorUuids) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('descriptorsDiscover', uuid, serviceUuid, characteristicUuid, descriptorUuids);
};

nobleBindings.readValue = function(peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].readValue(serviceUuid, characteristicUuid, descriptorUuid);
};

nobleBindings.onValueRead = function(address, serviceUuid, characteristicUuid, descriptorUuid, data) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('valueRead', uuid, serviceUuid, characteristicUuid, descriptorUuid, data);
};

nobleBindings.writeValue = function(peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid, data) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].writeValue(serviceUuid, characteristicUuid, descriptorUuid, data);
};

nobleBindings.onValueWrite = function(address, serviceUuid, characteristicUuid, descriptorUuid) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('valueWrite', uuid, serviceUuid, characteristicUuid, descriptorUuid);
};

nobleBindings.readHandle = function(peripheralUuid, handle) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].readHandle(handle);
};

nobleBindings.onHandleRead = function(address, handle, data) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('handleRead', uuid, handle, data);
};

nobleBindings.writeHandle = function(peripheralUuid, handle, data, withoutResponse) {
  var address = this._addresses[peripheralUuid];

  this._l2capBle[address].writeHandle(handle, data, withoutResponse);
};

nobleBindings.onHandleWrite = function(address, handle) {
  var uuid = address.split(':').join('').toLowerCase();

  this.emit('handleWrite', uuid, handle);
};

nobleBindings.init();

module.exports = nobleBindings;
<|endoftext|>


<commit_before>var path = require("path");
var aliasNpm = require("./alias_npm");

module.exports = function(loader){
	// Configure the loader to set our overrides.
	loader.config({
		map: {
			"live-reload": "@empty"
		},
		paths: {
			"steal-server-side-render": path.resolve(__dirname + "/extension.js"),
			"steal-server-side-render/system-config": path.resolve(__dirname + "/system_config.js")
		},
		configDependencies: [
			"steal-server-side-render/system-config"
		]
	});

	// Alias our module with the default, that way we can require can
	aliasNpm(loader, path.resolve(__dirname+"/.."));

	overrideConfig(loader);

	// Ensure the extension loads before the main.
	var loaderImport = loader.import;
	loader.import = function(name){
		if(name === loader.main) {
			var args = arguments;

			// Set up the renderingLoader to be used by plugins to know what root
			// to attach urls to.
			if(!loader.renderingLoader) {
				loader.renderingLoader = loader.clone();
				loader.renderingLoader.baseURL = loader.renderingBaseURL || loader.baseURL;
			}

			return loader.import("steal-server-side-render").then(function(){
				return loaderImport.apply(loader, args);
			});
		}
		return loaderImport.apply(this, arguments);
	};
};

// Override config to prevent the baseURL from being set to something that
// can't be used to render.
function overrideConfig(loader){
	var config = loader.config;
	loader.config = function(){
		var res = config.apply(this, arguments);

		var envs = this.envs;
		if(envs) {
			Object.keys(envs).forEach(function(key){
				var config = envs[key];
				if(config.baseURL) {
					loader.renderingBaseURL = config.baseURL;
					delete config.baseURL;
				}
			});
		}

		return res;
	};
}
<commit_msg>Set a default renderingLoader.baseURL<commit_after>var path = require("path");
var aliasNpm = require("./alias_npm");

module.exports = function(loader){
	// Configure the loader to set our overrides.
	loader.config({
		map: {
			"live-reload": "@empty"
		},
		paths: {
			"steal-server-side-render": path.resolve(__dirname + "/extension.js"),
			"steal-server-side-render/system-config": path.resolve(__dirname + "/system_config.js")
		},
		configDependencies: [
			"steal-server-side-render/system-config"
		]
	});

	// Alias our module with the default, that way we can require can
	aliasNpm(loader, path.resolve(__dirname+"/.."));

	overrideConfig(loader);

	// Ensure the extension loads before the main.
	var loaderImport = loader.import;
	loader.import = function(name){
		if(name === loader.main) {
			var args = arguments;

			// Set up the renderingLoader to be used by plugins to know what root
			// to attach urls to.
			if(!loader.renderingLoader) {
				loader.renderingLoader = loader.clone();
				var baseURL = loader.renderingBaseURL || loader.baseURL;
				if(baseURL.indexOf("file:") === 0) {
					baseURL = "/";
				}
				loader.renderingLoader.baseURL = baseURL;

			}

			return loader.import("steal-server-side-render").then(function(){
				return loaderImport.apply(loader, args);
			});
		}
		return loaderImport.apply(this, arguments);
	};
};

// Override config to prevent the baseURL from being set to something that
// can't be used to render.
function overrideConfig(loader){
	var config = loader.config;
	loader.config = function(){
		var res = config.apply(this, arguments);

		var envs = this.envs;
		if(envs) {
			Object.keys(envs).forEach(function(key){
				var config = envs[key];
				if(config.baseURL) {
					loader.renderingBaseURL = config.baseURL;
					delete config.baseURL;
				}
			});
		}

		return res;
	};
}
<|endoftext|>


<commit_before>var fs = require('fs');
var ursa = require('ursa');
var dgram = require('dgram');
var tls = require('tls');
var net = require('net');
var mongoose = require('mongoose');

var message_parser = function(){

	/************************************************************************/
	//Webサーバーから送られてきた子機への命令
	var command = {};
	var receive_command = function(str){
		var obj = JSON.parse(str);
		command.type = obj["type"];
		command.functionName = obj["value"]["functionName"];
		command.id = obj["value"]["id"];
		command.args = JSON.stringify(obj["value"]["args"]);
	};

	var send_command = function(str){
		receive_command(str);
		var obj = {
			"id" : command.id,
			"message" : {
				"type" : command.type,
				"value" : {
					"functionName" : command.functionName,
					"args" : JSON.parse(command.args)
				}
			}
		};
		var str = JSON.stringify(obj);
		return str;
	};
	/************************************************************************/
	//子機から送られてきたWebサーバーへの機能の通知
	var functions = {};
	var receive_functions = function(str){
		var obj = JSON.parse(str);
		functions.name = obj["name"];
		functions.id = obj["id"];
		functions.dest = obj["dest"];
		functions.type = obj["type"];
		functions.value = [];
		for(var i=0;i<obj["value"].length;i++){
			functions.value[i] = JSON.stringify(obj["value"][i]);
		}
	};

	var send_functions = function(str){
		receive_functions(str);
		var obj = {
			"type" : "notice",
			"value" : {
				"id" : functions.id,
				"name" : functions.name,
				"functions" : []
			}
		};
		for(var i=0;i<functions.value.length;i++){
			obj["value"]["functions"][i] = JSON.parse(functions.value[i]);
		}
		var str = JSON.stringify(obj);
		return str;
	};
	/************************************************************************/
	//子機から命令の結果
	var result = {};
	var receive_result = function(str){
		var obj = JSON.parse(str);
		result.name = obj["name"];
		result.id = obj["id"];
		result.dest = obj["dest"];
		result.type = obj["type"];
		result.value = JSON.stringify(obj["value"]);

	};

	var send_result = function(str){
		receive_result(str);
		var obj = {
			"type" : "result",
			"value" : {
				"id" : result.id,
				"name" : result.name,
				"value" : JSON.parse(result.value)
			}
		};
		var str = JSON.stringify(obj);
		return str;
	};
	/*******************************************************************************/
	//サーバー&クライアント
	var th = this;

	var check_message = function(str){
		var obj = JSON.parse(str);
		switch(obj["type"]){
			//子機から機能の通知
			case 'function':
				var send_json = send_functions(str);
				webclient_sender.write(send_json);
				break;
			//子機からの命令結果
			case 'result':
				var send_json = send_result(str);
				webclient_sender.write(send_json);
			    break;
			//Webサーバーからの命令
			case 'call':
				var send_json = send_command(str);
				children_sender.write(send_json);
				break;
		}
	};

	var message_server = new net.Server(function(socket){
		socket.on('data',function(str){
			check_message(str);
		});:
	});

	var webclient_server_port = 10000;
	var webclient_sender = new net.Socket();
	webclient_sender.on('error',function(error){});
	webclient_sender.on('close',function(){
		webclient_sender.setTimeout(500,function(){
			webclient_sender.connect(webclient_server_port);
		});
	});

	var children_server_port = 20000;
	var children_sender = new net.Socket();
	children_sender.on('error',function(error){});
	children_sender.on('close',function(error){
		children_sender.setTimeout(500,function(){
			children_sender.connect(children_server_port);
		});
	});

	this.start = function(){
		message_server.listen(12000);
		webclient_sender.connect(this.webclient_server_port);
		children_sender.connect(this.children_server_port);
	};
}

module.exports = message_parser;
<commit_msg>Fix send_result function and add output of Command<commit_after>var fs = require('fs');
var ursa = require('ursa');
var dgram = require('dgram');
var tls = require('tls');
var net = require('net');
var mongoose = require('mongoose');

var message_parser = function(){

	/************************************************************************/
	//Webサーバーから送られてきた子機への命令
	var command = {};
	var receive_command = function(str){
		var obj = JSON.parse(str);
		command.type = obj["type"];
		command.functionName = obj["value"]["functionName"];
		command.id = obj["value"]["id"];
		command.args = JSON.stringify(obj["value"]["args"]);
	};

	var send_command = function(str){
		receive_command(str);
		var obj = {
			"id" : command.id,
			"message" : {
				"type" : command.type,
				"value" : {
					"functionName" : command.functionName,
					"args" : JSON.parse(command.args)
				}
			}
		};
		console.log("[RECIVE COMMAND] id: " + command.id + " functionName: " + command.functionName);
		var str = JSON.stringify(obj);
		return str;
	};
	/************************************************************************/
	//子機から送られてきたWebサーバーへの機能の通知
	var functions = {};
	var receive_functions = function(str){
		var obj = JSON.parse(str);
		functions.name = obj["name"];
		functions.id = obj["id"];
		functions.dest = obj["dest"];
		functions.type = obj["type"];
		functions.value = [];
		for(var i=0;i<obj["value"].length;i++){
			functions.value[i] = JSON.stringify(obj["value"][i]);
		}
	};

	var send_functions = function(str){
		receive_functions(str);
		var obj = {
			"type" : "notice",
			"value" : {
				"id" : functions.id,
				"name" : functions.name,
				"functions" : []
			}
		};
		for(var i=0;i<functions.value.length;i++){
			obj["value"]["functions"][i] = JSON.parse(functions.value[i]);
		}
		console.log("[SEND FUNCTION] id: " + functions.id + " name: " + functions.name);
		var str = JSON.stringify(obj);
		return str;
	};
	/************************************************************************/
	//子機から命令の結果
	var result = {};
	var receive_result = function(str){
		var obj = JSON.parse(str);
		result.name = obj["name"];
		result.id = obj["id"];
		result.dest = obj["dest"];
		result.type = obj["type"];
		result.value = obj["value"];

	};

	var send_result = function(str){
		receive_result(str);
		if(result.value.result == undefined || result.value.result == null){
			result.value.result = {};
		}
		var obj = {
			"type" : "result",
			"value" : {
				"id" : result.id,
				"functionName" : result.value.functionName,
				"hasError": result.value.hasError,
				"result" : result.value.result
			}
		};
		console.log("[FUNCTION RESULT] id: " + result.id + " name ");
		var str = JSON.stringify(obj);
		return str;
	};
	/*******************************************************************************/
	//サーバー&クライアント
	var th = this;

	var check_message = function(str){
		var obj = JSON.parse(str);
		switch(obj["type"]){
			//子機から機能の通知
			case 'function':
				var send_json = send_functions(str);
				webclient_sender.write(send_json);
				break;
			//子機からの命令結果
			case 'result':
			case 'message':
				var send_json = send_result(str);
				webclient_sender.write(send_json);
			    break;
			//Webサーバーからの命令
			case 'call':
				var send_json = send_command(str);
				children_sender.write(send_json);
				break;
		}
	};

	var message_server = new net.Server(function(socket){
		socket.on('data',function(str){
			check_message(str);
		});
	});

	var webclient_server_port = 10000;
	var webclient_sender = new net.Socket();
	webclient_sender.on('error',function(error){});
	webclient_sender.on('close',function(){
		webclient_sender.setTimeout(500,function(){
			webclient_sender.connect(webclient_server_port);
		});
	});

	var children_server_port = 20000;
	var children_sender = new net.Socket();
	children_sender.on('error',function(error){});
	children_sender.on('close',function(error){
		children_sender.setTimeout(500,function(){
			children_sender.connect(children_server_port);
		});
	});

	this.start = function(){
		message_server.listen(12000);
		webclient_sender.connect(this.webclient_server_port);
		children_sender.connect(this.children_server_port);
	};
}

module.exports = message_parser;
<|endoftext|>