<commit_before>module.exports = rimraf
rimraf.sync = rimrafSync

var assert = require("assert")
var path = require("path")
var fs = require("fs")
var glob = require("glob")

var defaultGlobOpts = {
  nosort: true,
  silent: true
}

// for EMFILE handling
var timeout = 0

var isWindows = (process.platform === "win32")

function defaults (options) {
  var methods = [
    'unlink',
    'chmod',
    'stat',
    'lstat',
    'rmdir',
    'readdir'
  ]
  methods.forEach(function(m) {
    options[m] = options[m] || fs[m]
    m = m + 'Sync'
    options[m] = options[m] || fs[m]
  })

  options.maxBusyTries = options.maxBusyTries || 3
  options.emfileWait = options.emfileWait || 1000
  if (options.glob === false) {
    options.disableGlob = true
  }
  options.disableGlob = options.disableGlob || false
  options.glob = options.glob || defaultGlobOpts
}

function rimraf (p, options, cb) {
  if (typeof options === 'function') {
    cb = options
    options = {}
  }

  assert(p, 'rimraf: missing path')
  assert.equal(typeof p, 'string', 'rimraf: path should be a string')
  assert.equal(typeof cb, 'function', 'rimraf: callback function required')
  assert(options, 'rimraf: invalid options argument provided')
  assert.equal(typeof options, 'object', 'rimraf: options should be object')

  defaults(options)

  var busyTries = 0
  var errState = null
  var n = 0

  if (options.disableGlob || !glob.hasMagic(p))
    return afterGlob(null, [p])

  options.lstat(p, function (er, stat) {
    if (!er)
      return afterGlob(null, [p])

    glob(p, options.glob, afterGlob)
  })

  function next (er) {
    errState = errState || er
    if (--n === 0)
      cb(errState)
  }

  function afterGlob (er, results) {
    if (er)
      return cb(er)

    n = results.length
    if (n === 0)
      return cb()

    results.forEach(function (p) {
      rimraf_(p, options, function CB (er) {
        if (er) {
          if ((er.code === "EBUSY" || er.code === "ENOTEMPTY" || er.code === "EPERM") &&
              busyTries < options.maxBusyTries) {
            busyTries ++
            var time = busyTries * 100
            // try again, with the same exact callback as this one.
            return setTimeout(function () {
              rimraf_(p, options, CB)
            }, time)
          }

          // this one won't happen if graceful-fs is used.
          if (er.code === "EMFILE" && timeout < options.emfileWait) {
            return setTimeout(function () {
              rimraf_(p, options, CB)
            }, timeout ++)
          }

          // already gone
          if (er.code === "ENOENT") er = null
        }

        timeout = 0
        next(er)
      })
    })
  }
}

// Two possible strategies.
// 1. Assume it's a file.  unlink it, then do the dir stuff on EPERM or EISDIR
// 2. Assume it's a directory.  readdir, then do the file stuff on ENOTDIR
//
// Both result in an extra syscall when you guess wrong.  However, there
// are likely far more normal files in the world than directories.  This
// is based on the assumption that a the average number of files per
// directory is >= 1.
//
// If anyone ever complains about this, then I guess the strategy could
// be made configurable somehow.  But until then, YAGNI.
function rimraf_ (p, options, cb) {
  assert(p)
  assert(options)
  assert(typeof cb === 'function')

  // sunos lets the root user unlink directories, which is... weird.
  // so we have to lstat here and make sure it's not a dir.
  options.lstat(p, function (er, st) {
    if (er && er.code === "ENOENT")
      return cb(null)

    // Windows can EPERM on stat.  Life is suffering.
    if (er && er.code === "EPERM" && isWindows)
      fixWinEPERM(p, options, er, cb)

    if (st && st.isDirectory())
      return rmdir(p, options, er, cb)

    options.unlink(p, function (er) {
      if (er) {
        if (er.code === "ENOENT")
          return cb(null)
        if (er.code === "EPERM")
          return (isWindows)
            ? fixWinEPERM(p, options, er, cb)
            : rmdir(p, options, er, cb)
        if (er.code === "EISDIR")
          return rmdir(p, options, er, cb)
      }
      return cb(er)
    })
  })
}

function fixWinEPERM (p, options, er, cb) {
  assert(p)
  assert(options)
  assert(typeof cb === 'function')
  if (er)
    assert(er instanceof Error)

  options.chmod(p, 666, function (er2) {
    if (er2)
      cb(er2.code === "ENOENT" ? null : er)
    else
      options.stat(p, function(er3, stats) {
        if (er3)
          cb(er3.code === "ENOENT" ? null : er)
        else if (stats.isDirectory())
          rmdir(p, options, er, cb)
        else
          options.unlink(p, cb)
      })
  })
}

function fixWinEPERMSync (p, options, er) {
  assert(p)
  assert(options)
  if (er)
    assert(er instanceof Error)

  try {
    options.chmodSync(p, 666)
  } catch (er2) {
    if (er2.code === "ENOENT")
      return
    else
      throw er
  }

  try {
    var stats = options.statSync(p)
  } catch (er3) {
    if (er3.code === "ENOENT")
      return
    else
      throw er
  }

  if (stats.isDirectory())
    rmdirSync(p, options, er)
  else
    options.unlinkSync(p)
}

