<commit_before>'use strict'

const Qs = require('querystring')
const Url = require('url')

const DevToolsHelper = require('./DevToolsHelper')

/**
 * internals
 * To wrap private methods and properties
 *   when bound to a instantiated object of this class
 */
const internals = {
}

/**
* @class HarEntryBuilder
*/
class HarEntryBuilder extends DevToolsHelper {
  /**
  * @constructor
  */
  constructor (remoteDebugChrome) {
    super()
    this._parent = remoteDebugChrome
    this._requestsMap = new Map()
    this._harEntries = new Map()  // after request/response processed
    this._options = remoteDebugChrome.options
  }

  /**
   * @public
   * @method destroy - clean up
  */
  destroy () {
    this._requestsMap.clear()
    this._harEntries.clear()
    this._harEntries = null
    this._requestsMap = null
    this._parent = null
  }

  /**
   * @public
   * @method addRequest
   *
  */
  addRequest (reqObj, cookies) {
    const request = {
      method: reqObj.request.method,
      url: reqObj.request.url,
      cookies: cookies,
      headers: reqObj.request.headers,
      httpVersion: '',
      queryString: internals.harQueryString(reqObj.request.url),
      postData: {},
      headersSize: -1,
      bodySize: -1
    }

    if (reqObj.request.hasOwnProperty('postData')) {
      request.postData = internals.harPostdata(reqObj.request.postData,
                                                request.headers)
    }

    // since there may be many updated (redirect, etc...) to a
    // single requestId, keep as an array for later response comparasion
    let harEntry = this._requestsMap.get(reqObj.requestId)
    if (harEntry === undefined) {
      harEntry = {
        requestId: reqObj.requestId,
        wallTime: reqObj.wallTime,
        requestArr: []
      }
    } else if (reqObj.hasOwnProperty('redirectResponse')) {
      const { requestArr } = harEntry
       // if this is a new request created from a redirect response, save it too
      const prevReq = requestArr[requestArr.length - 1]
      prevReq.redirectResponse = reqObj.redirectResponse
    }

    harEntry.requestArr.push(request)
    this._requestsMap.set(reqObj.requestId, harEntry)

    if (this.listenerCount(`event${reqObj.requestId}`) > 0) {
      // notify the responseHandler, which may have arrived before this
      // requestHandler finished for this requestId
      this.emitAsync(`event${reqObj.requestId}`)
    }
  }

  /**
   * @public
   * @method addResponse
   *
  */
  addResponse (respObj) {
    if (this._requestsMap.has(respObj.requestId) === false) {
      // sometimes (e.g. on http failure), the Network.loadingFailed
      // arrvies before Network.requestWillBeSent is finished waiting
      // for an async request out asking the devToolProtocol for the cookies
      this.once(`event${respObj.requestId}`,
              this.addResponse.bind(this, respObj))
      return
    }

    const entryObj = this._requestsMap.get(respObj.requestId)
    this._requestsMap.delete(respObj.requestId) // clean up

    // match the response obj to associated request object
    internals.addResponse.call(this, entryObj, respObj)
  }
}

/********************************************************/

/**
 * @private
 * @method addResponse
*/
internals.addResponse = function (entryObj, respObj) {
  const { networkDevTools } = this._parent
  const { requestArr, wallTime } = entryObj

  if (respObj.hasOwnProperty('errorText')) {
    internals.addFailedResponse.call(this, wallTime, requestArr[0], respObj)
    return
  }

  // check if should ignore filtered response attributes
  if (internals.ignoreRespOnFilters.call(this, respObj)) {
    return
  }

  // now request the body and cookies. Asynchronously
  const respBodyPromise = networkDevTools.retrieveResponseBody(respObj)
  const respCookiesPromise = networkDevTools.retrieveResponseCookies(respObj)
  const self = this

  // await for the body and cookies to both arrive
  Promise.all([respBodyPromise, respCookiesPromise])
    .then((respData) => {
      const respDataObj = {
        respBodyObj: respData[0],
        cookiesObj: respData[1],
        wallTime: wallTime
      }
      const addResponseDataFn =
              internals.addResponseData.bind(self, respDataObj, respObj)
      requestArr.forEach(addResponseDataFn)
      internals.finishRequest.call(self, { requestId: respObj.requestId })
    })
}

/**
 * @private
 * @method addResponseData - now that optional response data has been
 * retrieved, build the har entry
*/
internals.addResponseData = function (respDataObj, respObj, reqObj) {
  const { respBodyObj, cookiesObj } = respDataObj
  if (respBodyObj.base64Encoded === true && this._options.filters.ignoreRespBodyBase64) {
    return
  }

  let respMsg = respObj.response
  let redirectUrl = ''
  if (reqObj.hasOwnProperty('redirectResponse')) {
    // use the redirect response ignoring the one passed in
    redirectUrl = respMsg.url // before replacing, get this url
    respMsg = reqObj.redirectResponse
  }

  const response = {
    status: respMsg.status,
    statusText: respMsg.statusText,
    cookies: cookiesObj.cookies,
    headers: respMsg.headers,
    content: {
      size: respBodyObj.body.length,
      mimeType: respMsg.headers['Content-Type'],
      text: respBodyObj.body,
      encoding: respBodyObj.base64Encoding ? 'base64' : 'ascii'
    },
    redirectURL: redirectUrl,
    headersSize: respMsg.headersText === undefined ? -1
                  : respMsg.headersText.length,
    bodySize: respBodyObj.body.length
  }

  // no need to bind to THIS context
  internals.applyHttpVersion(response, respMsg, reqObj)

  internals.addHarEntry.call(this, respObj.requestId, respDataObj.wallTime,
                              reqObj, response)
}

/**
 * @private
 * @method applyHttpVersion - apply http version string to the passed objects
*/
internals.applyHttpVersion = function (response, respMsg, reqObj) {
  const regExVer = /HTTP\/\d+\.\d+/
  const httpRespVerArr = regExVer.exec(respMsg.headersText)
  const httpReqVerArr = regExVer.exec(respMsg.requestHeadersText)

  response.httpVersion = (httpRespVerArr === null)
                  ? respMsg.protocol.toUpperCase() : httpRespVerArr[0]

  // default to use the response HTTP version if the requestHeadersText is null
  reqObj.httpVersion = (httpReqVerArr === null)
                  ? response.httpVersion : httpReqVerArr[0]
}

/**
 * @private
 * @method ignoreRespOnFilters - passed in options decide which
 * response urls, mimtypes, etc... to ignore
*/
internals.ignoreRespOnFilters = function (respObj) {
  const ignoreIsAMatch = function isaMatch (regexArray, strToTest) {
    return regexArray.some(rx => rx.test(strToTest))
  }

  const { filters } = this._options
  if (ignoreIsAMatch(filters.ignoreRespMime, respObj.response.mimeType)) {
    return true
  } else if (ignoreIsAMatch(filters.ignoreRespUrl, respObj.response.url)) {
    return true
  } else return false
}

/**
 * @private
 * @method addFailedResponse
*/
internals.addFailedResponse = function (wallTime, reqObj, respObj) {
  const response = {
    status: -1,
    statusText: respObj.errorText,
    httpVersion: '',
    cookies: [],
    headers: [],
    content: {},
    redirectURL: '',
    headersSize: -1,
    bodySize: -1
  }

  const { requestId } = respObj
  internals.addHarEntry.call(this, requestId, wallTime, reqObj, response)
  internals.finishRequest.call(this, { requestId: respObj.requestId })
}

/**
 * @private
 * @method addHarEntry
*/
internals.addHarEntry = function (requestId, wallTime, reqObj, response) {
  const timings = {
    send: 0,
    wait: 0,
    receive: 0
  }

  const harRequest = {
    startedDateTime: new Date(wallTime * 1000).toISOString(),
    time: 0,
    request: reqObj,
    response: response,
    cache: {},
    timings: timings
  }

  // there will be multiple entries with same requestId when redirected
  let entriesArr = this._harEntries.get(requestId)
  if (entriesArr === undefined) {
    entriesArr = []
  }

  entriesArr.push(harRequest)

  // save this entry
  this._harEntries.set(requestId, entriesArr)
}

/**
 * @private
 * @method internals.finishRequest
 *
*/
internals.finishRequest = function (loadingObj) {
  const requestId = loadingObj.requestId
  if (this._harEntries.has(requestId) === false) return

  const entriesArr = this._harEntries.get(requestId)
  this._harEntries.delete(requestId) // clean up

  const err = null
  const emitHarEntry = this._parent.emitAsync.bind(this._parent, 'harEntry')
  entriesArr.forEach(function emitEachHarEntry (entry) {
    emitHarEntry(err, entry)
  })
}

/**
 * @private
 * @method harQueryString - har queryString is represented as an Array
 * @returns {Array}
*/
internals.harQueryString = function (url) {
  const queryString = Url.parse(url, true).query
  const queryStringArr = internals.harConvertToPairs(queryString)

  return queryStringArr
}

/**
 * @private
 * @method harPostdata - har postdata is represented as a Object
 * @returns {Object}
*/
internals.harPostdata = function (postdataStr, headers) {
  function isConentUrlEncoded (headers) {
    return headers.hasOwnProperty('Content-Type') &&
      headers['Content-Type'].indexOf('application/x-www-form-urlencoded') >= 0
  }

  let postDataObj = { mimeType: headers['Content-Type'] }
  if (isConentUrlEncoded(headers)) {
    const qsParamsObj = Qs.parse(postdataStr)
    postDataObj.params = internals.harConvertToPairs(qsParamsObj)
  } else {
    postDataObj.text = postdataStr
  }

  return postDataObj
}

/**
 * @private
 * @method harConvertToPairs
 * @returns {Array}
*/
internals.harConvertToPairs = function (pairsObject) {
  const pairsMap = Object.keys(pairsObject).map(key => {
    const pair = {
      name: key
    }

    if (pairsObject[key] !== undefined && pairsObject[key] !== null) {
      pair.value = pairsObject[key]
    }

    return pair
  })

  return pairsMap  // an Array
}

module.exports = HarEntryBuilder
<commit_msg>Correctly require \"devToolsHelper\" with its case sensitive name issue #5<commit_after>'use strict'

const Qs = require('querystring')
const Url = require('url')

const DevToolsHelper = require('./devToolsHelper')

/**
 * internals
 * To wrap private methods and properties
 *   when bound to a instantiated object of this class
 */
const internals = {
}

/**
* @class HarEntryBuilder
*/
class HarEntryBuilder extends DevToolsHelper {
  /**
  * @constructor
  */
  constructor (remoteDebugChrome) {
    super()
    this._parent = remoteDebugChrome
    this._requestsMap = new Map()
    this._harEntries = new Map()  // after request/response processed
    this._options = remoteDebugChrome.options
  }

  /**
   * @public
   * @method destroy - clean up
  */
  destroy () {
    this._requestsMap.clear()
    this._harEntries.clear()
    this._harEntries = null
    this._requestsMap = null
    this._parent = null
  }

  /**
   * @public
   * @method addRequest
   *
  */
  addRequest (reqObj, cookies) {
    const request = {
      method: reqObj.request.method,
      url: reqObj.request.url,
      cookies: cookies,
      headers: reqObj.request.headers,
      httpVersion: '',
      queryString: internals.harQueryString(reqObj.request.url),
      postData: {},
      headersSize: -1,
      bodySize: -1
    }

    if (reqObj.request.hasOwnProperty('postData')) {
      request.postData = internals.harPostdata(reqObj.request.postData,
                                                request.headers)
    }

    // since there may be many updated (redirect, etc...) to a
    // single requestId, keep as an array for later response comparasion
    let harEntry = this._requestsMap.get(reqObj.requestId)
    if (harEntry === undefined) {
      harEntry = {
        requestId: reqObj.requestId,
        wallTime: reqObj.wallTime,
        requestArr: []
      }
    } else if (reqObj.hasOwnProperty('redirectResponse')) {
      const { requestArr } = harEntry
       // if this is a new request created from a redirect response, save it too
      const prevReq = requestArr[requestArr.length - 1]
      prevReq.redirectResponse = reqObj.redirectResponse
    }

    harEntry.requestArr.push(request)
    this._requestsMap.set(reqObj.requestId, harEntry)

    if (this.listenerCount(`event${reqObj.requestId}`) > 0) {
      // notify the responseHandler, which may have arrived before this
      // requestHandler finished for this requestId
      this.emitAsync(`event${reqObj.requestId}`)
    }
  }

