<commit_before>/*
 * Copyright (c) Maximilian Antoni <max@javascript.studio>
 *
 * @license MIT
 */
'use strict';

const topics = require('./topics');

function createDefaultTransform() {
  const StringifyTransform = require('@studio/ndjson/stringify');
  return new StringifyTransform();
}

// Make it work with local symlinks:
let state = global['@studio/log'];
if (!state) {
  state = global['@studio/log'] = {
    loggers: {},
    filter: null,
    filters: {},
    transform: null,
    stream: null,
    muted: {},
    muted_all: null
  };
}

function addError(entry, error) {
  const cause = error.cause;
  const cause_code = cause && cause.code;
  if (error.code || cause_code) {
    entry.data = entry.data ? Object.assign({}, entry.data) : {};
    entry.data.code = error.code;
    if (cause_code) {
      entry.data.cause = { code: cause_code };
    }
  }
  entry.stack = error.stack || String(error);
  if (cause) {
    entry.cause = cause.stack || String(cause);
  }
}

function write(ns, base_data, topic, msg, data, error) {
  const mutes = state.muted[ns];
  if (mutes && (!mutes.length || mutes.indexOf(topic) !== -1)) {
    return;
  }
  if (state.muted_all && state.muted_all.indexOf(topic) !== -1) {
    return;
  }
  const entry = { ts: Date.now(), ns, topic };
  if (typeof msg === 'string') {
    entry.msg = msg;
  } else {
    error = data;
    data = msg;
  }
  if (data) {
    if (data instanceof Error) {
      addError(entry, data);
    } else {
      entry.data = base_data ? Object.assign({}, base_data, data) : data;
      if (error) {
        addError(entry, error);
      }
    }
  } else if (base_data) {
    entry.data = base_data;
  }
  (state.filters[ns] || state.filter || state.transform).write(entry);
}

function rewire() {
  if (state.transform) {
    if (state.filter) {
      state.filter.unpipe().pipe(state.transform);
    }
    Object.keys(state.filters).forEach((ns) => {
      state.filters[ns].unpipe().pipe(state.filter || state.transform);
    });
  }
}

function filter(ns, filter_stream) {
  if (typeof ns === 'string') {
    state.filters[ns] = filter_stream;
  } else {
    state.filter = ns;
  }
  rewire();
  return this;
}

function mute(ns) {
  state.muted[ns] = Array.prototype.slice.call(arguments, 1);
  return this;
}

function log(topic) {
  return function (message, data, error) {
    if (state.stream) {
      write(this.ns, this.data, topic, message, data, error);
    }
  };
}

function errorHandler() {
  let writing = false;
  return (err) => {
    if (writing) {
      return; // Prevent recursive failures
    }
    writing = true;
    write('logger', null, 'error', 'Transform failed', err);
    writing = false;
  };
}

function setTransform(transform) {
  transform.on('error', errorHandler());
  state.transform = transform;
  rewire();
}

class Logger {

  constructor(ns) {
    this.ns = ns;
  }

  filter(ns, filter_stream) {
    if (typeof ns === 'string') {
      filter(`${this.ns} ${ns}`, filter_stream);
    } else {
      filter(this.ns, ns);
    }
  }

  mute() {
    mute(this.ns);
  }

  child(ns, data) {
    if (this.data) {
      data = data ? Object.assign({}, this.data, data) : this.data;
    }
    return module.exports(`${this.ns} ${ns}`, data);
  }

}

Object.keys(topics).forEach((topic) => {
  Logger.prototype[topic] = log(topic);
});

module.exports = Object.assign((ns, data) => {
  const log = state.loggers[ns] || (state.loggers[ns] = new Logger(ns));
  log.data = data || null;
  return log;
}, {

  out(out_stream) {
    if (state.transform) {
      state.transform.unpipe(state.stream);
    }
    state.stream = out_stream;
    if (out_stream) {
      if (!state.transform) {
        setTransform(createDefaultTransform());
      }
      state.transform.pipe(state.stream);
    }
    return this;
  },

  transform(transform_stream) {
    if (state.transform) {
      state.transform.unpipe(state.stream);
    }
    setTransform(transform_stream);
    if (state.stream) {
      state.transform.pipe(state.stream);
    }
    return this;
  },

  filter,

  mute,

  muteAll() {
    state.muted_all = Array.prototype.slice.call(arguments);
    return this;
  },

  hasStream() {
    return Boolean(state.stream);
  },

  reset() {
    Object.keys(state.filters).forEach((ns) => {
      state.filters[ns].unpipe();
    });
    if (state.filter) {
      state.filter.unpipe();
      state.filter = null;
    }
    if (state.transform) {
      state.transform.unpipe();
      state.transform = null;
    }
    state.filter = null;
    state.filters = {};
    state.stream = null;
    state.muted = {};
    state.muted_all = null;
  }

});
<commit_msg>Fix unwiring filters<commit_after>/*
 * Copyright (c) Maximilian Antoni <max@javascript.studio>
 *
 * @license MIT
 */
'use strict';

const topics = require('./topics');

function createDefaultTransform() {
  const StringifyTransform = require('@studio/ndjson/stringify');
  return new StringifyTransform();
}

// Make it work with local symlinks:
let state = global['@studio/log'];
if (!state) {
  state = global['@studio/log'] = {
    loggers: {},
    filter: null,
    filters: {},
    transform: null,
    stream: null,
    muted: {},
    muted_all: null
  };
}

function addError(entry, error) {
  const cause = error.cause;
  const cause_code = cause && cause.code;
  if (error.code || cause_code) {
    entry.data = entry.data ? Object.assign({}, entry.data) : {};
    entry.data.code = error.code;
    if (cause_code) {
      entry.data.cause = { code: cause_code };
    }
  }
  entry.stack = error.stack || String(error);
  if (cause) {
    entry.cause = cause.stack || String(cause);
  }
}

function write(ns, base_data, topic, msg, data, error) {
  const mutes = state.muted[ns];
  if (mutes && (!mutes.length || mutes.indexOf(topic) !== -1)) {
    return;
  }
  if (state.muted_all && state.muted_all.indexOf(topic) !== -1) {
    return;
  }
  const entry = { ts: Date.now(), ns, topic };
  if (typeof msg === 'string') {
    entry.msg = msg;
  } else {
    error = data;
    data = msg;
  }
  if (data) {
    if (data instanceof Error) {
      addError(entry, data);
    } else {
      entry.data = base_data ? Object.assign({}, base_data, data) : data;
      if (error) {
        addError(entry, error);
      }
    }
  } else if (base_data) {
    entry.data = base_data;
  }
  (state.filters[ns] || state.filter || state.transform).write(entry);
}

function wiring(action) {
  if (state.transform) {
    if (state.filter) {
      state.filter[action](state.transform);
    }
    Object.keys(state.filters).forEach((ns) => {
      state.filters[ns][action](state.filter || state.transform);
    });
  }
}

function filter(ns, filter_stream) {
  wiring('unpipe');
  if (typeof ns === 'string') {
    state.filters[ns] = filter_stream;
  } else {
    state.filter = ns;
  }
  wiring('pipe');
  return this;
}

function mute(ns) {
  state.muted[ns] = Array.prototype.slice.call(arguments, 1);
  return this;
}

function log(topic) {
  return function (message, data, error) {
    if (state.stream) {
      write(this.ns, this.data, topic, message, data, error);
    }
  };
}

function errorHandler() {
  let writing = false;
  return (err) => {
    if (writing) {
      return; // Prevent recursive failures
    }
    writing = true;
    write('logger', null, 'error', 'Transform failed', err);
    writing = false;
  };
}

function setTransform(transform) {
  transform.on('error', errorHandler());
  wiring('unpipe');
  state.transform = transform;
  wiring('pipe');
}

class Logger {

  constructor(ns) {
    this.ns = ns;
  }

  filter(ns, filter_stream) {
    if (typeof ns === 'string') {
      filter(`${this.ns} ${ns}`, filter_stream);
    } else {
      filter(this.ns, ns);
    }
  }

  mute() {
    mute(this.ns);
  }

  child(ns, data) {
    if (this.data) {
      data = data ? Object.assign({}, this.data, data) : this.data;
    }
    return module.exports(`${this.ns} ${ns}`, data);
  }

}

Object.keys(topics).forEach((topic) => {
  Logger.prototype[topic] = log(topic);
});

module.exports = Object.assign((ns, data) => {
  const log = state.loggers[ns] || (state.loggers[ns] = new Logger(ns));
  log.data = data || null;
  return log;
}, {

  out(out_stream) {
    if (state.transform) {
      state.transform.unpipe(state.stream);
    }
    state.stream = out_stream;
    if (out_stream) {
      if (!state.transform) {
        setTransform(createDefaultTransform());
      }
      state.transform.pipe(state.stream);
    }
    return this;
  },

  transform(transform_stream) {
    if (state.transform) {
      state.transform.unpipe(state.stream);
    }
    setTransform(transform_stream);
    if (state.stream) {
      state.transform.pipe(state.stream);
    }
    return this;
  },

  filter,

  mute,

  muteAll() {
    state.muted_all = Array.prototype.slice.call(arguments);
    return this;
  },

  hasStream() {
    return Boolean(state.stream);
  },

  reset() {
    wiring('unpipe');
    if (state.transform) {
      state.transform.unpipe();
      state.transform = null;
    }
    state.filter = null;
    state.filters = {};
    state.stream = null;
    state.muted = {};
    state.muted_all = null;
  }

});
<|endoftext|>