function rmdir (p, options, originalEr, cb) {
  assert(p)
  assert(options)
  if (originalEr)
    assert(originalEr instanceof Error)
  assert(typeof cb === 'function')

  // try to rmdir first, and only readdir on ENOTEMPTY or EEXIST (SunOS)
  // if we guessed wrong, and it's not a directory, then
  // raise the original error.
  options.rmdir(p, function (er) {
    if (er && (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM"))
      rmkids(p, options, cb)
    else if (er && er.code === "ENOTDIR")
      cb(originalEr)
    else
      cb(er)
  })
}

function rmkids(p, options, cb) {
  assert(p)
  assert(options)
  assert(typeof cb === 'function')

  options.readdir(p, function (er, files) {
    if (er)
      return cb(er)
    var n = files.length
    if (n === 0)
      return options.rmdir(p, cb)
    var errState
    files.forEach(function (f) {
      rimraf(path.join(p, f), options, function (er) {
        if (errState)
          return
        if (er)
          return cb(errState = er)
        if (--n === 0)
          options.rmdir(p, cb)
      })
    })
  })
}

// this looks simpler, and is strictly *faster*, but will
// tie up the JavaScript thread and fail on excessively
// deep directory trees.
function rimrafSync (p, options) {
  options = options || {}
  defaults(options)

  assert(p, 'rimraf: missing path')
  assert.equal(typeof p, 'string', 'rimraf: path should be a string')
  assert(options, 'rimraf: missing options')
  assert.equal(typeof options, 'object', 'rimraf: options should be object')

  var results

  if (options.disableGlob || !glob.hasMagic(p)) {
    results = [p]
  } else {
    try {
      options.lstatSync(p)
      results = [p]
    } catch (er) {
      results = glob.sync(p, options.glob)
    }
  }

  if (!results.length)
    return

  for (var i = 0; i < results.length; i++) {
    var p = results[i]

    try {
      var st = options.lstatSync(p)
    } catch (er) {
      if (er.code === "ENOENT")
        return

      // Windows can EPERM on stat.  Life is suffering.
      if (er.code === "EPERM" && isWindows)
        fixWinEPERMSync(p, options, er)
    }

    try {
      // sunos lets the root user unlink directories, which is... weird.
      if (st && st.isDirectory())
        rmdirSync(p, options, null)
      else
        options.unlinkSync(p)
    } catch (er) {
      if (er.code === "ENOENT")
        return
      if (er.code === "EPERM")
        return isWindows ? fixWinEPERMSync(p, options, er) : rmdirSync(p, options, er)
      if (er.code !== "EISDIR")
        throw er

      rmdirSync(p, options, er)
    }
  }
}

function rmdirSync (p, options, originalEr) {
  assert(p)
  assert(options)
  if (originalEr)
    assert(originalEr instanceof Error)

  try {
    options.rmdirSync(p)
  } catch (er) {
    if (er.code === "ENOENT")
      return
    if (er.code === "ENOTDIR")
      throw originalEr
    if (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM")
      rmkidsSync(p, options)
  }
}

function rmkidsSync (p, options) {
  assert(p)
  assert(options)
  options.readdirSync(p).forEach(function (f) {
    rimrafSync(path.join(p, f), options)
  })

  // We only end up here once we got ENOTEMPTY at least once, and
  // at this point, we are guaranteed to have removed all the kids.
  // So, we know that it won't be ENOENT or ENOTDIR or anything else.
  // try really hard to delete stuff on windows, because it has a
  // PROFOUNDLY annoying habit of not closing handles promptly when
  // files are deleted, resulting in spurious ENOTEMPTY errors.
  var retries = isWindows ? 100 : 1
  var i = 0
  do {
    try {
      return options.rmdirSync(p, options)
    } finally {
      if (++i < retries)
        continue
    }
  } while (true)
}
<commit_msg>only run rmdirSync 'retries' times when it throws<commit_after>module.exports = rimraf
rimraf.sync = rimrafSync

var assert = require("assert")
var path = require("path")
var fs = require("fs")
var glob = require("glob")

var defaultGlobOpts = {
  nosort: true,
  silent: true
}

// for EMFILE handling
var timeout = 0

var isWindows = (process.platform === "win32")

function defaults (options) {
  var methods = [
    'unlink',
    'chmod',
    'stat',
    'lstat',
    'rmdir',
    'readdir'
  ]
  methods.forEach(function(m) {
    options[m] = options[m] || fs[m]
    m = m + 'Sync'
    options[m] = options[m] || fs[m]
  })

  options.maxBusyTries = options.maxBusyTries || 3
  options.emfileWait = options.emfileWait || 1000
  if (options.glob === false) {
    options.disableGlob = true
  }
  options.disableGlob = options.disableGlob || false
  options.glob = options.glob || defaultGlobOpts
}

function rimraf (p, options, cb) {
  if (typeof options === 'function') {
    cb = options
    options = {}
  }

  assert(p, 'rimraf: missing path')
  assert.equal(typeof p, 'string', 'rimraf: path should be a string')
  assert.equal(typeof cb, 'function', 'rimraf: callback function required')
  assert(options, 'rimraf: invalid options argument provided')
  assert.equal(typeof options, 'object', 'rimraf: options should be object')

  defaults(options)

  var busyTries = 0
  var errState = null
  var n = 0

  if (options.disableGlob || !glob.hasMagic(p))
    return afterGlob(null, [p])

  options.lstat(p, function (er, stat) {
    if (!er)
      return afterGlob(null, [p])

    glob(p, options.glob, afterGlob)
  })

  function next (er) {
    errState = errState || er
    if (--n === 0)
      cb(errState)
  }

  function afterGlob (er, results) {
    if (er)
      return cb(er)

    n = results.length
    if (n === 0)
      return cb()

    results.forEach(function (p) {
      rimraf_(p, options, function CB (er) {
        if (er) {
          if ((er.code === "EBUSY" || er.code === "ENOTEMPTY" || er.code === "EPERM") &&
              busyTries < options.maxBusyTries) {
            busyTries ++
            var time = busyTries * 100
            // try again, with the same exact callback as this one.
            return setTimeout(function () {
              rimraf_(p, options, CB)
            }, time)
          }

          // this one won't happen if graceful-fs is used.
          if (er.code === "EMFILE" && timeout < options.emfileWait) {
            return setTimeout(function () {
              rimraf_(p, options, CB)
            }, timeout ++)
          }

          // already gone
          if (er.code === "ENOENT") er = null
        }

        timeout = 0
        next(er)
      })
    })
  }
}

// Two possible strategies.
// 1. Assume it's a file.  unlink it, then do the dir stuff on EPERM or EISDIR
// 2. Assume it's a directory.  readdir, then do the file stuff on ENOTDIR
//
// Both result in an extra syscall when you guess wrong.  However, there
// are likely far more normal files in the world than directories.  This
// is based on the assumption that a the average number of files per
// directory is >= 1.
//
// If anyone ever complains about this, then I guess the strategy could
// be made configurable somehow.  But until then, YAGNI.
function rimraf_ (p, options, cb) {
  assert(p)
  assert(options)
  assert(typeof cb === 'function')

  // sunos lets the root user unlink directories, which is... weird.
  // so we have to lstat here and make sure it's not a dir.
  options.lstat(p, function (er, st) {
    if (er && er.code === "ENOENT")
      return cb(null)

    // Windows can EPERM on stat.  Life is suffering.
    if (er && er.code === "EPERM" && isWindows)
      fixWinEPERM(p, options, er, cb)

    if (st && st.isDirectory())
      return rmdir(p, options, er, cb)

    options.unlink(p, function (er) {
      if (er) {
        if (er.code === "ENOENT")
          return cb(null)
        if (er.code === "EPERM")
          return (isWindows)
            ? fixWinEPERM(p, options, er, cb)
            : rmdir(p, options, er, cb)
        if (er.code === "EISDIR")
          return rmdir(p, options, er, cb)
      }
      return cb(er)
    })
  })
}

function fixWinEPERM (p, options, er, cb) {
  assert(p)
  assert(options)
  assert(typeof cb === 'function')
  if (er)
    assert(er instanceof Error)

  options.chmod(p, 666, function (er2) {
    if (er2)
      cb(er2.code === "ENOENT" ? null : er)
    else
      options.stat(p, function(er3, stats) {
        if (er3)
          cb(er3.code === "ENOENT" ? null : er)
        else if (stats.isDirectory())
          rmdir(p, options, er, cb)
        else
          options.unlink(p, cb)
      })
  })
}

function fixWinEPERMSync (p, options, er) {
  assert(p)
  assert(options)
  if (er)
    assert(er instanceof Error)

  try {
    options.chmodSync(p, 666)
  } catch (er2) {
    if (er2.code === "ENOENT")
      return
    else
      throw er
  }

  try {
    var stats = options.statSync(p)
  } catch (er3) {
    if (er3.code === "ENOENT")
      return
    else
      throw er
  }

  if (stats.isDirectory())
    rmdirSync(p, options, er)
  else
    options.unlinkSync(p)
}

function rmdir (p, options, originalEr, cb) {
  assert(p)
  assert(options)
  if (originalEr)
    assert(originalEr instanceof Error)
  assert(typeof cb === 'function')

  // try to rmdir first, and only readdir on ENOTEMPTY or EEXIST (SunOS)
  // if we guessed wrong, and it's not a directory, then
  // raise the original error.
  options.rmdir(p, function (er) {
    if (er && (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM"))
      rmkids(p, options, cb)
    else if (er && er.code === "ENOTDIR")
      cb(originalEr)
    else
      cb(er)
  })
}

function rmkids(p, options, cb) {
  assert(p)
  assert(options)
  assert(typeof cb === 'function')

  options.readdir(p, function (er, files) {
    if (er)
      return cb(er)
    var n = files.length
    if (n === 0)
      return options.rmdir(p, cb)
    var errState
    files.forEach(function (f) {
      rimraf(path.join(p, f), options, function (er) {
        if (errState)
          return
        if (er)
          return cb(errState = er)
        if (--n === 0)
          options.rmdir(p, cb)
      })
    })
  })
}

// this looks simpler, and is strictly *faster*, but will
// tie up the JavaScript thread and fail on excessively
// deep directory trees.
function rimrafSync (p, options) {
  options = options || {}
  defaults(options)

  assert(p, 'rimraf: missing path')
  assert.equal(typeof p, 'string', 'rimraf: path should be a string')
  assert(options, 'rimraf: missing options')
  assert.equal(typeof options, 'object', 'rimraf: options should be object')

  var results

  if (options.disableGlob || !glob.hasMagic(p)) {
    results = [p]
  } else {
    try {
      options.lstatSync(p)
      results = [p]
    } catch (er) {
      results = glob.sync(p, options.glob)
    }
  }

  if (!results.length)
    return

  for (var i = 0; i < results.length; i++) {
    var p = results[i]

    try {
      var st = options.lstatSync(p)
    } catch (er) {
      if (er.code === "ENOENT")
        return

      // Windows can EPERM on stat.  Life is suffering.
      if (er.code === "EPERM" && isWindows)
        fixWinEPERMSync(p, options, er)
    }

    try {
      // sunos lets the root user unlink directories, which is... weird.
      if (st && st.isDirectory())
        rmdirSync(p, options, null)
      else
        options.unlinkSync(p)
    } catch (er) {
      if (er.code === "ENOENT")
        return
      if (er.code === "EPERM")
        return isWindows ? fixWinEPERMSync(p, options, er) : rmdirSync(p, options, er)
      if (er.code !== "EISDIR")
        throw er

      rmdirSync(p, options, er)
    }
  }
}

function rmdirSync (p, options, originalEr) {
  assert(p)
  assert(options)
  if (originalEr)
    assert(originalEr instanceof Error)

  try {
    options.rmdirSync(p)
  } catch (er) {
    if (er.code === "ENOENT")
      return
    if (er.code === "ENOTDIR")
      throw originalEr
    if (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM")
      rmkidsSync(p, options)
  }
}

function rmkidsSync (p, options) {
  assert(p)
  assert(options)
  options.readdirSync(p).forEach(function (f) {
    rimrafSync(path.join(p, f), options)
  })

  // We only end up here once we got ENOTEMPTY at least once, and
  // at this point, we are guaranteed to have removed all the kids.
  // So, we know that it won't be ENOENT or ENOTDIR or anything else.
  // try really hard to delete stuff on windows, because it has a
  // PROFOUNDLY annoying habit of not closing handles promptly when
  // files are deleted, resulting in spurious ENOTEMPTY errors.
  var retries = isWindows ? 100 : 1
  var i = 0
  do {
    var threw = true
    try {
      var ret = options.rmdirSync(p, options)
      threw = false
      return ret
    } finally {
      if (++i < retries && threw)
        continue
    }
  } while (true)
}
<|endoftext|>


<commit_before>(function(kopf, JSONTree) {
  "use strict";
  kopf.directive('kopfJsonTree',function() {
    var directive = {
      restrict: 'E',
      template:'

',
      link: function(scope, element, attrs, requires){
        var scopeAttr = attrs.kopfBind;
        if(scopeAttr) {
          scope.$watch(scopeAttr, function(value) {
            if (value) {
              try {
                value = JSONTree.create(value);
              } catch (invalidJsonError) {
                value = invalidJsonError;
              }
            } else {
              value = '';
            }
            element.html(value);
          });
        }
      }
    };
    return directive;
  });
})(kopf, JSONTree);
<commit_msg>Improve JSON Tree directive code<commit_after>(function(kopf, JSONTree) {
  "use strict";
  kopf.directive('kopfJsonTree',function($sce) {
    var directive = {
      restrict: 'E',
      template:'

',
      scope: {
        kopfBind: '='
      },
      link: function(scope, element, attrs, requires){
          scope.$watch('kopfBind', function(value) {
            var result;
            if (value) {
              try {
                result = JSONTree.create(value);
              } catch (invalidJsonError) {
                result = invalidJsonError;
              }
            } else {
              result = '';
            }

            scope.result = $sce.trustAsHtml(result);
          });
      }
    };
    return directive;
  });
})(kopf, JSONTree);
<|endoftext|>


<commit_before>
L.Icon.Default = L.Icon.extend({

	options: {
		iconSize: new L.Point(25, 41),
		iconAnchor: new L.Point(13, 41),
		popupAnchor: new L.Point(1, -34),

		shadowSize: new L.Point(41, 41)
	},

	_getIconUrl: function (name) {
		var key = name + 'Url';

		if (this.options[key]) {
			return this.options[key];
		}

		var path = L.Icon.Default.imagePath;

		if (!path) {
			throw new Error("Couldn't autodetect L.Icon.Default.imagePath, set it manually.");
		}

		return path + '/marker-' + name + '.png';
	}
});

L.Icon.Default.imagePath = (function () {
	var scripts = document.getElementsByTagName('script'),
	    leafletRe = /\/?leaflet[\-\._]?([\w\-\._]*)\.js\??/;

	var i, len, src, matches;

	for (i = 0, len = scripts.length; i < len; i++) {
		src = scripts[i].src;
		matches = src.match(leafletRe);

		if (matches) {
			return src.split(leafletRe)[0] + '/images';
		}
	}
}());
<commit_msg>fix default icon anchor<commit_after>
L.Icon.Default = L.Icon.extend({

	options: {
		iconSize: new L.Point(25, 41),
		iconAnchor: new L.Point(12, 41),
		popupAnchor: new L.Point(1, -34),

		shadowSize: new L.Point(41, 41)
	},

	_getIconUrl: function (name) {
		var key = name + 'Url';

		if (this.options[key]) {
			return this.options[key];
		}

		var path = L.Icon.Default.imagePath;

		if (!path) {
			throw new Error("Couldn't autodetect L.Icon.Default.imagePath, set it manually.");
		}

		return path + '/marker-' + name + '.png';
	}
});

L.Icon.Default.imagePath = (function () {
	var scripts = document.getElementsByTagName('script'),
	    leafletRe = /\/?leaflet[\-\._]?([\w\-\._]*)\.js\??/;

	var i, len, src, matches;

	for (i = 0, len = scripts.length; i < len; i++) {
		src = scripts[i].src;
		matches = src.match(leafletRe);

		if (matches) {
			return src.split(leafletRe)[0] + '/images';
		}
	}
}());
<|endoftext|>


<commit_before>(function() {

    L.Control.TagFilterButton = L.Control.extend({

        options: {
            icon: "fa-filter", //buton icon default is fa-filter
            onSelectionComplete: null, // the callback function for selected tags
            data: null, // the data to be used for tags popup, it can be array or function
            clearText: 'clear', // the text of the clear button

            ajaxData: null // it can be used for remote data TODO: implement it!
        },

        _map: null,
        _container: null,
        _easyButton: null,
        _tagEl: null,
        _selectedTags: [],
        _invisibles: [],

        _preparePopup: function(data) {
            for (var i = 0; i < data.length; i++) {
                var div = L.DomUtil.create('div', '', this._container);
                var label = L.DomUtil.create('label', '', div);
                var text = data[i];
                var value = data[i];
                if (typeof text == 'object' && Object.keys(data[i]) == 2) { // key,value
                    text = data[i].name;
                    value = data[i].value;
                }
                var checked = this._selectedTags.indexOf(value) !== -1;
                label.innerHTML = '<input type="checkbox" ' + (checked ? 'checked="true"' : '') + 'data-value="' + value + '" class="regular-checkbox"/> ' + text;
                label.style.width = '100%';

                L.DomEvent.addListener(label, 'dblclick', L.DomEvent.stop);
                L.DomEvent.addListener(label, 'click', function(e) {
                    L.DomEvent.stop(e);
                    var checkbox = this.getElementsByTagName("input")[0];
                    checkbox.checked = !checkbox.checked;
                });
            }
            this._container.style.display = "block";
        },

        _clearSelections: function(e) {
            L.DomEvent.stop(e);
            this._selectedTags = [];
            var checkboxContainer = (this._container.getElementsByTagName('div')[0]),
                childCount = this._container.childElementCount,
                children = this._container.children,
                childCheckbox, i;

            this._selectedTags = [];

            for (i = 0; i < childCount; i++) {
                childCheckbox = children[i].getElementsByTagName('input')[0];
                if (childCheckbox && childCheckbox.checked) {
                    childCheckbox.checked = false;
                }
            }
        },

        _showTagFilterPopup: function() {

            this._easyButton.button.style.display = "none";

            if (!this._container) {
                throw 'container is not initialized!';
            }

            if (!this.options.data && !this.options.ajaxData) {
                throw 'data is empty!';
            }

            this._container.innerHTML = '' + this.options.clearText + '';
            var clearButton = this._container.getElementsByTagName('a')[0];
            L.DomEvent.addListener(this._container, 'click', this._clearSelections.bind(this));

            if (this.options.data) {
                if (typeof this.options.data === 'function') {
                    this._preparePopup(this.options.data());
                } else {
                    this._preparePopup(this.options.data);
                }
            }

        },

        hide: function(accept) {

            if (this._container.style.display == "none") {
                return;
            }

            if (this._container) {
                this._container.style.display = "none";
            }

            var checkboxContainer = (this._container.getElementsByTagName('div')[0]),
                childCount = this._container.childElementCount,
                children = this._container.children,
                childCheckbox, i, j;

            this._selectedTags = [];

            for (i = 0; i < childCount; i++) {
                childCheckbox = children[i].getElementsByTagName('input')[0];
                if (childCheckbox && childCheckbox.checked) {
                    this._selectedTags.push(childCheckbox.getAttribute('data-value'));
                }
            }

            var toBeRemovedFromInvisibles = [];

            for (i = 0; i < this._invisibles.length; i++) {
                for (j = 0; j < this._invisibles[i].options.tags.length; j++) {
                    if (this._selectedTags.length == 0 || this._selectedTags.indexOf(this._invisibles[i].options.tags[j]) !== -1) {
                        this._map.addLayer(this._invisibles[i]);
                        toBeRemovedFromInvisibles.push(i);
                        break;
                    }
                }
            }

            while(toBeRemovedFromInvisibles.length > 0) {
                this._invisibles.splice(toBeRemovedFromInvisibles.pop(), 1);
            }

            var removedMarkers = [];

            if (this._selectedTags.length > 0) {
                this._map.eachLayer(function(layer) {
                    if (layer && layer.options && layer.options.tags) {
                        var found = false;
                        for (var i = 0; i < layer.options.tags.length; i++) {
                            found = this._selectedTags.indexOf(layer.options.tags[i]) !== -1;
                            if (found) {
                                break;
                            }
                        }
                        if (!found) {
                            removedMarkers.push(layer);
                        }
                    }
                }.bind(this));

                for (i = 0; i < removedMarkers.length; i++) {
                    this._map.removeLayer(removedMarkers[i]);
                    this._invisibles.push(removedMarkers[i]);
                }
            }

            if (this.options.onSelectionComplete && typeof this.options.onSelectionComplete == 'function') {
                this.options.onSelectionComplete.call(this, this._selectedTags);
            }

            this._easyButton.button.style.display = "block";
        },

        initialize: function(options) {
            L.Util.setOptions(this, options || {});
        },

        addTo: function(map) {
            this._map = map;
            this._easyButton = L.easyButton(this.options.icon, this._showTagFilterPopup.bind(this)).addTo(map);
            this._container = L.DomUtil.create('div', 'tag-filter-tags-container', this._easyButton._container);
            this._tagEl = L.DomUtil.create('ul', '', this._container);
            this._map.on('dragstart click', this.hide, this);
            L.DomEvent.addListener(this._container, 'dblclick', L.DomEvent.stop);
            L.DomEvent.addListener(this._container, 'click', L.DomEvent.stop);
            return this;
        },

        onRemove: function(map) {
            this._container.parentNode.removeChild(this._container);
            return this;
        }

    });

    L.control.tagFilterButton = function(options) {
        return new L.Control.TagFilterButton(options);
    };

}).call(this);<commit_msg>Multi layer source support<commit_after>(function() {

    L.Control.TagFilterButton = L.Control.extend({

        options: {
            icon: "fa-filter", //buton icon default is fa-filter
            onSelectionComplete: null, // the callback function for selected tags
            data: null, // the data to be used for tags popup, it can be array or function
            clearText: 'clear', // the text of the clear button

            ajaxData: null // it can be used for remote data TODO: implement it!
        },

        _map: null,
        _container: null,
        _easyButton: null,
        _tagEl: null,
        _filterInfo: null,
        _selectedTags: [],
        _invisibles: [],

        // GLOBAL FUNCTIONS

        /**
         * @function: update
         * Update markers by last selected tags
         *
         * */
        update: function() {
            var filteredCount = this.layerSources.currentSource.hide.call(this, this.layerSources.currentSource);
            this._showFilterInfo(filteredCount);
        },

        /**
         * @function: hasFiltered
         * returns true if any tag(s) selected otherwise false
         *
         * */
        hasFiltered: function () {
          return this._selectedTags.length > 0;
        },

        /**
         * @function: registerCustomSource
         * Register @source object for filtering markers by tags. If you want to use this function
         * you must implement @hide function.
         * @param source reference of the new marker source. It must have name and source item
         *
         * */
        registerCustomSource: function(source) {
            if (source.name && source.source && typeof source.source.hide === 'function') {
                this.layerSources.sources[source.name] = source.source;
            } else {
                throw 'Layer source is incompatible';
            }
        },

        /**
         * @function: enablePruneCluster
         * @param pruneClusterInstance adds pruneCluster reference to layersources
         *
         * */
        enablePruneCluster: function (pruneClusterInstance) {
            this.registerCustomSource({
                "name": "pruneCluster",
                "source": {
                    pruneCluster: pruneClusterInstance,
                    hide: function(layerSource) {
                        var toBeRemovedFromInvisibles = [], i, j;

                        for (i = 0; i < this._invisibles.length; i++) {
                            for (j = 0; j < this._invisibles[i].data.tags.length; j++) {
                                if (this._selectedTags.length == 0 || this._selectedTags.indexOf(this._invisibles[i].data.tags[j]) !== -1) {
                                    layerSource.pruneCluster.RegisterMarker(this._invisibles[i]);
                                    toBeRemovedFromInvisibles.push(i);
                                    break;
                                }
                            }
                        }

                        while(toBeRemovedFromInvisibles.length > 0) {
                            this._invisibles.splice(toBeRemovedFromInvisibles.pop(), 1);
                        }

                        var removedMarkers = [];
                        var totalCount = 0;

                        if (this._selectedTags.length > 0) {

                            var markers = layerSource.pruneCluster.GetMarkers();
                            for (i = 0; i < markers.length; i++) {
                                if (markers[i].data && markers[i].data.tags) {
                                    totalCount++;
                                    var found = false;
                                    for (var j = 0; j < markers[i].data.tags.length; j++) {
                                        found = this._selectedTags.indexOf(markers[i].data.tags[j]) !== -1;
                                        if (found) {
                                            break;
                                        }
                                    }
                                    if (!found) {
                                        removedMarkers.push(markers[i]);
                                    }
                                }
                            }

                            for (i = 0; i < removedMarkers.length; i++) {
                                this._invisibles.push(removedMarkers[i]);
                            }

                            layerSource.pruneCluster.RemoveMarkers(removedMarkers);

                        }

                        layerSource.pruneCluster.ProcessView();

                        return totalCount - removedMarkers.length;
                    }
                }
            });

            this.layerSources.currentSource = this.layerSources.sources["pruneCluster"];
        },

        layerSources: {

            currentSource: null,

            sources: {
                default: {
                    hide: function() {

                        var toBeRemovedFromInvisibles = [], i;

                        for (i = 0; i < this._invisibles.length; i++) {
                            for (j = 0; j < this._invisibles[i].options.tags.length; j++) {
                                if (this._selectedTags.length == 0 || this._selectedTags.indexOf(this._invisibles[i].options.tags[j]) !== -1) {
                                    this._map.addLayer(this._invisibles[i]);
                                    toBeRemovedFromInvisibles.push(i);
                                    break;
                                }
                            }
                        }

                        while(toBeRemovedFromInvisibles.length > 0) {
                            this._invisibles.splice(toBeRemovedFromInvisibles.pop(), 1);
                        }

                        var removedMarkers = [];
                        var totalCount = 0;

                        if (this._selectedTags.length > 0) {

                            this._map.eachLayer(function(layer) {
                                if (layer && layer.options && layer.options.tags) {
                                    totalCount++;
                                    var found = false;
                                    for (var i = 0; i < layer.options.tags.length; i++) {
                                        found = this._selectedTags.indexOf(layer.options.tags[i]) !== -1;
                                        if (found) {
                                            break;
                                        }
                                    }
                                    if (!found) {
                                        removedMarkers.push(layer);
                                    }
                                }
                            }.bind(this));

                            for (i = 0; i < removedMarkers.length; i++) {
                                this._map.removeLayer(removedMarkers[i]);
                                this._invisibles.push(removedMarkers[i]);
                            }

                        }

                        return totalCount - removedMarkers.length;
                    }
                }
            }
        },

        _showFilterInfo: function(filteredCount) {
            if (this._selectedTags.length > 0) {
                this._filterInfo.innerText = filteredCount.toString();
                this._filterInfo.style.display = "";
            } else {
                this._filterInfo.style.display = "none";
            }
        },

        _preparePopup: function(data) {
            for (var i = 0; i < data.length; i++) {
                var div = L.DomUtil.create('div', '', this._container);
                var label = L.DomUtil.create('label', '', div);
                var text = data[i];
                var value = data[i];
                if (typeof text == 'object' && Object.keys(data[i]) == 2) { // key,value
                    text = data[i].name;
                    value = data[i].value;
                }
                var checked = this._selectedTags.indexOf(value) !== -1;
                label.innerHTML = '<input type="checkbox" ' + (checked ? 'checked="true"' : '') + 'data-value="' + value + '" class="regular-checkbox"/> ' + text;
                label.style.width = '100%';

                L.DomEvent.addListener(label, 'dblclick', L.DomEvent.stop);
                L.DomEvent.addListener(label, 'click', function(e) {
                    L.DomEvent.stop(e);
                    var checkbox = this.getElementsByTagName("input")[0];
                    checkbox.checked = !checkbox.checked;
                });
            }
            this._container.style.display = "block";
        },

        _clearSelections: function(e) {
            L.DomEvent.stop(e);
            this._selectedTags = [];
            var checkboxContainer = (this._container.getElementsByTagName('div')[0]),
                childCount = this._container.childElementCount,
                children = this._container.children,
                childCheckbox, i;

            this._selectedTags = [];

            for (i = 0; i < childCount; i++) {
                childCheckbox = children[i].getElementsByTagName('input')[0];
                if (childCheckbox && childCheckbox.checked) {
                    childCheckbox.checked = false;
                }
            }
        },

        _showTagFilterPopup: function() {

            this._easyButton.button.style.display = "none";
            this._filterInfo.style.display = "none";

            if (!this._container) {
                throw 'container is not initialized!';
            }

            if (!this.options.data && !this.options.ajaxData) {
                throw 'data is empty!';
            }

            this._container.innerHTML = '' + this.options.clearText + '';
            var clearButton = this._container.getElementsByTagName('a')[0];
            L.DomEvent.addListener(this._container, 'click', this._clearSelections.bind(this));

            if (this.options.data) {
                if (typeof this.options.data === 'function') {
                    this._preparePopup(this.options.data());
                } else {
                    this._preparePopup(this.options.data);
                }
            }

        },

        hide: function(accept) {
            if (this._container.style.display == "none") {
                return;
            }

            if (this._container) {
                this._container.style.display = "none";
            }

            var checkboxContainer = (this._container.getElementsByTagName('div')[0]),
                childCount = this._container.childElementCount,
                children = this._container.children,
                childCheckbox, i, j;

            this._selectedTags = [];

            for (i = 0; i < childCount; i++) {
                childCheckbox = children[i].getElementsByTagName('input')[0];
                if (childCheckbox && childCheckbox.checked) {
                    this._selectedTags.push(childCheckbox.getAttribute('data-value'));
                }
            }

            var filteredCount = this.layerSources.currentSource.hide.call(this, this.layerSources.currentSource);
            this._showFilterInfo(filteredCount);

            if (this.options.onSelectionComplete && typeof this.options.onSelectionComplete == 'function') {
                this.options.onSelectionComplete.call(this, this._selectedTags);
            }

            this._easyButton.button.style.display = "block";
        },

        initialize: function(options) {
            L.Util.setOptions(this, options || {});
            this.layerSources.currentSource = this.layerSources.sources["default"];
        },

        addTo: function(map) {
            this._map = map;
            this._easyButton = L.easyButton(this.options.icon, this._showTagFilterPopup.bind(this)).addTo(map);
            this._container = L.DomUtil.create('div', 'tag-filter-tags-container', this._easyButton._container);

            this._filterInfo = L.DomUtil.create('span', 'label bg-dark-cold-grey', this._easyButton._container);
            this._filterInfo.style.position = "absolute";
            this._filterInfo.style.marginTop = "-5px";
            this._filterInfo.style.marginLeft = "-5px";
            this._filterInfo.style.color = "white";
            this._filterInfo.style.fontSize = "12px";

            this._tagEl = L.DomUtil.create('ul', '', this._container);
            this._map.on('dragstart click', this.hide, this);
            L.DomEvent.addListener(this._container, 'dblclick', L.DomEvent.stop);
            L.DomEvent.addListener(this._container, 'click', L.DomEvent.stop);
            return this;
        },

        onRemove: function(map) {
            this._container.parentNode.removeChild(this._container);
            return this;
        }

    });

    L.control.tagFilterButton = function(options) {
        return new L.Control.TagFilterButton(options);
    };

}).call(this);<|endoftext|>


<commit_before>import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import babel from 'rollup-plugin-babel';
import json from 'rollup-plugin-json';
import replace from 'rollup-plugin-replace';
import analyze from 'rollup-analyzer-plugin';
import uglify from 'rollup-plugin-uglify';

import PropTypes from 'prop-types';

export default [
  {
    input: 'src/index.js',
    output: [
      {
        file: 'dist/bundle-es.js',
        format: 'es',
        exports: 'named'
      }
    ],
    external: ['react', 'react-dom', 'react-redux'],
    plugins: [
      replace({
        'process.env.NODE_ENV': JSON.stringify('production')
      }),

      babel({
        include: ['src/**/*.js']
      }),

      resolve({
        module: true,
        jsnext: true,
        main: true,
        browser: true,
        preferBuiltins: false,
        customResolveOptions: {
          moduleDirectory: ['../../node_modules', 'node_modules']
        }
        // modulesOnly: true
      }),
      commonjs({
        include: ['../../node_modules/**', 'node_modules/**', '../**'],
        namedExports: {
          'prop-types': Object.keys(PropTypes)
        }
      }),

      json(),
      uglify({
        compress: { passes: 4, toplevel: true }
      }),
      analyze({
        limit: 5,
        stdout: true
      })
    ]
  }
];
<commit_msg>don't uglify bundle<commit_after>import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import babel from 'rollup-plugin-babel';
import json from 'rollup-plugin-json';
import replace from 'rollup-plugin-replace';
import analyze from 'rollup-analyzer-plugin';
// import uglify from 'rollup-plugin-uglify';

import PropTypes from 'prop-types';

export default [
  {
    input: 'src/index.js',
    output: [
      {
        file: 'dist/bundle-es.js',
        format: 'es',
        exports: 'named'
      }
    ],
    external: ['react', 'react-dom', 'react-redux'],
    plugins: [
      replace({
        'process.env.NODE_ENV': JSON.stringify('production')
      }),

      babel({
        include: ['src/**/*.js']
      }),

      resolve({
        module: true,
        jsnext: true,
        main: true,
        browser: true,
        preferBuiltins: false,
        customResolveOptions: {
          moduleDirectory: ['../../node_modules', 'node_modules']
        }
        // modulesOnly: true
      }),
      commonjs({
        include: ['../../node_modules/**', 'node_modules/**', '../**'],
        namedExports: {
          'prop-types': Object.keys(PropTypes)
        }
      }),

      json(),
      // uglify({
      //   compress: { passes: 4, toplevel: true, keep_fnames: true },
      //   mangle: { keep_fnames: true },
      //   beautify: true
      // }),
      analyze({
        limit: 5,
        stdout: true
      })
    ]
  }
];
<|endoftext|>


<commit_before>import { graphqlExpress, graphiqlExpress } from 'apollo-server-express';
import bodyParser from 'body-parser';
import express from 'express';
import { makeExecutableSchema } from 'graphql-tools';
import deepmerge from 'deepmerge';
import DataLoader from 'dataloader';
import { formatError } from 'apollo-errors';
import compression from 'compression';
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
// import { Accounts } from 'meteor/accounts-base';
import { ApolloEngine } from 'apollo-engine';

import { GraphQLSchema } from '../modules/graphql.js';
import { Utils } from '../modules/utils.js';
import { webAppConnectHandlersUse } from './meteor_patch.js';

import { getSetting, registerSetting } from '../modules/settings.js';
import { Collections } from '../modules/collections.js';
import findByIds from '../modules/findbyids.js';
import { runCallbacks } from '../modules/callbacks.js';
import cookiesMiddleware from 'universal-cookie-express';
// import Cookies from 'universal-cookie';
import { _hashLoginToken, _tokenExpiration } from './accounts_helpers';

import timber from 'timber';
import cors from 'cors';

export let executableSchema;

registerSetting('apolloEngine.logLevel', 'INFO', 'Log level (one of INFO, DEBUG, WARN, ERROR');

// see https://github.com/apollographql/apollo-cache-control
const timberApiKey = getSetting('timber.apiKey');
const engineApiKey = getSetting('apolloEngine.apiKey');
const engineLogLevel = getSetting('apolloEngine.logLevel', 'INFO')
const engineConfig = {
  apiKey: engineApiKey,
  "origins": [
    {
      requestTimeout: '120s'
    }
  ],
  "stores": [
    {
      "name": "vulcanCache",
      "inMemory": {
        "cacheSize": 20000000
      }
    }
  ],
  "sessionAuth": {
    "store": "vulcanCache",
    "header": "Authorization"
  },
  // "frontends": [
  //   {
  //     "host": "127.0.0.1",
  //     "port": 3000,
  //     "endpoint": "/graphql",
  //     "extensions": {
  //       "strip": []
  //     }
  //   }
  // ],
  "queryCache": {
    "publicFullQueryStore": "vulcanCache",
    "privateFullQueryStore": "vulcanCache"
  },
  // "reporting": {
  //   "endpointUrl": "https://engine-report.apollographql.com",
  //   "debugReports": true
  // },
  "logging": {
    "level": engineLogLevel
  }
};

// defaults
const defaultConfig = {
  path: '/graphql',
  maxAccountsCacheSizeInMB: 1,
  graphiql: true,
  graphiqlPath: '/graphiql',
  graphiqlOptions: {
    passHeader: "'Authorization': localStorage['Meteor.loginToken']", // eslint-disable-line quotes
  },
  configServer: (graphQLServer) => { },
};

const defaultOptions = {
  formatError: e => ({
    message: e.message,
    locations: e.locations,
    path: e.path,
  }),
};

if (Meteor.isDevelopment) {
  defaultOptions.debug = true;
}

// createApolloServer
const createApolloServer = (givenOptions = {}, givenConfig = {}) => {
  const graphiqlOptions = { ...defaultConfig.graphiqlOptions, ...givenConfig.graphiqlOptions };
  const config = { ...defaultConfig, ...givenConfig };
  config.graphiqlOptions = graphiqlOptions;

  const graphQLServer = express();

  config.configServer(graphQLServer);

  // cookies
  graphQLServer.use(cookiesMiddleware());

  // compression
  graphQLServer.use(compression());
  // function customDetection(req){
  //   var ipAddress;
  //   ipAddress = req.connection.remoteAddress.replace(/\//g, '.');
  //   console.info("ipAddress: ", ipAddress);
  //   return ipAddress;
  // }

  // LESSWRONG: ACTIVATE IP FILTER
  // graphQLServer.use(IpFilter(["127.0.0.1"], {detectIp: customDetection}));

  // LESSWRONG: USE CORS TO ALLOW MULTIPLE URLS
  graphQLServer.use(cors({origin:[
    "http://lesswrong.com",
    "https://lesswrong.com",
    "http://www.lesswrong.com",
    "https://www.lesswrong.com",
    "http://lesserwrong.com",
    "https://lesserwrong.com",
    "http://www.lesserwrong.com",
    "https://www.lesserwrong.com",
    "http://lessestwrong.com",
    "https://lessestwrong.com",
    "http://www.lessestwrong.com",
    "https://www.lessestwrong.com",
  ]}))

  // GraphQL endpoint
  graphQLServer.use(config.path, bodyParser.json({limit: '30mb'}), graphqlExpress(async (req) => {
    let options;
    let user = null;

    if (typeof givenOptions === 'function') {
      options = givenOptions(req);
    } else {
      options = givenOptions;
    }

    // Merge in the defaults
    options = { ...defaultOptions, ...options };
    if (options.context) {
      // don't mutate the context provided in options
      options.context = { ...options.context };
    } else {
      options.context = {};
    }

    // enable tracing and caching
    options.tracing = true;
    options.cacheControl = true;

    // note: custom default resolver doesn't currently work
    // see https://github.com/apollographql/apollo-server/issues/716
    // options.fieldResolver = (source, args, context, info) => {
    //   return source[info.fieldName];
    // }

    // Get the token from the header
    if (req.headers.authorization) {
      const token = req.headers.authorization;
      check(token, String);
      const hashedToken = _hashLoginToken(token);

      // Get the user from the database
      user = await Meteor.users.findOne(
        { 'services.resume.loginTokens.hashedToken': hashedToken },
      );

      if (user) {

        // identify user to any server-side analytics providers
        runCallbacks('events.identify', user);

        const loginToken = Utils.findWhere(user.services.resume.loginTokens, { hashedToken });
        const expiresAt = _tokenExpiration(loginToken.when);
        const isExpired = expiresAt < new Date();

        if (!isExpired) {
          options.context.userId = user._id;
          options.context.currentUser = user;
        }
      }
    }

    // merge with custom context
    options.context = deepmerge(options.context, GraphQLSchema.context);

    // go over context and add Dataloader to each collection
    Collections.forEach(collection => {
      options.context[collection.options.collectionName].loader = new DataLoader(ids => findByIds(collection, ids, options.context), { cache: true });
      // LESSWRONG: Support for custom loaders
      options.context[collection.options.collectionName].extraLoaders = null;
    });

    // console.log('// apollo_server.js user-agent:', req.headers['user-agent']);
    // console.log('// apollo_server.js locale:', req.headers.locale);

    options.context.locale = user && user.locale || req.headers.locale || getSetting('locale', 'en');

    // add error formatting from apollo-errors
    options.formatError = formatError;

    return options;
  }));

  // LESSWRONG: Timber logging integration
  if (timberApiKey) {
    //eslint-disable-next-line no-console
    console.info("Starting timber integration")
    graphQLServer.use(timber.middlewares.express({capture_request_body: true, capture_response_body: true}))
  }

  // Start GraphiQL if enabled
  if (config.graphiql) {
    graphQLServer.use(config.graphiqlPath, graphiqlExpress({ ...config.graphiqlOptions, endpointURL: config.path }));
  }

  // This binds the specified paths to the Express server running Apollo + GraphiQL
  webAppConnectHandlersUse(Meteor.bindEnvironment(graphQLServer), {
    name: 'graphQLServerMiddleware_bindEnvironment',
    order: 30,
  });

  // Use Engine middleware
  if (engineApiKey) {
    let engine = new ApolloEngine({ ...engineConfig });
    engine.meteorListen(WebApp)
  }

};

// createApolloServer when server startup
Meteor.startup(() => {

  runCallbacks('graphql.init.before');

  // typeDefs
  const generateTypeDefs = () => [`
scalar JSON
scalar Date

${GraphQLSchema.getAdditionalSchemas()}

${GraphQLSchema.getCollectionsSchemas()}

type Query {

${GraphQLSchema.queries.map(q => (
    `${q.description ? `  # ${q.description}
` : ''}  ${q.query}
  `)).join('\n')}
}

${GraphQLSchema.mutations.length > 0 ? `type Mutation {

${GraphQLSchema.mutations.map(m => (
`${m.description ? `  # ${m.description}
` : ''}  ${m.mutation}
`)).join('\n')}
}
` : ''}
`];

  const typeDefs = generateTypeDefs();

  GraphQLSchema.finalSchema = typeDefs;

  executableSchema = makeExecutableSchema({
    typeDefs,
    resolvers: GraphQLSchema.resolvers,
    schemaDirectives: GraphQLSchema.directives,
  });

  createApolloServer({
    schema: executableSchema,
  });
});
<commit_msg>Initialize extraLoaders to {}<commit_after>import { graphqlExpress, graphiqlExpress } from 'apollo-server-express';
import bodyParser from 'body-parser';
import express from 'express';
import { makeExecutableSchema } from 'graphql-tools';
import deepmerge from 'deepmerge';
import DataLoader from 'dataloader';
import { formatError } from 'apollo-errors';
import compression from 'compression';
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
// import { Accounts } from 'meteor/accounts-base';
import { ApolloEngine } from 'apollo-engine';

import { GraphQLSchema } from '../modules/graphql.js';
import { Utils } from '../modules/utils.js';
import { webAppConnectHandlersUse } from './meteor_patch.js';

import { getSetting, registerSetting } from '../modules/settings.js';
import { Collections } from '../modules/collections.js';
import findByIds from '../modules/findbyids.js';
import { runCallbacks } from '../modules/callbacks.js';
import cookiesMiddleware from 'universal-cookie-express';
// import Cookies from 'universal-cookie';
import { _hashLoginToken, _tokenExpiration } from './accounts_helpers';

import timber from 'timber';
import cors from 'cors';

export let executableSchema;

registerSetting('apolloEngine.logLevel', 'INFO', 'Log level (one of INFO, DEBUG, WARN, ERROR');

// see https://github.com/apollographql/apollo-cache-control
const timberApiKey = getSetting('timber.apiKey');
const engineApiKey = getSetting('apolloEngine.apiKey');
const engineLogLevel = getSetting('apolloEngine.logLevel', 'INFO')
const engineConfig = {
  apiKey: engineApiKey,
  "origins": [
    {
      requestTimeout: '120s'
    }
  ],
  "stores": [
    {
      "name": "vulcanCache",
      "inMemory": {
        "cacheSize": 20000000
      }
    }
  ],
  "sessionAuth": {
    "store": "vulcanCache",
    "header": "Authorization"
  },
  // "frontends": [
  //   {
  //     "host": "127.0.0.1",
  //     "port": 3000,
  //     "endpoint": "/graphql",
  //     "extensions": {
  //       "strip": []
  //     }
  //   }
  // ],
  "queryCache": {
    "publicFullQueryStore": "vulcanCache",
    "privateFullQueryStore": "vulcanCache"
  },
  // "reporting": {
  //   "endpointUrl": "https://engine-report.apollographql.com",
  //   "debugReports": true
  // },
  "logging": {
    "level": engineLogLevel
  }
};

// defaults
const defaultConfig = {
  path: '/graphql',
  maxAccountsCacheSizeInMB: 1,
  graphiql: true,
  graphiqlPath: '/graphiql',
  graphiqlOptions: {
    passHeader: "'Authorization': localStorage['Meteor.loginToken']", // eslint-disable-line quotes
  },
  configServer: (graphQLServer) => { },
};

const defaultOptions = {
  formatError: e => ({
    message: e.message,
    locations: e.locations,
    path: e.path,
  }),
};

if (Meteor.isDevelopment) {
  defaultOptions.debug = true;
}

// createApolloServer
const createApolloServer = (givenOptions = {}, givenConfig = {}) => {
  const graphiqlOptions = { ...defaultConfig.graphiqlOptions, ...givenConfig.graphiqlOptions };
  const config = { ...defaultConfig, ...givenConfig };
  config.graphiqlOptions = graphiqlOptions;

  const graphQLServer = express();

  config.configServer(graphQLServer);

  // cookies
  graphQLServer.use(cookiesMiddleware());

  // compression
  graphQLServer.use(compression());
  // function customDetection(req){
  //   var ipAddress;
  //   ipAddress = req.connection.remoteAddress.replace(/\//g, '.');
  //   console.info("ipAddress: ", ipAddress);
  //   return ipAddress;
  // }

  // LESSWRONG: ACTIVATE IP FILTER
  // graphQLServer.use(IpFilter(["127.0.0.1"], {detectIp: customDetection}));

  // LESSWRONG: USE CORS TO ALLOW MULTIPLE URLS
  graphQLServer.use(cors({origin:[
    "http://lesswrong.com",
    "https://lesswrong.com",
    "http://www.lesswrong.com",
    "https://www.lesswrong.com",
    "http://lesserwrong.com",
    "https://lesserwrong.com",
    "http://www.lesserwrong.com",
    "https://www.lesserwrong.com",
    "http://lessestwrong.com",
    "https://lessestwrong.com",
    "http://www.lessestwrong.com",
    "https://www.lessestwrong.com",
  ]}))

  // GraphQL endpoint
  graphQLServer.use(config.path, bodyParser.json({limit: '30mb'}), graphqlExpress(async (req) => {
    let options;
    let user = null;

    if (typeof givenOptions === 'function') {
      options = givenOptions(req);
    } else {
      options = givenOptions;
    }

    // Merge in the defaults
    options = { ...defaultOptions, ...options };
    if (options.context) {
      // don't mutate the context provided in options
      options.context = { ...options.context };
    } else {
      options.context = {};
    }

    // enable tracing and caching
    options.tracing = true;
    options.cacheControl = true;

    // note: custom default resolver doesn't currently work
    // see https://github.com/apollographql/apollo-server/issues/716
    // options.fieldResolver = (source, args, context, info) => {
    //   return source[info.fieldName];
    // }

    // Get the token from the header
    if (req.headers.authorization) {
      const token = req.headers.authorization;
      check(token, String);
      const hashedToken = _hashLoginToken(token);

      // Get the user from the database
      user = await Meteor.users.findOne(
        { 'services.resume.loginTokens.hashedToken': hashedToken },
      );

      if (user) {

        // identify user to any server-side analytics providers
        runCallbacks('events.identify', user);

        const loginToken = Utils.findWhere(user.services.resume.loginTokens, { hashedToken });
        const expiresAt = _tokenExpiration(loginToken.when);
        const isExpired = expiresAt < new Date();

        if (!isExpired) {
          options.context.userId = user._id;
          options.context.currentUser = user;
        }
      }
    }

    // merge with custom context
    options.context = deepmerge(options.context, GraphQLSchema.context);

    // go over context and add Dataloader to each collection
    Collections.forEach(collection => {
      options.context[collection.options.collectionName].loader = new DataLoader(ids => findByIds(collection, ids, options.context), { cache: true });
      // LESSWRONG: Support for custom loaders
      options.context[collection.options.collectionName].extraLoaders = {};
    });

    // console.log('// apollo_server.js user-agent:', req.headers['user-agent']);
    // console.log('// apollo_server.js locale:', req.headers.locale);

    options.context.locale = user && user.locale || req.headers.locale || getSetting('locale', 'en');

    // add error formatting from apollo-errors
    options.formatError = formatError;

    return options;
  }));

  // LESSWRONG: Timber logging integration
  if (timberApiKey) {
    //eslint-disable-next-line no-console
    console.info("Starting timber integration")
    graphQLServer.use(timber.middlewares.express({capture_request_body: true, capture_response_body: true}))
  }

  // Start GraphiQL if enabled
  if (config.graphiql) {
    graphQLServer.use(config.graphiqlPath, graphiqlExpress({ ...config.graphiqlOptions, endpointURL: config.path }));
  }

  // This binds the specified paths to the Express server running Apollo + GraphiQL
  webAppConnectHandlersUse(Meteor.bindEnvironment(graphQLServer), {
    name: 'graphQLServerMiddleware_bindEnvironment',
    order: 30,
  });

  // Use Engine middleware
  if (engineApiKey) {
    let engine = new ApolloEngine({ ...engineConfig });
    engine.meteorListen(WebApp)
  }

};

// createApolloServer when server startup
Meteor.startup(() => {

  runCallbacks('graphql.init.before');

  // typeDefs
  const generateTypeDefs = () => [`
scalar JSON
scalar Date

${GraphQLSchema.getAdditionalSchemas()}

${GraphQLSchema.getCollectionsSchemas()}

type Query {

${GraphQLSchema.queries.map(q => (
    `${q.description ? `  # ${q.description}
` : ''}  ${q.query}
  `)).join('\n')}
}

${GraphQLSchema.mutations.length > 0 ? `type Mutation {

${GraphQLSchema.mutations.map(m => (
`${m.description ? `  # ${m.description}
` : ''}  ${m.mutation}
`)).join('\n')}
}
` : ''}
`];

  const typeDefs = generateTypeDefs();

  GraphQLSchema.finalSchema = typeDefs;

  executableSchema = makeExecutableSchema({
    typeDefs,
    resolvers: GraphQLSchema.resolvers,
    schemaDirectives: GraphQLSchema.directives,
  });

  createApolloServer({
    schema: executableSchema,
  });
});
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'com.google.foam.demos.sevenguis',
  name: 'CellParser',
  extends: 'foam.parse.ImperativeGrammar',

  properties: [
    {
      name: 'symbols',
      factory: function() {
        return function(alt, sym, seq1, seq, literalIC, repeat, str, optional, plus, range, anyChar) {
          return {
            START: alt(sym('number'), sym('formula'), sym('string')),

            formula: seq1(1, '=', sym('expr')),

            expr: alt(
              sym('number'),
              sym('cell'),
              sym('add'),
              sym('sub'),
              sym('mul'),
              sym('div'),
              sym('mod'),
              sym('sum'),
              sym('prod')
            ),

            add:  seq(literalIC('add('),  sym('expr'), ',', sym('expr'), ')'),
            sub:  seq(literalIC('sub('),  sym('expr'), ',', sym('expr'), ')'),
            mul:  seq(literalIC('mul('),  sym('expr'), ',', sym('expr'), ')'),
            div:  seq(literalIC('div('),  sym('expr'), ',', sym('expr'), ')'),
            mod:  seq(literalIC('mod('),  sym('expr'), ',', sym('expr'), ')'),
            sum:  seq(literalIC('sum('),  sym('vargs'), ')'),
            prod: seq(literalIC('prod('), sym('vargs'), ')'),

            vargs: repeat(alt(sym('range'), sym('expr')), ','),

            range: seq(sym('col'), sym('row'), ':', sym('col'), sym('row')),

            number: str(seq(
              optional('-'),
              str(alt(
                seq(str(repeat(sym('digit'))), '.', str(plus(sym('digit')))),
                plus(sym('digit')))))),

            cell: seq(sym('col'), sym('row')),

            col: alt(sym('az'), sym('AZ')),

            digit: range('0', '9'),

            az: range('a', 'z'),

            AZ: range('A', 'Z'),

            row: str(repeat(sym('digit'), null, 1, 2)),

            string: str(repeat(anyChar()))
          };
        }
      }
    }
  ],
  methods: [
    function init() {
      this.addActions({
        add: function(a) { return function(cs) { return a[1](cs) + a[3](cs); }; },
        sub: function(a) { return function(cs) { return a[1](cs) - a[3](cs); }; },
        mul: function(a) { return function(cs) { return a[1](cs) * a[3](cs); }; },
        div: function(a) { return function(cs) { return a[1](cs) / a[3](cs); }; },
        mod: function(a) { return function(cs) { return a[1](cs) % a[3](cs); }; },
        sum: function(a) { return function(cs) {
          var arr = a[1](cs), sum = 0;
          for ( var i = 0 ; i < arr.length ; i++ ) sum += arr[i];
          return sum;
        }; },
        prod: function(a) { return function(cs) {
          var arr = a[1](cs), prod = 1;
          for ( var i = 0 ; i < arr.length ; i++ ) prod *= arr[i];
          return prod;
        }; },
        az:  function(c) { return c.toUpperCase(); },
        //AZ:  function(c) { return c.charCodeAt(0) - 'A'.charCodeAt(0); },
        row: function(c) { return parseInt(c); },
        number: function(s) { var f = parseFloat(s); return function() { return f; }; },
        cell: function(a) { return function(cs) { return cs.cell(a[0] + a[1]).numValue; }; },
        vargs: function(a) {
          return function(cs) {
            var ret = [];
            for ( var i = 0 ; i < a.length ; i++ ) {
              var r = a[i](cs);
              if ( Array.isArray(r) )
                ret.pushAll(r);
              else
                ret.push(r);
            }
            return ret;
          }
        },
        range: function(a) {
          var c1 = a[0], r1 = a[1], c2 = a[3], r2 = a[4];
          return function(cs) {
            var ret = [];
            for ( var c = c1 ; c <= c2; c++ )
              for ( var r = r1 ; r <= r2 ; r++ )
                ret.push(cs.cell(c + r).numValue);
            return ret;
          }
        },
        string: function(s) { return function() { return s; }; }
      });
    }
  ]
});

// https://www.artima.com/pins1ed/the-scells-spreadsheet.html
foam.CLASS({
  package: 'com.google.foam.demos.sevenguis',
  name: 'Cells',
  extends: 'foam.u2.Element',

  requires: [
    'foam.u2.tag.Input',
    'foam.u2.ElementParser',
    'foam.u2.PropertyView',
    'com.google.foam.demos.sevenguis.CellParser'
  ],

  exports:  [ 'as cells' ],

  classes: [
    {
      name: 'Cell',
      extends: 'foam.u2.ReadWriteView',
      requires: [ 'foam.u2.tag.Input' ],
      imports: [ 'cells' ],
      documentation: function() {/*
        Doesn't build inner views until value is set or user clicks on view.
        This complicates the design but saves memory and startup time.
      */},
      axioms: [
        foam.u2.CSS.create({
          code: function() {/*
            ^ > span {
              display: block;
              height: 15px;
              padding: 2px;
              width: 100%;
            }
            ^ > input {
              border: none;
              outline: 1px solid blue;
              outline-offset: 0;
              padding-left: 2px;
              width: 100%;
            }
          */}
        })
      ],
      properties: [
        [ 'nodeName', 'span' ],
        {
          name: 'formula',
          displayWidth: 10
        },
        {
          name: 'value',
          adapt: function(_, v) {
            var ret = parseFloat(v);
            return ret && ! Number.isInteger(ret) ? ret.toFixed(2) : v;
          },
          displayWidth: 12
        },
        {
          name: 'numValue',
          getter: function() { return parseFloat(this.value); }
        }
      ],
      methods: [
        function initE() { this.cssClass(this.myCls()); },
        function isLoaded() { return this.value; },
        function listenForLoad() { this.value$.addListener(this.onDataLoad); },
        function toReadE() { return this.E('span').add(this.value$); },
        function toWriteE() {
          this.formula$.addListener(this.onDataLoad);
          var e = this.E('input');
          e.data$ = this.formula$;
          return e;
        }
      ]
    }
  ],

  axioms: [
    foam.u2.CSS.create({
      code: function() {/*
      ^ tr, ^ td, ^ th, ^ input {
        color: #333;
        font: 13px roboto, arial, sans-serif;
      }
      ^ tr { height: 26px; }
      ^cell { min-width: 102px; }
      ^, ^ th, ^ td { border: 1px solid #ccc; }
      ^ td { height: 100%; }
      ^ th, ^ td {
        border-right: none;
        border-bottom: none;
      }
      ^ th {
        background: #eee;
        color: #333;
        padding: 2px 18px;
      }
      ^ {
        border-left: none;
        border-top: none;
        overflow: auto;
      }
      */}
    })
  ],

  properties: [
    [ 'rows',    99 ],
    [ 'columns', 26 ],
    {
      name: 'cells',
      factory: function() { return {}; }
    },
    {
      name: 'parser',
      factory: function() { return this.CellParser.create(); }
    }
  ],

  methods: [
    function init() {
      this.SUPER();

      this.ElementParser.getPrototype();

      // Two sample spreadsheets
      // Spreadsheet taken from Visicalc
// this.loadCells({"A0":"Item","B0":"No.","C0":"Unit","D0":"Cost","A1":"Muck Rake","B1":"43","C1":"12.95","D1":"=mul(B1,C1)","A2":"Buzz Cut","B2":"15","C2":"6.76","D2":"=mul(B2,C2)","A3":"Toe Toner","B3":"250","C3":"49.95","D3":"=mul(B3,C3)","A4":"Eye Snuff","B4":"2","C4":"4.95","D4":"=mul(B4,C4)","C5":"Subtotal","D5":"=sum(D1:D4)","B6":"9.75","C6":"Tax","D6":"=div(mul(B6,D5),100)","C7":"Total","D7":"=add(D5,D6)"});

      // Spreadsheet to test all functions
//      this.loadCells({"A0":"Formulas","B0":"Values","A1":" 1","B1":"1","A2":" 10","B2":"10","A3":" 10.12","B3":"10.12","A4":" -10.1","B4":"-10.1","A5":" foobar","B5":"foobar","A6":" =add(1,2)","B6":"=add(1,2)","A7":" =sub(2,1)","B7":"=sub(2,1)","A8":" =mul(2,3)","B8":"=mul(2,3)","A9":" =div(9,3)","B9":"=div(9,3)","A10":" =mod(8,3)","B10":"=mod(8,3)","A11":" =add(mul(2,3),div(3,2))","B11":"=add(mul(2,3),div(3,2))","A12":" =A1","B12":"=A1","A13":" =add(A1,B1)","B13":"=add(A1,B1)","A14":" =sum(1,2,3,4,5)","B14":"=sum(1,2,3,4,5)","A15":" =sum(B6:B10)","B15":"=sum(B6:B10)","A16":" =prod(B6:B10)","B16":"=prod(B6:B10)"});

this.loadCells({"A0":"
Benchmark
","B0":"IndexedDB","C0":"DAO","A1":"Create Albums","B1":"190","C1":"366","A2":"Create Photos","B2":"2772","C2":"2492","A3":"Select All Albums","B3":"168","C3":"1.93","A4":"Select All Photos","B4":"1361","C4":"3.86","B5":"1.43","C5":"0.06","B6":"1.56","C6":"0.63","B7":"10.28","C7":"1.12","D0":"Speedup","D1":"=div(B1,C1)","D2":"=div(B2,C2)","D3":"=div(B3,C3)","D4":"=div(B4,C4)","A5":"Single Key Query","D5":"=div(B5,C5)","A6":"Multi-Key Query","D6":"=div(B6,C6)","A7":"Multi-Key Query","D7":"=div(B7,C7)","A8":"Multi-Key Query","B8":"102","C8":"12.24","D8":"=div(B8,C8)","A9":"Multi-Key Query","B9":"561","C9":"15.24","D9":"=div(B9,C9)","A10":"Indexed Field Query","B10":"4.63","C10":"0.46","D10":"=div(B10,C10)","A11":"Ad-Hoc Query","B11":"658","C11":"9.91","D11":"=div(B11,C11)","A12":"Simple Inner-Join","B12":"721","C12":"9.55","D12":"=div(B12,C12)","A13":"Inner-Join Aggregation","B13":"647","C13":"38.56","D13":"=div(B13,C13)","A14":"Order-By","B14":"59","C14":"0.55","D14":"=div(B14,C14)","A15":"Order and Group By","B15":"1232","C15":"3.63","D15":"=div(B15,C15)","A16":"Average:","B16":"=SUM(B1:B15)","C16":"=SUM(C1:C15)","D16":"=div(B14,C14)"});
    },

    function initE() {
      this.setNodeName('table').cssClass(this.myCls()).attrs({cellspacing: 0}).
        start('tr').
          tag('th').
          call(function () {
            for ( var i = 0 ; i < this.columns ; i++ ) {
              this.start('th').add(String.fromCharCode(65 + i)).end();
            }
          }).
        end().
        call(function() {
          for ( var i = 0 ; i < this.rows ; i++ ) {
            this.start('tr').
              start('th').add(i).end().
              start('td').
                call(function() {
                  for ( var j = 0 ; j < this.columns ; j++ ) {
                    this.add(this.cell(this.cellName(j, i)));
                  }
                }).
              end().
            end();
          }
        });
    },

              /*
    function initE() {

          {{String.fromCharCode(65 + j)}}

          {{i}}
          {{this.cell(this.cellName(j, i))}}

    },
                */

    function loadCells(map) {
      for ( var key in map ) this.cell(key).formula = String(map[key]);
    },

    function save() {
      var map = {};
      for ( var key in this.cells ) {
        var cell = this.cells[key];
        if ( cell.formula !== '' ) map[key] = cell.formula;
      }
      return map;
    },

    function cellName(c, r) { return String.fromCharCode(65 + c) + r; },

    function cell(name) {
      var self = this;
      var cell = this.cells[name];
      var cancel = null;
      if ( ! cell ) {
        cell = this.cells[name] = this.Cell.create();
        cell.formula$.addListener(function(_, __, ___, formula) {
          var f = self.parser.parseString(formula);
          cancel && cancel.destroy();
          cancel = self.dynamicFn(f.bind(null, self), function(v) {
            cell.value = v;
          });
        });
      }
      return cell;
    }
  ],
  templates: [
  ]
});
<commit_msg>Switched Cells demo to use repeat() instead of call().<commit_after>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'com.google.foam.demos.sevenguis',
  name: 'CellParser',
  extends: 'foam.parse.ImperativeGrammar',

  properties: [
    {
      name: 'symbols',
      factory: function() {
        return function(alt, sym, seq1, seq, literalIC, repeat, str, optional, plus, range, anyChar) {
          return {
            START: alt(sym('number'), sym('formula'), sym('string')),

            formula: seq1(1, '=', sym('expr')),

            expr: alt(
              sym('number'),
              sym('cell'),
              sym('add'),
              sym('sub'),
              sym('mul'),
              sym('div'),
              sym('mod'),
              sym('sum'),
              sym('prod')
            ),

            add:  seq(literalIC('add('),  sym('expr'), ',', sym('expr'), ')'),
            sub:  seq(literalIC('sub('),  sym('expr'), ',', sym('expr'), ')'),
            mul:  seq(literalIC('mul('),  sym('expr'), ',', sym('expr'), ')'),
            div:  seq(literalIC('div('),  sym('expr'), ',', sym('expr'), ')'),
            mod:  seq(literalIC('mod('),  sym('expr'), ',', sym('expr'), ')'),
            sum:  seq(literalIC('sum('),  sym('vargs'), ')'),
            prod: seq(literalIC('prod('), sym('vargs'), ')'),

            vargs: repeat(alt(sym('range'), sym('expr')), ','),

            range: seq(sym('col'), sym('row'), ':', sym('col'), sym('row')),

            number: str(seq(
              optional('-'),
              str(alt(
                seq(str(repeat(sym('digit'))), '.', str(plus(sym('digit')))),
                plus(sym('digit')))))),

            cell: seq(sym('col'), sym('row')),

            col: alt(sym('az'), sym('AZ')),

            digit: range('0', '9'),

            az: range('a', 'z'),

            AZ: range('A', 'Z'),

            row: str(repeat(sym('digit'), null, 1, 2)),

            string: str(repeat(anyChar()))
          };
        }
      }
    }
  ],
  methods: [
    function init() {
      this.addActions({
        add: function(a) { return function(cs) { return a[1](cs) + a[3](cs); }; },
        sub: function(a) { return function(cs) { return a[1](cs) - a[3](cs); }; },
        mul: function(a) { return function(cs) { return a[1](cs) * a[3](cs); }; },
        div: function(a) { return function(cs) { return a[1](cs) / a[3](cs); }; },
        mod: function(a) { return function(cs) { return a[1](cs) % a[3](cs); }; },
        sum: function(a) { return function(cs) {
          var arr = a[1](cs), sum = 0;
          for ( var i = 0 ; i < arr.length ; i++ ) sum += arr[i];
          return sum;
        }; },
        prod: function(a) { return function(cs) {
          var arr = a[1](cs), prod = 1;
          for ( var i = 0 ; i < arr.length ; i++ ) prod *= arr[i];
          return prod;
        }; },
        az:  function(c) { return c.toUpperCase(); },
        //AZ:  function(c) { return c.charCodeAt(0) - 'A'.charCodeAt(0); },
        row: function(c) { return parseInt(c); },
        number: function(s) { var f = parseFloat(s); return function() { return f; }; },
        cell: function(a) { return function(cs) { return cs.cell(a[0] + a[1]).numValue; }; },
        vargs: function(a) {
          return function(cs) {
            var ret = [];
            for ( var i = 0 ; i < a.length ; i++ ) {
              var r = a[i](cs);
              if ( Array.isArray(r) )
                ret.pushAll(r);
              else
                ret.push(r);
            }
            return ret;
          }
        },
        range: function(a) {
          var c1 = a[0], r1 = a[1], c2 = a[3], r2 = a[4];
          return function(cs) {
            var ret = [];
            for ( var c = c1 ; c <= c2; c++ )
              for ( var r = r1 ; r <= r2 ; r++ )
                ret.push(cs.cell(c + r).numValue);
            return ret;
          }
        },
        string: function(s) { return function() { return s; }; }
      });
    }
  ]
});

// https://www.artima.com/pins1ed/the-scells-spreadsheet.html
foam.CLASS({
  package: 'com.google.foam.demos.sevenguis',
  name: 'Cells',
  extends: 'foam.u2.Element',

  requires: [
    'foam.u2.tag.Input',
    'foam.u2.ElementParser',
    'foam.u2.PropertyView',
    'com.google.foam.demos.sevenguis.CellParser'
  ],

  exports:  [ 'as cells' ],

  classes: [
    {
      name: 'Cell',
      extends: 'foam.u2.ReadWriteView',
      requires: [ 'foam.u2.tag.Input' ],
      imports: [ 'cells' ],
      documentation: function() {/*
        Doesn't build inner views until value is set or user clicks on view.
        This complicates the design but saves memory and startup time.
      */},
      axioms: [
        foam.u2.CSS.create({
          code: function() {/*
            ^ > span {
              display: block;
              height: 15px;
              padding: 2px;
              width: 100%;
            }
            ^ > input {
              border: none;
              outline: 1px solid blue;
              outline-offset: 0;
              padding-left: 2px;
              width: 100%;
            }
          */}
        })
      ],
      properties: [
        [ 'nodeName', 'span' ],
        {
          name: 'formula',
          displayWidth: 10
        },
        {
          name: 'value',
          adapt: function(_, v) {
            var ret = parseFloat(v);
            return ret && ! Number.isInteger(ret) ? ret.toFixed(2) : v;
          },
          displayWidth: 12
        },
        {
          name: 'numValue',
          getter: function() { return parseFloat(this.value); }
        }
      ],
      methods: [
        function initE() { this.cssClass(this.myCls()); },
        function isLoaded() { return this.value; },
        function listenForLoad() { this.value$.addListener(this.onDataLoad); },
        function toReadE() { return this.E('span').add(this.value$); },
        function toWriteE() {
          this.formula$.addListener(this.onDataLoad);
          var e = this.E('input');
          e.data$ = this.formula$;
          return e;
        }
      ]
    }
  ],

  axioms: [
    foam.u2.CSS.create({
      code: function() {/*
      ^ tr, ^ td, ^ th, ^ input {
        color: #333;
        font: 13px roboto, arial, sans-serif;
      }
      ^ tr { height: 26px; }
      ^cell { min-width: 102px; }
      ^, ^ th, ^ td { border: 1px solid #ccc; }
      ^ td { height: 100%; }
      ^ th, ^ td {
        border-right: none;
        border-bottom: none;
      }
      ^ th {
        background: #eee;
        color: #333;
        padding: 2px 18px;
      }
      ^ {
        border-left: none;
        border-top: none;
        overflow: auto;
      }
      */}
    })
  ],

  properties: [
    [ 'rows',    99 ],
    [ 'columns', 26 ],
    {
      name: 'cells',
      factory: function() { return {}; }
    },
    {
      name: 'parser',
      factory: function() { return this.CellParser.create(); }
    }
  ],

  methods: [
    function init() {
      this.SUPER();

      this.ElementParser.getPrototype();

      // Two sample spreadsheets
      // Spreadsheet taken from Visicalc
// this.loadCells({"A0":"Item","B0":"No.","C0":"Unit","D0":"Cost","A1":"Muck Rake","B1":"43","C1":"12.95","D1":"=mul(B1,C1)","A2":"Buzz Cut","B2":"15","C2":"6.76","D2":"=mul(B2,C2)","A3":"Toe Toner","B3":"250","C3":"49.95","D3":"=mul(B3,C3)","A4":"Eye Snuff","B4":"2","C4":"4.95","D4":"=mul(B4,C4)","C5":"Subtotal","D5":"=sum(D1:D4)","B6":"9.75","C6":"Tax","D6":"=div(mul(B6,D5),100)","C7":"Total","D7":"=add(D5,D6)"});

      // Spreadsheet to test all functions
//      this.loadCells({"A0":"Formulas","B0":"Values","A1":" 1","B1":"1","A2":" 10","B2":"10","A3":" 10.12","B3":"10.12","A4":" -10.1","B4":"-10.1","A5":" foobar","B5":"foobar","A6":" =add(1,2)","B6":"=add(1,2)","A7":" =sub(2,1)","B7":"=sub(2,1)","A8":" =mul(2,3)","B8":"=mul(2,3)","A9":" =div(9,3)","B9":"=div(9,3)","A10":" =mod(8,3)","B10":"=mod(8,3)","A11":" =add(mul(2,3),div(3,2))","B11":"=add(mul(2,3),div(3,2))","A12":" =A1","B12":"=A1","A13":" =add(A1,B1)","B13":"=add(A1,B1)","A14":" =sum(1,2,3,4,5)","B14":"=sum(1,2,3,4,5)","A15":" =sum(B6:B10)","B15":"=sum(B6:B10)","A16":" =prod(B6:B10)","B16":"=prod(B6:B10)"});

this.loadCells({"A0":"
Benchmark
","B0":"IndexedDB","C0":"DAO","A1":"Create Albums","B1":"190","C1":"366","A2":"Create Photos","B2":"2772","C2":"2492","A3":"Select All Albums","B3":"168","C3":"1.93","A4":"Select All Photos","B4":"1361","C4":"3.86","B5":"1.43","C5":"0.06","B6":"1.56","C6":"0.63","B7":"10.28","C7":"1.12","D0":"Speedup","D1":"=div(B1,C1)","D2":"=div(B2,C2)","D3":"=div(B3,C3)","D4":"=div(B4,C4)","A5":"Single Key Query","D5":"=div(B5,C5)","A6":"Multi-Key Query","D6":"=div(B6,C6)","A7":"Multi-Key Query","D7":"=div(B7,C7)","A8":"Multi-Key Query","B8":"102","C8":"12.24","D8":"=div(B8,C8)","A9":"Multi-Key Query","B9":"561","C9":"15.24","D9":"=div(B9,C9)","A10":"Indexed Field Query","B10":"4.63","C10":"0.46","D10":"=div(B10,C10)","A11":"Ad-Hoc Query","B11":"658","C11":"9.91","D11":"=div(B11,C11)","A12":"Simple Inner-Join","B12":"721","C12":"9.55","D12":"=div(B12,C12)","A13":"Inner-Join Aggregation","B13":"647","C13":"38.56","D13":"=div(B13,C13)","A14":"Order-By","B14":"59","C14":"0.55","D14":"=div(B14,C14)","A15":"Order and Group By","B15":"1232","C15":"3.63","D15":"=div(B15,C15)","A16":"Average:","B16":"=SUM(B1:B15)","C16":"=SUM(C1:C15)","D16":"=div(B14,C14)"});
    },

    function initE() {
      this.setNodeName('table').cssClass(this.myCls()).attrs({cellspacing: 0}).
        start('tr').
          tag('th').
          repeat(0, this.columns-1, function (i) {
            this.start('th').add(String.fromCharCode(65 + i)).end();
          }).
        end().
        repeat(0, this.rows-1, function(i) {
            this.start('tr').
              start('th').add(i).end().
              start('td').
                repeat(0, this.columns-1, function(j) {
                  this.add(this.cell(this.cellName(j, i)));
                }).
              end().
            end();
          }
        });
    },

              /*
    function initE() {

          {{String.fromCharCode(65 + j)}}

          {{i}}
          {{this.cell(this.cellName(j, i))}}

    },
                */

    function loadCells(map) {
      for ( var key in map ) this.cell(key).formula = String(map[key]);
    },

    function save() {
      var map = {};
      for ( var key in this.cells ) {
        var cell = this.cells[key];
        if ( cell.formula !== '' ) map[key] = cell.formula;
      }
      return map;
    },

    function cellName(c, r) { return String.fromCharCode(65 + c) + r; },

    function cell(name) {
      var self = this;
      var cell = this.cells[name];
      var cancel = null;
      if ( ! cell ) {
        cell = this.cells[name] = this.Cell.create();
        cell.formula$.addListener(function(_, __, ___, formula) {
          var f = self.parser.parseString(formula);
          cancel && cancel.destroy();
          cancel = self.dynamicFn(f.bind(null, self), function(v) {
            cell.value = v;
          });
        });
      }
      return cell;
    }
  ],
  templates: [
  ]
});
<|endoftext|>


<commit_before>import R from 'ramda';

class TagsRepository {

  static TAGS_REPOSITORY_FILE_NAME = 'tags.json';

  constructor(gitRepo) {
    this._gitRepo = gitRepo;
  }

  async getTags() {
    return await this._getParsedTags();
  }

  async mergeNewTags(newTags, author) {
    const currentTags = await this._getParsedTags();
    const combined = JSON.stringify(R.uniqBy(x => x.name, [...currentTags, ...newTags]), null, 4);

    return await this._gitRepo.updateFile(TagsRepository.TAGS_REPOSITORY_FILE_NAME, combined, author);
  }

  async _getParsedTags() {
    try {
      const tagsFile = await this._gitRepo.readFile(TagsRepository.TAGS_REPOSITORY_FILE_NAME);
      return JSON.parse(tagsFile.fileContent);
    } catch (exp) {
      return [];
    }
  }
}

export default TagsRepository;
<commit_msg>- trigging a build<commit_after>import R from 'ramda';

class TagsRepository {

  static TAGS_REPOSITORY_FILE_NAME = 'tags.json';

  constructor(gitRepo) {
    this._gitRepo = gitRepo;
  }

  async getTags() {
    return await this._getParsedTags();
  }

  async mergeNewTags(newTags, author) {
    const currentTags = await this._getParsedTags();
    const combined = JSON.stringify(R.uniqBy(x => x.name, [...currentTags, ...newTags]), null, 4);

    return await this._gitRepo.updateFile(TagsRepository.TAGS_REPOSITORY_FILE_NAME, combined, author);
  }

  async _getParsedTags() {
    try {
      const tagsFile = await this._gitRepo.readFile(TagsRepository.TAGS_REPOSITORY_FILE_NAME);

      return JSON.parse(tagsFile.fileContent);
    } catch (exp) {
      return [];
    }
  }
}

export default TagsRepository;
<|endoftext|>


<commit_before>(function () {
    "use strict";

    angular.module('map')
    .directive('googleMapMarker', ['$q', '$rootScope', 'eventHandlerService', function ($q, $rootScope, eventHandlerService) {
        return {
            restrict: 'E',
            transclude: true,
            templateUrl: 'shared/map/marker/marker_template.html',
            scope: {
                gmapElement: '@',
                gmapTarget: '=',
                position: '=',
                title: '@',
                draggable: '='
            },
            controller: function() {

            },
            link: function (scope, element, attrs, controller, transcludeFn) {
                var deferred = $q.defer();

                // Put the marker promise on the transcluded scope.
                var transclusionTarget = element[0].querySelector('[transclude-target]');
                transcludeFn(function (clone, transclusionScope) {
                    transclusionScope[scope.gmapElement] = deferred.promise;
                    angular.element(transclusionTarget).append(clone);
                });

                // Put a promise on the controller, to be used by attributes.
                controller.gmapElement = deferred.promise;

                scope.gmapTarget.then(function (gmapElement) {
                    // Create a marker.
                    var marker = new google.maps.Marker({
                        position: scope.position,
                        map: gmapElement.map,
                        title: scope.title,
                        draggable: scope.draggable || false
                    });

                    // Watch for changes in position.
                    scope.$watch('position', function (newValue, oldValue) {
                        marker.setPosition(newValue);
                    }, true);

                    // Watch for drag events on the marker.
                    if (scope.draggable) {
                        marker.addListener('dragend', function () {
                            scope.position.lat = marker.position.lat();
                            scope.position.lng = marker.position.lng();
                            $rootScope.$digest();
                        });
                    }

                    // Watch for changes in title.
                    scope.$watch('title', function (newValue, oldValue) {
                        marker.setTitle(newValue);
                    });

                    // Create an event handler, that can register multiple callbacks to the same event.
                    var eventHandler = eventHandlerService.createEventHandler(marker);

                    // The marker is ready for use.
                    deferred.resolve({
                        map: gmapElement.map,
                        element: marker,
                        eventHandler: eventHandler
                    });

                    scope.$on('$destroy', function () {
                        marker.setMap(null);
                    });
                });
            }
        };
    }]);
})();<commit_msg>Removed unnecessary spaces.<commit_after>(function () {
    "use strict";

    angular.module('map')
    .directive('googleMapMarker', ['$q', '$rootScope', 'eventHandlerService', function ($q, $rootScope, eventHandlerService) {
        return {
            restrict: 'E',
            transclude: true,
            templateUrl: 'shared/map/marker/marker_template.html',
            scope: {
                gmapElement: '@',
                gmapTarget: '=',
                position: '=',
                title: '@',
                draggable: '='
            },
            controller: function() {

            },
            link: function (scope, element, attrs, controller, transcludeFn) {
                var deferred = $q.defer();

                // Put the marker promise on the transcluded scope.
                var transclusionTarget = element[0].querySelector('[transclude-target]');
                transcludeFn(function (clone, transclusionScope) {
                    transclusionScope[scope.gmapElement] = deferred.promise;
                    angular.element(transclusionTarget).append(clone);
                });

                // Put a promise on the controller, to be used by attributes.
                controller.gmapElement = deferred.promise;

                scope.gmapTarget.then(function (gmapElement) {
                    // Create a marker.
                    var marker = new google.maps.Marker({
                        position: scope.position,
                        map: gmapElement.map,
                        title: scope.title,
                        draggable: scope.draggable || false
                    });

                    // Watch for changes in position.
                    scope.$watch('position', function (newValue, oldValue) {
                        marker.setPosition(newValue);
                    }, true);

                    // Watch for drag events on the marker.
                    if (scope.draggable) {
                        marker.addListener('dragend', function () {
                            scope.position.lat = marker.position.lat();
                            scope.position.lng = marker.position.lng();
                            $rootScope.$digest();
                        });
                    }

                    // Watch for changes in title.
                    scope.$watch('title', function (newValue, oldValue) {
                        marker.setTitle(newValue);
                    });

                    // Create an event handler, that can register multiple callbacks to the same event.
                    var eventHandler = eventHandlerService.createEventHandler(marker);

                    // The marker is ready for use.
                    deferred.resolve({
                        map: gmapElement.map,
                        element: marker,
                        eventHandler: eventHandler
                    });

                    scope.$on('$destroy', function () {
                        marker.setMap(null);
                    });
                });
            }
        };
    }]);
})();<|endoftext|>