  /**
   * @public
   * @method addResponse
   *
  */
  addResponse (respObj) {
    if (this._requestsMap.has(respObj.requestId) === false) {
      // sometimes (e.g. on http failure), the Network.loadingFailed
      // arrvies before Network.requestWillBeSent is finished waiting
      // for an async request out asking the devToolProtocol for the cookies
      this.once(`event${respObj.requestId}`,
              this.addResponse.bind(this, respObj))
      return
    }

    const entryObj = this._requestsMap.get(respObj.requestId)
    this._requestsMap.delete(respObj.requestId) // clean up

    // match the response obj to associated request object
    internals.addResponse.call(this, entryObj, respObj)
  }
}

/********************************************************/

/**
 * @private
 * @method addResponse
*/
internals.addResponse = function (entryObj, respObj) {
  const { networkDevTools } = this._parent
  const { requestArr, wallTime } = entryObj

  if (respObj.hasOwnProperty('errorText')) {
    internals.addFailedResponse.call(this, wallTime, requestArr[0], respObj)
    return
  }

  // check if should ignore filtered response attributes
  if (internals.ignoreRespOnFilters.call(this, respObj)) {
    return
  }

  // now request the body and cookies. Asynchronously
  const respBodyPromise = networkDevTools.retrieveResponseBody(respObj)
  const respCookiesPromise = networkDevTools.retrieveResponseCookies(respObj)
  const self = this

  // await for the body and cookies to both arrive
  Promise.all([respBodyPromise, respCookiesPromise])
    .then((respData) => {
      const respDataObj = {
        respBodyObj: respData[0],
        cookiesObj: respData[1],
        wallTime: wallTime
      }
      const addResponseDataFn =
              internals.addResponseData.bind(self, respDataObj, respObj)
      requestArr.forEach(addResponseDataFn)
      internals.finishRequest.call(self, { requestId: respObj.requestId })
    })
}

/**
 * @private
 * @method addResponseData - now that optional response data has been
 * retrieved, build the har entry
*/
internals.addResponseData = function (respDataObj, respObj, reqObj) {
  const { respBodyObj, cookiesObj } = respDataObj
  if (respBodyObj.base64Encoded === true && this._options.filters.ignoreRespBodyBase64) {
    return
  }

  let respMsg = respObj.response
  let redirectUrl = ''
  if (reqObj.hasOwnProperty('redirectResponse')) {
    // use the redirect response ignoring the one passed in
    redirectUrl = respMsg.url // before replacing, get this url
    respMsg = reqObj.redirectResponse
  }

  const response = {
    status: respMsg.status,
    statusText: respMsg.statusText,
    cookies: cookiesObj.cookies,
    headers: respMsg.headers,
    content: {
      size: respBodyObj.body.length,
      mimeType: respMsg.headers['Content-Type'],
      text: respBodyObj.body,
      encoding: respBodyObj.base64Encoding ? 'base64' : 'ascii'
    },
    redirectURL: redirectUrl,
    headersSize: respMsg.headersText === undefined ? -1
                  : respMsg.headersText.length,
    bodySize: respBodyObj.body.length
  }

  // no need to bind to THIS context
  internals.applyHttpVersion(response, respMsg, reqObj)

  internals.addHarEntry.call(this, respObj.requestId, respDataObj.wallTime,
                              reqObj, response)
}

/**
 * @private
 * @method applyHttpVersion - apply http version string to the passed objects
*/
internals.applyHttpVersion = function (response, respMsg, reqObj) {
  const regExVer = /HTTP\/\d+\.\d+/
  const httpRespVerArr = regExVer.exec(respMsg.headersText)
  const httpReqVerArr = regExVer.exec(respMsg.requestHeadersText)

  response.httpVersion = (httpRespVerArr === null)
                  ? respMsg.protocol.toUpperCase() : httpRespVerArr[0]

  // default to use the response HTTP version if the requestHeadersText is null
  reqObj.httpVersion = (httpReqVerArr === null)
                  ? response.httpVersion : httpReqVerArr[0]
}

/**
 * @private
 * @method ignoreRespOnFilters - passed in options decide which
 * response urls, mimtypes, etc... to ignore
*/
internals.ignoreRespOnFilters = function (respObj) {
  const ignoreIsAMatch = function isaMatch (regexArray, strToTest) {
    return regexArray.some(rx => rx.test(strToTest))
  }

  const { filters } = this._options
  if (ignoreIsAMatch(filters.ignoreRespMime, respObj.response.mimeType)) {
    return true
  } else if (ignoreIsAMatch(filters.ignoreRespUrl, respObj.response.url)) {
    return true
  } else return false
}

/**
 * @private
 * @method addFailedResponse
*/
internals.addFailedResponse = function (wallTime, reqObj, respObj) {
  const response = {
    status: -1,
    statusText: respObj.errorText,
    httpVersion: '',
    cookies: [],
    headers: [],
    content: {},
    redirectURL: '',
    headersSize: -1,
    bodySize: -1
  }

  const { requestId } = respObj
  internals.addHarEntry.call(this, requestId, wallTime, reqObj, response)
  internals.finishRequest.call(this, { requestId: respObj.requestId })
}

/**
 * @private
 * @method addHarEntry
*/
internals.addHarEntry = function (requestId, wallTime, reqObj, response) {
  const timings = {
    send: 0,
    wait: 0,
    receive: 0
  }

  const harRequest = {
    startedDateTime: new Date(wallTime * 1000).toISOString(),
    time: 0,
    request: reqObj,
    response: response,
    cache: {},
    timings: timings
  }

  // there will be multiple entries with same requestId when redirected
  let entriesArr = this._harEntries.get(requestId)
  if (entriesArr === undefined) {
    entriesArr = []
  }

  entriesArr.push(harRequest)

  // save this entry
  this._harEntries.set(requestId, entriesArr)
}

/**
 * @private
 * @method internals.finishRequest
 *
*/
internals.finishRequest = function (loadingObj) {
  const requestId = loadingObj.requestId
  if (this._harEntries.has(requestId) === false) return

  const entriesArr = this._harEntries.get(requestId)
  this._harEntries.delete(requestId) // clean up

  const err = null
  const emitHarEntry = this._parent.emitAsync.bind(this._parent, 'harEntry')
  entriesArr.forEach(function emitEachHarEntry (entry) {
    emitHarEntry(err, entry)
  })
}

/**
 * @private
 * @method harQueryString - har queryString is represented as an Array
 * @returns {Array}
*/
internals.harQueryString = function (url) {
  const queryString = Url.parse(url, true).query
  const queryStringArr = internals.harConvertToPairs(queryString)

  return queryStringArr
}

/**
 * @private
 * @method harPostdata - har postdata is represented as a Object
 * @returns {Object}
*/
internals.harPostdata = function (postdataStr, headers) {
  function isConentUrlEncoded (headers) {
    return headers.hasOwnProperty('Content-Type') &&
      headers['Content-Type'].indexOf('application/x-www-form-urlencoded') >= 0
  }

  let postDataObj = { mimeType: headers['Content-Type'] }
  if (isConentUrlEncoded(headers)) {
    const qsParamsObj = Qs.parse(postdataStr)
    postDataObj.params = internals.harConvertToPairs(qsParamsObj)
  } else {
    postDataObj.text = postdataStr
  }

  return postDataObj
}

/**
 * @private
 * @method harConvertToPairs
 * @returns {Array}
*/
internals.harConvertToPairs = function (pairsObject) {
  const pairsMap = Object.keys(pairsObject).map(key => {
    const pair = {
      name: key
    }

    if (pairsObject[key] !== undefined && pairsObject[key] !== null) {
      pair.value = pairsObject[key]
    }

    return pair
  })

  return pairsMap  // an Array
}

module.exports = HarEntryBuilder
<|endoftext|>


<commit_before>var Q = require('q'),
_ = require('underscore'),
    heinzel = require('heinzelmannchen');

module.exports = {
    command: 'install',
    alias: 'in',
    description: 'install templates and generators',
    options: [
        ['-g, --gen <items>', 'install generators', 'LIST'],
        ['-t, --tem <items>', 'install templates', 'LIST']
    ],
    action: install
};

function install(options) {
    var result = {},
        promises = [],
        q;

    if (!options.gen && !options.tem) {
        q = Q.defer();
        q.reject(new Error('You should specify a generator or a template'));
        return q.promise;
    }

    if (options.gen) {
        promises.push(heinzel.installGenerators(options.gen)
            .then(function(generators) {
                result.generators = generators;
            }));
    }

    if (options.tem) {
        promises.push(heinzel.installTemplates(options.tem)
            .then(function(templates) {
                result.templates = templates;
            }));
    }

    return Q.allSettled(promises).then(function() {
        return result;
    });
}
<commit_msg>fixed create<commit_after>var Q = require('q'),
_ = require('underscore'),
    heinzel = require('heinzelmannchen');

module.exports = {
    command: 'install',
    alias: 'in',
    description: 'install templates and generators',
    options: [
        ['-g, --gen <items>', 'install generators', 'LIST'],
        ['-t, --tem <items>', 'install templates', 'LIST']
    ],
    action: install
};

function install(options) {
    var result = {},
        promises = [],
        q;

    if (!options.gen && !options.tem) {
        q = Q.defer();
        q.reject(new Error('You should specify a generator or a template'));
        return q.promise;
    }

    if (options.gen) {
        promises.push(heinzel.installGenerators(options.gen)
            .then(function(generators) {
                result.generators = mapForOutput(generators);
            }));
    }

    if (options.tem) {
        promises.push(heinzel.installTemplates(options.tem)
            .then(function(templates) {
                result.templates = mapForOutput(templates);
            }));
    }

    return Q.allSettled(promises).then(function() {
        return result;
    });
}
<|endoftext|>