<commit_before>$(function() {

  $('.logcontent').hide()
  $('tr.log').click(function() {
    $(this).next('.logcontent').fadeToggle()
  })

  function getToolTip(x, y) {
    len = 0
    e = ''
    var ty = ''
    for (i = 0; i < visit_info.length; i++) {
        v = visit_info[i]['data'][1]

        if (v[2] <= x && v[0] >= x && v[1] == y) {
            len = (v[0]-v[2])/1000
            if (y == 2 || y == 4) e = visit_info[i]['status']
            if (y == 3) ty = visit_info[i]['type']

            break

        }

    }

     return (y == 1 ? 'Data Collection': (y == 2 ? 'Robot Action' : (y == 3 ? (ty == 'mca' ? 'MCA Spectrum' : 'Edge Scan'): 'Issue'))) + ': ' + len + 's ' + e
  }

  options = {
      grid: {
          borderWidth: 0,
      },

      selection: { mode: "x" },

      bars: {
        horizontal: true,
        show: true,
        lineWidth: 0.5,
        barWidth: 0.8,
        stack: true,
      },

      xaxis: {
            mode: 'time',
            timezone: 'browser',
            //timeformat: "%H:%M",
            min: start,
            max: end,
      },

      yaxis: {
        show: false,
      }
  }

  options2 = $.extend(true, {}, options);
  options2.tooltip = true;
  options2.grid.hoverable = true
  options2.tooltipOpts = { content: getToolTip }

  var main = $.plot('#avg_time', visit_info, options2);

  $('#avg_time').bind("plotselected", function (event, ranges) {
    $.plot($('#avg_time'), visit_info,
        $.extend(true, {}, options2, { xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to },
    }));

    overview.setSelection(ranges, true);
  });

  var overview = $.plot('#overview', visit_info, options);
  $('.plot_container button[name=reset]').button({ icons: { primary: 'ui-icon-refresh' }, text: false }).click(function() { main.setSelection({xaxis: { from: start, to: end } }); overview.clearSelection(); })

  $('#overview').bind("plotselected", function (event, ranges) {
    main.setSelection(ranges);
  });

  var dc_opts = {
     bars: {
        show: true,
     },
     grid: {
        borderWidth: 0,
     },
     xaxis: {
        ticks: dc_hist2[0],
        tickSize: 1,
        tickLength: 0,
     },
  }

  $.plot('#dc_hist', [dc_hist[1]], dc_opts)

  $.plot('#dc_hist2', [dc_hist2[1]], dc_opts)

  $.plot('#visit_pie', pie, {
         series: {
            pie: {
                show: true,
                radius: 1,
                label: {
                    show: true,
                    radius: 2/3,
                    formatter: labelFormatter,
                    //threshold: 0.1
                }
            }
         },
         legend: {
            show: false
         },
         grid: {
            hoverable: true,
         }
    });

    function labelFormatter(label, series) {
        return "
" + label + "
" + Math.round(series.percent) + "%
";
    }

    var dt = $('.robot_actions.robot').dataTable({
        'sPaginationType': 'full_numbers',
        'aaSorting': [[0,'desc']]
    });

    $(window).resize(function() { _resize() })

    function _resize() {
      $.each([1,2,3,4,5,6],function(i,n) {
        dt.fnSetColumnVis(n, !($(window).width() <= 600))
      })
    }

    _resize()

});
<commit_msg>Link back to data collections<commit_after>$(function() {

  $('a.dcs').button({ icons: { primary: 'ui-icon-search' } })

  $('.logcontent').hide()
  $('tr.log').click(function() {
    $(this).next('.logcontent').fadeToggle()
  })

  function getToolTip(x, y) {
    len = 0
    e = ''
    var ty = ''
    for (i = 0; i < visit_info.length; i++) {
        v = visit_info[i]['data'][1]

        if (v[2] <= x && v[0] >= x && v[1] == y) {
            len = (v[0]-v[2])/1000
            if (y == 2 || y == 4) e = visit_info[i]['status']
            if (y == 3) ty = visit_info[i]['type']

            break

        }

    }

     return (y == 1 ? 'Data Collection': (y == 2 ? 'Robot Action' : (y == 3 ? (ty == 'mca' ? 'MCA Spectrum' : 'Edge Scan'): 'Issue'))) + ': ' + len + 's ' + e
  }

  options = {
      grid: {
          borderWidth: 0,
      },

      selection: { mode: "x" },

      bars: {
        horizontal: true,
        show: true,
        lineWidth: 0.5,
        barWidth: 0.8,
        stack: true,
      },

      xaxis: {
            mode: 'time',
            timezone: 'browser',
            //timeformat: "%H:%M",
            min: start,
            max: end,
      },

      yaxis: {
        show: false,
      }
  }

  options2 = $.extend(true, {}, options);
  options2.tooltip = true;
  options2.grid.hoverable = true
  options2.tooltipOpts = { content: getToolTip }

  var main = $.plot('#avg_time', visit_info, options2);

  $('#avg_time').bind("plotselected", function (event, ranges) {
    $.plot($('#avg_time'), visit_info,
        $.extend(true, {}, options2, { xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to },
    }));

    overview.setSelection(ranges, true);
  });

  var overview = $.plot('#overview', visit_info, options);
  $('.plot_container button[name=reset]').button({ icons: { primary: 'ui-icon-refresh' }, text: false }).click(function() { main.setSelection({xaxis: { from: start, to: end } }); overview.clearSelection(); })

  $('#overview').bind("plotselected", function (event, ranges) {
    main.setSelection(ranges);
  });

  var dc_opts = {
     bars: {
        show: true,
     },
     grid: {
        borderWidth: 0,
     },
     xaxis: {
        ticks: dc_hist2[0],
        tickSize: 1,
        tickLength: 0,
     },
  }

  $.plot('#dc_hist', [dc_hist[1]], dc_opts)

  $.plot('#dc_hist2', [dc_hist2[1]], dc_opts)

  $.plot('#visit_pie', pie, {
         series: {
            pie: {
                show: true,
                radius: 1,
                label: {
                    show: true,
                    radius: 2/3,
                    formatter: labelFormatter,
                    //threshold: 0.1
                }
            }
         },
         legend: {
            show: false
         },
         grid: {
            hoverable: true,
         }
    });

    function labelFormatter(label, series) {
        return "
" + label + "
" + Math.round(series.percent) + "%
";
    }

    var dt = $('.robot_actions.robot').dataTable({
        'sPaginationType': 'full_numbers',
        'aaSorting': [[0,'desc']]
    });

    $(window).resize(function() { _resize() })

    function _resize() {
      $.each([1,2,3,4,5,6],function(i,n) {
        dt.fnSetColumnVis(n, !($(window).width() <= 600))
      })
    }

    _resize()

});
<|endoftext|>


<commit_before>define(['map/clientlayer', 'map/labellayer', 'map/button', 'leaflet', 'map/activearea'],
  function (ClientLayer, LabelLayer, Button, L) {
    'use strict';

    var options = {
      worldCopyJump: true,
      zoomControl: true,
      minZoom: 0
    };

    return function (linkScale, sidebar, buttons) {
      var self = this;
      var savedView;

      var map;
      var layerControl;
      var baseLayers = {};

      function saveView() {
        savedView = {
          center: map.getCenter(),
          zoom: map.getZoom()
        };
      }

      function contextMenuOpenLayerMenu() {
        document.querySelector('.leaflet-control-layers').classList.add('leaflet-control-layers-expanded');
      }

      function mapActiveArea() {
        map.setActiveArea({
          position: 'absolute',
          left: sidebar.getWidth() + 'px',
          right: 0,
          top: 0,
          bottom: 0
        });
      }

      function setActiveArea() {
        setTimeout(mapActiveArea, 300);
      }

      var el = document.createElement('div');
      el.classList.add('map');

      map = L.map(el, options);
      mapActiveArea();

      var now = new Date();
      config.mapLayers.forEach(function (item, i) {
        if ((typeof item.config.start === 'number' && item.config.start <= now.getHours()) || (typeof item.config.end === 'number' && item.config.end > now.getHours())) {
          item.config.order = item.config.start * -1;
        } else {
          item.config.order = i;
        }
      });

      config.mapLayers = config.mapLayers.sort(function (a, b) {
        return a.config.order - b.config.order;
      });

      var layers = config.mapLayers.map(function (d) {
        return {
          'name': d.name,
          'layer': L.tileLayer(d.url.replace('{retina}', L.Browser.retina ? '@2x' : ''), d.config)
        };
      });

      map.addLayer(layers[0].layer);

      layers.forEach(function (d) {
        baseLayers[d.name] = d.layer;
      });

      var button = new Button(map, buttons);

      map.on('locationfound', button.locationFound);
      map.on('locationerror', button.locationError);
      map.on('dragend', saveView);
      map.on('contextmenu', contextMenuOpenLayerMenu);

      if (config.geo) {
        [].forEach.call(config.geo, function (geo) {
          L.geoJSON(geo.json, geo.option).addTo(map);
        });
      }

      button.init();

      layerControl = L.control.layers(baseLayers, [], { position: 'bottomright' });
      layerControl.addTo(map);

      map.zoomControl.setPosition('topright');

      var clientLayer = new ClientLayer({ minZoom: config.clientZoom });
      clientLayer.addTo(map);
      clientLayer.setZIndex(5);

      var labelLayer = new LabelLayer({ minZoom: config.labelZoom });
      labelLayer.addTo(map);
      labelLayer.setZIndex(6);

      sidebar.button.addEventListener('visibility', setActiveArea);

      map.on('zoom', function () {
        clientLayer.redraw();
        labelLayer.redraw();
      });

      map.on('baselayerchange', function (e) {
        map.options.maxZoom = e.layer.options.maxZoom;
        clientLayer.options.maxZoom = map.options.maxZoom;
        labelLayer.options.maxZoom = map.options.maxZoom;
        if (map.getZoom() > map.options.maxZoom) {
          map.setZoom(map.options.maxZoom);
        }

        var style = document.querySelector('.css-mode:not([media="not"])');
        if (style && e.layer.options.mode !== '' && !style.classList.contains(e.layer.options.mode)) {
          style.media = 'not';
          labelLayer.updateLayer();
        }
        if (e.layer.options.mode) {
          var newStyle = document.querySelector('.css-mode.' + e.layer.options.mode);
          newStyle.media = '';
          newStyle.appendChild(document.createTextNode(''));
          labelLayer.updateLayer();
        }
      });

      map.on('load', function () {
        var inputs = document.querySelectorAll('.leaflet-control-layers-selector');
        [].forEach.call(inputs, function (input) {
          input.setAttribute('role', 'radiogroup');
          input.setAttribute('aria-label', input.nextSibling.innerHTML.trim());
        });
      });

      var nodeDict = {};
      var linkDict = {};
      var highlight;

      function resetMarkerStyles(nodes, links) {
        Object.keys(nodes).forEach(function (d) {
          nodes[d].resetStyle();
        });

        Object.keys(links).forEach(function (d) {
          links[d].resetStyle();
        });
      }

      function setView(bounds, zoom) {
        map.fitBounds(bounds, { maxZoom: (zoom ? zoom : config.nodeZoom) });
      }

      function goto(m) {
        var bounds;

        if ('getBounds' in m) {
          bounds = m.getBounds();
        } else {
          bounds = L.latLngBounds([m.getLatLng()]);
        }

        setView(bounds);

        return m;
      }

      function updateView(nopanzoom) {
        resetMarkerStyles(nodeDict, linkDict);
        var m;

        if (highlight !== undefined) {
          if (highlight.type === 'node' && nodeDict[highlight.o.node_id]) {
            m = nodeDict[highlight.o.node_id];
            m.setStyle(config.map.highlightNode);
          } else if (highlight.type === 'link' && linkDict[highlight.o.id]) {
            m = linkDict[highlight.o.id];
            m.setStyle(config.map.highlightLink);
          }
        }

        if (!nopanzoom) {
          if (m) {
            goto(m);
          } else if (savedView) {
            map.setView(savedView.center, savedView.zoom);
          } else {
            setView(config.fixedCenter);
          }
        }
      }

      self.setData = function setData(data) {
        nodeDict = {};
        linkDict = {};

        clientLayer.setData(data);
        labelLayer.setData(data, map, nodeDict, linkDict, linkScale);

        updateView(true);
      };

      self.resetView = function resetView() {
        button.disableTracking();
        highlight = undefined;
        updateView();
      };

      self.gotoNode = function gotoNode(d) {
        button.disableTracking();
        highlight = { type: 'node', o: d };
        updateView();
      };

      self.gotoLink = function gotoLink(d) {
        button.disableTracking();
        highlight = { type: 'link', o: d[0] };
        updateView();
      };

      self.gotoLocation = function gotoLocation(d) {
        button.disableTracking();
        map.setView([d.lat, d.lng], d.zoom);
      };

      self.destroy = function destroy() {
        button.clearButtons();
        sidebar.button.removeEventListener('visibility', setActiveArea);
        map.remove();

        if (el.parentNode) {
          el.parentNode.removeChild(el);
        }
      };

      self.render = function render(d) {
        d.appendChild(el);
        map.invalidateSize();
      };

      return self;
    };
  });