<commit_before>define(["leaflet", "rbush"],
  function (L, rbush) {
    var labelLocations = [["left",   "middle",      0 / 8],
                          ["center", "top",         6 / 8],
                          ["right",  "middle",      4 / 8],
                          ["left",   "top",         7 / 8],
                          ["left",   "ideographic", 1 / 8],
                          ["right",  "top",         5 / 8],
                          ["center", "ideographic", 2 / 8],
                          ["right",  "ideographic", 3 / 8]]

    var fontFamily = "Roboto"
    var nodeRadius = 4

    var ctx = document.createElement("canvas").getContext("2d")

    function measureText(font, text) {
      ctx.font = font
      return ctx.measureText(text)
    }

    function mapRTree(d) {
      var o = [d.position.lat, d.position.lng, d.position.lat, d.position.lng]

      o.label = d

      return o
    }

    function prepareLabel(fillStyle, fontSize, offset, stroke, minZoom) {
      return function (d) {
        var font = fontSize + "px " + fontFamily
        return { position: L.latLng(d.nodeinfo.location.latitude, d.nodeinfo.location.longitude),
                 label: d.nodeinfo.hostname,
                 offset: offset,
                 fillStyle: fillStyle,
                 height: fontSize * 1.2,
                 font: font,
                 stroke: stroke,
                 minZoom: minZoom,
                 width: measureText(font, d.nodeinfo.hostname).width
               }
      }
    }

    function calcOffset(offset, loc) {
      return [ offset * Math.cos(loc[2] * 2 * Math.PI),
              -offset * Math.sin(loc[2] * 2 * Math.PI)]
    }

    function labelRect(p, offset, anchor, label) {
      var dx = { left: 0,
                 right: -label.width,
                 center: -label.width /  2
               }

      var dy = { top: 0,
                 ideographic: -label.height,
                 middle: -label.height / 2
               }

      var x = p.x + offset[0] + dx[anchor[0]]
      var y = p.y + offset[1] + dy[anchor[1]]

      return [x, y, x + label.width, y + label.height]
    }

    var c = L.TileLayer.Canvas.extend({
      onAdd: function (map) {
        L.TileLayer.Canvas.prototype.onAdd.call(this, map)
        if (this.data)
          this.prepareLabels()
      },
      setData: function (d) {
        this.data = d
        if (this._map)
          this.prepareLabels()
      },
      prepareLabels: function () {
        var d = this.data

        // label:
        // - position (WGS84 coords)
        // - offset (2D vector in pixels)
        // - anchor (tuple, textAlignment, textBaseline)
        // - minZoom (inclusive)
        // - label (string)
        // - color (string)

        var labelsOnline = d.online.map(prepareLabel("rgba(0, 0, 0, 0.9)", 10, 8, true, 13))
        var labelsOffline = d.offline.map(prepareLabel("rgba(212, 62, 42, 0.9)", 9, 5, false, 16))
        var labelsNew = d.new.map(prepareLabel("rgba(48, 99, 20, 0.9)", 11, 8, true, 0))
        var labelsLost = d.lost.map(prepareLabel("rgba(212, 62, 42, 0.9)", 11, 8, true, 0))

        var labels = []
                     .concat(labelsNew)
                     .concat(labelsLost)
                     .concat(labelsOnline)
                     .concat(labelsOffline)

        var minZoom = this.options.minZoom
        var maxZoom = this.options.maxZoom

        var trees = []

        var map = this._map

        function nodeToRect(z) {
          return function (d) {
            var p = map.project(d.position, z)
            return [p.x - nodeRadius, p.y - nodeRadius,
                    p.x + nodeRadius, p.y + nodeRadius]
          }
        }

        for (var z = minZoom; z <= maxZoom; z++) {
          trees[z] = rbush(9)
          trees[z].load(labels.map(nodeToRect(z)))
        }

        labels = labels.map(function (d) {
          var best = labelLocations.map(function (loc) {
            var offset = calcOffset(d.offset, loc)
            var z

            for (z = maxZoom; z >= d.minZoom; z--) {
              var p = map.project(d.position, z)
              var rect = labelRect(p, offset, loc, d)
              var candidates = trees[z].search(rect)

              if (candidates.length > 0)
                break
            }

            return {loc: loc, z: z + 1}
          }).filter(function (d) {
            return d.z <= maxZoom
          }).sort(function (a, b) {
            return a.z - b.z
          })[0]

          if (best !== undefined) {
            d.offset = calcOffset(d.offset, best.loc)
            d.minZoom = best.z
            d.anchor = best.loc

            for (var z = maxZoom; z >= best.z; z--) {
              var p = map.project(d.position, z)
              var rect = labelRect(p, d.offset, best.loc, d)
              trees[z].insert(rect)
            }

            return d
          } else
            return undefined
        }).filter(function (d) { return d !== undefined })

        this.margin = 16

        if (labels.length > 0)
          this.margin += labels.map(function (d) {
            return d.width
          }).sort().reverse()[0]

        this.labels = rbush(9)
        this.labels.load(labels.map(mapRTree))

        this.redraw()
      },
      drawTile: function (canvas, tilePoint, zoom) {
        function getTileBBox(s, map, tileSize, margin) {
          var tl = map.unproject([s.x - margin, s.y - margin])
          var br = map.unproject([s.x + margin + tileSize, s.y + margin + tileSize])

          return [br.lat, tl.lng, tl.lat, br.lng]
        }

        if (!this.labels)
          return

        var tileSize = this.options.tileSize
        var s = tilePoint.multiplyBy(tileSize)
        var map = this._map

        function projectNodes(d) {
          var p = map.project(d.label.position)

          p.x -= s.x
          p.y -= s.y

          return {p: p, label: d.label}
        }

        var bbox = getTileBBox(s, map, tileSize, this.margin)

        var labels = this.labels.search(bbox).map(projectNodes)

        var ctx = canvas.getContext("2d")

        ctx.lineWidth = 5
        ctx.strokeStyle = "rgba(255, 255, 255, 0.8)"
        ctx.miterLimit = 2

        function drawLabel(d) {
          ctx.font = d.label.font
          ctx.textAlign = d.label.anchor[0]
          ctx.textBaseline = d.label.anchor[1]
          ctx.fillStyle = d.label.fillStyle

          if (d.label.stroke)
            ctx.strokeText(d.label.label, d.p.x + d.label.offset[0], d.p.y + d.label.offset[1])

          ctx.fillText(d.label.label, d.p.x + d.label.offset[0], d.p.y + d.label.offset[1])
        }

        labels.filter(function (d) {
          return zoom >= d.label.minZoom
        }).forEach(drawLabel)
      }
    })

    return c
})
<commit_msg>map/labels: show less labels on lower zoom levels<commit_after>define(["leaflet", "rbush"],
  function (L, rbush) {
    var labelLocations = [["left",   "middle",      0 / 8],
                          ["center", "top",         6 / 8],
                          ["right",  "middle",      4 / 8],
                          ["left",   "top",         7 / 8],
                          ["left",   "ideographic", 1 / 8],
                          ["right",  "top",         5 / 8],
                          ["center", "ideographic", 2 / 8],
                          ["right",  "ideographic", 3 / 8]]

    var fontFamily = "Roboto"
    var nodeRadius = 4

    var ctx = document.createElement("canvas").getContext("2d")

    function measureText(font, text) {
      ctx.font = font
      return ctx.measureText(text)
    }

    function mapRTree(d) {
      var o = [d.position.lat, d.position.lng, d.position.lat, d.position.lng]

      o.label = d

      return o
    }

    function prepareLabel(fillStyle, fontSize, offset, stroke, minZoom) {
      return function (d) {
        var font = fontSize + "px " + fontFamily
        return { position: L.latLng(d.nodeinfo.location.latitude, d.nodeinfo.location.longitude),
                 label: d.nodeinfo.hostname,
                 offset: offset,
                 fillStyle: fillStyle,
                 height: fontSize * 1.2,
                 font: font,
                 stroke: stroke,
                 minZoom: minZoom,
                 width: measureText(font, d.nodeinfo.hostname).width
               }
      }
    }

    function calcOffset(offset, loc) {
      return [ offset * Math.cos(loc[2] * 2 * Math.PI),
              -offset * Math.sin(loc[2] * 2 * Math.PI)]
    }

    function labelRect(p, offset, anchor, label, minZoom, maxZoom, z) {
      var margin = 1 + 1.41 * (1 - (z - minZoom) / (maxZoom - minZoom))

      var width = label.width * margin
      var height = label.height * margin

      var dx = { left: 0,
                 right: -width,
                 center: -width /  2
               }

      var dy = { top: 0,
                 ideographic: -height,
                 middle: -height / 2
               }

      var x = p.x + offset[0] + dx[anchor[0]]
      var y = p.y + offset[1] + dy[anchor[1]]

      return [x, y, x + width, y + height]
    }

    var c = L.TileLayer.Canvas.extend({
      onAdd: function (map) {
        L.TileLayer.Canvas.prototype.onAdd.call(this, map)
        if (this.data)
          this.prepareLabels()
      },
      setData: function (d) {
        this.data = d
        if (this._map)
          this.prepareLabels()
      },
      prepareLabels: function () {
        var d = this.data

        // label:
        // - position (WGS84 coords)
        // - offset (2D vector in pixels)
        // - anchor (tuple, textAlignment, textBaseline)
        // - minZoom (inclusive)
        // - label (string)
        // - color (string)

        var labelsOnline = d.online.map(prepareLabel("rgba(0, 0, 0, 0.9)", 10, 8, true, 13))
        var labelsOffline = d.offline.map(prepareLabel("rgba(212, 62, 42, 0.9)", 9, 5, false, 16))
        var labelsNew = d.new.map(prepareLabel("rgba(48, 99, 20, 0.9)", 11, 8, true, 0))
        var labelsLost = d.lost.map(prepareLabel("rgba(212, 62, 42, 0.9)", 11, 8, true, 0))

        var labels = []
                     .concat(labelsNew)
                     .concat(labelsLost)
                     .concat(labelsOnline)
                     .concat(labelsOffline)

        var minZoom = this.options.minZoom
        var maxZoom = this.options.maxZoom

        var trees = []

        var map = this._map

        function nodeToRect(z) {
          return function (d) {
            var p = map.project(d.position, z)
            return [p.x - nodeRadius, p.y - nodeRadius,
                    p.x + nodeRadius, p.y + nodeRadius]
          }
        }

        for (var z = minZoom; z <= maxZoom; z++) {
          trees[z] = rbush(9)
          trees[z].load(labels.map(nodeToRect(z)))
        }

        labels = labels.map(function (d) {
          var best = labelLocations.map(function (loc) {
            var offset = calcOffset(d.offset, loc)
            var z

            for (z = maxZoom; z >= d.minZoom; z--) {
              var p = map.project(d.position, z)
              var rect = labelRect(p, offset, loc, d, minZoom, maxZoom, z)
              var candidates = trees[z].search(rect)

              if (candidates.length > 0)
                break
            }

            return {loc: loc, z: z + 1}
          }).filter(function (d) {
            return d.z <= maxZoom
          }).sort(function (a, b) {
            return a.z - b.z
          })[0]

          if (best !== undefined) {
            d.offset = calcOffset(d.offset, best.loc)
            d.minZoom = best.z
            d.anchor = best.loc

            for (var z = maxZoom; z >= best.z; z--) {
              var p = map.project(d.position, z)
              var rect = labelRect(p, d.offset, best.loc, d, minZoom, maxZoom, z)
              trees[z].insert(rect)
            }

            return d
          } else
            return undefined
        }).filter(function (d) { return d !== undefined })

        this.margin = 16

        if (labels.length > 0)
          this.margin += labels.map(function (d) {
            return d.width
          }).sort().reverse()[0]

        this.labels = rbush(9)
        this.labels.load(labels.map(mapRTree))

        this.redraw()
      },
      drawTile: function (canvas, tilePoint, zoom) {
        function getTileBBox(s, map, tileSize, margin) {
          var tl = map.unproject([s.x - margin, s.y - margin])
          var br = map.unproject([s.x + margin + tileSize, s.y + margin + tileSize])

          return [br.lat, tl.lng, tl.lat, br.lng]
        }

        if (!this.labels)
          return

        var tileSize = this.options.tileSize
        var s = tilePoint.multiplyBy(tileSize)
        var map = this._map

        function projectNodes(d) {
          var p = map.project(d.label.position)

          p.x -= s.x
          p.y -= s.y

          return {p: p, label: d.label}
        }

        var bbox = getTileBBox(s, map, tileSize, this.margin)

        var labels = this.labels.search(bbox).map(projectNodes)

        var ctx = canvas.getContext("2d")

        ctx.lineWidth = 5
        ctx.strokeStyle = "rgba(255, 255, 255, 0.8)"
        ctx.miterLimit = 2

        function drawLabel(d) {
          ctx.font = d.label.font
          ctx.textAlign = d.label.anchor[0]
          ctx.textBaseline = d.label.anchor[1]
          ctx.fillStyle = d.label.fillStyle

          if (d.label.stroke)
            ctx.strokeText(d.label.label, d.p.x + d.label.offset[0], d.p.y + d.label.offset[1])

          ctx.fillText(d.label.label, d.p.x + d.label.offset[0], d.p.y + d.label.offset[1])
        }

        labels.filter(function (d) {
          return zoom >= d.label.minZoom
        }).forEach(drawLabel)
      }
    })

    return c
})
<|endoftext|>


<commit_before>'use strict';

var Schema = require('warehouse').Schema;
var util = require('hexo-util');
var slugize = util.slugize;

module.exports = function(ctx) {
  var Category = new Schema({
    name: {type: String, required: true},
    parent: {type: Schema.Types.CUID, ref: 'Category'}
  });

  Category.virtual('slug').get(function() {
    var map = ctx.config.category_map || {};
    var name = this.name;
    var str = '';

    if (!name) return;

    if (this.parent) {
      var parent = ctx.model('Category').findById(this.parent);
      str += parent.slug + '/';
    }

    name = map[name] || name;
    str += slugize(name, {transform: ctx.config.filename_case});

    return str;
  });

  Category.virtual('path').get(function() {
    var catDir = ctx.config.category_dir;
    if (catDir[catDir.length - 1] !== '/') catDir += '/';

    return catDir + this.slug + '/';
  });

  Category.virtual('permalink').get(function() {
    return ctx.config.url + '/' + this.path;
  });

  Category.virtual('posts').get(function() {
    var PostCategory = ctx.model('PostCategory');

    var ids = PostCategory.find({category_id: this._id}).map(function(item) {
      return item.post_id;
    });

    return ctx.locals.get('posts').find({
      _id: {$in: ids}
    });
  });

  Category.virtual('length').get(function() {
    return this.posts.length;
  });

  // Check whether a category exists
  Category.pre('save', function(data) {
    var name = data.name;
    var parent = data.parent;
    if (!name) return;

    var Category = ctx.model('Category');
    var cat = Category.findOne({
      name: name,
      parent: parent || {$exists: false}
    }, {lean: true});

    if (cat) {
      throw new Error('Category `' + name + '` has already existed!');
    }
  });

  // Remove PostCategory references
  Category.pre('remove', function(data) {
    var PostCategory = ctx.model('PostCategory');
    return PostCategory.remove({category_id: data._id});
  });

  return Category;
};
<commit_msg>Fix category path when placed on root<commit_after>'use strict';

var Schema = require('warehouse').Schema;
var util = require('hexo-util');
var slugize = util.slugize;

module.exports = function(ctx) {
  var Category = new Schema({
    name: {type: String, required: true},
    parent: {type: Schema.Types.CUID, ref: 'Category'}
  });

  Category.virtual('slug').get(function() {
    var map = ctx.config.category_map || {};
    var name = this.name;
    var str = '';

    if (!name) return;

    if (this.parent) {
      var parent = ctx.model('Category').findById(this.parent);
      str += parent.slug + '/';
    }

    name = map[name] || name;
    str += slugize(name, {transform: ctx.config.filename_case});

    return str;
  });

  Category.virtual('path').get(function() {
    var catDir = ctx.config.category_dir;
    if (catDir === '/') catDir = '';
    if (catDir.length && catDir[catDir.length - 1] !== '/') catDir += '/';

    return catDir + this.slug + '/';
  });

  Category.virtual('permalink').get(function() {
    return ctx.config.url + '/' + this.path;
  });

  Category.virtual('posts').get(function() {
    var PostCategory = ctx.model('PostCategory');

    var ids = PostCategory.find({category_id: this._id}).map(function(item) {
      return item.post_id;
    });

    return ctx.locals.get('posts').find({
      _id: {$in: ids}
    });
  });

  Category.virtual('length').get(function() {
    return this.posts.length;
  });

  // Check whether a category exists
  Category.pre('save', function(data) {
    var name = data.name;
    var parent = data.parent;
    if (!name) return;

    var Category = ctx.model('Category');
    var cat = Category.findOne({
      name: name,
      parent: parent || {$exists: false}
    }, {lean: true});

    if (cat) {
      throw new Error('Category `' + name + '` has already existed!');
    }
  });

  // Remove PostCategory references
  Category.pre('remove', function(data) {
    var PostCategory = ctx.model('PostCategory');
    return PostCategory.remove({category_id: data._id});
  });

  return Category;
};
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Telefonica Investigación y Desarrollo, S.A.U
 *
 * This file is part of perseo-fe
 *
 * perseo-fe is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * perseo-fe is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with perseo-fe.
 * If not, see http://www.gnu.org/licenses/.
 *
 * For those usages not covered by the GNU Affero General Public License
 * please contact with::[contacto@tid.es]
 */
'use strict';

var util = require('util'),
    domain = require('domain'),
    uuid = require('uuid'),
    logger = require('logops'),
    myutils = require('../myutils'),
    constants = require('../constants'),
    entitiesStore = require('./entitiesStore'),
    actions = require('./actions'),
    config = require('../../config'),
    nsRulesByInterval = {},
    checkers = {},
    intervalUnit = 1000 * 60,
    SERVICE = 0,
    SUBSERVICE = 1,
    NAME = 2,
    ATTRIBUTE = 3,
    ID = 4,
    ID_REGEXP = 5,
    TYPE = 6,
    REPORT_INTERVAL = 7,
    CHECK_INTERVAL = 8,
    context = { op: 'checkNonSignal', comp: constants.COMPONENT_NAME, corr: 'n/a', trans: 'n/a' },
    lastTime,
    MIN_INTERVAL_MS = 30e3,
    MAX_INTERVAL_MS = 2147483647;

function alertFunc(nsLineRule, entity) {
    var d = domain.create();
    d.context = {};
    d.context.trans = uuid.v4();
    d.context.corr = d.context.trans;
    d.context.srv = 'n/a';
    d.context.subsrv = 'n/a';
    d.context.op = 'alertNS';
    d.context.comp = constants.COMPONENT_NAME;

    d.on('error', function(err) {
        myutils.logErrorIf(err, 'alertFunc on ', d.context);
        d.exit();
    });
    d.run(function() {
        // We duplicate info in event and event.ev for VR and non-VR action parameters
        var event = {
            service: nsLineRule[SERVICE],
            subservice: nsLineRule[SUBSERVICE],
            ruleName: nsLineRule[NAME],
            reportInterval: nsLineRule[REPORT_INTERVAL],
            id: entity._id.id,
            type: entity._id.type,
            internalCurentTime: new Date(new Date().toUTCString())
        };

        // Search for modDate of the entity's attribute
        // and copy every attribute (if not in event yet)
        // for use in action template
        Object.keys(entity.attrs).forEach(function(attrName) {
            if (attrName === nsLineRule[ATTRIBUTE]) {
                try {
                    lastTime = new Date(entity.attrs[attrName].modDate * 1000).toISOString();
                } catch (ex) {
                    myutils.logErrorIf(ex, 'run ', d.context);
                }
            }
            if (event[attrName] === undefined) {
                event[attrName] = entity.attrs[attrName].value;
            }
        });

        logger.debug(context, 'lastTime could be ', lastTime);
        if (lastTime !== undefined && lastTime !== null) {
            event.lastTime = lastTime;
        }
        var delay;
        if (config.isMaster) {
            delay = 0;
        } else {
            delay = config.slaveDelay;
        }
        setTimeout(function() {
            actions.Do(event, function(err) {
                myutils.logErrorIf(err, 'DoEvent', d.context);
            });
        }, delay);
    });
}

function checkNoSignal(period) {
    var list = nsRulesByInterval[period] || [];
    logger.debug(context, 'Executing no-signal handler for period of %d (%d rules)', period, list.length);
    list.forEach(function(nsrule) {
        var currentContext = context;
        currentContext.srv = nsrule[SERVICE];
        currentContext.subsrv = nsrule[SUBSERVICE];
        entitiesStore.FindSilentEntities(
            nsrule[SERVICE],
            nsrule[SUBSERVICE],
            {
                attribute: nsrule[ATTRIBUTE],
                id: nsrule[ID],
                idRegexp: nsrule[ID_REGEXP],
                type: nsrule[TYPE],
                reportInterval: nsrule[REPORT_INTERVAL]
            },
            alertFunc.bind({}, nsrule),
            function(err, data) {
                myutils.logErrorIf(err, 'checkNoSignal nsrule %s' % nsrule.name ? nsrule.name : '', currentContext);
                logger.debug(currentContext, 'silent entities: ', data);
            }
        );
    });
}

function nsr2arr(service, subservice, name, nsr) {
    var arrayRule = [];
    arrayRule[SUBSERVICE] = subservice;
    arrayRule[SERVICE] = service;
    arrayRule[NAME] = name;
    arrayRule[ATTRIBUTE] = nsr.attribute;
    arrayRule[ID] = nsr.id;
    arrayRule[ID_REGEXP] = nsr.idRegexp;
    arrayRule[TYPE] = nsr.type;
    arrayRule[REPORT_INTERVAL] = nsr.reportInterval;
    arrayRule[CHECK_INTERVAL] = nsr.checkInterval;
    return arrayRule;
}

function addNSRule(service, subservice, name, nsr) {
    var arrayRule,
        alreadyExists = false,
        intervalAsNum;

    // Verify the interval is valid. It should be as it is checked at rule creation time
    // but an invalid modification of DB could cause a "big" problem
    intervalAsNum = parseInt(nsr.checkInterval, 10);
    if (isNaN(intervalAsNum)) {
        logger.error(
            context,
            util.format('Invalid check interval %s for rule (%s, %s, %s)', nsr.checkInterval, service, subservice, name)
        );
        return 0;
    }
    intervalAsNum *= intervalUnit;
    if (intervalAsNum > MAX_INTERVAL_MS) {
        logger.warn(
            context,
            util.format('Check interval %s too big for rule (%s, %s, %s)', nsr.checkInterval, service, subservice, name)
        );
        intervalAsNum = MAX_INTERVAL_MS;
    }
    if (intervalAsNum < MIN_INTERVAL_MS) {
        logger.warn(
            context,
            util.format(
                'Check interval %s too small for rule (%s, %s, %s)',
                nsr.checkInterval,
                service,
                subservice,
                name
            )
        );
        intervalAsNum = MIN_INTERVAL_MS;
    }
    arrayRule = nsr2arr(service, subservice, name, nsr);
    nsRulesByInterval[nsr.checkInterval] = nsRulesByInterval[nsr.checkInterval] || [];
    nsRulesByInterval[nsr.checkInterval].forEach(function(element, index, array) {
        if (element[NAME] === name && element[SERVICE] === service && element[SUBSERVICE] === subservice) {
            array[index] = arrayRule; //Update rule
            alreadyExists = true;
            logger.debug(context, util.format('Updating no-signal rule (%s, %s, %s)', service, subservice, name));
        }
    });
    if (!alreadyExists) {
        nsRulesByInterval[nsr.checkInterval].push(arrayRule);
        logger.debug(context, util.format('Adding no-signal rule (%s, %s, %s)', service, subservice, name));
    }
    if (!checkers.hasOwnProperty(nsr.checkInterval)) {
        checkers[nsr.checkInterval] = setInterval(checkNoSignal, intervalAsNum, nsr.checkInterval);
        checkers[nsr.checkInterval].unref();
    }
    return intervalAsNum;
}

function deleteNSRuleIf(predicate) {
    Object.keys(nsRulesByInterval).forEach(function(chkInt) {
        var line = nsRulesByInterval[chkInt] || [];
        line.forEach(function(element, index) {
            if (predicate(element[SERVICE], element[SUBSERVICE], element[NAME])) {
                line.splice(index, 1);
                if (line.length === 0) {
                    // There are no rules left for this interval
                    if (checkers.hasOwnProperty(chkInt)) {
                        clearInterval(checkers[chkInt]);
                        delete checkers[chkInt];
                    }
                    if (nsRulesByInterval.hasOwnProperty(chkInt)) {
                        delete nsRulesByInterval[chkInt];
                    }
                }
                logger.debug(
                    context,
                    util.format(
                        'Deleting no-signal rule (%s, %s, %s)',
                        element[SERVICE],
                        element[SUBSERVICE],
                        element[NAME]
                    )
                );
            }
        });
    });
}

function deleteNSRule(service, subservice, name) {
    deleteNSRuleIf(function(serviceElement, subserviceElement, nameElement) {
        return serviceElement === service && subserviceElement === subservice && nameElement === name;
    });
}