<commit_msg>[TASK] Use Promises for GeoJSON<commit_after>define(['map/clientlayer', 'map/labellayer', 'map/button', 'leaflet', 'map/activearea'],
  function (ClientLayer, LabelLayer, Button, L) {
    'use strict';

    var options = {
      worldCopyJump: true,
      zoomControl: true,
      minZoom: 0
    };

    return function (linkScale, sidebar, buttons) {
      var self = this;
      var savedView;

      var map;
      var layerControl;
      var baseLayers = {};

      function saveView() {
        savedView = {
          center: map.getCenter(),
          zoom: map.getZoom()
        };
      }

      function contextMenuOpenLayerMenu() {
        document.querySelector('.leaflet-control-layers').classList.add('leaflet-control-layers-expanded');
      }

      function mapActiveArea() {
        map.setActiveArea({
          position: 'absolute',
          left: sidebar.getWidth() + 'px',
          right: 0,
          top: 0,
          bottom: 0
        });
      }

      function setActiveArea() {
        setTimeout(mapActiveArea, 300);
      }

      var el = document.createElement('div');
      el.classList.add('map');

      map = L.map(el, options);
      mapActiveArea();

      var now = new Date();
      config.mapLayers.forEach(function (item, i) {
        if ((typeof item.config.start === 'number' && item.config.start <= now.getHours()) || (typeof item.config.end === 'number' && item.config.end > now.getHours())) {
          item.config.order = item.config.start * -1;
        } else {
          item.config.order = i;
        }
      });

      config.mapLayers = config.mapLayers.sort(function (a, b) {
        return a.config.order - b.config.order;
      });

      var layers = config.mapLayers.map(function (d) {
        return {
          'name': d.name,
          'layer': L.tileLayer(d.url.replace('{retina}', L.Browser.retina ? '@2x' : ''), d.config)
        };
      });

      map.addLayer(layers[0].layer);

      layers.forEach(function (d) {
        baseLayers[d.name] = d.layer;
      });

      var button = new Button(map, buttons);

      map.on('locationfound', button.locationFound);
      map.on('locationerror', button.locationError);
      map.on('dragend', saveView);
      map.on('contextmenu', contextMenuOpenLayerMenu);

      if (config.geo) {
        [].forEach.call(config.geo, function (geo) {
          geo.json().then(function (result) {
            if (result) {
              L.geoJSON(result, geo.option).addTo(map);
            }
          });
        });
      }

      button.init();

      layerControl = L.control.layers(baseLayers, [], { position: 'bottomright' });
      layerControl.addTo(map);

      map.zoomControl.setPosition('topright');

      var clientLayer = new ClientLayer({ minZoom: config.clientZoom });
      clientLayer.addTo(map);
      clientLayer.setZIndex(5);

      var labelLayer = new LabelLayer({ minZoom: config.labelZoom });
      labelLayer.addTo(map);
      labelLayer.setZIndex(6);

      sidebar.button.addEventListener('visibility', setActiveArea);

      map.on('zoom', function () {
        clientLayer.redraw();
        labelLayer.redraw();
      });

      map.on('baselayerchange', function (e) {
        map.options.maxZoom = e.layer.options.maxZoom;
        clientLayer.options.maxZoom = map.options.maxZoom;
        labelLayer.options.maxZoom = map.options.maxZoom;
        if (map.getZoom() > map.options.maxZoom) {
          map.setZoom(map.options.maxZoom);
        }

        var style = document.querySelector('.css-mode:not([media="not"])');
        if (style && e.layer.options.mode !== '' && !style.classList.contains(e.layer.options.mode)) {
          style.media = 'not';
          labelLayer.updateLayer();
        }
        if (e.layer.options.mode) {
          var newStyle = document.querySelector('.css-mode.' + e.layer.options.mode);
          newStyle.media = '';
          newStyle.appendChild(document.createTextNode(''));
          labelLayer.updateLayer();
        }
      });

      map.on('load', function () {
        var inputs = document.querySelectorAll('.leaflet-control-layers-selector');
        [].forEach.call(inputs, function (input) {
          input.setAttribute('role', 'radiogroup');
          input.setAttribute('aria-label', input.nextSibling.innerHTML.trim());
        });
      });

      var nodeDict = {};
      var linkDict = {};
      var highlight;

      function resetMarkerStyles(nodes, links) {
        Object.keys(nodes).forEach(function (d) {
          nodes[d].resetStyle();
        });

        Object.keys(links).forEach(function (d) {
          links[d].resetStyle();
        });
      }

      function setView(bounds, zoom) {
        map.fitBounds(bounds, { maxZoom: (zoom ? zoom : config.nodeZoom) });
      }

      function goto(m) {
        var bounds;

        if ('getBounds' in m) {
          bounds = m.getBounds();
        } else {
          bounds = L.latLngBounds([m.getLatLng()]);
        }

        setView(bounds);

        return m;
      }

      function updateView(nopanzoom) {
        resetMarkerStyles(nodeDict, linkDict);
        var m;

        if (highlight !== undefined) {
          if (highlight.type === 'node' && nodeDict[highlight.o.node_id]) {
            m = nodeDict[highlight.o.node_id];
            m.setStyle(config.map.highlightNode);
          } else if (highlight.type === 'link' && linkDict[highlight.o.id]) {
            m = linkDict[highlight.o.id];
            m.setStyle(config.map.highlightLink);
          }
        }

        if (!nopanzoom) {
          if (m) {
            goto(m);
          } else if (savedView) {
            map.setView(savedView.center, savedView.zoom);
          } else {
            setView(config.fixedCenter);
          }
        }
      }

      self.setData = function setData(data) {
        nodeDict = {};
        linkDict = {};

        clientLayer.setData(data);
        labelLayer.setData(data, map, nodeDict, linkDict, linkScale);

        updateView(true);
      };

      self.resetView = function resetView() {
        button.disableTracking();
        highlight = undefined;
        updateView();
      };

      self.gotoNode = function gotoNode(d) {
        button.disableTracking();
        highlight = { type: 'node', o: d };
        updateView();
      };

      self.gotoLink = function gotoLink(d) {
        button.disableTracking();
        highlight = { type: 'link', o: d[0] };
        updateView();
      };

      self.gotoLocation = function gotoLocation(d) {
        button.disableTracking();
        map.setView([d.lat, d.lng], d.zoom);
      };

      self.destroy = function destroy() {
        button.clearButtons();
        sidebar.button.removeEventListener('visibility', setActiveArea);
        map.remove();

        if (el.parentNode) {
          el.parentNode.removeChild(el);
        }
      };

      self.render = function render(d) {
        d.appendChild(el);
        map.invalidateSize();
      };

      return self;
    };
  });
<|endoftext|>


<commit_before>/**
 * 使用更简洁的EventEmitter(完全没用dom的影子，只是一个callback队列)作为我们的消息中心
 *
 * 在没用使用React之前，使用jQuery使用pubsub的方案对模块进行解耦，不需要借助第三方的插件
 * 简单的使用jquery自定义事件来做即可。
 * 比如var msg = $({});
 *
 * msg.on('loveYou', function(event, param){});
 * msg.trigger('loveYou');
 *
 * 不好地方，一个pubsub却带有dom的影子会走jQuery的event dispatcher，然后参数的传递不能传递数组类型。
 *
 * 主要想简单的使用node EventEmitter模块，其实略感这个模块有点大，其实很可以简化。
 * 做到一个minievent。
 */
 var EventEmitter;

/**
 * 兼容React和React-Native
 *
 * React-Native中没有require('events')
 * 且EventEmitter没有setMaxListeners方法
 */
 try {
   EventEmitter = require('EventEmitter');
 } catch (err) {
   EventEmitter = require('events').EventEmitter;
 }

var emitter = module.exports = new EventEmitter();

if (emitter.setMaxListeners) {
  //infinit max listeners
  emitter.setMaxListeners(0);
}
<commit_msg>modify the exports of eventEmitter to ajust the mobile<commit_after>/**
 * 使用更简洁的EventEmitter(完全没用dom的影子，只是一个callback队列)作为我们的消息中心
 *
 * 在没用使用React之前，使用jQuery使用pubsub的方案对模块进行解耦，不需要借助第三方的插件
 * 简单的使用jquery自定义事件来做即可。
 * 比如var msg = $({});
 *
 * msg.on('loveYou', function(event, param){});
 * msg.trigger('loveYou');
 *
 * 不好地方，一个pubsub却带有dom的影子会走jQuery的event dispatcher，然后参数的传递不能传递数组类型。
 *
 * 主要想简单的使用node EventEmitter模块，其实略感这个模块有点大，其实很可以简化。
 * 做到一个minievent。
 */
 var EventEmitter;

/**
 * 兼容React和React-Native
 *
 * React-Native中没有require('events')
 * 且EventEmitter没有setMaxListeners方法
 */
 try {
    var EventEmitter = require('EventEmitter');
    var emitter = module.exports = new EventEmitter();
    emitter.on = emitter.addListener;
  } catch (err) {
    var EventEmitter = require('events').EventEmitter;

    //react
    var emitter = module.exports = new EventEmitter();
    //infinit max listeners
    emitter.setMaxListeners(0);
  }
<|endoftext|>


<commit_before>var fs = require('fs')
var path = require('path')
var request = require('request')

// # of tries for webserver to start up on specified port
// We test once per second
var RETRIES = 10

// Port on which the application-under-test should bind to on localhost.
// Sauce Connector will tunnel from this to Sauce Cloud for Selenium tests
var PORT = 8031

// Custom prepare function - runs `npm install`
function prepare(ctx, cb) {
  console.log("SAUCE prepare")
  var tsh = ctx.shellWrap("npm install")
  ctx.forkProc(ctx.workingDir, tsh.cmd, tsh.args, function(exitCode) {
    if (exitCode === 0) {
      ctx.striderMessage("npm install success")
    }
    cb(exitCode)
  })
}

// Read & parse a JSON file
function getJson(filename, cb) {
  fs.readFile(filename, function(err, data) {
    if (err) return cb(err, null)
    try {
      var json = JSON.parse(data)
      cb(null, json)
    } catch(e) {
      cb(e, null)
    }
  })
}

// `npm install` has succeeded at this point.
// We run `npm test` and assuming that has passed,
// then we start the Sauce test process.
// If `npm test` fails, we don't bother with the overhead of running the Sauce tests.
function test(ctx, cb) {
  console.log("SAUCE test")
  var startPhaseDone = false
  var tsh = ctx.shellWrap("npm test")
  // Run
  ctx.forkProc(ctx.workingDir, tsh.cmd, tsh.args, function(exitCode) {
    if (exitCode !== 0) {
      return cb(exitCode)
    } else {
      ctx.striderMessage("npm test success - trying Sauce tests...")
      // Parse package.json so we can run the start script directly.
      // This is important because `npm start` will fork a subprocess a la shell
      // which means we cannot track the PID and shut it down later.
      getJson(path.join(ctx.workingDir, "package.json"), npmTestPassed)
    }
  })
  function npmTestPassed(err, packageJson) {
    if (err || packageJson.scripts === undefined || packageJson.scripts.start === undefined) {
      striderMessage("could not read package.json to find start command - failing test")
      return cb(1)
    }
    // `npm test` succeeded, so we go through the Sauce tests.

    // Start the app, suggesting a port via PORT environment variable
    var tsh = ctx.shellWrap(packageJson.scripts.start)
    var serverProc = ctx.forkProc({
      args:tsh.args,
      cmd:tsh.cmd,
      cwd:ctx.workingDir,
      env:{PORT:PORT},
    }, function(exitCode) {
      // Could perhaps be backgrounding itself. This should be avoided.
      if (exitCode !== 0 && !startPhaseDone) {
        // If we haven't already called back with completion,
        // and `npm start` exits with non-zero exit code,
        // call back with error and mark done.
        ctx.striderMessage("npm start failed - failing test")
        startPhaseDone = true
        return cb(exitCode)
      }
    })

    // The project webserver should be available via HTTP once started.
    // This section implements a check which will attempt to make a HTTP request for /
    // expecting a 200 response code. It will try RETRIES times, waiting 1 second
    // between checks. If it fails after RETRIES times, the server process will be killed
    // and the test failed.
    var tries = 0
    ctx.striderMessage("Waiting for webserver to come up on localhost:" + PORT)
    var intervalId = setInterval(function() {
      // Check for http status 200 on http://localhost:PORT/
      request("http://localhost:"+PORT+"/", function(err, response) {
        if (startPhaseDone) {
          clearInterval(intervalId)
          return
        }
        if (!err && response.statusCode == 200) {
          ctx.striderMessage("Got HTTP 200 on localhost:" + PORT + " indicating server is up")
          startPhaseDone = true
          clearInterval(intervalId)
          serverUp()
        } else {
          tries++
          console.log("Error on localhost:%d: %s", PORT, err)
          if (tries >= RETRIES) {
            var msg = ("HTTP 200 check on localhost:" + PORT + " failed after " + tries
              + " retries, server not up - failing test")
            ctx.striderMessage(msg)
            clearInterval(intervalId)
            startPhaseDone = true
            return cb(1)
          }
        }
      })
    }, 1000)

    // Start the Sauce Connector. Returns childProcess object.
    function startConnector(username, apiKey, cb) {
      var jarPath = path.join(__dirname, "thirdparty", "Sauce-Connect.jar")
      var jsh = ctx.shellWrap("java -jar " + jarPath + " " + username + " " + apiKey)

      ctx.striderMessage("Starting Sauce Connector")
      return ctx.forkProc(__dirname, jsh.cmd, jsh.args, cb)
    }

    // Server is up, start Sauce Connector and run the tests via `npm sauce` invocations
    function serverUp() {
      var done = false
      var connectorProc = startConnector(process.env.SAUCE_USERNAME, process.env.SAUCE_ACCESS_KEY,
        function(exitCode) {
        console.log("Connector exited with code: %d", exitCode)
        if (!done) {
          ctx.striderMessage("Error starting Sauce Connector - failing test")
          ctx.striderMessage("Shutting down server")
          serverProc.kill("SIGKILL")
          done = true
          return cb(1)
        }
      })

      // Wait until connector outputs "You may start your tests"
      // before executing Sauce tests
      connectorProc.stdout.on('data', function(data) {
        if (/Connected! You may start your tests./.exec(data) !== null) {
          var saucesh = ctx.shellWrap("npm run-script sauce")
          //: TODO this should be a loop, executing `npm run-script sauce` for each
          // browser/OS combo specified for the project.
          var sauceProc = ctx.forkProc({
            args: saucesh.args,
            cmd: saucesh.cmd,
            cwd: ctx.workingDir,
            // TODO: Read Sauce creds from Strider per-project storage.
            env: {
              SAUCE_USERNAME:process.env.SAUCE_USERNAME,
              SAUCE_ACCESS_KEY:process.env.SAUCE_ACCESS_KEY
            }
          }, function(code) {
            ctx.striderMessage("npm run-script sauce exited with code " + code)
            if (!done) {
              done = true
              ctx.striderMessage("Shutting down Sauce Connector")
              connectorProc.kill("SIGINT")
              ctx.striderMessage("Shutting down server")
              serverProc.kill()
              // Give Sauce Connector & server 5 seconds to gracefully stop before sending SIGKILL
              setTimeout(function() {
                connectorProc.kill("SIGKILL")
                serverProc.kill("SIGKILL")
                return cb(code)
              }, 5000)
            }
          })
        }
      })
    }
  }
}

module.exports = function(ctx, cb) {

  ctx.addDetectionRule({
    filename:"package.json",
    jsonKeyExists:"scripts.sauce",
    language:"node.js",
    framework:null,
    hasSauce:true,
    prepare:prepare,
    test:test
  })

  console.log("strider-sauce extension loaded")
  cb(null, null)
}
<commit_msg>moar commentz<commit_after>var fs = require('fs')
var path = require('path')
var request = require('request')

// # of tries for application-under-test webserver to start up on specified port
// We test once per second
var RETRIES = 10

// Port on which the application-under-test webserver should bind to on localhost.
// Sauce Connector will tunnel from this to Sauce Cloud for Selenium tests
var PORT = 8031

// Custom prepare function - runs `npm install`
function prepare(ctx, cb) {
  console.log("SAUCE prepare")
  var tsh = ctx.shellWrap("npm install")
  ctx.forkProc(ctx.workingDir, tsh.cmd, tsh.args, function(exitCode) {
    if (exitCode === 0) {
      ctx.striderMessage("npm install success")
    }
    cb(exitCode)
  })
}

// Read & parse a JSON file
function getJson(filename, cb) {
  fs.readFile(filename, function(err, data) {
    if (err) return cb(err, null)
    try {
      var json = JSON.parse(data)
      cb(null, json)
    } catch(e) {
      cb(e, null)
    }
  })
}

// `npm install` has succeeded at this point.
// We run `npm test` and assuming that has passed,
// then we start the Sauce test process.
// If `npm test` fails, we don't bother with the overhead of running the Sauce tests.
function test(ctx, cb) {
  console.log("SAUCE test")
  var startPhaseDone = false
  var tsh = ctx.shellWrap("npm test")
  // Run
  ctx.forkProc(ctx.workingDir, tsh.cmd, tsh.args, function(exitCode) {
    if (exitCode !== 0) {
      return cb(exitCode)
    } else {
      ctx.striderMessage("npm test success - trying Sauce tests...")
      // Parse package.json so we can run the start script directly.
      // This is important because `npm start` will fork a subprocess a la shell
      // which means we cannot track the PID and shut it down later.
      getJson(path.join(ctx.workingDir, "package.json"), npmTestPassed)
    }
  })
  function npmTestPassed(err, packageJson) {
    if (err || packageJson.scripts === undefined || packageJson.scripts.start === undefined) {
      striderMessage("could not read package.json to find start command - failing test")
      return cb(1)
    }
    // `npm test` succeeded, so we go through the Sauce tests.

    // Start the app, suggesting a port via PORT environment variable
    var tsh = ctx.shellWrap(packageJson.scripts.start)
    var serverProc = ctx.forkProc({
      args:tsh.args,
      cmd:tsh.cmd,
      cwd:ctx.workingDir,
      env:{PORT:PORT},
    }, function(exitCode) {
      // Could perhaps be backgrounding itself. This should be avoided.
      if (exitCode !== 0 && !startPhaseDone) {
        // If we haven't already called back with completion,
        // and `npm start` exits with non-zero exit code,
        // call back with error and mark done.
        ctx.striderMessage("npm start failed - failing test")
        startPhaseDone = true
        return cb(exitCode)
      }
    })

    // The project webserver should be available via HTTP once started.
    // This section implements a check which will attempt to make a HTTP request for /
    // expecting a 200 response code. It will try RETRIES times, waiting 1 second
    // between checks. If it fails after RETRIES times, the server process will be killed
    // and the test failed.
    var tries = 0
    ctx.striderMessage("Waiting for webserver to come up on localhost:" + PORT)
    var intervalId = setInterval(function() {
      // Check for http status 200 on http://localhost:PORT/
      request("http://localhost:"+PORT+"/", function(err, response) {
        if (startPhaseDone) {
          clearInterval(intervalId)
          return
        }
        if (!err && response.statusCode == 200) {
          ctx.striderMessage("Got HTTP 200 on localhost:" + PORT + " indicating server is up")
          startPhaseDone = true
          clearInterval(intervalId)
          serverUp()
        } else {
          tries++
          console.log("Error on localhost:%d: %s", PORT, err)
          if (tries >= RETRIES) {
            var msg = ("HTTP 200 check on localhost:" + PORT + " failed after " + tries
              + " retries, server not up - failing test")
            ctx.striderMessage(msg)
            clearInterval(intervalId)
            startPhaseDone = true
            return cb(1)
          }
        }
      })
    }, 1000)

    // Start the Sauce Connector. Returns childProcess object.
    function startConnector(username, apiKey, cb) {
      var jarPath = path.join(__dirname, "thirdparty", "Sauce-Connect.jar")
      var jsh = ctx.shellWrap("java -jar " + jarPath + " " + username + " " + apiKey)

      ctx.striderMessage("Starting Sauce Connector")
      return ctx.forkProc(__dirname, jsh.cmd, jsh.args, cb)
    }

    // Server is up, start Sauce Connector and run the tests via `npm sauce` invocations
    function serverUp() {
      var done = false
      var connectorProc = startConnector(process.env.SAUCE_USERNAME, process.env.SAUCE_ACCESS_KEY,
        function(exitCode) {
        console.log("Connector exited with code: %d", exitCode)
        if (!done) {
          ctx.striderMessage("Error starting Sauce Connector - failing test")
          ctx.striderMessage("Shutting down server")
          serverProc.kill("SIGKILL")
          done = true
          return cb(1)
        }
      })

      // Wait until connector outputs "You may start your tests"
      // before executing Sauce tests
      connectorProc.stdout.on('data', function(data) {
        if (/Connected! You may start your tests./.exec(data) !== null) {
          var saucesh = ctx.shellWrap("npm run-script sauce")
          //: TODO this should be a loop, executing `npm run-script sauce` for each
          // browser/OS combo specified for the project.
          var sauceProc = ctx.forkProc({
            args: saucesh.args,
            cmd: saucesh.cmd,
            cwd: ctx.workingDir,
            // TODO: Read Sauce creds from Strider per-project storage.
            env: {
              SAUCE_USERNAME:process.env.SAUCE_USERNAME,
              SAUCE_ACCESS_KEY:process.env.SAUCE_ACCESS_KEY
            }
          }, function(code) {
            ctx.striderMessage("npm run-script sauce exited with code " + code)
            if (!done) {
              done = true
              ctx.striderMessage("Shutting down Sauce Connector")
              connectorProc.kill("SIGINT")
              ctx.striderMessage("Shutting down server")
              serverProc.kill()
              // Give Sauce Connector & server 5 seconds to gracefully stop before sending SIGKILL
              setTimeout(function() {
                connectorProc.kill("SIGKILL")
                serverProc.kill("SIGKILL")
                return cb(code)
              }, 5000)
            }
          })
        }
      })
    }
  }
}

module.exports = function(ctx, cb) {

  ctx.addDetectionRule({
    filename:"package.json",
    jsonKeyExists:"scripts.sauce",
    language:"node.js",
    framework:null,
    hasSauce:true,
    prepare:prepare,
    test:test
  })

  console.log("strider-sauce extension loaded")
  cb(null, null)
}
<|endoftext|>


<commit_before>

var fs = require('fs'),
    path = require('path');

var ncp = exports;

ncp.ncp = function (source, dest, options, callback) {
  if (!callback) {
    callback = options;
    options = {};
  }

  var basePath = process.cwd(),
      currentPath = (source[0] === '/') ? source : basePath + '/' + source,
      targetPath = (dest[0] === '/') ? dest : basePath + '/' + dest,
      filter = options.filter,
      errs = null,
      started = 0,
      finished = 0,
      running = 0,
      limit = options.limit || ncp.limit || 16;

  limit = (limit < 1) ? 1 : (limit > 512) ? 512 : limit;

  startCopy(currentPath);

  function startCopy(item) {
    started++;
    if (filter) {
      if (filter instanceof RegExp) {
        if (!filter.test(item)) {
          return cb();
        }
      }
      else if (typeof filter === 'function') {
        if (!filter(item)) {
          return cb();
        }
      }
    }
    return getStats(item);
  }

  function getStats(item) {
    if (running >= limit) {
      return process.nextTick(function () {
        getStats(item);
      });
    }
    running++;
    fs.lstat(item, function (err, stats) {
      if (err) {
        return onError(err);
      }
      if (stats.isDirectory()) {
        return onDir(item);
      }
      else if (stats.isFile()) {
        return onFile(item);
      }
      else if (stats.isSymbolicLink()) {
        return onLink(item);
      }
    });
  }

  function onFile(file) {
    var target = file.replace(currentPath, targetPath);
    path.exists(target, function (exists) {
      if (exists) {
        return rmFile(target, function () {
          copyFile(file, target);
        });
      }
      copyFile(file, target);
    });
  }

  function copyFile(file, target) {
    var readStream = fs.createReadStream(file),
        writeStream = fs.createWriteStream(target);
    readStream.pipe(writeStream);
    readStream.once('end', cb);
  }

  function rmFile(file, done) {
    fs.unlink(file, function (err) {
      if (err) {
        return onError(err);
      }
      return done();
    });
  }

  function onDir(dir) {
    var target = dir.replace(currentPath, targetPath);
    path.exists(target, function (exists) {
      if (exists) {
        return copyDir(dir, target);
      }
      mkDir(dir, target);
    });
  }

  function mkDir(dir, target) {
    fs.mkdir(target, 0755, function (err) {
      if (err) {
        return onError(err);
      }
      copyDir(dir);
    });
  }

  function copyDir(dir) {
    fs.readdir(dir, function (err, items) {
      if (err) {
        return onError(err);
      }
      items.forEach(function (item) {
        startCopy(dir + '/' + item);
      });
      return cb();
    });
  }

  function onLink(link) {
    var target = link.replace(currentPath, targetPath);
    fs.readlink(link, function (err, resolvedPath) {
      if (err) {
        return onError(err);
      }
      checkLink(resolvedPath, target);
    });
  }

  function checkLink(resolvedPath, target) {
    path.exists(target, function (exists) {
      if (exists) {
        return fs.readlink(target, function (err, targetDest) {
          if (err) {
            return onError(err);
          }
          if (targetDest === resolvedPath) {
            return cb();
          }
          return rmFile(link, function () {
            makeLink(resolvedPath, target);
          });
        });
      }
      makeLink(resolvedPath, target);
    });
  }

  function makeLink(linkPath, target) {
    fs.symlink(linkPath, target, function (err) {
      if (err) {
        return onError(err);
      }
      return cb();
    });
  }

  function onError(err) {
    if (options.stopOnError) {
      return callback(err);
    }
    else if (!errs && options.errs) {
      errs = fs.createWriteStream(options.errs);
    }
    else if (!errs) {
      errs = [];
    }
    else if (options.errs) {
      if (typeof errs.write === 'undefined') {
        errs.push(err);
      }
      else {
        errs.write(err.stack + '\n\n');
      }
    }
    return cb();
  }

  function cb() {
    running--;
    finished++;
    if ((started === finished) && (running === 0)) {
      return errs ? callback(errs) : callback(null);
    }
  }
}