function getNSRule(service, subservice, name) {
    var intervals = Object.keys(nsRulesByInterval),
        chkInt,
        line;
    for (var i = 0; i < intervals.length; i++) {
        chkInt = intervals[i];
        line = nsRulesByInterval[chkInt] || [];
        for (var j = 0; j < line.length; j++) {
            if (line[j][SERVICE] === service && line[j][SUBSERVICE] === subservice && line[j][NAME] === name) {
                return line[j];
            }
        }
    }
    return null;
}

function RuleSet() {
    this.set = {};
}
RuleSet.prototype.add = function(service, subservice, name) {
    var srvObj;
    if (this.set[service] === undefined) {
        this.set[service] = {};
    }
    srvObj = this.set[service];
    if (srvObj[subservice] === undefined) {
        srvObj[subservice] = {};
    }
    srvObj[subservice][name] = true;
};

RuleSet.prototype.includes = function(service, subservice, name) {
    return this.set[service] && this.set[service][subservice] && this.set[service][subservice][name] === true;
};

function refreshAllRules(rules) {
    var count = 0,
        ruleSet = new RuleSet(),
        oldRuleArr = [];

    logger.debug(context, 'Refreshing all no-signal rules');
    rules.forEach(function(rule) {
        if (rule.nosignal) {
            //check if any checkInterval has been modified, and delete if so.
            oldRuleArr = getNSRule(rule.service, rule.subservice, rule.name);
            deleteNSRuleIf(function() {
                return oldRuleArr && oldRuleArr[CHECK_INTERVAL] !== rule.nosignal.checkInterval;
            });
            if (addNSRule(rule.service, rule.subservice, rule.name, rule.nosignal) > 0) {
                count++;
                ruleSet.add(rule.service, rule.subservice, rule.name);
            }
        }
    });
    // remove old rules not in the new set
    deleteNSRuleIf(function(srv, subsrv, nm) {
        return !ruleSet.includes(srv, subsrv, nm);
    });
    logger.debug(
        context,
        util.format('no-signal rules %d/%d, checkers: %d', count, rules.length, Object.keys(checkers).length)
    );
}

module.exports.AddNSRule = addNSRule;
module.exports.DeleteNSRule = deleteNSRule;
module.exports.RefreshAllRules = refreshAllRules;
module.exports.GetNSArrRule = getNSRule;
module.exports.CheckNoSignal = checkNoSignal;
module.exports.Nsr2Arr = nsr2arr;
module.exports.getMinIntervalMs = function() {
    return MIN_INTERVAL_MS;
};
module.exports.getIntervalUnit = function() {
    return intervalUnit;
};
<commit_msg>Update noSignal.js<commit_after>/*
 * Copyright 2015 Telefonica Investigación y Desarrollo, S.A.U
 *
 * This file is part of perseo-fe
 *
 * perseo-fe is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * perseo-fe is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with perseo-fe.
 * If not, see http://www.gnu.org/licenses/.
 *
 * For those usages not covered by the GNU Affero General Public License
 * please contact with::[contacto@tid.es]
 */
'use strict';

var util = require('util'),
    domain = require('domain'),
    uuid = require('uuid'),
    logger = require('logops'),
    myutils = require('../myutils'),
    constants = require('../constants'),
    entitiesStore = require('./entitiesStore'),
    actions = require('./actions'),
    config = require('../../config'),
    nsRulesByInterval = {},
    checkers = {},
    intervalUnit = 1000 * 60,
    SERVICE = 0,
    SUBSERVICE = 1,
    NAME = 2,
    ATTRIBUTE = 3,
    ID = 4,
    ID_REGEXP = 5,
    TYPE = 6,
    REPORT_INTERVAL = 7,
    CHECK_INTERVAL = 8,
    context = { op: 'checkNonSignal', comp: constants.COMPONENT_NAME, corr: 'n/a', trans: 'n/a' },
    lastTime,
    MIN_INTERVAL_MS = 30e3,
    MAX_INTERVAL_MS = 2147483647; // 2^31-1 which is 2,147,483,647ms (maximum value of a signed 32 bit integer in ms)

function alertFunc(nsLineRule, entity) {
    var d = domain.create();
    d.context = {};
    d.context.trans = uuid.v4();
    d.context.corr = d.context.trans;
    d.context.srv = 'n/a';
    d.context.subsrv = 'n/a';
    d.context.op = 'alertNS';
    d.context.comp = constants.COMPONENT_NAME;

    d.on('error', function(err) {
        myutils.logErrorIf(err, 'alertFunc on ', d.context);
        d.exit();
    });
    d.run(function() {
        // We duplicate info in event and event.ev for VR and non-VR action parameters
        var event = {
            service: nsLineRule[SERVICE],
            subservice: nsLineRule[SUBSERVICE],
            ruleName: nsLineRule[NAME],
            reportInterval: nsLineRule[REPORT_INTERVAL],
            id: entity._id.id,
            type: entity._id.type,
            internalCurentTime: new Date(new Date().toUTCString())
        };

        // Search for modDate of the entity's attribute
        // and copy every attribute (if not in event yet)
        // for use in action template
        Object.keys(entity.attrs).forEach(function(attrName) {
            if (attrName === nsLineRule[ATTRIBUTE]) {
                try {
                    lastTime = new Date(entity.attrs[attrName].modDate * 1000).toISOString();
                } catch (ex) {
                    myutils.logErrorIf(ex, 'run ', d.context);
                }
            }
            if (event[attrName] === undefined) {
                event[attrName] = entity.attrs[attrName].value;
            }
        });

        logger.debug(context, 'lastTime could be ', lastTime);
        if (lastTime !== undefined && lastTime !== null) {
            event.lastTime = lastTime;
        }
        var delay;
        if (config.isMaster) {
            delay = 0;
        } else {
            delay = config.slaveDelay;
        }
        setTimeout(function() {
            actions.Do(event, function(err) {
                myutils.logErrorIf(err, 'DoEvent', d.context);
            });
        }, delay);
    });
}

function checkNoSignal(period) {
    var list = nsRulesByInterval[period] || [];
    logger.debug(context, 'Executing no-signal handler for period of %d (%d rules)', period, list.length);
    list.forEach(function(nsrule) {
        var currentContext = context;
        currentContext.srv = nsrule[SERVICE];
        currentContext.subsrv = nsrule[SUBSERVICE];
        entitiesStore.FindSilentEntities(
            nsrule[SERVICE],
            nsrule[SUBSERVICE],
            {
                attribute: nsrule[ATTRIBUTE],
                id: nsrule[ID],
                idRegexp: nsrule[ID_REGEXP],
                type: nsrule[TYPE],
                reportInterval: nsrule[REPORT_INTERVAL]
            },
            alertFunc.bind({}, nsrule),
            function(err, data) {
                myutils.logErrorIf(err, 'checkNoSignal nsrule %s' % nsrule.name ? nsrule.name : '', currentContext);
                logger.debug(currentContext, 'silent entities: ', data);
            }
        );
    });
}

function nsr2arr(service, subservice, name, nsr) {
    var arrayRule = [];
    arrayRule[SUBSERVICE] = subservice;
    arrayRule[SERVICE] = service;
    arrayRule[NAME] = name;
    arrayRule[ATTRIBUTE] = nsr.attribute;
    arrayRule[ID] = nsr.id;
    arrayRule[ID_REGEXP] = nsr.idRegexp;
    arrayRule[TYPE] = nsr.type;
    arrayRule[REPORT_INTERVAL] = nsr.reportInterval;
    arrayRule[CHECK_INTERVAL] = nsr.checkInterval;
    return arrayRule;
}

function addNSRule(service, subservice, name, nsr) {
    var arrayRule,
        alreadyExists = false,
        intervalAsNum;

    // Verify the interval is valid. It should be as it is checked at rule creation time
    // but an invalid modification of DB could cause a "big" problem
    intervalAsNum = parseInt(nsr.checkInterval, 10);
    if (isNaN(intervalAsNum)) {
        logger.error(
            context,
            util.format('Invalid check interval %s for rule (%s, %s, %s)', nsr.checkInterval, service, subservice, name)
        );
        return 0;
    }
    intervalAsNum *= intervalUnit;
    if (intervalAsNum > MAX_INTERVAL_MS) {
        logger.warn(
            context,
            util.format('Check interval %s too big for rule (%s, %s, %s)', nsr.checkInterval, service, subservice, name)
        );
        intervalAsNum = MAX_INTERVAL_MS;
    }
    if (intervalAsNum < MIN_INTERVAL_MS) {
        logger.warn(
            context,
            util.format(
                'Check interval %s too small for rule (%s, %s, %s)',
                nsr.checkInterval,
                service,
                subservice,
                name
            )
        );
        intervalAsNum = MIN_INTERVAL_MS;
    }
    arrayRule = nsr2arr(service, subservice, name, nsr);
    nsRulesByInterval[nsr.checkInterval] = nsRulesByInterval[nsr.checkInterval] || [];
    nsRulesByInterval[nsr.checkInterval].forEach(function(element, index, array) {
        if (element[NAME] === name && element[SERVICE] === service && element[SUBSERVICE] === subservice) {
            array[index] = arrayRule; //Update rule
            alreadyExists = true;
            logger.debug(context, util.format('Updating no-signal rule (%s, %s, %s)', service, subservice, name));
        }
    });
    if (!alreadyExists) {
        nsRulesByInterval[nsr.checkInterval].push(arrayRule);
        logger.debug(context, util.format('Adding no-signal rule (%s, %s, %s)', service, subservice, name));
    }
    if (!checkers.hasOwnProperty(nsr.checkInterval)) {
        checkers[nsr.checkInterval] = setInterval(checkNoSignal, intervalAsNum, nsr.checkInterval);
        checkers[nsr.checkInterval].unref();
    }
    return intervalAsNum;
}

function deleteNSRuleIf(predicate) {
    Object.keys(nsRulesByInterval).forEach(function(chkInt) {
        var line = nsRulesByInterval[chkInt] || [];
        line.forEach(function(element, index) {
            if (predicate(element[SERVICE], element[SUBSERVICE], element[NAME])) {
                line.splice(index, 1);
                if (line.length === 0) {
                    // There are no rules left for this interval
                    if (checkers.hasOwnProperty(chkInt)) {
                        clearInterval(checkers[chkInt]);
                        delete checkers[chkInt];
                    }
                    if (nsRulesByInterval.hasOwnProperty(chkInt)) {
                        delete nsRulesByInterval[chkInt];
                    }
                }
                logger.debug(
                    context,
                    util.format(
                        'Deleting no-signal rule (%s, %s, %s)',
                        element[SERVICE],
                        element[SUBSERVICE],
                        element[NAME]
                    )
                );
            }
        });
    });
}

function deleteNSRule(service, subservice, name) {
    deleteNSRuleIf(function(serviceElement, subserviceElement, nameElement) {
        return serviceElement === service && subserviceElement === subservice && nameElement === name;
    });
}

function getNSRule(service, subservice, name) {
    var intervals = Object.keys(nsRulesByInterval),
        chkInt,
        line;
    for (var i = 0; i < intervals.length; i++) {
        chkInt = intervals[i];
        line = nsRulesByInterval[chkInt] || [];
        for (var j = 0; j < line.length; j++) {
            if (line[j][SERVICE] === service && line[j][SUBSERVICE] === subservice && line[j][NAME] === name) {
                return line[j];
            }
        }
    }
    return null;
}

function RuleSet() {
    this.set = {};
}
RuleSet.prototype.add = function(service, subservice, name) {
    var srvObj;
    if (this.set[service] === undefined) {
        this.set[service] = {};
    }
    srvObj = this.set[service];
    if (srvObj[subservice] === undefined) {
        srvObj[subservice] = {};
    }
    srvObj[subservice][name] = true;
};

RuleSet.prototype.includes = function(service, subservice, name) {
    return this.set[service] && this.set[service][subservice] && this.set[service][subservice][name] === true;
};