<commit_msg>Check for ENOENT for files in limbo.<commit_after>

var fs = require('fs'),
    path = require('path');

var ncp = exports;

ncp.ncp = function (source, dest, options, callback) {
  if (!callback) {
    callback = options;
    options = {};
  }

  var basePath = process.cwd(),
      currentPath = (source[0] === '/') ? source : basePath + '/' + source,
      targetPath = (dest[0] === '/') ? dest : basePath + '/' + dest,
      filter = options.filter,
      errs = null,
      started = 0,
      finished = 0,
      running = 0,
      limit = options.limit || ncp.limit || 16;

  limit = (limit < 1) ? 1 : (limit > 512) ? 512 : limit;

  startCopy(currentPath);

  function startCopy(item) {
    started++;
    if (filter) {
      if (filter instanceof RegExp) {
        if (!filter.test(item)) {
          return cb();
        }
      }
      else if (typeof filter === 'function') {
        if (!filter(item)) {
          return cb();
        }
      }
    }
    return getStats(item);
  }

  function getStats(item) {
    if (running >= limit) {
      return process.nextTick(function () {
        getStats(item);
      });
    }
    running++;
    fs.lstat(item, function (err, stats) {
      if (err) {
        return onError(err);
      }
      if (stats.isDirectory()) {
        return onDir(item);
      }
      else if (stats.isFile()) {
        return onFile(item);
      }
      else if (stats.isSymbolicLink()) {
        return onLink(item);
      }
    });
  }

  function onFile(file) {
    var target = file.replace(currentPath, targetPath);
    path.exists(target, function (exists) {
      if (exists) {
        return rmFile(target, function () {
          copyFile(file, target);
        });
      }
      copyFile(file, target);
    });
  }

  function copyFile(file, target) {
    var readStream = fs.createReadStream(file),
        writeStream = fs.createWriteStream(target);
    readStream.pipe(writeStream);
    readStream.once('end', cb);
  }

  function rmFile(file, done) {
    fs.unlink(file, function (err) {
      if (err && err.code !== 'ENOENT') {
        return onError(err);
      }
      return done();
    });
  }

  function onDir(dir) {
    var target = dir.replace(currentPath, targetPath);
    path.exists(target, function (exists) {
      if (exists) {
        return copyDir(dir, target);
      }
      mkDir(dir, target);
    });
  }

  function mkDir(dir, target) {
    fs.mkdir(target, 0755, function (err) {
      if (err) {
        return onError(err);
      }
      copyDir(dir);
    });
  }

  function copyDir(dir) {
    fs.readdir(dir, function (err, items) {
      if (err) {
        return onError(err);
      }
      items.forEach(function (item) {
        startCopy(dir + '/' + item);
      });
      return cb();
    });
  }

  function onLink(link) {
    var target = link.replace(currentPath, targetPath);
    fs.readlink(link, function (err, resolvedPath) {
      if (err) {
        return onError(err);
      }
      checkLink(resolvedPath, target);
    });
  }

  function checkLink(resolvedPath, target) {
    path.exists(target, function (exists) {
      if (exists) {
        return fs.readlink(target, function (err, targetDest) {
          if (err) {
            return onError(err);
          }
          if (targetDest === resolvedPath) {
            return cb();
          }
          return rmFile(link, function () {
            makeLink(resolvedPath, target);
          });
        });
      }
      makeLink(resolvedPath, target);
    });
  }

  function makeLink(linkPath, target) {
    fs.symlink(linkPath, target, function (err) {
      if (err) {
        return onError(err);
      }
      return cb();
    });
  }

  function onError(err) {
    if (options.stopOnError) {
      return callback(err);
    }
    else if (!errs && options.errs) {
      errs = fs.createWriteStream(options.errs);
    }
    else if (!errs) {
      errs = [];
    }
    else if (options.errs) {
      if (typeof errs.write === 'undefined') {
        errs.push(err);
      }
      else {
        errs.write(err.stack + '\n\n');
      }
    }
    return cb();
  }

  function cb() {
    running--;
    finished++;
    if ((started === finished) && (running === 0)) {
      return errs ? callback(errs) : callback(null);
    }
  }
}

<|endoftext|>


<commit_before>//
// Strider Worker extension for Sauce Labs tests
//

var fs = require('fs')
var path = require('path')
var request = require('request')

// # of tries for application-under-test webserver to start up on specified port
// We test once per second
var HTTP_CHECK_RETRIES = 10

// Interval in between HTTP checks in ms
var HTTP_CHECK_INTERVAL = 1000

// Port on which the application-under-test webserver should bind to on localhost.
// Sauce Connector will tunnel from this to Sauce Cloud for Selenium tests
var HTTP_PORT = 8031

// Read & parse a JSON file
function getJson(filename, cb) {
  fs.readFile(filename, function(err, data) {
    if (err) return cb(err, null)
    try {
      var json = JSON.parse(data)
      cb(null, json)
    } catch(e) {
      cb(e, null)
    }
  })
}

// `npm install` has succeeded at this point.
// We run `npm test` and assuming that has passed,
// then we start the Sauce test process.
// If `npm test` fails, we don't bother with the overhead of running the Sauce tests.
function test(ctx, cb) {
  var sauceAccessKey = ctx.jobData.repo_config.sauce_access_key
  var sauceUsername = ctx.jobData.repo_config.sauce_username
  var sauceBrowsers = ctx.jobData.repo_config.sauce_browsers
  if (sauceBrowsers === undefined || sauceBrowsers.length === 0) {
    // Default to latest chrome on Windows Vista
    sauceBrowsers = [
      {
        browserName:"chrome",
        version:"",
        os:"Windows 2008'
      }
    ]
  }
  if (sauceAccessKey === undefined || sauceUsername === undefined) {
    ctx.striderMessage(("Sauce tests detected but Sauce credentials have not been configured!\n"
      + "  Please visit project config page to enter them"))
    return cb(1)
  }
  var startPhaseDone = false
  var tsh = ctx.shellWrap(ctx.npmCmd + " test")
  // Run
  ctx.forkProc(ctx.workingDir, tsh.cmd, tsh.args, function(exitCode) {
    if (exitCode !== 0) {
      return cb(exitCode)
    } else {
      ctx.striderMessage("npm test success - trying Sauce tests...")
      // Parse package.json so we can run the start script directly.
      // This is important because `npm start` will fork a subprocess a la shell
      // which means we cannot track the PID and shut it down later.
      getJson(path.join(ctx.workingDir, "package.json"), npmTestPassed)
    }
  })
  function npmTestPassed(err, packageJson) {
    if (err || packageJson.scripts === undefined || packageJson.scripts.start === undefined) {
      striderMessage("could not read package.json to find start command - failing test")
      return cb(1)
    }
    // `npm test` succeeded, so we go through the Sauce tests.

    // Start the app, suggesting a port via PORT environment variable
    var tsh = ctx.shellWrap(packageJson.scripts.start)
    var serverProc = ctx.forkProc({
      args:tsh.args,
      cmd:tsh.cmd,
      cwd:ctx.workingDir,
      env:{PORT:HTTP_PORT},
    }, function(exitCode) {
      // Could perhaps be backgrounding itself. This should be avoided.
      if (exitCode !== 0 && !startPhaseDone) {
        // If we haven't already called back with completion,
        // and `npm start` exits with non-zero exit code,
        // call back with error and mark done.
        ctx.striderMessage("npm start failed - failing test")
        startPhaseDone = true
        return cb(exitCode)
      }
    })

    // The project webserver should be available via HTTP once started.
    // This section implements a check which will attempt to make a HTTP request for /
    // expecting a 200 response code. It will try HTTP_CHECK_RETRIES times, waiting 1 second
    // between checks. If it fails after HTTP_CHECK_RETRIES times, the server process will be killed
    // and the test failed.
    var tries = 0
    ctx.striderMessage("Waiting for webserver to come up on localhost:" + HTTP_PORT)
    var intervalId = setInterval(function() {
      // Check for http status 200 on http://localhost:HTTP_PORT/
      request("http://localhost:"+HTTP_PORT+"/", function(err, response) {
        if (startPhaseDone) {
          clearInterval(intervalId)
          return
        }
        if (!err && response.statusCode == 200) {
          ctx.striderMessage("Got HTTP 200 on localhost:" + HTTP_PORT + " indicating server is up")
          startPhaseDone = true
          clearInterval(intervalId)
          serverUp()
        } else {
          tries++
          console.log("Error on localhost:%d: %s", HTTP_PORT, err)
          if (tries >= HTTP_CHECK_RETRIES) {
            var msg = ("HTTP 200 check on localhost:" + HTTP_PORT + " failed after " + tries
              + " retries, server not up - failing test")
            ctx.striderMessage(msg)
            clearInterval(intervalId)
            startPhaseDone = true
            return cb(1)
          }
        }
      })
    }, HTTP_CHECK_INTERVAL)

    // Start the Sauce Connector. Returns childProcess object.
    function startConnector(username, apiKey, cb) {
      var jarPath = path.join(__dirname, "thirdparty", "Sauce-Connect.jar")
      var jsh = ctx.shellWrap("java -jar " + jarPath + " " + username + " " + apiKey)

      ctx.striderMessage("Starting Sauce Connector")
      return ctx.forkProc(__dirname, jsh.cmd, jsh.args, cb)
    }

    // Server is up, start Sauce Connector and run the tests via `npm sauce` invocations
    function serverUp() {
      var done = false
      var connectorProc = startConnector(sauceUsername, sauceAccessKey,
        function(exitCode) {
        console.log("Connector exited with code: %d", exitCode)
        if (!done) {
          ctx.striderMessage("Error starting Sauce Connector - failing test")
          ctx.striderMessage("Shutting down server")
          serverProc.kill("SIGKILL")
          done = true
          return cb(1)
        }
      })

      // Wait until connector outputs "You may start your tests"
      // before executing Sauce tests
      connectorProc.stdout.on('data', function(data) {
        if (/Connected! You may start your tests./.exec(data) !== null) {
          var saucesh = ctx.shellWrap(ctx.npmCmd + " run-script sauce")
          //: TODO this should be a loop, executing `npm run-script sauce` for each
          // browser/OS combo specified for the project.
          var sauceDoneCount = 0
          var finaleStatusCode = 0
          sauceBrowsers.forEach(function(o) {
            ctx.striderMessage("Starting: SAUCE_BROWSER="+o.browserName
              +" SAUCE_OS="+o.platform+" SAUCE_BROWSER_VERSION="+o.version+" npm run-script sauce")
            var sauceProc = ctx.forkProc({
              args: saucesh.args,
              cmd: saucesh.cmd,
              cwd: ctx.workingDir,
              env: {
                SAUCE_USERNAME:sauceUsername,
                SAUCE_ACCESS_KEY:sauceAccessKey,
                SAUCE_OS:o.platform,
                SAUCE_BROWSER_VERSION:o.version,
                SAUCE_BROWSER:o.browserName,
              }
            }, function(code) {
              ctx.striderMessage("Exit code "+code
                +" for: SAUCE_BROWSER="+o.browserName +" SAUCE_OS="+o.platform+" SAUCE_BROWSER_VERSION="+o.version+" npm run-script sauce")
              sauceDoneCount++
              // If a single test fails, the whole test job fails.
              if (finaleStatusCode === 0 && code !== 0) {
                finaleStatusCode = 1
              }
              if (!done && sauceDoneCount === sauceBrowsers.length) {
                done = true
                ctx.striderMessage("Shutting down Sauce Connector")
                connectorProc.kill("SIGINT")
                ctx.striderMessage("Shutting down server")
                serverProc.kill()
                // Give Sauce Connector & server 5 seconds to gracefully stop before sending SIGKILL
                setTimeout(function() {
                  connectorProc.kill("SIGKILL")
                  serverProc.kill("SIGKILL")
                  return cb(finaleStatusCode)
                }, 5000)
              }
            })
          })
        }
      })
    }
  }
}

module.exports = function(ctx, cb) {

  ctx.addDetectionRule({
    filename:"package.json",
    jsonKeyExists:"scripts.sauce",
    language:"node.js",
    framework:null,
    hasSauce:true,
    prepare:ctx.npmCmd + " install",
    test:test
  })

  function saucePlugin(schema, opts) {
    schema.add({
      sauce_access_key: String,
      sauce_username: String,
      sauce_browsers: [],
    })

  }

  // Extend RepoConfig model with 'Sauce' properties
  ctx.models.RepoConfig.plugin(saucePlugin)

  console.log("strider-sauce worker extension loaded")
  cb(null, null)
}
<commit_msg>fix typo<commit_after>//
// Strider Worker extension for Sauce Labs tests
//

var fs = require('fs')
var path = require('path')
var request = require('request')

// # of tries for application-under-test webserver to start up on specified port
// We test once per second
var HTTP_CHECK_RETRIES = 10

// Interval in between HTTP checks in ms
var HTTP_CHECK_INTERVAL = 1000

// Port on which the application-under-test webserver should bind to on localhost.
// Sauce Connector will tunnel from this to Sauce Cloud for Selenium tests
var HTTP_PORT = 8031

// Read & parse a JSON file
function getJson(filename, cb) {
  fs.readFile(filename, function(err, data) {
    if (err) return cb(err, null)
    try {
      var json = JSON.parse(data)
      cb(null, json)
    } catch(e) {
      cb(e, null)
    }
  })
}

// `npm install` has succeeded at this point.
// We run `npm test` and assuming that has passed,
// then we start the Sauce test process.
// If `npm test` fails, we don't bother with the overhead of running the Sauce tests.
function test(ctx, cb) {
  var sauceAccessKey = ctx.jobData.repo_config.sauce_access_key
  var sauceUsername = ctx.jobData.repo_config.sauce_username
  var sauceBrowsers = ctx.jobData.repo_config.sauce_browsers
  if (sauceBrowsers === undefined || sauceBrowsers.length === 0) {
    // Default to latest chrome on Windows Vista
    sauceBrowsers = [
      {
        browserName:"chrome",
        version:"",
        os:"Windows 2008"
      }
    ]
  }
  if (sauceAccessKey === undefined || sauceUsername === undefined) {
    ctx.striderMessage(("Sauce tests detected but Sauce credentials have not been configured!\n"
      + "  Please visit project config page to enter them"))
    return cb(1)
  }
  var startPhaseDone = false
  var tsh = ctx.shellWrap(ctx.npmCmd + " test")
  // Run
  ctx.forkProc(ctx.workingDir, tsh.cmd, tsh.args, function(exitCode) {
    if (exitCode !== 0) {
      return cb(exitCode)
    } else {
      ctx.striderMessage("npm test success - trying Sauce tests...")
      // Parse package.json so we can run the start script directly.
      // This is important because `npm start` will fork a subprocess a la shell
      // which means we cannot track the PID and shut it down later.
      getJson(path.join(ctx.workingDir, "package.json"), npmTestPassed)
    }
  })
  function npmTestPassed(err, packageJson) {
    if (err || packageJson.scripts === undefined || packageJson.scripts.start === undefined) {
      striderMessage("could not read package.json to find start command - failing test")
      return cb(1)
    }
    // `npm test` succeeded, so we go through the Sauce tests.

    // Start the app, suggesting a port via PORT environment variable
    var tsh = ctx.shellWrap(packageJson.scripts.start)
    var serverProc = ctx.forkProc({
      args:tsh.args,
      cmd:tsh.cmd,
      cwd:ctx.workingDir,
      env:{PORT:HTTP_PORT},
    }, function(exitCode) {
      // Could perhaps be backgrounding itself. This should be avoided.
      if (exitCode !== 0 && !startPhaseDone) {
        // If we haven't already called back with completion,
        // and `npm start` exits with non-zero exit code,
        // call back with error and mark done.
        ctx.striderMessage("npm start failed - failing test")
        startPhaseDone = true
        return cb(exitCode)
      }
    })

    // The project webserver should be available via HTTP once started.
    // This section implements a check which will attempt to make a HTTP request for /
    // expecting a 200 response code. It will try HTTP_CHECK_RETRIES times, waiting 1 second
    // between checks. If it fails after HTTP_CHECK_RETRIES times, the server process will be killed
    // and the test failed.
    var tries = 0
    ctx.striderMessage("Waiting for webserver to come up on localhost:" + HTTP_PORT)
    var intervalId = setInterval(function() {
      // Check for http status 200 on http://localhost:HTTP_PORT/
      request("http://localhost:"+HTTP_PORT+"/", function(err, response) {
        if (startPhaseDone) {
          clearInterval(intervalId)
          return
        }
        if (!err && response.statusCode == 200) {
          ctx.striderMessage("Got HTTP 200 on localhost:" + HTTP_PORT + " indicating server is up")
          startPhaseDone = true
          clearInterval(intervalId)
          serverUp()
        } else {
          tries++
          console.log("Error on localhost:%d: %s", HTTP_PORT, err)
          if (tries >= HTTP_CHECK_RETRIES) {
            var msg = ("HTTP 200 check on localhost:" + HTTP_PORT + " failed after " + tries
              + " retries, server not up - failing test")
            ctx.striderMessage(msg)
            clearInterval(intervalId)
            startPhaseDone = true
            return cb(1)
          }
        }
      })
    }, HTTP_CHECK_INTERVAL)

    // Start the Sauce Connector. Returns childProcess object.
    function startConnector(username, apiKey, cb) {
      var jarPath = path.join(__dirname, "thirdparty", "Sauce-Connect.jar")
      var jsh = ctx.shellWrap("java -jar " + jarPath + " " + username + " " + apiKey)

      ctx.striderMessage("Starting Sauce Connector")
      return ctx.forkProc(__dirname, jsh.cmd, jsh.args, cb)
    }

    // Server is up, start Sauce Connector and run the tests via `npm sauce` invocations
    function serverUp() {
      var done = false
      var connectorProc = startConnector(sauceUsername, sauceAccessKey,
        function(exitCode) {
        console.log("Connector exited with code: %d", exitCode)
        if (!done) {
          ctx.striderMessage("Error starting Sauce Connector - failing test")
          ctx.striderMessage("Shutting down server")
          serverProc.kill("SIGKILL")
          done = true
          return cb(1)
        }
      })

      // Wait until connector outputs "You may start your tests"
      // before executing Sauce tests
      connectorProc.stdout.on('data', function(data) {
        if (/Connected! You may start your tests./.exec(data) !== null) {
          var saucesh = ctx.shellWrap(ctx.npmCmd + " run-script sauce")
          //: TODO this should be a loop, executing `npm run-script sauce` for each
          // browser/OS combo specified for the project.
          var sauceDoneCount = 0
          var finaleStatusCode = 0
          sauceBrowsers.forEach(function(o) {
            ctx.striderMessage("Starting: SAUCE_BROWSER="+o.browserName
              +" SAUCE_OS="+o.platform+" SAUCE_BROWSER_VERSION="+o.version+" npm run-script sauce")
            var sauceProc = ctx.forkProc({
              args: saucesh.args,
              cmd: saucesh.cmd,
              cwd: ctx.workingDir,
              env: {
                SAUCE_USERNAME:sauceUsername,
                SAUCE_ACCESS_KEY:sauceAccessKey,
                SAUCE_OS:o.platform,
                SAUCE_BROWSER_VERSION:o.version,
                SAUCE_BROWSER:o.browserName,
              }
            }, function(code) {
              ctx.striderMessage("Exit code "+code
                +" for: SAUCE_BROWSER="+o.browserName +" SAUCE_OS="+o.platform+" SAUCE_BROWSER_VERSION="+o.version+" npm run-script sauce")
              sauceDoneCount++
              // If a single test fails, the whole test job fails.
              if (finaleStatusCode === 0 && code !== 0) {
                finaleStatusCode = 1
              }
              if (!done && sauceDoneCount === sauceBrowsers.length) {
                done = true
                ctx.striderMessage("Shutting down Sauce Connector")
                connectorProc.kill("SIGINT")
                ctx.striderMessage("Shutting down server")
                serverProc.kill()
                // Give Sauce Connector & server 5 seconds to gracefully stop before sending SIGKILL
                setTimeout(function() {
                  connectorProc.kill("SIGKILL")
                  serverProc.kill("SIGKILL")
                  return cb(finaleStatusCode)
                }, 5000)
              }
            })
          })
        }
      })
    }
  }
}

module.exports = function(ctx, cb) {

  ctx.addDetectionRule({
    filename:"package.json",
    jsonKeyExists:"scripts.sauce",
    language:"node.js",
    framework:null,
    hasSauce:true,
    prepare:ctx.npmCmd + " install",
    test:test
  })

  function saucePlugin(schema, opts) {
    schema.add({
      sauce_access_key: String,
      sauce_username: String,
      sauce_browsers: [],
    })

  }

  // Extend RepoConfig model with 'Sauce' properties
  ctx.models.RepoConfig.plugin(saucePlugin)

  console.log("strider-sauce worker extension loaded")
  cb(null, null)
}
<|endoftext|>


<commit_before>process.execArgv[0] = process.execArgv[0].replace('-brk', '');

const cluster = require('cluster');
const gm = require('gm');
const Jimp = require('jimp');
const path = require('path');
const GIFEncoder = require('gifencoder');
const util = require('util');
const request = require('request');
const fs = require('fs');

const logger = {
    cluster: function(msg) {
        process.send({
            cmd: 'log',
            level: 'cluster',
            msg
        })
    },
    debug: function(msg) {
        process.send({
            cmd: 'log',
            level: 'debug',
            msg
        })
    },
    warn: function(msg) {
        process.send({
            cmd: 'log',
            level: 'warn',
            msg
        })
    },
    error: function(msg) {
        process.send({
            cmd: 'log',
            level: 'error',
            msg
        })
    },
    worker: function(msg) {
        process.send({
            cmd: 'log',
            level: 'worker',
            msg
        })
    }
};

process.on('message', async function(msg, handle) {
    switch (msg.cmd) {
        case 'img':
            let command = msg.command;
            try {
                switch (command) {
                    case 'shit':
                        await imgShit(msg);
                        break;
                    case 'retarded':
                        await imgRetarded(msg);
                        break;
                    case 'triggered':
                        await imgTriggered(msg);
                        break;
                    case 'art':
                        await imgArt(msg);
                        break;
                    case 'free':
                        await imgFree(msg);
                        break;
                    case 'caption':
                        await imgCaption(msg);
                        break;
                    case 'cah':
                        await imgCah(msg);
                        break;
                }
            } catch (err) {
                logger.error(err.stack);
            }
            break;
        default:
            logger.worker(`Worker ${cluster.worker.id} got a message!\n${util.inspect(msg)}`);
    }
});

async function submitBuffer(code, buffer) {
    logger.worker('Finished, submitting as base64');
    process.send({
        cmd: 'img',
        code: code,
        buffer: buffer.toString('base64')
    })
}