function refreshAllRules(rules) {
    var count = 0,
        ruleSet = new RuleSet(),
        oldRuleArr = [];

    logger.debug(context, 'Refreshing all no-signal rules');
    rules.forEach(function(rule) {
        if (rule.nosignal) {
            //check if any checkInterval has been modified, and delete if so.
            oldRuleArr = getNSRule(rule.service, rule.subservice, rule.name);
            deleteNSRuleIf(function() {
                return oldRuleArr && oldRuleArr[CHECK_INTERVAL] !== rule.nosignal.checkInterval;
            });
            if (addNSRule(rule.service, rule.subservice, rule.name, rule.nosignal) > 0) {
                count++;
                ruleSet.add(rule.service, rule.subservice, rule.name);
            }
        }
    });
    // remove old rules not in the new set
    deleteNSRuleIf(function(srv, subsrv, nm) {
        return !ruleSet.includes(srv, subsrv, nm);
    });
    logger.debug(
        context,
        util.format('no-signal rules %d/%d, checkers: %d', count, rules.length, Object.keys(checkers).length)
    );
}

module.exports.AddNSRule = addNSRule;
module.exports.DeleteNSRule = deleteNSRule;
module.exports.RefreshAllRules = refreshAllRules;
module.exports.GetNSArrRule = getNSRule;
module.exports.CheckNoSignal = checkNoSignal;
module.exports.Nsr2Arr = nsr2arr;
module.exports.getMinIntervalMs = function() {
    return MIN_INTERVAL_MS;
};
module.exports.getIntervalUnit = function() {
    return intervalUnit;
};
<|endoftext|>


<commit_before>'use strict';