async function imgFree(msg) {
    let topCaption = await Jimp.read(await createCaption({
        text: msg.top,
        font: 'impact.ttf',
        fill: 'white',
        stroke: 'black',
        strokewidth: 5,
        gravity: 'north',
        size: '380x100'
    }));
    let bottomText = msg.bottom || 'CLICK HERE TO\nFIND OUT HOW';
    let bottomCaption = await Jimp.read(await createCaption({
        text: bottomText,
        font: 'arial.ttf',
        fill: 'white',
        gravity: 'center',
        size: '380x70'
    }));

    let back1 = await Jimp.read(path.join(__dirname, 'img', 'freefreefree0.png'));
    let back2 = await Jimp.read(path.join(__dirname, 'img', 'freefreefree1.png'));

    let frameCount = 6;
    let frames = [];

    let buffers = [];
    let encoder = new GIFEncoder(400, 300);
    let stream = encoder.createReadStream();

    stream.on('data', function(buffer) {
        buffers.push(buffer);
    });
    stream.on('end', function() {
        submitBuffer(msg.code, Buffer.concat(buffers));
    });

    let base = new Jimp(400, 300);

    for (let i = 0; i < frameCount; i++) {
        let temp = base.clone();
        temp.composite(i < frameCount / 2 ? back1 : back2, 0, 0);
        temp.composite(topCaption, i == 0 ? 10 : getRandomInt(-25, 25), i == 0 ? 15 : getRandomInt(0, 20));
        temp.composite(bottomCaption, 10, 228);
        frames.push(temp.bitmap.data);
    }

    encoder.start();
    encoder.setRepeat(0);
    encoder.setDelay(50);
    for (let frame of frames) encoder.addFrame(frame);
    encoder.finish();
}

async function imgCaption(msg) {
    let img = await Jimp.read(await getResource(msg.url));
    let height = img.bitmap.height;
    let width = img.bitmap.width;
    let topbuf;
    let botbuf;
    let input = msg.input;
    let font = msg.font;
    if (input.t) {
        topbuf = await createCaption({
            text: input.t.join(' '),
            font,
            size: `${width}x${height / 6}`,
            gravity: 'north',
            fill: 'white',
            stroke: 'black',
            strokewidth: 4
        })
        let topcap = await Jimp.read(topbuf);
        img.composite(topcap, 0, 0);
    }
    if (input.b) {
        botbuf = await createCaption({
            text: input.b.join(' '),
            font,
            size: `${width}x${height / 6}`,
            gravity: 'south',
            fill: 'white',
            stroke: 'black',
            strokewidth: 4
        })
        let botcap = await Jimp.read(botbuf);
        img.composite(botcap, 0, height / 6 * 5);
    }
    img.scaleToFit(800, 800);

    img.getBuffer(Jimp.MIME_JPEG, (err, buffer) => {
        submitBuffer(msg.code, buffer);
    })
}

async function imgCah(msg) {
    let blackCard = await Jimp.read(path.join(__dirname, 'img', 'blackcard.png'))
    let whiteCard = await Jimp.read(path.join(__dirname, 'img', 'whitecard.png'))

    let finalImg = new Jimp(183 * (msg.white.length + 1), 254);
    let blackCaption = await Jimp.read(await createCaption({
        font: 'arial.ttf',
        fill: '#ffffff',
        text: msg.black,
        size: '144x190',
        gravity: 'northwest'
    }));
    finalImg.composite(blackCard, 0, 0);
    finalImg.composite(blackCaption, 19, 19);

    for (let i = 0; i < msg.white.length; i++) {
        let whiteCaption = await Jimp.read(await createCaption({
            font: 'arial.ttf',
            fill: 'black',
            text: msg.white[i],
            size: '144x190',
            gravity: 'northwest'
        }));
        finalImg.composite(whiteCard, 183 * (i + 1), 0);
        finalImg.composite(whiteCaption, 183 * (i + 1) + 19, 19);
    }

    finalImg.getBuffer(Jimp.MIME_PNG, (err, buffer) => {
        submitBuffer(msg.code, buffer);
    })
}

async function imgRetarded(msg) {
    let buf = await createCaption({
        font: 'ARCENA.ttf',
        fill: 'black',
        stroke: 'white',
        strokewidth: 5,
        text: msg.text,
        size: '272x60'
    });

    let text = await Jimp.read(buf);
    let img = await Jimp.read(path.join(__dirname, 'img', `retarded.png`));
    if (msg.avatar) {
        let avatar = await Jimp.read(await getResource(msg.avatar));
        let smallAvatar = avatar.clone();
        smallAvatar.resize(74, 74);
        img.composite(smallAvatar, 166, 131);
        avatar.resize(171, 171);
        avatar.rotate(18)
        img.composite(avatar, 277, 32);
    }
    img.composite(text, 268, 0);
    img.getBuffer(Jimp.MIME_PNG, (err, buffer) => {
        submitBuffer(msg.code, buffer);
    })
}

async function imgShit(msg) {
    let buf = await createCaption({
        text: msg.text,
        font: 'animeace.ttf',
        size: '200x160',
        gravity: 'South'
    });

    let text = await Jimp.read(buf);
    let img = await Jimp.read(path.join(__dirname, 'img', `SHIT${msg.plural ? 'S' : ''}.png`));
    img.composite(text, 810, 31);

    img.getBuffer(Jimp.MIME_PNG, (err, buffer) => {
        submitBuffer(msg.code, buffer);
    })
}

async function imgArt(msg) {
    let avatar = await Jimp.read(await getResource(msg.avatar));
    avatar.resize(370, 370);
    let foreground = await Jimp.read(path.join(__dirname, 'img', `art.png`));
    let img = new Jimp(1364, 1534);
    img.composite(avatar, 903, 92);
    img.composite(avatar, 903, 860);
    img.composite(foreground, 0, 0);

    img.getBuffer(Jimp.MIME_PNG, (err, buffer) => {
        submitBuffer(msg.code, buffer);
    })
}

async function imgTriggered(msg) {
    let frameCount = 8;
    let frames = [];
    let avatar = await Jimp.read(await getResource(msg.avatar));
    avatar.resize(320, 320);
    if (msg.inverted) avatar.invert();
    if (msg.horizontal) avatar.flip(true, false);
    if (msg.vertical) avatar.flip(false, true);
    if (msg.sepia) avatar.sepia();
    if (msg.blur) avatar.blur(10);
    if (msg.greyscale) avatar.greyscale();

    let triggered = await Jimp.read(path.join(__dirname, 'img', `triggered.png`))
    triggered.resize(280, 60);
    triggered.opacity(0.8);
    let overlay = await Jimp.read(path.join(__dirname, 'img', `red.png`));

    let buffers = [];
    let encoder = new GIFEncoder(256, 256);
    let stream = encoder.createReadStream();

    stream.on('data', function(buffer) {
        buffers.push(buffer);
    });
    stream.on('end', function() {
        let buffer = Buffer.concat(buffers);
        submitBuffer(msg.code, buffer);
    });

    let base = new Jimp(256, 256);

    let temp, x, y;
    for (let i = 0; i < frameCount; i++) {
        temp = base.clone();
        if (i == 0) {
            x = -16;
            y = -16
        } else {
            x = -32 + (getRandomInt(-16, 16));
            y = -32 + (getRandomInt(-16, 16));
        }
        temp.composite(avatar, x, y);
        if (i == 0) {
            x = -10;
            y = 200;
        } else {
            x = -12 + (getRandomInt(-8, 8));
            y = 200 + (getRandomInt(-0, 12));
        }
        temp.composite(overlay, 0, 0);
        temp.composite(triggered, x, y);
        frames.push(temp.bitmap.data);
    }
    encoder.start();
    encoder.setRepeat(0);
    encoder.setDelay(20);
    for (let frame of frames) encoder.addFrame(frame);
    encoder.finish();
}

function createCaption(options) {
    return new Promise((fulfill, reject) => {
        if (!options.text) {
            reject(new Error('No text provided'));
            return;
        }
        if (!options.font) {
            reject(new Error('No font provided'));
            return;
        }
        if (!options.size) {
            reject(new Error('No size provided'));
            return;
        }
        if (!options.fill) options.fill = 'black';
        if (!options.gravity) options.gravity = 'Center';
        logger.debug(`Generating caption for text '${options.text}'`)

        let image = gm().command('convert');

        image.font(path.join(__dirname, 'img', 'fonts', options.font));
        image.out('-size').out(options.size);
        image.out('-background').out('transparent');
        image.out('-fill').out(options.fill);
        image.out('-gravity').out(options.gravity);
        image.out()
        if (options.stroke) {
            image.out('-stroke').out(options.stroke);
            if (options.strokewidth) image.out('-strokewidth').out(options.strokewidth);
        }
        image.out(`caption:${options.text}`);
        if (options.stroke) {
            image.out('-compose').out('Over')
            image.out('-size').out(options.size);
            image.out('-background').out('transparent');
            image.out('-fill').out(options.fill);
            image.out('-gravity').out(options.gravity);
            image.out('-stroke').out('none');
            image.out(`caption:${options.text}`);
            image.out('-composite');
        }

        image.options({
            imageMagick: true
        }).toBuffer('PNG', function(err, buf) {
            if (err) {
                reject(err);
                return;
            }
            fulfill(buf);
        })
    })
}

function padRight(value, length) {
    return (value.toString().length < length) ? padRight(value + ' ', length) : value;
};

function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
};

function getResource(url) {
    return new Promise(async function(fulfill, reject) {
        let r = await aRequest({
            uri: url
        });
        if (r.res.headers['content-type'] == 'image/gif') {
            gm(r.body, 'temp.gif').selectFrame(0).setFormat('png').toBuffer(function(err, buffer) {
                if (err) {
                    logger.error('Error converting gif');
                    reject(err);
                    return;
                }
                fulfill(buffer);
            });
        } else if (r.res.headers['content-type'] == 'image/png' ||
            r.res.headers['content-type'] == 'image/jpeg' ||
            r.res.headers['content-type'] == 'image/bmp') {
            fulfill(r.body);
        } else {
            reject('Wrong file type!');
        }
    });
}

function aRequest(obj) {
    return new Promise((fulfill, reject) => {
        if (!obj.encoding) obj.encoding = null;
        request(obj, (err, res, body) => {
            if (err) {
                reject(err);
                return;
            }
            fulfill({
                res: res,
                body: body
            });
        })
    });
}<commit_msg>error messages<commit_after>process.execArgv[0] = process.execArgv[0].replace('-brk', '');

const cluster = require('cluster');
const gm = require('gm');
const Jimp = require('jimp');
const path = require('path');
const GIFEncoder = require('gifencoder');
const util = require('util');
const request = require('request');
const fs = require('fs');

const logger = {
    cluster: function(msg) {
        process.send({
            cmd: 'log',
            level: 'cluster',
            msg
        })
    },
    debug: function(msg) {
        process.send({
            cmd: 'log',
            level: 'debug',
            msg
        })
    },
    warn: function(msg) {
        process.send({
            cmd: 'log',
            level: 'warn',
            msg
        })
    },
    error: function(msg) {
        process.send({
            cmd: 'log',
            level: 'error',
            msg
        })
    },
    worker: function(msg) {
        process.send({
            cmd: 'log',
            level: 'worker',
            msg
        })
    }
};

process.on('message', async function(msg, handle) {
    switch (msg.cmd) {
        case 'img':
            let command = msg.command;
            try {
                switch (command) {
                    case 'shit':
                        await imgShit(msg);
                        break;
                    case 'retarded':
                        await imgRetarded(msg);
                        break;
                    case 'triggered':
                        await imgTriggered(msg);
                        break;
                    case 'art':
                        await imgArt(msg);
                        break;
                    case 'free':
                        await imgFree(msg);
                        break;
                    case 'caption':
                        await imgCaption(msg);
                        break;
                    case 'cah':
                        await imgCah(msg);
                        break;
                }
            } catch (err) {
                logger.error(err.stack);
            }
            break;
        default:
            logger.worker(`Worker ${cluster.worker.id} got a message!\n${util.inspect(msg)}`);
    }
});

async function submitBuffer(code, buffer) {
    logger.worker('Finished, submitting as base64');
    process.send({
        cmd: 'img',
        code: code,
        buffer: buffer.toString('base64')
    })
}

async function imgFree(msg) {
    let topCaption = await Jimp.read(await createCaption({
        text: msg.top,
        font: 'impact.ttf',
        fill: 'white',
        stroke: 'black',
        strokewidth: 5,
        gravity: 'north',
        size: '380x100'
    }));
    let bottomText = msg.bottom || 'CLICK HERE TO\nFIND OUT HOW';
    let bottomCaption = await Jimp.read(await createCaption({
        text: bottomText,
        font: 'arial.ttf',
        fill: 'white',
        gravity: 'center',
        size: '380x70'
    }));

    let back1 = await Jimp.read(path.join(__dirname, 'img', 'freefreefree0.png'));
    let back2 = await Jimp.read(path.join(__dirname, 'img', 'freefreefree1.png'));

    let frameCount = 6;
    let frames = [];

    let buffers = [];
    let encoder = new GIFEncoder(400, 300);
    let stream = encoder.createReadStream();

    stream.on('data', function(buffer) {
        buffers.push(buffer);
    });
    stream.on('end', function() {
        submitBuffer(msg.code, Buffer.concat(buffers));
    });

    let base = new Jimp(400, 300);

    for (let i = 0; i < frameCount; i++) {
        let temp = base.clone();
        temp.composite(i < frameCount / 2 ? back1 : back2, 0, 0);
        temp.composite(topCaption, i == 0 ? 10 : getRandomInt(-25, 25), i == 0 ? 15 : getRandomInt(0, 20));
        temp.composite(bottomCaption, 10, 228);
        frames.push(temp.bitmap.data);
    }

    encoder.start();
    encoder.setRepeat(0);
    encoder.setDelay(50);
    for (let frame of frames) encoder.addFrame(frame);
    encoder.finish();
}

async function imgCaption(msg) {
    let img = await Jimp.read(await getResource(msg.url));
    let height = img.bitmap.height;
    let width = img.bitmap.width;
    let topbuf;
    let botbuf;
    let input = msg.input;
    let font = msg.font;
    if (input.t) {
        topbuf = await createCaption({
            text: input.t.join(' '),
            font,
            size: `${width}x${height / 6}`,
            gravity: 'north',
            fill: 'white',
            stroke: 'black',
            strokewidth: 4
        })
        let topcap = await Jimp.read(topbuf);
        img.composite(topcap, 0, 0);
    }
    if (input.b) {
        botbuf = await createCaption({
            text: input.b.join(' '),
            font,
            size: `${width}x${height / 6}`,
            gravity: 'south',
            fill: 'white',
            stroke: 'black',
            strokewidth: 4
        })
        let botcap = await Jimp.read(botbuf);
        img.composite(botcap, 0, height / 6 * 5);
    }
    img.scaleToFit(800, 800);

    img.getBuffer(Jimp.MIME_JPEG, (err, buffer) => {
        submitBuffer(msg.code, buffer);
    })
}

async function imgCah(msg) {
    let blackCard = await Jimp.read(path.join(__dirname, 'img', 'blackcard.png'))
    let whiteCard = await Jimp.read(path.join(__dirname, 'img', 'whitecard.png'))

    let finalImg = new Jimp(183 * (msg.white.length + 1), 254);
    let blackCaption = await Jimp.read(await createCaption({
        font: 'arial.ttf',
        fill: '#ffffff',
        text: msg.black,
        size: '144x190',
        gravity: 'northwest'
    }));
    finalImg.composite(blackCard, 0, 0);
    finalImg.composite(blackCaption, 19, 19);

    for (let i = 0; i < msg.white.length; i++) {
        let whiteCaption = await Jimp.read(await createCaption({
            font: 'arial.ttf',
            fill: 'black',
            text: msg.white[i],
            size: '144x190',
            gravity: 'northwest'
        }));
        finalImg.composite(whiteCard, 183 * (i + 1), 0);
        finalImg.composite(whiteCaption, 183 * (i + 1) + 19, 19);
    }

    finalImg.getBuffer(Jimp.MIME_PNG, (err, buffer) => {
        submitBuffer(msg.code, buffer);
    })
}

async function imgRetarded(msg) {
    let buf = await createCaption({
        font: 'ARCENA.ttf',
        fill: 'black',
        stroke: 'white',
        strokewidth: 5,
        text: msg.text,
        size: '272x60'
    });

    let text = await Jimp.read(buf);
    let img = await Jimp.read(path.join(__dirname, 'img', `retarded.png`));
    if (msg.avatar) {
        let avatar = await Jimp.read(await getResource(msg.avatar));
        let smallAvatar = avatar.clone();
        smallAvatar.resize(74, 74);
        img.composite(smallAvatar, 166, 131);
        avatar.resize(171, 171);
        avatar.rotate(18)
        img.composite(avatar, 277, 32);
    }
    img.composite(text, 268, 0);
    img.getBuffer(Jimp.MIME_PNG, (err, buffer) => {
        submitBuffer(msg.code, buffer);
    })
}

async function imgShit(msg) {
    let buf = await createCaption({
        text: msg.text,
        font: 'animeace.ttf',
        size: '200x160',
        gravity: 'South'
    });

    let text = await Jimp.read(buf);
    let img = await Jimp.read(path.join(__dirname, 'img', `SHIT${msg.plural ? 'S' : ''}.png`));
    img.composite(text, 810, 31);

    img.getBuffer(Jimp.MIME_PNG, (err, buffer) => {
        submitBuffer(msg.code, buffer);
    })
}

async function imgArt(msg) {
    let avatar = await Jimp.read(await getResource(msg.avatar));
    avatar.resize(370, 370);
    let foreground = await Jimp.read(path.join(__dirname, 'img', `art.png`));
    let img = new Jimp(1364, 1534);
    img.composite(avatar, 903, 92);
    img.composite(avatar, 903, 860);
    img.composite(foreground, 0, 0);

    img.getBuffer(Jimp.MIME_PNG, (err, buffer) => {
        submitBuffer(msg.code, buffer);
    })
}

async function imgTriggered(msg) {
    let frameCount = 8;
    let frames = [];
    let avatar = await Jimp.read(await getResource(msg.avatar));
    avatar.resize(320, 320);
    if (msg.inverted) avatar.invert();
    if (msg.horizontal) avatar.flip(true, false);
    if (msg.vertical) avatar.flip(false, true);
    if (msg.sepia) avatar.sepia();
    if (msg.blur) avatar.blur(10);
    if (msg.greyscale) avatar.greyscale();

    let triggered = await Jimp.read(path.join(__dirname, 'img', `triggered.png`))
    triggered.resize(280, 60);
    triggered.opacity(0.8);
    let overlay = await Jimp.read(path.join(__dirname, 'img', `red.png`));

    let buffers = [];
    let encoder = new GIFEncoder(256, 256);
    let stream = encoder.createReadStream();

    stream.on('data', function(buffer) {
        buffers.push(buffer);
    });
    stream.on('end', function() {
        let buffer = Buffer.concat(buffers);
        submitBuffer(msg.code, buffer);
    });

    let base = new Jimp(256, 256);

    let temp, x, y;
    for (let i = 0; i < frameCount; i++) {
        temp = base.clone();
        if (i == 0) {
            x = -16;
            y = -16
        } else {
            x = -32 + (getRandomInt(-16, 16));
            y = -32 + (getRandomInt(-16, 16));
        }
        temp.composite(avatar, x, y);
        if (i == 0) {
            x = -10;
            y = 200;
        } else {
            x = -12 + (getRandomInt(-8, 8));
            y = 200 + (getRandomInt(-0, 12));
        }
        temp.composite(overlay, 0, 0);
        temp.composite(triggered, x, y);
        frames.push(temp.bitmap.data);
    }
    encoder.start();
    encoder.setRepeat(0);
    encoder.setDelay(20);
    for (let frame of frames) encoder.addFrame(frame);
    encoder.finish();
}

function createCaption(options) {
    return new Promise((fulfill, reject) => {
        if (!options.text) {
            reject(new Error('No text provided'));
            return;
        }
        if (!options.font) {
            reject(new Error('No font provided'));
            return;
        }
        if (!options.size) {
            reject(new Error('No size provided'));
            return;
        }
        if (!options.fill) options.fill = 'black';
        if (!options.gravity) options.gravity = 'Center';
        logger.debug(`Generating caption for text '${options.text}'`)

        let image = gm().command('convert');

        image.font(path.join(__dirname, 'img', 'fonts', options.font));
        image.out('-size').out(options.size);
        image.out('-background').out('transparent');
        image.out('-fill').out(options.fill);
        image.out('-gravity').out(options.gravity);
        image.out()
        if (options.stroke) {
            image.out('-stroke').out(options.stroke);
            if (options.strokewidth) image.out('-strokewidth').out(options.strokewidth);
        }
        image.out(`caption:${options.text}`);
        if (options.stroke) {
            image.out('-compose').out('Over')
            image.out('-size').out(options.size);
            image.out('-background').out('transparent');
            image.out('-fill').out(options.fill);
            image.out('-gravity').out(options.gravity);
            image.out('-stroke').out('none');
            image.out(`caption:${options.text}`);
            image.out('-composite');
        }

        image.options({
            imageMagick: true
        }).toBuffer('PNG', function(err, buf) {
            if (err) {
                logger.error(`Failed to generate a caption: '${options.text}'`)
                reject(err);
                return;
            }
            logger.debug(`Caption generated: '${options.text}'`)
            fulfill(buf);
        })
    })
}

function padRight(value, length) {
    return (value.toString().length < length) ? padRight(value + ' ', length) : value;
};

function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
};

function getResource(url) {
    return new Promise(async function(fulfill, reject) {
        let r = await aRequest({
            uri: url
        });
        if (r.res.headers['content-type'] == 'image/gif') {
            gm(r.body, 'temp.gif').selectFrame(0).setFormat('png').toBuffer(function(err, buffer) {
                if (err) {
                    logger.error('Error converting gif');
                    reject(err);
                    return;
                }
                fulfill(buffer);
            });
        } else if (r.res.headers['content-type'] == 'image/png' ||
            r.res.headers['content-type'] == 'image/jpeg' ||
            r.res.headers['content-type'] == 'image/bmp') {
            fulfill(r.body);
        } else {
            reject('Wrong file type!');
        }
    });
}

function aRequest(obj) {
    return new Promise((fulfill, reject) => {
        if (!obj.encoding) obj.encoding = null;
        request(obj, (err, res, body) => {
            if (err) {
                reject(err);
                return;
            }
            fulfill({
                res: res,
                body: body
            });
        })
    });
}<|endoftext|>


<commit_before>
GLOBAL.worker = {

  emit : function ( _type ) {

    process.send( { _type : _type , args : Array.prototype.slice.call( arguments , 1 ) } ) ;

  },

  main : function(){ GLOBAL.worker.emit(new Error('No Worker Function Provided')) }

};

process.on( 'message' , function ( m , socket ) {

  if ( m.module ) {

    GLOBAL.worker.main = require( m.module ) ;

  }

  if ( m.fn ) {

    GLOBAL.worker.main = eval( "(" + m.fn + ")" ) ;

  }

  if ( m.process ) {

    GLOBAL.worker.main.apply(GLOBAL,m.process)

  }

  if ( socket ) {

    GLOBAL.worker.socket = socket ;

  }

});

process.on('uncaughtException',function(err){

  GLOBAL.worker.emit('complete',err.stack) ;

})
<commit_msg>no uncaught exception<commit_after>
GLOBAL.worker = {

  emit : function ( _type ) {

    process.send( { _type : _type , args : Array.prototype.slice.call( arguments , 1 ) } ) ;

  },

  main : function(){ GLOBAL.worker.emit(new Error('No Worker Function Provided')) }

};

process.on( 'message' , function ( m , socket ) {

  if ( m.module ) {

    GLOBAL.worker.main = require( m.module ) ;

  }

  if ( m.fn ) {

    GLOBAL.worker.main = eval( "(" + m.fn + ")" ) ;

  }

  if ( m.process ) {

    GLOBAL.worker.main.apply(GLOBAL,m.process)

  }

  if ( socket ) {

    GLOBAL.worker.socket = socket ;

  }

});
<|endoftext|>