var isElement = require('dom-ext/element/is-element')
  , isAnchor  = require('dom-ext/html-anchor-element/is-html-anchor-element')

  , isExternalLink = RegExp.prototype.test.bind(/^(?:[a-zA-Z]+:(?:\d+)?)?\/\//)
  , isFileLink = RegExp.prototype.test.bind(/\.[a-z0-9A-Z]+$/)
  , forEach = Array.prototype.forEach;

exports = module.exports = function (dom) {
	forEach.call(dom.childNodes, function (child) {
		var href;
		if (!isElement(child)) return;
		if (!isAnchor(child)) return exports(child);
		href = child.getAttribute('href');
		if (!href) return;
		if (!isExternalLink(href) && !isFileLink(child.pathname)) return;
		child.setAttribute('target', '_blank');
	});
};
<commit_msg>Fix file link detection<commit_after>'use strict';

var isElement = require('dom-ext/element/is-element')
  , isAnchor  = require('dom-ext/html-anchor-element/is-html-anchor-element')

  , isExternalLink = RegExp.prototype.test.bind(/^(?:[a-zA-Z]+:(?:\d+)?)?\/\//)
  , isFileLink = RegExp.prototype.test.bind(/\.[a-z0-9A-Z]+$/)
  , forEach = Array.prototype.forEach;

exports = module.exports = function (dom) {
	forEach.call(dom.childNodes, function (child) {
		var href;
		if (!isElement(child)) return;
		if (!isAnchor(child)) return exports(child);
		href = child.getAttribute('href');
		if (!href) return;
		if (!isExternalLink(href) && !isFileLink(child.pathname || href)) return;
		child.setAttribute('target', '_blank');
	});
};
<|endoftext|>


<commit_before>var Complex = function (re,im) {
  this.re = re;
  this.im = im;
}

/**
 * Add a complex number to this one.
 *
 * @param {Complex} Number to add.
 * @return {Complex} New complex number (sum).
 */
Complex.prototype.add = function(addend) {
  return new Complex( this.re + addend.re, this.im + addend.im );
}

/**
 * Subtract a complex number from this one.
 *
 * @param {Complex} Number to subtract.
 * @return {Complex} New complex number (difference).
 */
Complex.prototype.subtract = function(subtrahend) {
  return new Complex( this.re - subtrahend.im, this.im - subtrahend.im );
}

/**
 * Multiply a complex number with this one.
 *
 * @param {Complex} Number to multiply by.
 * @return {Complex} New complex number (product).
 */
Complex.prototype.multiply = function(multiplier) {
  var re = this.re*multiplier.re - this.im*multiplier.im;
  var im = this.im*multiplier.re + this.re*multiplier.im;
  return new Complex(re,im);
}

/**
 * Divide this number with another complex number.
 *
 * @param {Complex} Divisor.
 * @return {Complex} New complex number (quotient).
 */
Complex.prototype.divide = function(divisor) {
  var denominator = divisor.re*divisor.re+divisor.im*divisor.im
  var re = (this.re*divisor.re+this.im*divisor.im)/denominator;
  var im = (this.im*divisor.re-this.real*divisor.im)/denominator;
  return new Complex(re,im);
}

/**
 * Get the magnitude of this number.
 *
 * @return {Number} Magnitude.
 */
Complex.prototype.magnitude = function() {
  return Math.sqrt(this.re*this.re+this.im*this.im);
}

/**
 * Get the phase of this number.
 *
 * @return {Number} Phase.
 */
Complex.prototype.phase = function() {
  return Math.atan2(this.im,this.re)
}

//export
exports.Complex = Complex;
<commit_msg>Add missing semicolon<commit_after>var Complex = function (re,im) {
  this.re = re;
  this.im = im;
}

/**
 * Add a complex number to this one.
 *
 * @param {Complex} Number to add.
 * @return {Complex} New complex number (sum).
 */
Complex.prototype.add = function(addend) {
  return new Complex( this.re + addend.re, this.im + addend.im );
}

/**
 * Subtract a complex number from this one.
 *
 * @param {Complex} Number to subtract.
 * @return {Complex} New complex number (difference).
 */
Complex.prototype.subtract = function(subtrahend) {
  return new Complex( this.re - subtrahend.im, this.im - subtrahend.im );
}

/**
 * Multiply a complex number with this one.
 *
 * @param {Complex} Number to multiply by.
 * @return {Complex} New complex number (product).
 */
Complex.prototype.multiply = function(multiplier) {
  var re = this.re*multiplier.re - this.im*multiplier.im;
  var im = this.im*multiplier.re + this.re*multiplier.im;
  return new Complex(re,im);
}

/**
 * Divide this number with another complex number.
 *
 * @param {Complex} Divisor.
 * @return {Complex} New complex number (quotient).
 */
Complex.prototype.divide = function(divisor) {
  var denominator = divisor.re*divisor.re+divisor.im*divisor.im;
  var re = (this.re*divisor.re+this.im*divisor.im)/denominator;
  var im = (this.im*divisor.re-this.real*divisor.im)/denominator;
  return new Complex(re,im);
}

/**
 * Get the magnitude of this number.
 *
 * @return {Number} Magnitude.
 */
Complex.prototype.magnitude = function() {
  return Math.sqrt(this.re*this.re+this.im*this.im);
}

/**
 * Get the phase of this number.
 *
 * @return {Number} Phase.
 */
Complex.prototype.phase = function() {
  return Math.atan2(this.im,this.re)
}

//export
exports.Complex = Complex;
<|endoftext|>


<commit_before>'use strict';
var Class           = require('appolo').Class,
    path            = require('path'),
    gaze            = require('gaze');

module.exports = Class.define({

    $config: {
        id: 'watcher',
        singleton: false,
        inject: ['env', 'utils']
    },

    constructor: function(root, options, callback) {
        this._FSwatcher = null;
        this._timer = null;
        this._changes = [];
        this.callback = callback;
        this.path = root;

        // any file in project
        this._watchDir = path.resolve(this.path) + '/**/*';

        if(options instanceof Array) {
            this._setWatchDir(options);
        }
    },

    start: function() {
        if(!this._FSwatcher) {
            gaze(this._watchDir, { interval: 5007 }, this._onGazeWatcherStart.bind(this));
        }
    },

    stop: function() {
        if(this._FSwatcher) {
            this._FSwatcher.close();
            this._FSwatcher = null;
        }
    },

    _onGazeWatcherStart: function(err, watcher) {
        if(err) {
            this.callback && this.callback(err);
            return;
        }
        this._FSwatcher = watcher;
        this._FSwatcher.setMaxListeners(0);
        this._FSwatcher.on('all', this._onWatcherEvent.bind(this));
    },

    _onWatcherEvent: function(event, file) {

        if(!this._timer) {
            this._changes.push({ event: event, path: file });
            this._timer = setTimeout(this._fireChangeEvent.bind(this, event, file), this.env.watcherTurtle);
        } else {
            clearTimeout(this._timer);
            this._timer = null;
            this._onWatcherEvent(event, file);
        }

    },

    _setWatchDir: function(options) {
        this._watchDir = [];
        for(var i = 0, len = options.length; i < len; i ++) {
            this._watchDir.push(path.resolve(this.path, options[i]));
        }
    },

    _fireChangeEvent: function(event, file) {
        this._timer = null;
        this.callback && this.callback(null, this._changes);
        this._changes = [];
    }
});<commit_msg>stopping the watcher when for service when their are too many open files<commit_after>'use strict';
var Class           = require('appolo').Class,
    path            = require('path'),
    gaze            = require('gaze');

module.exports = Class.define({

    $config: {
        id: 'watcher',
        singleton: false,
        inject: ['env', 'utils']
    },

    constructor: function(root, options, callback) {
        this._FSwatcher = null;
        this._timer = null;
        this._changes = [];
        this.callback = callback;
        this.path = root;

        // any file in project
        this._watchDir = path.resolve(this.path) + '/**/*';

        if(options instanceof Array) {
            this._setWatchDir(options);
        }
    },

    start: function() {
        if(!this._FSwatcher) {
            gaze(this._watchDir, { interval: 5007 }, this._onGazeWatcherStart.bind(this));
        }
    },

    stop: function() {
        if(this._FSwatcher) {
            this._FSwatcher.close();
            this._FSwatcher = null;
        }
    },

    _onGazeWatcherStart: function(err, watcher) {
        if(err) {
            this.callback && this.callback(err);
            return;
        }
        this._FSwatcher = watcher;
        this._FSwatcher.on('all', this._onWatcherEvent.bind(this));
    },

    _onWatcherEvent: function(event, file) {

        if(!this._timer) {
            this._changes.push({ event: event, path: file });
            this._timer = setTimeout(this._fireChangeEvent.bind(this, event, file), this.env.watcherTurtle);
        } else {
            clearTimeout(this._timer);
            this._timer = null;
            this._onWatcherEvent(event, file);
        }

    },

    _setWatchDir: function(options) {
        this._watchDir = [];
        for(var i = 0, len = options.length; i < len; i ++) {
            this._watchDir.push(path.resolve(this.path, options[i]));
        }
    },

    _fireChangeEvent: function(event, file) {
        this._timer = null;
        this.callback && this.callback(null, this._changes);
        this._changes = [];
    }
});<|endoftext|>


<commit_before>import { eq } from 'orbit/lib/eq';
import { clone, isArray } from 'orbit/lib/objects';
import { arrayToOptions } from 'orbit/lib/config';

/**
 Determines the patch operations required to convert `a` to `b`.

 @method diffs
 @for Orbit
 @param a
 @param b
 @param [options]
 @returns {Array} array of patch operations
 */
var diffs = function(a, b, options) {
  if (a === b) {
    return undefined;

  } else {
    options = options || {};

    var ignore = arrayToOptions(options.ignore),
        basePath = options.basePath || '';

    if (isArray(basePath)) {
      basePath = basePath.join('/');
    }

    var type = Object.prototype.toString.call(a);
    if (type === Object.prototype.toString.call(b)) {
      if (typeof a === 'object') {
        var i,
            d;

        if (isArray(a)) {
          var aLength = a.length,
              bLength = b.length,
              maxLength = bLength > aLength ? bLength : aLength,
              match,
              ai = 0,
              bi = 0,
              bj;

          for (i = 0; i < maxLength; i++) {
            if (ai >= aLength) {
              if (d === undefined) d = [];
              d.push({op: 'add', path: basePath + '/' + bi, value: clone(b[bi])});
              bi++;

            } else if (bi >= bLength) {
              if (d === undefined) d = [];
              d.push({op: 'remove', path: basePath + '/' + ai});
              ai++;

            } else if (!eq(a[ai], b[bi])) {
              match = -1;
              for (bj = bi + 1; bj < bLength; bj++) {
                if (eq(a[ai], b[bj])) {
                  match = bj;
                  break;
                }
              }
              if (match === -1) {
                if (d === undefined) d = [];
                d.push({op: 'remove', path: basePath + '/' + ai});
                ai++;

              } else {
                if (d === undefined) d = [];
                d.push({op: 'add', path: basePath + '/' + bi, value: clone(b[bi])});
                bi++;
              }
            } else {
              ai++;
              bi++;
            }
          }

        } else { // general (non-array) object
          for (i in b) {
            if (!ignore[i] && b.hasOwnProperty(i)) {
              if (a[i] === undefined) {
                if (d === undefined) d = [];
                d.push({op: 'add', path: basePath + '/' + i, value: clone(b[i])});

              } else if (!eq(a[i], b[i])) {
                if (d === undefined) d = [];
                d = d.concat(diffs(a[i], b[i], {basePath: basePath + '/' + i}));
              }
            }
          }

          for (i in a) {
            if (!ignore[i] && a.hasOwnProperty(i)) {
              if (b[i] === undefined) {
                if (d === undefined) d = [];
                d.push({op: 'remove', path: basePath + '/' + i});
              }
            }
          }
        }

        return d;

      } else if (eq(a, b)) {
        return undefined;
      }
    }

    return [{op: 'replace', path: basePath, value: clone(b)}];
  }
};

export { diffs };<commit_msg>Improve `diffs` docs<commit_after>import { eq } from 'orbit/lib/eq';
import { clone, isArray } from 'orbit/lib/objects';
import { arrayToOptions } from 'orbit/lib/config';

/**
 Determines the patch operations required to convert one object to another.

 See [RFC 6902](http://tools.ietf.org/html/rfc6902) for a description of patch
 operations and a full set of examples.

 @example

 ``` javascript
 var a, b;

 a = {foo: 'bar'};
 b = {foo: 'bar', 'baz': 'qux'};

 Orbit.diffs(a, b); // [{op: 'add', path: '/baz', value: 'qux'}]
 ```

 @method diffs
 @for Orbit
 @param a
 @param b
 @param {Object} [options]
 @param {Array}  [options.ignore] Properties to ignore
 @param {String} [options.basePath] A base path to be prefixed to all paths in return patch operations
 @returns {Array} Array of patch operations to get from `a` to `b` (or undefined if they are equal)
 */
var diffs = function(a, b, options) {
  if (a === b) {
    return undefined;

  } else {
    options = options || {};

    var ignore = arrayToOptions(options.ignore),
        basePath = options.basePath || '';

    if (isArray(basePath)) {
      basePath = basePath.join('/');
    }

    var type = Object.prototype.toString.call(a);
    if (type === Object.prototype.toString.call(b)) {
      if (typeof a === 'object') {
        var i,
            d;

        if (isArray(a)) {
          var aLength = a.length,
              bLength = b.length,
              maxLength = bLength > aLength ? bLength : aLength,
              match,
              ai = 0,
              bi = 0,
              bj;

          for (i = 0; i < maxLength; i++) {
            if (ai >= aLength) {
              if (d === undefined) d = [];
              d.push({op: 'add', path: basePath + '/' + bi, value: clone(b[bi])});
              bi++;

            } else if (bi >= bLength) {
              if (d === undefined) d = [];
              d.push({op: 'remove', path: basePath + '/' + ai});
              ai++;

            } else if (!eq(a[ai], b[bi])) {
              match = -1;
              for (bj = bi + 1; bj < bLength; bj++) {
                if (eq(a[ai], b[bj])) {
                  match = bj;
                  break;
                }
              }
              if (match === -1) {
                if (d === undefined) d = [];
                d.push({op: 'remove', path: basePath + '/' + ai});
                ai++;

              } else {
                if (d === undefined) d = [];
                d.push({op: 'add', path: basePath + '/' + bi, value: clone(b[bi])});
                bi++;
              }
            } else {
              ai++;
              bi++;
            }
          }

        } else { // general (non-array) object
          for (i in b) {
            if (!ignore[i] && b.hasOwnProperty(i)) {
              if (a[i] === undefined) {
                if (d === undefined) d = [];
                d.push({op: 'add', path: basePath + '/' + i, value: clone(b[i])});

              } else if (!eq(a[i], b[i])) {
                if (d === undefined) d = [];
                d = d.concat(diffs(a[i], b[i], {basePath: basePath + '/' + i}));
              }
            }
          }

          for (i in a) {
            if (!ignore[i] && a.hasOwnProperty(i)) {
              if (b[i] === undefined) {
                if (d === undefined) d = [];
                d.push({op: 'remove', path: basePath + '/' + i});
              }
            }
          }
        }

        return d;

      } else if (eq(a, b)) {
        return undefined;
      }
    }

    return [{op: 'replace', path: basePath, value: clone(b)}];
  }
};

export { diffs };<|endoftext|>


<commit_before>import nugetResolver from '../resolver/nuget';
import {
  NET_PACKAGE,
  NET_PROJ_PACKAGE,
} from '../../packages/helper-grammar-regex-collection/index.js';

export default {
  name: 'DotNet',

  resolve({ target }) {
    return nugetResolver({ target });
  },

  getPattern() {
    return {
      pathRegexes: [/packages\.config$/, /\.(cs|vb)proj$/],
      githubClasses: [],
    };
  },

  getLinkRegexes() {
    return [NET_PACKAGE, NET_PROJ_PACKAGE];
  },
};
<commit_msg>Add support for F# project files and .net props files (#424)<commit_after>import nugetResolver from '../resolver/nuget';
import {
  NET_PACKAGE,
  NET_PROJ_PACKAGE,
} from '../../packages/helper-grammar-regex-collection/index.js';

export default {
  name: 'DotNet',

  resolve({ target }) {
    return nugetResolver({ target });
  },

  getPattern() {
    return {
      pathRegexes: [/packages\.config$/, /\.(cs|fs|vb)proj$/, /\.props$/],
      githubClasses: [],
    };
  },

  getLinkRegexes() {
    return [NET_PACKAGE, NET_PROJ_PACKAGE];
  },
};
<|endoftext|>


<commit_before>// Copyright 2015 Yahoo! Inc.
// Copyrights licensed under the Mit License. See the accompanying LICENSE file for terms.

// PLTE - Palette

var BufferedStream = require('../utils/bufferedStream');

/**
 * @class PLTE
 * @module PNG
 * @submodule PNGChunks
 */
module.exports = {

	/**
	 * Gets the sequence
	 *
	 * @method getSequence
	 * @return {int}
	 */
	getSequence: function () {
		return 250;
	},

	/**
	 * Searches the platte to find the index of a color
	 *
	 * @method findColor
	 * @param {object} color Color object with red, green, and blue components
	 * @return {int|null}
	 */
	findColor: function (color) {

		if (!this._lookup) {
			this._createLookUpTable();
		}

		return this._lookup[color.red + '_' + color.green + '_' + color.blue];
	},

	/**
	 * Creates a look-up table for faster finds
	 *
	 * @method _createLookUpTable
	 * @private
	 */
	_createLookUpTable: function () {

		var i, len,
			lookup = {},
			colors = this.getColors();

		for (i = 0, len = colors.length; i < len; i++) {
			lookup[colors[i].red + '_' + colors[i].green + '_' + colors[i].blue] = i;
		}

		this._lookup = lookup;
	},

	/**
	 * Gets all colors at once
	 *
	 * @method getColors
	 * @return {object[]}
	 */
	getColors: function () {
		return this._colors || [];
	},

	/**
	 * Sets all colors at once
	 *
	 * @method setColors
	 * @param {object[]} colors
	 */
	setColors: function (colors) {
		this._colors = colors;
		this._lookup = null;
	},

	/**
	 * Parsing of chunk data
	 *
	 * Phase 1
	 *
	 * @method parse
	 * @param {BufferedStream} stream Data stream
	 * @param {int} length Length of chunk data
	 * @param {boolean} strict Should parsing be strict?
	 */
	parse: function (stream, length, strict) {

		var i, len,
			colors = [];

		// Validation
		if (strict && (this.getFirstChunk(this.getType(), false) !== null)) {
			throw new Error('Only one ' + this.getType() + ' is allowed in the data.');
		}

		// Palette length should be divisible by three (each of r, g, b has one byte)
		if ((length % 3) !== 0) {
			throw new Error('Palette length should be a multiple of 3. Length: ' + length);
		}

		// Copy palette

		for (i = 0, len = length / 3; i < len; i++) {
			colors.push({
				red: stream.readUInt8(),
				green: stream.readUInt8(),
				blue: stream.readUInt8()
			});
		}

		this.setColors(colors);
	},

	/**
	 * Decoding of chunk data after scaling
	 *
	 * Phase 3
	 *
	 * @method postDecode
	 * @param {Buffer} image
	 * @param {boolean} strict Should parsing be strict?
	 * @return {Buffer}
	 */
	postDecode: function (image, strict) {

		var i, len, index,
			color, colors, colorsLength,
			imageStream, outputStream,
			headerChunk;

		headerChunk = this.getHeaderChunk();

		// Check if image requires a palette or if the colors are suggested
		if (!headerChunk.hasIndexedColor()) {
			return image; // Ignore these since they are not needed
		}

		colors = this._colors;
		colorsLength = colors.length;
		imageStream = new BufferedStream(image, false);

		outputStream = new BufferedStream(image, false); // use same buffer
		outputStream.writeOffset = 0;

		// Convert an index color image to true-color image
		for (i = 0, len = image.length; i < len; i += 4) {

			// Get index from input
			index = imageStream.readUInt8();
			imageStream.skip(3); // Skip the next three bytes
			if (index >= colorsLength) {

				if (strict) {
					throw new Error('Palette: Index of color out of bounds.');

				} else {

					// Use black as unknown color in non-strict mode
					color = {
						red: 0,
						green: 0,
						blue: 0
					};
				}

			} else {
				color = colors[index];
			}

			// Write to image
			outputStream.writeUInt8(color.red);
			outputStream.writeUInt8(color.green);
			outputStream.writeUInt8(color.blue);
			outputStream.writeUInt8(255);
		}

		return outputStream.toBuffer(true);
	},

	/**
	 * Gathers chunk-data from decoded chunks
	 *
	 * Phase 4
	 *
	 * @static
	 * @method decodeData
	 * @param {object} data Data-object that will be used to export values
	 * @param {boolean} strict Should parsing be strict?
	 */
	decodeData: function (data, strict) {

		var chunks = this.getChunksByType(this.getType());

		if (!chunks) {
			return ;
		}

		if (strict && (chunks.length !== 1)) {
			throw new Error('Not more than one chunk allowed for ' + this.getType() + '.');
		}

		data.volatile = data.volatile || {};
		data.volatile.paletteColors = chunks[0].getColors();
	},

	/**
	 * Returns a list of chunks to be added to the data-stream
	 *
	 * Phase 1
	 *
	 * @static
	 * @method encodeData
	 * @param {Buffer} image Image data
	 * @param {object} data Object that will be used to import data to the chunk
	 * @return {Chunk[]} List of chunks to encode
	 */
	encodeData: function (image, data) {

		if (data.paletteColors) {

			var chunk = this.createChunk(this.getType(), this.getChunks());

			chunk.setColors(data.paletteColors);

			return [chunk];
		} else {
			return [];
		}
	},

	/**
	 * Before encoding of chunk data
	 *
	 * Phase 2
	 *
	 * @method preEncode
	 * @param {Buffer} image
	 * @return {Buffer}
	 */
	preEncode: function (image) {

		var i, len,
			imageStream, outputStream,
			headerChunk,
			index, a;

		// Check if image requires a palette or if the colors are suggested
		headerChunk = this.getHeaderChunk();
		if (!headerChunk.hasIndexedColor()) {
			//TODO: May be give an option for using these suggested colors?
			return image; // Ignore these since they are not needed
		}

		// Convert true-color to indexed color
		imageStream = new BufferedStream(image, false);
		outputStream = new BufferedStream(null, null, image.length / 4);

		for (i = 0, len = image.length; i < len; i += 4) {

			index = this.findColor({
				red: imageStream.readUInt8(i),
				green: imageStream.readUInt8(i + 1),
				blue: imageStream.readUInt8(i + 2)
			});
			a = imageStream.readUInt8(i + 3);

			if (index === undefined) {
				throw new Error('Color not find color in palette.');
			}

			// Write to image
			outputStream.writeUInt8(index);
		}

		return outputStream.toBuffer(true);
	},

	/**
	 * Composing of chunk data
	 *
	 * Phase 4
	 *
	 * @method compose
	 * @param {BufferedStream} stream Data stream
	 */
	compose: function (stream) {

		var i, len,
			colors = this.getColors();

		for (i = 0, len = colors.length; i < len; i++) {
			stream.writeUInt8(colors[i].red);
			stream.writeUInt8(colors[i].green);
			stream.writeUInt8(colors[i].blue);
		}
	}
};
<commit_msg>Bugfixes for Palette<commit_after>// Copyright 2015 Yahoo! Inc.
// Copyrights licensed under the Mit License. See the accompanying LICENSE file for terms.

// PLTE - Palette

var BufferedStream = require('../utils/bufferedStream');

/**
 * @class PLTE
 * @module PNG
 * @submodule PNGChunks
 */
module.exports = {

	/**
	 * Gets the sequence
	 *
	 * @method getSequence
	 * @return {int}
	 */
	getSequence: function () {
		return 250;
	},

	/**
	 * Searches the platte to find the index of a color
	 *
	 * @method findColor
	 * @param {object} color Color object with red, green, and blue components
	 * @return {int|null}
	 */
	findColor: function (color) {

		if (!this._lookup) {
			this._createLookUpTable();
		}

		return this._lookup[color.red + '_' + color.green + '_' + color.blue];
	},

	/**
	 * Creates a look-up table for faster finds
	 *
	 * @method _createLookUpTable
	 * @private
	 */
	_createLookUpTable: function () {

		var i, len,
			lookup = {},
			colors = this.getColors();

		for (i = 0, len = colors.length; i < len; i++) {
			lookup[colors[i].red + '_' + colors[i].green + '_' + colors[i].blue] = i;
		}

		this._lookup = lookup;
	},

	/**
	 * Gets all colors at once
	 *
	 * @method getColors
	 * @return {object[]}
	 */
	getColors: function () {
		return this._colors || [];
	},

	/**
	 * Sets all colors at once
	 *
	 * @method setColors
	 * @param {object[]} colors
	 */
	setColors: function (colors) {
		this._colors = colors;
		this._lookup = null;
	},

	/**
	 * Parsing of chunk data
	 *
	 * Phase 1
	 *
	 * @method parse
	 * @param {BufferedStream} stream Data stream
	 * @param {int} length Length of chunk data
	 * @param {boolean} strict Should parsing be strict?
	 * @param {object} options Decoding options
	 */
	parse: function (stream, length, strict, options) {

		var i, len,
			colors = [];

		// Validation
		if (strict && (this.getFirstChunk(this.getType(), false) !== null)) {
			throw new Error('Only one ' + this.getType() + ' is allowed in the data.');
		}

		// Palette length should be divisible by three (each of r, g, b has one byte)
		if ((length % 3) !== 0) {
			throw new Error('Palette length should be a multiple of 3. Length: ' + length);
		}

		// Create palette
		for (i = 0, len = length / 3; i < len; i++) {
			colors.push({
				red: stream.readUInt8(),
				green: stream.readUInt8(),
				blue: stream.readUInt8()
			});
		}

		this.setColors(colors);
	},

	/**
	 * Decoding of chunk data after scaling
	 *
	 * Phase 3
	 *
	 * @method postDecode
	 * @param {Buffer} image
	 * @param {boolean} strict Should parsing be strict?
	 * @param {object} options Decoding options
	 * @return {Buffer}
	 */
	postDecode: function (image, strict, options) {

		var i, len, index, alpha,
			color, colors, colorsLength,
			imageStream, outputStream,
			headerChunk;

		headerChunk = this.getHeaderChunk();

		// Check if image requires a palette or if the colors are suggested
		if (!headerChunk.hasIndexedColor()) {
			return image; // Ignore these since they are not needed
		}

		colors = this._colors;
		colorsLength = colors.length;
		imageStream = new BufferedStream(image, false);

		outputStream = new BufferedStream(image, false); // use same buffer
		outputStream.writeOffset = 0;

		// Convert an index color image to true-color image
		for (i = 0, len = image.length; i < len; i += 4) {

			// Get index from input
			index = imageStream.readUInt8();
			imageStream.skip(2); // Skip the next three bytes
			alpha = imageStream.readUInt8();
			if (index >= colorsLength) {

				if (strict) {
					throw new Error('Palette: Index of color out of bounds.');

				} else {

					// Use black as unknown color in non-strict mode
					color = {
						red: 0,
						green: 0,
						blue: 0
					};
				}

			} else {
				color = colors[index];
			}

			// Write to image
			outputStream.writeUInt8(color.red);
			outputStream.writeUInt8(color.green);
			outputStream.writeUInt8(color.blue);
			outputStream.writeUInt8(alpha);
		}

		return outputStream.toBuffer(true);
	},

	/**
	 * Gathers chunk-data from decoded chunks
	 *
	 * Phase 5
	 *
	 * @static
	 * @method decodeData
	 * @param {object} data Data-object that will be used to export values
	 * @param {boolean} strict Should parsing be strict?
	 * @param {object} options Decoding options
	 */
	decodeData: function (data, strict, options) {

		var chunks = this.getChunksByType(this.getType());

		if (!chunks) {
			return ;
		}

		if (strict && (chunks.length !== 1)) {
			throw new Error('Not more than one chunk allowed for ' + this.getType() + '.');
		}

		data.volatile = data.volatile || {};
		data.volatile.paletteColors = chunks[0].getColors();
	},

	/**
	 * Returns a list of chunks to be added to the data-stream
	 *
	 * Phase 1
	 *
	 * @static
	 * @method encodeData
	 * @param {Buffer} image Image data
	 * @param {object} data Object that will be used to import data to the chunk
	 * @return {Chunk[]} List of chunks to encode
	 */
	encodeData: function (image, data) {

		if (data.paletteColors) {

			var chunk = this.createChunk(this.getType(), this.getChunks());

			chunk.setColors(data.paletteColors);

			return [chunk];
		} else {
			return [];
		}
	},

	/**
	 * Before encoding of chunk data
	 *
	 * Phase 2
	 *
	 * @method preEncode
	 * @param {Buffer} image
	 * @return {Buffer}
	 */
	preEncode: function (image) {

		var i, len,
			imageStream, outputStream,
			headerChunk,
			index, a;

		// Check if image requires a palette or if the colors are suggested
		headerChunk = this.getHeaderChunk();
		if (!headerChunk.hasIndexedColor()) {
			//TODO: May be give an option for using these suggested colors?
			return image; // Ignore these since they are not needed
		}

		// Convert true-color to indexed color
		imageStream = new BufferedStream(image, false);
		outputStream = new BufferedStream(null, null, image.length / 4);

		for (i = 0, len = image.length; i < len; i += 4) {

			index = this.findColor({
				red: imageStream.readUInt8(i),
				green: imageStream.readUInt8(i + 1),
				blue: imageStream.readUInt8(i + 2)
			});
			a = imageStream.readUInt8(i + 3);

			if (index === undefined) {
				throw new Error('Color not find color in palette.');
			}

			// Write to image
			outputStream.writeUInt8(index);
		}

		return outputStream.toBuffer(true);
	},

	/**
	 * Composing of chunk data
	 *
	 * Phase 4
	 *
	 * @method compose
	 * @param {BufferedStream} stream Data stream
	 */
	compose: function (stream) {

		var i, len,
			colors = this.getColors();

		for (i = 0, len = colors.length; i < len; i++) {
			stream.writeUInt8(colors[i].red);
			stream.writeUInt8(colors[i].green);
			stream.writeUInt8(colors[i].blue);
		}
	}
};
<|endoftext|>


<commit_before>(function () {

  var _ = require("underscore"),
    async = require('async'),
    fs = require('fs'),
    marked = require("marked"),
    path = require('path'),
    contentFiles = fs.readdirSync(path.join(__dirname, "../content")),
    imageFiles = fs.readdirSync(path.join(__dirname, "../public/images")),
    stylesheets = fs.readdirSync(path.join(__dirname, "../public/stylesheets"));

  var loadContentFile = function (filename, done) {
    if (!_.contains([".markdown", ".md"], path.extname(filename))) {
      done(); // don't serve non-markdown content files
      return;
    }
    fs.readFile(path.join(__dirname, "../content", filename), "utf8", function (err, data) {
      if (err) {
        return done(err);
      }
      var dataLines = data.split("\n");
      var basename = path.basename(filename, path.extname(filename));
      var imageName = _.find(imageFiles, function (imageFile) {
        return path.basename(imageFile, path.extname(imageFile)) === basename;
      });
      var stylesheetName = _.find(stylesheets, function (stylesheet) {
        return path.basename(stylesheet, path.extname(stylesheet)) === basename;
      });
      var stylesheetPath = stylesheetName &&
        "/stylesheets/" + path.basename(stylesheetName, path.extname(stylesheetName)) + ".css";

      done(null, {
        markdown: marked(dataLines.splice(2).join("\n")),
        file: basename,
        path: basename === "index" ? "" : basename,
        image: imageName ? "../images/" + imageName : "http://placekitten.com/g/1024/768",
        stylesheet: stylesheetPath,
        title: dataLines[0].replace(/^[^a-zA-Z]+/, ""), // delete leading non-alpha characters
        subtitle: dataLines[1].replace(/^[^a-zA-Z]+/, "")
      });
    });
  };

  exports.processContent = function (callback) {
    async.map(contentFiles, loadContentFile, callback);
  };
}());
<commit_msg>make this more tolerant for weird titled paths and files by URL encoding<commit_after>(function () {

  var _ = require("underscore"),
    async = require('async'),
    fs = require('fs'),
    marked = require("marked"),
    path = require('path'),
    contentFiles = fs.readdirSync(path.join(__dirname, "../content")),
    imageFiles = fs.readdirSync(path.join(__dirname, "../public/images")),
    stylesheets = fs.readdirSync(path.join(__dirname, "../public/stylesheets"));

  var loadContentFile = function (filename, done) {
    if (!_.contains([".markdown", ".md"], path.extname(filename))) {
      done(); // don't serve non-markdown content files
      return;
    }
    fs.readFile(path.join(__dirname, "../content", filename), "utf8", function (err, data) {
      if (err) {
        return done(err);
      }
      filename = encodeURIComponent(filename);
      var dataLines = data.split("\n");
      var basename = path.basename(filename, path.extname(filename));
      var imageName = _.find(imageFiles, function (imageFile) {
        return path.basename(imageFile, path.extname(imageFile)) === basename;
      });
      var stylesheetName = _.find(stylesheets, function (stylesheet) {
        return path.basename(stylesheet, path.extname(stylesheet)) === basename;
      });
      var stylesheetPath = stylesheetName &&
        "/stylesheets/" + path.basename(stylesheetName, path.extname(stylesheetName)) + ".css";

      done(null, {
        markdown: marked(dataLines.splice(2).join("\n")),
        file: basename,
        path: basename === "index" ? "" : basename,
        image: imageName ? "../images/" + imageName : "http://placekitten.com/g/1024/768",
        stylesheet: stylesheetPath,
        title: dataLines[0].replace(/^[^a-zA-Z]+/, ""), // delete leading non-alpha characters
        subtitle: dataLines[1].replace(/^[^a-zA-Z]+/, "")
      });
    });
  };

  exports.processContent = function (callback) {
    async.map(contentFiles, loadContentFile, callback);
  };
}());
<|endoftext|>