<commit_before>/*
Case Conductor is a Test Case Management system.
Copyright (C) 2011 uTest Inc.

This file is part of Case Conductor.

Case Conductor is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Case Conductor is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Case Conductor.  If not, see <http://www.gnu.org/licenses/>.
*/
/*jslint    browser:    true,
            indent:     4,
            confusion:  true,
            regexp:     true */
/*global    ich, jQuery, confirm */

var CC = (function (CC, $) {

    'use strict';

    CC.toggleAdvancedFiltering = function (context) {
        var advanced = $(context).find('.visual'),
            toggleAdvanced = $(context).find('.toggle a');

        // Shows/hides the advanced filtering
        toggleAdvanced.click(function (e) {
            e.preventDefault();
            advanced.toggleClass('compact expanded');
        });
    };

    // Ajax-load manage and results list item contents
    CC.loadListItemDetails = function () {
        $('#listcontent').on('click', '.items .item.details', function (event) {
            if ($(event.target).is("button, a")) {
                return;
            }
            var item = $(this),
                content = item.find('.content'),
                url = item.data('details-url');
            if (url && !content.hasClass('loaded')) {
                content.css('min-height', '4.854em').addClass('loaded');
                content.loadingOverlay();
                $.get(url, function (data) {
                    content.loadingOverlay('remove');
                    content.html(data.html);
                });
            }
        });
    };

    // Expand list item details on direct hashtag links
    CC.openListItemDetails = function () {
        if ($('.manage').length && window.location.hash && $(window.location.hash).length) {
            $(window.location.hash).children('.summary').click();
        }
    };

    // Ajax for manage list actions (clone and delete)
    CC.manageActionsAjax = function () {
        $('.manage').on(
            'click',
            'button[name^=action-]',
            function (e) {
                e.preventDefault();
                var button = $(this),
                    form = button.closest('form'),
                    url = form.prop('action'),
                    method = form.attr('method'),
                    replace = button.closest('.action-ajax-replace'),
                    success = function (response) {
                        var replacement = $(response.html);
                        if (!response.no_replace) {
                            replace.trigger('before-replace', [replacement]);
                            replace.replaceWith(replacement);
                            replacement.trigger('after-replace', [replacement]);
                            replacement.find('.details').html5accordion();
                        }
                        replace.loadingOverlay('remove');
                    },
                    data = {};
                data[button.attr('name')] = button.val();
                replace.loadingOverlay();
                $.ajax(url, {
                    type: method,
                    data: data,
                    success: success
                });
            }
        );
    };

    return CC;

}(CC || {}, jQuery));
<commit_msg>manage-results list ajax-load details updated to match new markup (needs python to work)<commit_after>/*
Case Conductor is a Test Case Management system.
Copyright (C) 2011 uTest Inc.

This file is part of Case Conductor.

Case Conductor is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Case Conductor is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Case Conductor.  If not, see <http://www.gnu.org/licenses/>.
*/
/*jslint    browser:    true,
            indent:     4,
            confusion:  true,
            regexp:     true */
/*global    ich, jQuery, confirm */

var CC = (function (CC, $) {

    'use strict';

    CC.toggleAdvancedFiltering = function (context) {
        var advanced = $(context).find('.visual'),
            toggleAdvanced = $(context).find('.toggle a');

        // Shows/hides the advanced filtering
        toggleAdvanced.click(function (e) {
            e.preventDefault();
            advanced.toggleClass('compact expanded');
        });
    };

    // Ajax-load manage and results list item contents
    CC.loadListItemDetails = function () {
        $('.itemlist').on('click', '.listitem .details .summary', function (event) {
            var item = $(this),
                content = item.siblings('.content'),
                url = item.closest('.listitem').data('details-url');
            if (url && !content.hasClass('loaded')) {
                content.css('min-height', '4.854em').addClass('loaded');
                content.loadingOverlay();
                $.get(url, function (data) {
                    content.loadingOverlay('remove');
                    content.html(data.html);
                });
            } else { content.css('min-height', '0px'); }
            return false;
        });
    };

    // Expand list item details on direct hashtag links
    CC.openListItemDetails = function () {
        if ($('.manage').length && window.location.hash && $(window.location.hash).length) {
            $(window.location.hash).children('.summary').click();
        }
    };

    // Ajax for manage list actions (clone and delete)
    CC.manageActionsAjax = function () {
        $('.manage').on(
            'click',
            'button[name^=action-]',
            function (e) {
                e.preventDefault();
                var button = $(this),
                    form = button.closest('form'),
                    url = form.prop('action'),
                    method = form.attr('method'),
                    replace = button.closest('.action-ajax-replace'),
                    success = function (response) {
                        var replacement = $(response.html);
                        if (!response.no_replace) {
                            replace.trigger('before-replace', [replacement]);
                            replace.replaceWith(replacement);
                            replacement.trigger('after-replace', [replacement]);
                            replacement.find('.details').html5accordion();
                        }
                        replace.loadingOverlay('remove');
                    },
                    data = {};
                data[button.attr('name')] = button.val();
                replace.loadingOverlay();
                $.ajax(url, {
                    type: method,
                    data: data,
                    success: success
                });
            }
        );
    };

    return CC;

}(CC || {}, jQuery));
<|endoftext|>


<commit_before>// setup shadow dom
const treeHead = document.querySelector('#product-search');
const parent = document.createElement('div');
const holder = document.createElement('div');
const shadow = treeHead.attachShadow({mode: 'open'});
parent.appendChild(holder);
shadow.appendChild(parent);

// ##### workarounds ahead!! ####
(function() {
  // https://github.com/vuetifyjs/vuetify/issues/7622
  const {querySelector} = document;
  document.querySelector = function(selector) {
    if (selector === '[data-app]') return shadow.querySelector(selector);
    return querySelector.call(this, selector);
  };
  // ugly hack until https://github.com/vuetifyjs/vuetify/issues/7622 is fixed
  // we're not using document.activeElement at the momemt so it should be fine
  // but shouldn't be mixed with monaco just in case.
  Object.defineProperty(document, 'activeElement', {
    get() {
      return shadow.activeElement;
    },
  });
  // workaround for vuetify's click-outside hack
  document.body.addEventListener('click', (e) => {
    const target = shadow.querySelector('.v-select__selections input[type=text]');
    if (e.target === target || e.target === treeHead) return;
    const evt = new KeyboardEvent('keydown', {
      keyCode: 9, // tab,
    });
    target.dispatchEvent(evt);
  });
  // https://github.com/mdn/interactive-examples/issues/887 and https://bugs.chromium.org/p/chromium/issues/detail?id=336876
  const fontFaceSheet = new CSSStyleSheet();
  fontFaceSheet.replaceSync(`@font-face {
    font-family: "Material Design Icons";
    src: url("https://cdn.jsdelivr.net/npm/@mdi/font@4.x/fonts/materialdesignicons-webfont.eot?v=4.9.95");
    src: url("https://cdn.jsdelivr.net/npm/@mdi/font@4.x/fonts/materialdesignicons-webfont.eot?#iefix&v=4.9.95") format("embedded-opentype"),url("https://cdn.jsdelivr.net/npm/@mdi/font@4.x/fonts/materialdesignicons-webfont.woff2?v=4.9.95") format("woff2"),url("https://cdn.jsdelivr.net/npm/@mdi/font@4.x/fonts/materialdesignicons-webfont.woff?v=4.9.95") format("woff"),url("https://cdn.jsdelivr.net/npm/@mdi/font@4.x/fonts/materialdesignicons-webfont.ttf?v=4.9.95") format("truetype");
    font-weight: normal;
    font-style: normal;
}`);
  document.adoptedStyleSheets = [fontFaceSheet];
  // fixing min-height of v-app
  const styles = new CSSStyleSheet();
  styles.replaceSync(`
    .v-application--wrap {
        min-height: inherit;
    }
`);
  shadow.adoptedStyleSheets = [styles];
})();
// ##### workarounds done!! ####

function loadStyle(url) {
  const el = document.createElement('link');
  el.setAttribute('rel', 'stylesheet');
  el.setAttribute('type', 'text/css');
  el.setAttribute('href', url);
  parent.appendChild(el);
}

loadStyle('https://cdn.jsdelivr.net/npm/@mdi/font@4.x/css/materialdesignicons.min.css');
loadStyle('https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css');

function sanitizeQueryText(val) {
  val = val.toLocaleLowerCase();
  val = val.replace(' ', '_');
  val = val.replace('-', '\\-');
  return val;
}

const ProductSearch = {
  template: '#product-search-template',

  props: {
    products: Array,
  },

  data() {
    return {
      internalProducts: this.products.slice(),
      internalItems: this.products.slice(),
      loading: false,
      search: null,
      timer: null,
    };
  },

  watch: {
    search(val) {
      val && val.length > 2 && this.querySelections(val);
    },
  },

  methods: {
    customFilter(item, queryText, itemText) {
      // Only search for the product name for now.
      const productName = item.product.toLowerCase();
      // const vendorName = item.vendor.toLowerCase();
      const searchText = sanitizeQueryText(queryText);
      return productName.indexOf(searchText) > -1;
    },

    remove(item) {
      const index = this.internalProducts.indexOf(item);
      if (index >= 0) {
        this.internalProducts.splice(index, 1);
        // propagate change
        this.$emit('change', this.internalProducts.map(this.toValue));
      }
    },

    toValue(item) {
      return `${item.vendor}#~#${item.product}`;
    },

    querySelections(v) {
      this.loading = true;
      clearTimeout(this.timer);
      this.timer = setTimeout(() => {
        $.getJSON('/product/list:' + sanitizeQueryText(v), (data) => {
          this.loading = false;
          if (!data || !data.length) {
            return;
          }
          // TODO: replace with Set?
          data.forEach((pair) =>
            this.internalItems.push({vendor: pair['vendor'], product: pair['product']}));
        });
      }, 500);
    },

    escapeHTML(html) {
      const n = document.createTextNode(html);
      const p = document.createElement('pre');
      p.appendChild(n);
      return p.innerHTML.replace('"', '"').replace('\'', ''');
    },

    formatProductText(val) {
      if (!val || !val.length) {
        return '';
      }
      val = val.replace('\\-', '-');
      val = val.replace('_', ' ');
      val = val.charAt(0).toUpperCase() + val.slice(1);
      return val;
    },

    highlightText(text) {
      const searchInput = (this.search || '').toString().toLocaleLowerCase();
      const index = text.toLocaleLowerCase().indexOf(searchInput);

      if (index < 0) return this.escapeHTML(text);

      const start = text.slice(0, index);
      const middle = text.slice(index, index + searchInput.length);
      const end = text.slice(index + searchInput.length);

      return this.escapeHTML(start) + `<span class="v-list-item__mask">${this.escapeHTML(middle)}</span>` + this.escapeHTML(end);
    },
  },
  delimiters: ['[[', ']]'],
};

// also accessed outside of this file
let selectedProducts = [];

// hook form submit
let el = treeHead;
while (el) {
  if (el.tagName === 'FORM') {
    el.addEventListener('submit', function() {
      const container = this.querySelector('#product-fields');
      // clear node
      while (container.firstChild) {
        container.removeChild(container.lastChild);
      }
      const input = document.createElement('input');
      input.type = 'hidden';
      input.name = 'products';
      input.value = JSON.stringify(selectedProducts);
      container.appendChild(input);
      return false;
    });
    break;
  }
  el = el.parentElement;
}
<commit_msg>fix FF render issues with the product selection widget.<commit_after>// setup shadow dom
const treeHead = document.querySelector('#product-search');
const parent = document.createElement('div');
const holder = document.createElement('div');
const shadow = treeHead.attachShadow({ mode: 'open' });
parent.appendChild(holder);
shadow.appendChild(parent);

// ##### workarounds ahead!! ####
(function () {
  // https://github.com/vuetifyjs/vuetify/issues/7622
  const { querySelector } = document;
  document.querySelector = function (selector) {
    if (selector === '[data-app]') return shadow.querySelector(selector);
    return querySelector.call(this, selector);
  };
  // ugly hack until https://github.com/vuetifyjs/vuetify/issues/7622 is fixed
  // we're not using document.activeElement at the momemt so it should be fine
  // but shouldn't be mixed with monaco just in case.
  Object.defineProperty(document, 'activeElement', {
    get() {
      return shadow.activeElement;
    },
  });
  // workaround for vuetify's click-outside hack
  document.body.addEventListener('click', (e) => {
    const target = shadow.querySelector('.v-select__selections input[type=text]');
    if (e.target === target || e.target === treeHead) return;
    const evt = new KeyboardEvent('keydown', {
      keyCode: 9, // tab,
    });
    target.dispatchEvent(evt);
  });

  // https://github.com/mdn/interactive-examples/issues/887
  const fontFaceStyle = `@font-face {
    font-family: "Material Design Icons";
    src: url("https://cdn.jsdelivr.net/npm/@mdi/font@4.x/fonts/materialdesignicons-webfont.eot?v=4.9.95");
    src: url("https://cdn.jsdelivr.net/npm/@mdi/font@4.x/fonts/materialdesignicons-webfont.eot?#iefix&v=4.9.95") format("embedded-opentype"),url("https://cdn.jsdelivr.net/npm/@mdi/font@4.x/fonts/materialdesignicons-webfont.woff2?v=4.9.95") format("woff2"),url("https://cdn.jsdelivr.net/npm/@mdi/font@4.x/fonts/materialdesignicons-webfont.woff?v=4.9.95") format("woff"),url("https://cdn.jsdelivr.net/npm/@mdi/font@4.x/fonts/materialdesignicons-webfont.ttf?v=4.9.95") format("truetype");
    font-weight: normal;
    font-style: normal;
  }`;
  // fixing min-height of v-app
  const shadowStyle = `
  .v-application--wrap {
    min-height: inherit;
  }
  `;

  if (document.adoptedStyleSheets) {
    // https://github.com/mdn/interactive-examples/issues/887 and https://bugs.chromium.org/p/chromium/issues/detail?id=336876
    const fontFaceSheet = new CSSStyleSheet();
    fontFaceSheet.replaceSync(fontFaceStyle);
    document.adoptedStyleSheets = [fontFaceSheet];
    const styles = new CSSStyleSheet();
    styles.replaceSync(shadowStyle);
    shadow.adoptedStyleSheets = [styles];
  } else {
    const fontFaceSheet = document.createElement('style');
    fontFaceSheet.textContent = fontFaceStyle;
    document.body.appendChild(fontFaceSheet);

    const styles = document.createElement('style');
    styles.textContent = shadowStyle;
    shadow.appendChild(styles);
  }
})();
// ##### workarounds done!! ####

function loadStyle(url) {
  const el = document.createElement('link');
  el.setAttribute('rel', 'stylesheet');
  el.setAttribute('type', 'text/css');
  el.setAttribute('href', url);
  parent.appendChild(el);
}

loadStyle('https://cdn.jsdelivr.net/npm/@mdi/font@4.x/css/materialdesignicons.min.css');
loadStyle('https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css');

function sanitizeQueryText(val) {
  val = val.toLocaleLowerCase();
  val = val.replace(' ', '_');
  val = val.replace('-', '\\-');
  return val;
}

const ProductSearch = {
  template: '#product-search-template',

  props: {
    products: Array,
  },

  data() {
    return {
      internalProducts: this.products.slice(),
      internalItems: this.products.slice(),
      loading: false,
      search: null,
      timer: null,
    };
  },

  watch: {
    search(val) {
      val && val.length > 2 && this.querySelections(val);
    },
  },

  methods: {
    customFilter(item, queryText, itemText) {
      // Only search for the product name for now.
      const productName = item.product.toLowerCase();
      // const vendorName = item.vendor.toLowerCase();
      const searchText = sanitizeQueryText(queryText);
      return productName.indexOf(searchText) > -1;
    },

    remove(item) {
      const index = this.internalProducts.indexOf(item);
      if (index >= 0) {
        this.internalProducts.splice(index, 1);
        // propagate change
        this.$emit('change', this.internalProducts.map(this.toValue));
      }
    },

    toValue(item) {
      return `${item.vendor}#~#${item.product}`;
    },

    querySelections(v) {
      this.loading = true;
      clearTimeout(this.timer);
      this.timer = setTimeout(() => {
        $.getJSON('/product/list:' + sanitizeQueryText(v), (data) => {
          this.loading = false;
          if (!data || !data.length) {
            return;
          }
          // TODO: replace with Set?
          data.forEach((pair) =>
            this.internalItems.push({ vendor: pair['vendor'], product: pair['product'] }));
        });
      }, 500);
    },

    escapeHTML(html) {
      const n = document.createTextNode(html);
      const p = document.createElement('pre');
      p.appendChild(n);
      return p.innerHTML.replace('"', '"').replace('\'', ''');
    },

    formatProductText(val) {
      if (!val || !val.length) {
        return '';
      }
      val = val.replace('\\-', '-');
      val = val.replace('_', ' ');
      val = val.charAt(0).toUpperCase() + val.slice(1);
      return val;
    },

    highlightText(text) {
      const searchInput = (this.search || '').toString().toLocaleLowerCase();
      const index = text.toLocaleLowerCase().indexOf(searchInput);

      if (index < 0) return this.escapeHTML(text);

      const start = text.slice(0, index);
      const middle = text.slice(index, index + searchInput.length);
      const end = text.slice(index + searchInput.length);

      return this.escapeHTML(start) + `<span class="v-list-item__mask">${this.escapeHTML(middle)}</span>` + this.escapeHTML(end);
    },
  },
  delimiters: ['[[', ']]'],
};

// also accessed outside of this file
let selectedProducts = [];

// hook form submit
let el = treeHead;
while (el) {
  if (el.tagName === 'FORM') {
    el.addEventListener('submit', function () {
      const container = this.querySelector('#product-fields');
      // clear node
      while (container.firstChild) {
        container.removeChild(container.lastChild);
      }
      const input = document.createElement('input');
      input.type = 'hidden';
      input.name = 'products';
      input.value = JSON.stringify(selectedProducts);
      container.appendChild(input);
      return false;
    });
    break;
  }
  el = el.parentElement;
}
<|endoftext|>


<commit_before><commit_msg>feat(gatsby-telemetry): Use v4 instead of v1 uuids (#15431)<commit_after><|endoftext|>


<commit_before>var Router = require('express')
var pluralize = require('pluralize')
var ok = require('./utils').ok
var fail = require('./utils').fail
var respond = require('./utils').respond
const logger = require('winston')
const MAX_RESULTS = 100

/**
  Generic controller that provides CRUD operations for a given Mongoose model
*/
module.exports = class BaseController {

  /**
    @param model Mongoose model
    @param key primary key of the model that will be used for searching, removing
    and reading
  */
  constructor(model, key) {
    this.model = model
    this.modelName = model.modelName.toLowerCase()
    this.key = key
  }

  create(data) {
    return this.model
      .create(data)
      .then((modelInstance) => {
        var response = {}
        response[this.modelName] = modelInstance
        return response
      })
  }

  read(id) {
    var filter = {}
    filter[this.key] = id

    return this.model
      .findOne(filter)
      .then((modelInstance) => {
        var response = {}
        response[this.modelName] = modelInstance
        return response
      })
  }

  list() {
    return this.model
      .find({})
      .limit(MAX_RESULTS)
      .then((modelInstances) => {
        var response = {}
        response[pluralize(this.modelName)] = modelInstances
        return response
      })
  }

  delete(id) {
    const filter = {}
    filter[this.key] = id

    return this.model
      .remove(filter)
      .then(() => {
        return {}
      })
  }

  /**
   */
  update(id, data) {
    var filter = {}
    filter[this.key] = id

    return this.model
      .findOne(filter)
      .then((modelInstance) => {
        for (var attribute in data) {
          if (data.hasOwnProperty(attribute) && attribute !== this.key && attribute !== '_id') {
            modelInstance[attribute] = data[attribute]
          }
        }

        return modelInstance.save()
      })
      .then((modelInstance) => {
        var response = {}
        response[this.modelName] = modelInstance
        return response
      })
  }

  routeAPI() {
    const router = new Router()

    router.get('/', (req, res) => {
      this
        .list()
        .then(ok(res))
        .then(null, fail(res))
    })

    router.post('/', (req, res) => {
      this
        .create(req.body)
        .then(ok(res))
        .then(null, fail(res))
    })

    router.get('/:key', (req, res) => {
      this
        .read(req.params.key)
        .then(ok(res))
        .then(null, fail(res))
    })

    router.put('/:key', (req, res) => {
      this
        .update(req.params.key, req.body)
        .then(ok(res))
        .then(null, fail(res))
    })

    router.delete('/:key', (req, res) => {
      this
        .delete(req.params.key)
        .then(ok(res))
        .then(null, fail(res))
    })

    return router
  }

  route() {
    const router = new Router()

    // Declare locals to use
    router.use((req, res, next) => {
      res.locals.moment = require('moment')
      next()
    })

    router.get('/', (req, res) => {
      this
        .list()
        .then((list) => {
          let pageResp = {
            title: this.model.modelName
          }
          const arr = []
          for (const obj of list[pluralize(this.modelName)]) {
            arr.push(obj.toObject())
          }
          pageResp[pluralize(this.modelName)] = arr
          respond(res, this.modelName + '/index', pageResp)
        })
        .then(null, fail(res))
    })

    router.get('/new', (req, res) => {
      res.render(this.modelName + '/new', { title: 'Add New ' + this.model.modelName });
    })

    router.post('/', (req, res) => {
      logger.info('Will create the object: ' + JSON.stringify(req.body))
      this
        .create(req.body)
        .then(res.redirect('/' + pluralize(this.modelName)))
        .then(null, fail(res))
    })

    router.get('/:key', (req, res) => {
      this
        .read(req.params.key)
        .then(obj => {
          let pageResp = {
            title: this.model.modelName
          }
          pageResp[this.modelName] = obj[this.modelName].toObject()
          respond(res, this.modelName + '/show', pageResp)
        })
        .then(null, fail(res))
    })

    router.route('/:key/edit').get((req, res) => {
      this
        .read(req.params.key)
        .then((obj) => {
          let pageResp = {
            title: this.model.modelName
          }
          pageResp[this.modelName] = obj[this.modelName].toObject()
          respond(res, this.modelName + '/edit', pageResp)
        })
        .then(null, fail(res))
    }).delete((req, res) => {
      logger.info('Will delete the object: ' + req.body.key)
      this
        .delete(req.body.key)
        .then(res.redirect('/' + pluralize(this.modelName)))
        .then(null, fail(res))
    }).put((req, res) => {
      logger.info('Will update the object: ' + req.params.id)
      this
        .update(req.body.id, req.body)
        .then(res.redirect('/' + pluralize(this.modelName) + '/' + req.params.key))
        .then(null, fail(res))
    })
    // TODO PUT and DELETE for Edit opeation

    return router
  }
}
<commit_msg>Basic Text Search working<commit_after>var Router = require('express')
var pluralize = require('pluralize')
var ok = require('./utils').ok
var fail = require('./utils').fail
var respond = require('./utils').respond
const logger = require('winston')
const MAX_RESULTS = 100

/**
  Generic controller that provides CRUD operations for a given Mongoose model
*/
module.exports = class BaseController {

  /**
    @param model Mongoose model
    @param key primary key of the model that will be used for searching, removing
    and reading
  */
  constructor(model, key) {
    this.model = model
    this.modelName = model.modelName.toLowerCase()
    this.key = key
  }

  create(data) {
    return this.model
      .create(data)
      .then((modelInstance) => {
        var response = {}
        response[this.modelName] = modelInstance
        return response
      })
  }

  read(id) {
    var filter = {}
    filter[this.key] = id

    return this.model
      .findOne(filter)
      .then((modelInstance) => {
        var response = {}
        response[this.modelName] = modelInstance
        return response
      })
  }

  list() {
    return this.model
      .find({})
      .limit(MAX_RESULTS)
      .then((modelInstances) => {
        var response = {}
        response[pluralize(this.modelName)] = modelInstances
        return response
      })
  }

  delete(id) {
    const filter = {}
    filter[this.key] = id

    return this.model
      .remove(filter)
      .then(() => {
        return {}
      })
  }

  /**
   */
  update(id, data) {
    var filter = {}
    filter[this.key] = id

    return this.model
      .findOne(filter)
      .then((modelInstance) => {
        for (var attribute in data) {
          if (data.hasOwnProperty(attribute) && attribute !== this.key && attribute !== '_id') {
            modelInstance[attribute] = data[attribute]
          }
        }

        return modelInstance.save()
      })
      .then((modelInstance) => {
        var response = {}
        response[this.modelName] = modelInstance
        return response
      })
  }

  search(text) {
    var queryArray = []

    for (var property in this.model.schema.paths) {
      if (this.model.schema.paths.hasOwnProperty(property) && this.model.schema.paths[property]["instance"] === "String") {
        queryArray.push(JSON.parse('{\"' + property + '\": { \"$regex\": "' + text + '", \"$options\": \"i\"} }'))
      }
    }

    var query = {
      $or: queryArray
    }

    return this.model.find(query).exec().then((modelInstances) => {
      var response = {}
      response[pluralize(this.modelName)] = modelInstances
      return response
    })
  }

  /**
   *  ROUTERS
   */

  routeAPI() {
    const router = new Router()

    router.get('/', (req, res) => {
      this
        .list()
        .then(ok(res))
        .then(null, fail(res))
    })

    router.post('/', (req, res) => {
      this
        .create(req.body)
        .then(ok(res))
        .then(null, fail(res))
    })

    router.post('/search', (req, res) => {
      this
        .search(req.body.text)
        .then(ok(res))
        .then(null, fail(res))
    })

    router.get('/:key', (req, res) => {
      this
        .read(req.params.key)
        .then(ok(res))
        .then(null, fail(res))
    })

    router.put('/:key', (req, res) => {
      this
        .update(req.params.key, req.body)
        .then(ok(res))
        .then(null, fail(res))
    })

    router.delete('/:key', (req, res) => {
      this
        .delete(req.params.key)
        .then(ok(res))
        .then(null, fail(res))
    })

    return router
  }

  route() {
    const router = new Router()

    // Declare locals to use
    router.use((req, res, next) => {
      res.locals.moment = require('moment')
      next()
    })

    router.get('/', (req, res) => {
      this
        .list()
        .then((list) => {
          let pageResp = {
            title: this.model.modelName
          }
          const arr = []
          for (const obj of list[pluralize(this.modelName)]) {
            arr.push(obj.toObject())
          }
          pageResp[pluralize(this.modelName)] = arr
          respond(res, this.modelName + '/index', pageResp)
        })
        .then(null, fail(res))
    })

    router.get('/new', (req, res) => {
      res.render(this.modelName + '/new', { title: 'Add New ' + this.model.modelName });
    })

    router.post('/', (req, res) => {
      logger.info('Will create the object: ' + JSON.stringify(req.body))
      this
        .create(req.body)
        .then(res.redirect('/' + pluralize(this.modelName)))
        .then(null, fail(res))
    })

    router.get('/:key', (req, res) => {
      this
        .read(req.params.key)
        .then(obj => {
          let pageResp = {
            title: this.model.modelName
          }
          pageResp[this.modelName] = obj[this.modelName].toObject()
          respond(res, this.modelName + '/show', pageResp)
        })
        .then(null, fail(res))
    })

    router.route('/:key/edit').get((req, res) => {
      this
        .read(req.params.key)
        .then((obj) => {
          let pageResp = {
            title: this.model.modelName
          }
          pageResp[this.modelName] = obj[this.modelName].toObject()
          respond(res, this.modelName + '/edit', pageResp)
        })
        .then(null, fail(res))
    }).delete((req, res) => {
      logger.info('Will delete the object: ' + req.body.key)
      this
        .delete(req.body.key)
        .then(res.redirect('/' + pluralize(this.modelName)))
        .then(null, fail(res))
    }).put((req, res) => {
      logger.info('Will update the object: ' + req.params.id)
      this
        .update(req.body.id, req.body)
        .then(res.redirect('/' + pluralize(this.modelName) + '/' + req.params.key))
        .then(null, fail(res))
    })
    // TODO PUT and DELETE for Edit opeation

    return router
  }
}
<|endoftext|>


<commit_before>var SuperPixelGrid = function (w, h , initArray) {
    if (!(this instanceof SuperPixelGrid)) {
        return new SuperPixelGrid(w, h, initArray);
    }
    Array2d.call(this, w, h, initArray);
};
SuperPixelGrid.prototype = new Array2d();
SuperPixelGrid.prototype.constructor = SuperPixelGrid;

SuperPixelGrid.prototype.setPixel = function(x, y, color) {
    try {
      this.set(x, y, color);
    }
    catch(e) {
      if (e instanceof RangeError) {
        // ignore range error hey it happens
      } else {
        throw e;
      }
    }
};

SuperPixelGrid.prototype.togglePixel = function(x, y) {
      this.setPixel(x, y, !this.get(x, y));
};

SuperPixelGrid.prototype.drawLine = function(x0, y0, x1, y1, color) {
    var self = this;
    self.forLine(x0, y0, x1, y1, function(val, x, y) {
        self.setPixel(x, y, color);});
    return this;
};

SuperPixelGrid.prototype.drawRectangle = function(x0, y0, x1, y1, color) {
    this.drawLine(x0, y0, x1, y0, color);
    this.drawLine(x1, y0, x1, y1, color);
    this.drawLine(x1, y1, x0, y1, color);
    this.drawLine(x0, y1, x0, y0, color);
    return this;
};

SuperPixelGrid.prototype.drawEllipse = function(x0, y0, x1, y1, color) {
    var self = this;
    x0 = 2 * x0 - x1;
    y0 = 2 * y0 - y1;
    var plot4EllipsePoints = function(x, y, color) {
        self.setPixel(x0 + x, y0 + y, color);
        self.setPixel(x0 - x, y0 + y, color);
        self.setPixel(x0 - x, y0 - y, color);
        self.setPixel(x0 + x, y0 - y, color);
    };
    var a = Math.abs(x1 - x0);
    var b = Math.abs(y1 - y0);
    var b1 = b % 2;
    var dx = 4 * (1 - a) * b * b;
    var dy = 4 * (b1 + 1) * a * a;
    var err = dx + dy + b1 * a * a;
    var e2;

    if (x0 > x1) {
        x0 = x1;
        x1 += a;
    }
    if (y0 > y1) {
        y0 = y1;
    }
    y0 += Math.round((b + 1) / 2);
    y1 = y0 - b1;
    a = a * 8 * a;
    b1 = 8 * b * b;

    do {
        self.setPixel(x1, y0, color);
        self.setPixel(x0, y0, color);
        self.setPixel(x0, y1, color);
        self.setPixel(x1, y1, color);
        e2 = 2 * err;
        if (e2 <= dy) {
            y0++;
            y1--;
            err += dy += a;
        }
        if (e2 >= dx || 2 * err > dy) {
            x0++;
            x1--;
            err += dx += b1;
        }
    } while (x0 <= x1);

    while (y0-y1 < b) {
       self.setPixel(x0 - 1, y0, color);
       self.setPixel(x1 + 1, y0++, color);
       self.setPixel(x0 - 1, y1, color);
       self.setPixel(x1 + 1, y1--, color);
    }
};

SuperPixelGrid.prototype.floodFill = function(x, y, color) {
  // if pixel is already toggled, stop
  if (this.get(x, y) != color) {
    this.setPixel(x, y, color);
    // fill up
    if (y > 0) {
      this.floodFill(x, y - 1, color);
    }
    // fill down
    if (y < this.height - 1) {
      this.floodFill(x, y + 1, color);
    }
    // fill left
    if (x > 0) {
      this.floodFill(x - 1, y, color);
    }
    // fill right
    if (x < this.width - 1) {
      this.floodFill(x + 1, y, color);
    }
  }
  return this;
};

SuperPixelGrid.prototype.lifeStep = function() {
    var self = this;
    var newFrame = self.map( function(value, x, y, w, h) {
      var neighbors = [];
      if (x > 0) {
        if (y > 0) { neighbors.push(self.get(x - 1, y - 1)); }
        neighbors.push(self.get(x - 1, y));
        if (y < self.height - 1) { neighbors.push(self.get(x - 1, y + 1)); }
      }
      if (y > 0) { neighbors.push(self.get(x, y - 1)); }
      if (y < self.height - 1) { neighbors.push(self.get(x, y + 1)); }
      if (x < self.width - 1) {
        if (y > 0) { neighbors.push(self.get(x + 1, y - 1)); }
        neighbors.push(self.get(x + 1, y));
        if (y < self.height + 1) { neighbors.push(self.get(x + 1, y + 1)); }
      }
      var liveNeighbors = neighbors
        .map( function(isTrue) {return isTrue ? 1 : 0;} ) //map bool to int
        .reduce( function(a,b) {return a + b;} ); //sum
      if (value === true) { // this cell is 'alive'
        if (liveNeighbors < 2 || liveNeighbors > 3) {
          return false;
        }
        else {
          return true;
        }
      } else { //this cell is 'dead'
        if (liveNeighbors === 3) {
          return true;
        } else {
          return false;
        }
      }
    });
    this.rawArray = newFrame.rawArray.slice();
    return this;
};

SuperPixelGrid.prototype.toString = function() {
    return this.rawArray.map( function(n){return n ? 1 : 0;} ).join('');
};

SuperPixelGrid.prototype.fromString = function(s) {
    var rawArray = s.split("").map( function(n) {return n == 1;} );
    this.rawArray = rawArray.slice();
    return this;
};

<commit_msg>Ellipse tweak<commit_after>var SuperPixelGrid = function (w, h , initArray) {
    if (!(this instanceof SuperPixelGrid)) {
        return new SuperPixelGrid(w, h, initArray);
    }
    Array2d.call(this, w, h, initArray);
};
SuperPixelGrid.prototype = new Array2d();
SuperPixelGrid.prototype.constructor = SuperPixelGrid;

SuperPixelGrid.prototype.setPixel = function(x, y, color) {
    try {
      this.set(x, y, color);
    }
    catch(e) {
      if (e instanceof RangeError) {
        // ignore range error hey it happens
      } else {
        throw e;
      }
    }
};

SuperPixelGrid.prototype.togglePixel = function(x, y) {
      this.setPixel(x, y, !this.get(x, y));
};

SuperPixelGrid.prototype.drawLine = function(x0, y0, x1, y1, color) {
    var self = this;
    self.forLine(x0, y0, x1, y1, function(val, x, y) {
        self.setPixel(x, y, color);});
    return this;
};

SuperPixelGrid.prototype.drawRectangle = function(x0, y0, x1, y1, color) {
    this.drawLine(x0, y0, x1, y0, color);
    this.drawLine(x1, y0, x1, y1, color);
    this.drawLine(x1, y1, x0, y1, color);
    this.drawLine(x0, y1, x0, y0, color);
    return this;
};

SuperPixelGrid.prototype.drawEllipse = function(x0, y0, x1, y1, color) {
    var self = this;
    x0 = 2 * x0 - x1;
    y0 = 2 * y0 - y1;
    y0--;
    y1--;
    var plot4EllipsePoints = function(x, y, color) {
        self.setPixel(x0 + x, y0 + y, color);
        self.setPixel(x0 - x, y0 + y, color);
        self.setPixel(x0 - x, y0 - y, color);
        self.setPixel(x0 + x, y0 - y, color);
    };
    var a = Math.abs(x1 - x0);
    var b = Math.abs(y1 - y0);
    var b1 = b % 2;
    var dx = 4 * (1 - a) * b * b;
    var dy = 4 * (b1 + 1) * a * a;
    var err = dx + dy + b1 * a * a;
    var e2;

    if (x0 > x1) {
        x0 = x1;
        x1 += a;
    }
    if (y0 > y1) {
        y0 = y1;
    }
    y0 += Math.round((b + 1) / 2);
    y1 = y0 - b1;
    a = a * 8 * a;
    b1 = 8 * b * b;

    do {
        self.setPixel(x1, y0, color);
        self.setPixel(x0, y0, color);
        self.setPixel(x0, y1, color);
        self.setPixel(x1, y1, color);
        e2 = 2 * err;
        if (e2 <= dy) {
            y0++;
            y1--;
            err += dy += a;
        }
        if (e2 >= dx || 2 * err > dy) {
            x0++;
            x1--;
            err += dx += b1;
        }
    } while (x0 <= x1);

    while (y0 - y1 < b) {
       self.setPixel(x0 - 1, y0, color);
       self.setPixel(x1 + 1, y0++, color);
       self.setPixel(x0 - 1, y1, color);
       self.setPixel(x1 + 1, y1--, color);
    }
};

SuperPixelGrid.prototype.floodFill = function(x, y, color) {
  // if pixel is already toggled, stop
  if (this.get(x, y) != color) {
    this.setPixel(x, y, color);
    // fill up
    if (y > 0) {
      this.floodFill(x, y - 1, color);
    }
    // fill down
    if (y < this.height - 1) {
      this.floodFill(x, y + 1, color);
    }
    // fill left
    if (x > 0) {
      this.floodFill(x - 1, y, color);
    }
    // fill right
    if (x < this.width - 1) {
      this.floodFill(x + 1, y, color);
    }
  }
  return this;
};

SuperPixelGrid.prototype.lifeStep = function() {
    var self = this;
    var newFrame = self.map( function(value, x, y, w, h) {
      var neighbors = [];
      if (x > 0) {
        if (y > 0) { neighbors.push(self.get(x - 1, y - 1)); }
        neighbors.push(self.get(x - 1, y));
        if (y < self.height - 1) { neighbors.push(self.get(x - 1, y + 1)); }
      }
      if (y > 0) { neighbors.push(self.get(x, y - 1)); }
      if (y < self.height - 1) { neighbors.push(self.get(x, y + 1)); }
      if (x < self.width - 1) {
        if (y > 0) { neighbors.push(self.get(x + 1, y - 1)); }
        neighbors.push(self.get(x + 1, y));
        if (y < self.height + 1) { neighbors.push(self.get(x + 1, y + 1)); }
      }
      var liveNeighbors = neighbors
        .map( function(isTrue) {return isTrue ? 1 : 0;} ) //map bool to int
        .reduce( function(a,b) {return a + b;} ); //sum
      if (value === true) { // this cell is 'alive'
        if (liveNeighbors < 2 || liveNeighbors > 3) {
          return false;
        }
        else {
          return true;
        }
      } else { //this cell is 'dead'
        if (liveNeighbors === 3) {
          return true;
        } else {
          return false;
        }
      }
    });
    this.rawArray = newFrame.rawArray.slice();
    return this;
};

SuperPixelGrid.prototype.toString = function() {
    return this.rawArray.map( function(n){return n ? 1 : 0;} ).join('');
};

SuperPixelGrid.prototype.fromString = function(s) {
    var rawArray = s.split("").map( function(n) {return n == 1;} );
    this.rawArray = rawArray.slice();
    return this;
};

<|endoftext|>


<commit_before>'use strict';
/**
 * GET /
 * Home page.
 */

var config = require('../config/config');
var Project = require('../models/project');
var Version = require('../models/version');
var fs = require('fs');
var connect = require('connect');
var fresh = require('fresh');
var mongoose = require('mongoose');
var moment = require('moment');
var prettyBytes = require('pretty-bytes');
var spawn = require('child_process').spawn;

exports.getIndex = function(req, res) {
	if (req.user) {
		return res.redirect('/manage');
	}
	Project
		.find()
		.populate('_version')
		.exec(function(err, projects) {
			projects = projects.map(function(project) {
				return project.toObject();
			});
			res.render('home', {
				title: 'Projects',
				projects: projects
			});
		});

};

exports.getInstall = function(req, res) {
	var project_id = req.params.project_id || '5317c368280b290000e8dcf8';
	Project
		.findById(project_id)
		.populate('_version')
		.exec(function(err, project) {
			if (err || !project) {
				return res.send(404);
			}

			var size = fs.statSync(project._version.signedPackagePath).size;

			res.render('install', {
				title: project.name,
				created: project._version.created.toUTCString(),
				createdAgo: moment(project._version.created).fromNow(),
				size: prettyBytes(size),
				manifestUrl: '/install/' + project._id + '/manifest',
				packageUrl: '/install/' + project._id + '/package',
				iconUrl: '/install/' + project._id + '/icon',
				version: project._version.version
			});
		});
};

exports.getManifest = function(req, res) {
	var project_id = req.params.project_id;
	Project
		.findById(project_id)
		.populate('_version')
		.exec(function(err, project) {
			if (err || !project) {
				return res.send(404);
			}

			if (setCacheFromIdAndVerifyFreshness(project._version.id, req, res)) {
				return;
			}

			var size = fs.statSync(project._version.signedPackagePath).size;
			var manifest = JSON.parse(project._version.manifest);
			manifest.package_path = '/install/' + project._id + '/package';
			manifest.size = size;
			var icons = manifest.icons || {
				256: ''
			};

			for (size in icons) {
				if (icons.hasOwnProperty(size)) {
					icons[size] = '/install/' + project_id + '/icon/' + size;
				}
			}
			manifest.icons = icons;

			res.setHeader('Content-Type', 'application/x-web-app-manifest+json');
			res.send(manifest);
		});
};

exports.getPackage = function(req, res) {
	var project_id = req.params.project_id;
	Project
		.findById(project_id)
		.populate('_version')
		.exec(function(err, project) {
			if (err || !project) {
				return res.send(404);
			}

			if (setCacheFromIdAndVerifyFreshness(project._version.id, req, res)) {
				return;
			}

			res.sendfile(project._version.signedPackagePath);
		});
};

exports.getIcon = function(req, res) {
	var project_id = req.params.project_id;
	var icon_size = req.params.icon_size;
	Project
		.findById(project_id)
		.populate('_version')
		.exec(function(err, project) {
			if (err || !project) {
				return res.send(404);
			}

			if (setCacheFromIdAndVerifyFreshness(project._version.id, req, res)) {
				return;
			}

			var manifest = JSON.parse(project._version.manifest);

			var icons = manifest.icons;
			var biggestSize = 0,
				biggestPath = '';
			if (!icon_size) {
				for (var size in icons) {
					if (icons.hasOwnProperty(size)) {
						if (biggestSize < +size) {
							biggestSize = +size;
							biggestPath = icons[size];
						}
					}
				}
			} else {
				biggestSize = +icon_size;
				biggestPath = icons[icon_size];
			}

			if (!biggestPath) {
				res.sendfile(__dirname + '/../public/images/favicon.png');
				return;
			}

			biggestPath = biggestPath.replace(/^\//, '');

			res.setHeader('Content-Type', 'image/png');
			var child = spawn('unzip', ['-j', '-p', project._version.signedPackagePath, biggestPath], {
				encoding: 'binary'
			});
			child.stdout.pipe(res);

		});
};

exports.getPhoneCertInstructions = function(req, res) {
	// TODO provide some instructions on how to install the cert
};

exports.getPhoneCert = function(req, res) {
	res.download(config.derFilePath, 'phone - cert.der ');
};

exports.getPhoneCertTools = function(req, res) {
	// TODO provide tools to install the cert.
};

/**
 * Set etag and last-modified from mongo id
 *
 * @param {Number} id
 * @param {Object} req
 * @param {Object} res
 * @return {Boolean}
 */
function setCacheFromIdAndVerifyFreshness(id, req, res) {
	var id = mongoose.Types.ObjectId(id);
	var headers = {
		'etag': id.toString(),
		'last-modified': id.getTimestamp().toUTCString()
	}
	for (var key in headers) {
		res.setHeader(key, headers[key]);
	}
	// Cache is stale
	if (!fresh(req.headers, headers)) {
		return false;
	}
	// Freshness!
	connect.utils.notModified(res);
	return true;
}<commit_msg>404 for missing routes, otherwise requests are not handled.<commit_after>'use strict';
/**
 * GET /
 * Home page.
 */

var config = require('../config/config');
var Project = require('../models/project');
var Version = require('../models/version');
var fs = require('fs');
var connect = require('connect');
var fresh = require('fresh');
var mongoose = require('mongoose');
var moment = require('moment');
var prettyBytes = require('pretty-bytes');
var spawn = require('child_process').spawn;

exports.getIndex = function(req, res) {
	if (req.user) {
		return res.redirect('/manage');
	}
	Project
		.find()
		.populate('_version')
		.exec(function(err, projects) {
			projects = projects.map(function(project) {
				return project.toObject();
			});
			res.render('home', {
				title: 'Projects',
				projects: projects
			});
		});

};

exports.getInstall = function(req, res) {
	var project_id = req.params.project_id || '5317c368280b290000e8dcf8';
	Project
		.findById(project_id)
		.populate('_version')
		.exec(function(err, project) {
			if (err || !project) {
				return res.send(404);
			}

			var size = fs.statSync(project._version.signedPackagePath).size;

			res.render('install', {
				title: project.name,
				created: project._version.created.toUTCString(),
				createdAgo: moment(project._version.created).fromNow(),
				size: prettyBytes(size),
				manifestUrl: '/install/' + project._id + '/manifest',
				packageUrl: '/install/' + project._id + '/package',
				iconUrl: '/install/' + project._id + '/icon',
				version: project._version.version
			});
		});
};

exports.getManifest = function(req, res) {
	var project_id = req.params.project_id;
	Project
		.findById(project_id)
		.populate('_version')
		.exec(function(err, project) {
			if (err || !project) {
				return res.send(404);
			}

			if (setCacheFromIdAndVerifyFreshness(project._version.id, req, res)) {
				return;
			}

			var size = fs.statSync(project._version.signedPackagePath).size;
			var manifest = JSON.parse(project._version.manifest);
			manifest.package_path = '/install/' + project._id + '/package';
			manifest.size = size;
			var icons = manifest.icons || {
				256: ''
			};

			for (size in icons) {
				if (icons.hasOwnProperty(size)) {
					icons[size] = '/install/' + project_id + '/icon/' + size;
				}
			}
			manifest.icons = icons;

			res.setHeader('Content-Type', 'application/x-web-app-manifest+json');
			res.send(manifest);
		});
};

exports.getPackage = function(req, res) {
	var project_id = req.params.project_id;
	Project
		.findById(project_id)
		.populate('_version')
		.exec(function(err, project) {
			if (err || !project) {
				return res.send(404);
			}

			if (setCacheFromIdAndVerifyFreshness(project._version.id, req, res)) {
				return;
			}

			res.sendfile(project._version.signedPackagePath);
		});
};

exports.getIcon = function(req, res) {
	var project_id = req.params.project_id;
	var icon_size = req.params.icon_size;
	Project
		.findById(project_id)
		.populate('_version')
		.exec(function(err, project) {
			if (err || !project) {
				return res.send(404);
			}

			if (setCacheFromIdAndVerifyFreshness(project._version.id, req, res)) {
				return;
			}

			var manifest = JSON.parse(project._version.manifest);

			var icons = manifest.icons;
			var biggestSize = 0,
				biggestPath = '';
			if (!icon_size) {
				for (var size in icons) {
					if (icons.hasOwnProperty(size)) {
						if (biggestSize < +size) {
							biggestSize = +size;
							biggestPath = icons[size];
						}
					}
				}
			} else {
				biggestSize = +icon_size;
				biggestPath = icons[icon_size];
			}

			if (!biggestPath) {
				res.sendfile(__dirname + '/../public/images/favicon.png');
				return;
			}

			biggestPath = biggestPath.replace(/^\//, '');

			res.setHeader('Content-Type', 'image/png');
			var child = spawn('unzip', ['-j', '-p', project._version.signedPackagePath, biggestPath], {
				encoding: 'binary'
			});
			child.stdout.pipe(res);

		});
};

exports.getPhoneCertInstructions = function(req, res) {
	// TODO provide some instructions on how to install the cert
	res.send(404, 'TODO');
};

exports.getPhoneCert = function(req, res) {
	res.download(config.derFilePath, 'phone-cert.der');
};

exports.getPhoneCertTools = function(req, res) {
	// TODO provide tools to install the cert.
	res.send(404, 'TODO');
};

/**
 * Set etag and last-modified from mongo id
 *
 * @param {Number} id
 * @param {Object} req
 * @param {Object} res
 * @return {Boolean}
 */
function setCacheFromIdAndVerifyFreshness(id, req, res) {
	var id = mongoose.Types.ObjectId(id);
	var headers = {
		'etag': id.toString(),
		'last-modified': id.getTimestamp().toUTCString()
	}
	for (var key in headers) {
		res.setHeader(key, headers[key]);
	}
	// Cache is stale
	if (!fresh(req.headers, headers)) {
		return false;
	}
	// Freshness!
	connect.utils.notModified(res);
	return true;
}<|endoftext|>


<commit_before>/* Chocolate Factory v0.1

DOM object builder. (Thanks to DeviCat for the name!)

TODO: Document this. Because docs.

The MIT License (MIT)

Copyright (c) 2019 Chris Angelico

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

function set_content(elem, children) {
	while (elem.lastChild) elem.removeChild(elem.lastChild);
	if (!Array.isArray(children)) children = [children];
	for (let child of children) {
		if (child === "") continue;
		if (typeof child === "string") child = document.createTextNode(child);
		elem.appendChild(child);
	}
	return elem;
}

function choc(tag, attributes, children) {
	const ret = document.createElement(tag);
	if (attributes) for (let attr in attributes) {
		if (attr.startsWith("data-")) //Simplistic - we don't transform "data-foo-bar" into "fooBar" per HTML.
			ret.dataset[attr.slice(5)] = attributes[attr];
		else ret[attr] = attributes[attr];
	}
	if (children) set_content(ret, children);
	return ret;
}
//TODO: Enumerate these somehow
function BUTTON(a,c) {return choc("BUTTON", a, c);}
function DIV(a,c) {return choc("DIV", a, c);}
function IMG(a,c) {return choc("LI", a, c);}
function INPUT(a,c) {return choc("INPUT", a, c);}
function LABEL(a,c) {return choc("LABEL", a, c);}
function LI(a,c) {return choc("LI", a, c);}
function TD(a,c) {return choc("TD", a, c);}
function TR(a,c) {return choc("TR", a, c);}
<commit_msg>chocfac: I'm still an idiot<commit_after>/* Chocolate Factory v0.1

DOM object builder. (Thanks to DeviCat for the name!)

TODO: Document this. Because docs.

The MIT License (MIT)

Copyright (c) 2019 Chris Angelico

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

function set_content(elem, children) {
	while (elem.lastChild) elem.removeChild(elem.lastChild);
	if (!Array.isArray(children)) children = [children];
	for (let child of children) {
		if (child === "") continue;
		if (typeof child === "string") child = document.createTextNode(child);
		elem.appendChild(child);
	}
	return elem;
}

function choc(tag, attributes, children) {
	const ret = document.createElement(tag);
	if (attributes) for (let attr in attributes) {
		if (attr.startsWith("data-")) //Simplistic - we don't transform "data-foo-bar" into "fooBar" per HTML.
			ret.dataset[attr.slice(5)] = attributes[attr];
		else ret[attr] = attributes[attr];
	}
	if (children) set_content(ret, children);
	return ret;
}
//TODO: Enumerate these somehow
function BUTTON(a,c) {return choc("BUTTON", a, c);}
function DIV(a,c) {return choc("DIV", a, c);}
function IMG(a,c) {return choc("IMG", a, c);}
function INPUT(a,c) {return choc("INPUT", a, c);}
function LABEL(a,c) {return choc("LABEL", a, c);}
function LI(a,c) {return choc("LI", a, c);}
function TD(a,c) {return choc("TD", a, c);}
function TR(a,c) {return choc("TR", a, c);}
<|endoftext|>


<commit_before>// See post: http://asmaloney.com/2014/01/code/creating-an-interactive-map-with-leaflet-and-openstreetmap/

var map = L.map( 'map', {
    center: [41.0, 12.0],
    minZoom: 3,
    zoom: 5
});

L.tileLayer( 'http://{s}.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.png', {
    attribution: '© OpenStreetMap contributors | Tiles Courtesy of MapQuest ',
    subdomains: ['otile1','otile2','otile3','otile4']
}).addTo( map );

var myURL = jQuery( 'script[src$="segnalazioni.js"]' ).attr( 'src' ).replace( 'segnalazioni.js', '' );

var myIcon = L.icon({
    iconUrl: myURL + 'images/pin24.png',
    iconRetinaUrl: myURL + 'images/pin48.png',
    iconSize: [29, 24],
    iconAnchor: [9, 21],
    popupAnchor: [0, -14]
});

for ( var i=0; i < markers.length; ++i )
{
   L.marker( [markers[i].lat, markers[i].lng], {icon: myIcon} )
      .bindPopup( '
' + markers[i].when + ' ' + markers[i].caption )
      .addTo( map );
}<commit_msg>fix errore mapquest: direct tile access discontinued<commit_after>var map = new L.Map('map', {
  center: new L.LatLng(41.7, 12.0),
  minZoom: 3,
  zoom: 6
});

// create a new tile layer
var tileUrl = 'https://{s}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png',
layer = new L.TileLayer(tileUrl, {
    maxZoom: 18,
    attribution: 'Data © OpenStreetMap contributors | Maps © Thunderforest',
    });

// add the layer to the map
map.addLayer(layer);

var myURL = jQuery( 'script[src$="segnalazioni.js"]' ).attr( 'src' ).replace( 'segnalazioni.js', '' );

var myIcon = L.icon({
    iconUrl: myURL + 'images/pin24.png',
    iconRetinaUrl: myURL + 'images/pin48.png',
    iconSize: [29, 24],
    iconAnchor: [9, 21],
    popupAnchor: [0, -14]
});

for ( var i=0; i < markers.length; ++i )
{
   L.marker( [markers[i].lat, markers[i].lng], {icon: myIcon} )
      .bindPopup( '
' + markers[i].when + ' ' + markers[i].caption )
      .addTo( map );
}

<|endoftext|>


<commit_before>var _ = require('lodash')
var random_name = require('node-random-name');
var Firebase = require('firebase');

// San Francisco
var city_location = {
  lat: 37.78,
  lon: -122.41
}

var radius = 0.03

// simualate a random person entering, staying for a duration, and leaving
function simulate(){

  // generate a random person with a random name,
  // random location, and random duration
  var name = random_name()
  var duration = 1 + 5 * Math.random()
  var lat = city_location.lat + radius * (Math.random() - 0.5) * 2
  var lon = city_location.lon + radius * (Math.random() - 0.5) * 2
  var person = {
    name: name,
    duration: duration,
    lat: lat,
    lon: lon
  }

  // simulate this person entering
  enter(person)

  // simulate this person leaving after 'duration' seconds
  setTimeout(function(){
    leave(person)
  }, duration * 1000)

}

function enter(person){
  console.log('enter', person)
  // TODO: put this person in the Firebase
  // var ref = new Firebase('your-firebase-url')
  // ...
}

function leave(person){
  console.log('leave', person)
  // TODO: remove this person from the Firebase
  // var ref = new Firebase('your-firebase-url')
  // ...
}

function clear(){
  // TODO: remove all people from the Firebase
  // var ref = new Firebase('your-firebase-url')
  // ...
}

// clear the firebase, so that the simulation always starts from no one
clear()

// run each second
setInterval(simulate, 2000)
<commit_msg>Push, delete and clear now work<commit_after>var _ = require('lodash')
var random_name = require('node-random-name');
var Firebase = require('firebase');

// San Francisco
var city_location = {
    lat: 37.78,
    lon: -122.41
}

var radius = 0.03

// simualate a random person entering, staying for a duration, and leaving
function simulate() {

    // generate a random person with a random name,
    // random location, and random duration
    var name = random_name()
    var duration = 1 + 5 * Math.random()
    var lat = city_location.lat + radius * (Math.random() - 0.5) * 2
    var lon = city_location.lon + radius * (Math.random() - 0.5) * 2
    var person = {
        name: name,
        duration: duration,
        lat: lat,
        lon: lon
    }

    // simulate this person entering
    enter(person)

    // simulate this person leaving after 'duration' seconds
    setTimeout(function() {
        leave(person)
    }, duration * 1000)

}

function enter(person) {
    console.log('enter', person)
    var ref = new Firebase('https://ucdd2teamtwo.firebaseio.com');
    var usersRef = ref.child("customers");
    usersRef.child(person.name).set({
        duration: person.duration,
        lat: person.lat,
        lon: person.lon
    });
}

function leave(person) {
    console.log('leave', person)
    var ref = new Firebase('https://ucdd2teamtwo.firebaseio.com/customers/' + person.name);
    ref.remove();
}

function clear() {
   var ref = new Firebase('https://ucdd2teamtwo.firebaseio.com/customers/');
    ref.remove();
}

// clear the firebase, so that the simulation always starts from no one
clear()

// run each second
setInterval(simulate, 2000)
<|endoftext|>


<commit_before>(function () {
  var tableVisualization = angular.module('redash.visualization');

  tableVisualization.config(['VisualizationProvider', function (VisualizationProvider) {
    VisualizationProvider.registerVisualization({
      type: 'TABLE',
      name: 'Table',
      renderTemplate: '<grid-renderer options="visualization.options" query-result="queryResult"></grid-renderer>',
      skipTypes: true
    });
  }]);

  tableVisualization.directive('gridRenderer', function () {
    return {
      restrict: 'E',
      scope: {
        queryResult: '=',
        itemsPerPage: '='
      },
      templateUrl: "/views/grid_renderer.html",
      replace: false,
      controller: ['$scope', '$filter', function ($scope, $filter) {
        $scope.gridColumns = [];
        $scope.gridData = [];
        $scope.gridConfig = {
          isPaginationEnabled: true,
          itemsByPage: $scope.itemsPerPage || 15,
          maxSize: 8
        };

        $scope.$watch('queryResult && queryResult.getData()', function (data) {
          if (!data) {
            return;
          }

          if ($scope.queryResult.getData() == null) {
            $scope.gridColumns = [];
            $scope.gridData = [];
            $scope.filters = [];
          } else {
            $scope.filters = $scope.queryResult.getFilters();

            var prepareGridData = function (data) {
              var gridData = _.map(data, function (row) {
                var newRow = {};
                _.each(row, function (val, key) {
                  newRow[$scope.queryResult.getColumnCleanName(key)] = val;
                })
                return newRow;
              });

              return gridData;
            };

            $scope.gridData = prepareGridData($scope.queryResult.getData());

            var columns = $scope.queryResult.getColumns();
            $scope.gridColumns = _.map($scope.queryResult.getColumnCleanNames(), function (col, i) {
              var columnDefinition = {
                'label': $scope.queryResult.getColumnFriendlyNames()[i],
                'map': col
              };

              var columnType = columns[i].type;

              if (!columnType) {
                var rawData = $scope.queryResult.getRawData();

                if (rawData.length > 0) {
                  var exampleData = rawData[0][col];
                  if (angular.isNumber(exampleData)) {
                    columnType = 'float';
                  } else if (moment.isMoment(exampleData)) {
                    if (exampleData._i.match(/^\d{4}-\d{2}-\d{2}T/)) {
                      columnType = 'datetime';
                    } else {
                      columnType = 'date';
                    }
                  }
                }
              }

              if (columnType === 'integer') {
                columnDefinition.formatFunction = 'number';
                columnDefinition.formatParameter = 0;
              } else if (columnType === 'float') {
                columnDefinition.formatFunction = 'number';
                columnDefinition.formatParameter = 2;
              } else if (columnType === 'date') {
                columnDefinition.formatFunction = function (value) {
                  if (value) {
                    return value.format("DD/MM/YY");
                  }
                  return value;
                };
              } else if (columnType === 'datetime') {
                columnDefinition.formatFunction = function (value) {
                  if (value) {
                    return value.format("DD/MM/YY HH:mm");
                  }
                  return value;
                };
              } else {
                columnDefinition.formatFunction = function (value) {
                  if (angular.isString(value)) {
                    value = $filter('linkify')(value);
                  }
                  return value;
                }
              }

              return columnDefinition;
            });
          }
        });
      }]
    }
  })
}());<commit_msg>when the value is false, display false instead of empty cell<commit_after>(function () {
  var tableVisualization = angular.module('redash.visualization');

  tableVisualization.config(['VisualizationProvider', function (VisualizationProvider) {
    VisualizationProvider.registerVisualization({
      type: 'TABLE',
      name: 'Table',
      renderTemplate: '<grid-renderer options="visualization.options" query-result="queryResult"></grid-renderer>',
      skipTypes: true
    });
  }]);

  tableVisualization.directive('gridRenderer', function () {
    return {
      restrict: 'E',
      scope: {
        queryResult: '=',
        itemsPerPage: '='
      },
      templateUrl: "/views/grid_renderer.html",
      replace: false,
      controller: ['$scope', '$filter', function ($scope, $filter) {
        $scope.gridColumns = [];
        $scope.gridData = [];
        $scope.gridConfig = {
          isPaginationEnabled: true,
          itemsByPage: $scope.itemsPerPage || 15,
          maxSize: 8
        };

        $scope.$watch('queryResult && queryResult.getData()', function (data) {
          if (!data) {
            return;
          }

          if ($scope.queryResult.getData() == null) {
            $scope.gridColumns = [];
            $scope.gridData = [];
            $scope.filters = [];
          } else {
            $scope.filters = $scope.queryResult.getFilters();

            var prepareGridData = function (data) {
              var gridData = _.map(data, function (row) {
                var newRow = {};
                _.each(row, function (val, key) {
                  newRow[$scope.queryResult.getColumnCleanName(key)] = val;
                })
                return newRow;
              });

              return gridData;
            };

            $scope.gridData = prepareGridData($scope.queryResult.getData());

            var columns = $scope.queryResult.getColumns();
            $scope.gridColumns = _.map($scope.queryResult.getColumnCleanNames(), function (col, i) {
              var columnDefinition = {
                'label': $scope.queryResult.getColumnFriendlyNames()[i],
                'map': col
              };

              var columnType = columns[i].type;

              if (!columnType) {
                var rawData = $scope.queryResult.getRawData();

                if (rawData.length > 0) {
                  var exampleData = rawData[0][col];
                  if (angular.isNumber(exampleData)) {
                    columnType = 'float';
                  } else if (moment.isMoment(exampleData)) {
                    if (exampleData._i.match(/^\d{4}-\d{2}-\d{2}T/)) {
                      columnType = 'datetime';
                    } else {
                      columnType = 'date';
                    }
                  }
                }
              }

              if (columnType === 'integer') {
                columnDefinition.formatFunction = 'number';
                columnDefinition.formatParameter = 0;
              } else if (columnType === 'float') {
                columnDefinition.formatFunction = 'number';
                columnDefinition.formatParameter = 2;
              } else if (columnType === 'boolean') {
                columnDefinition.formatFunction = function (value) {
                  if (value !== undefined) {
                    return "" + value;
                  }
                  return value;
                };
              } else if (columnType === 'date') {
                columnDefinition.formatFunction = function (value) {
                  if (value) {
                    return value.format("DD/MM/YY");
                  }
                  return value;
                };
              } else if (columnType === 'datetime') {
                columnDefinition.formatFunction = function (value) {
                  if (value) {
                    return value.format("DD/MM/YY HH:mm");
                  }
                  return value;
                };
              } else {
                columnDefinition.formatFunction = function (value) {
                  if (angular.isString(value)) {
                    value = $filter('linkify')(value);
                  }
                  return value;
                }
              }

              return columnDefinition;
            });
          }
        });
      }]
    }
  })
}());<|endoftext|>


<commit_before>'use strict';

const mixins = require('../lib/mixins');
const utils = require('../lib/utils');

const DUPLICATE = { status: 200, body: true };
const NOT_DUPLICATE = { status: 200, body: false };

class Deduplicator extends mixins.mix(Object).with(mixins.Redis) {
    constructor(options) {
        super(options);

        this._options = options || {};
        this._expire_timeout = options.window || 86400;
        this._prefix = this._options.redis_prefix || 'CP';
    }

    /**
     * Checks whether the message is a duplicate
     * @param {HyperSwitch} hyper
     * @param {Object} req
     * @return {Promise} response status shows whether it's a duplicate or not.
     */
    checkDuplicate(hyper, req) {
        const name = req.params.name;
        const message = req.body;

        // First, look at the individual event duplication based on ID
        // This happens when we restart ChangeProp and reread some of the
        // exact same events which were executed but was not committed.
        const messageKey = `${this._prefix}_dedupe_${name}_${message.meta.id}`;
        return this._redis.setnxAsync(messageKey, '1')
        // Expire the key or renew the expiration timestamp if the key existed
        .tap(() => this._redis.expireAsync(messageKey, Math.ceil(this._expire_timeout / 24)))
        // If that key already existed - that means it's a duplicate
        .then((setResult) => {
            if (setResult) {
                return NOT_DUPLICATE;
            }
            hyper.metrics.increment(`${name}_dedupe`);
            hyper.logger.log('trace/dedupe', () => ({
                message: 'Event was deduplicated based on id',
                event_str: utils.stringify(message)
            }));
            return DUPLICATE;
        })
        .then((individualDuplicate) => {
            if (individualDuplicate.body || !message.sha1) {
                // If the message was deduped based on its event ID or if it has no SHA-1 hash,
                // don't try to deduplicate by SHA-1
                return individualDuplicate;
            }
            const messageKey = `${this._prefix}_dedupe_${name}_${message.sha1}`;
            return this._redis.getAsync(messageKey)
            .then((previousExecutionTime) => {
                // If the same event (by sha1) was created before the previous execution
                // time, the changes that caused it were already in the database, so it
                // will be a no-op and can be deduplicated.
                if (previousExecutionTime &&
                        // Give that the resolution of the event dt is 1 second, this could
                        // be false-positive when the job queue is so quick that it executes
                        // two jobs with the same SHA1 within a single second. To be on the safe
                        // side - subtract 1 second from the previous execution time to allow for
                        // some lag.
                        new Date(previousExecutionTime) - 1000 > new Date(message.meta.dt)) {
                    hyper.metrics.increment(`${name}_dedupe`);
                    hyper.logger.log('trace/dedupe', () => ({
                        message: 'Event was deduplicated based on sha1',
                        event_str: utils.stringify(message),
                        newer_dt: previousExecutionTime
                    }));
                    return DUPLICATE;
                }
                // If the root event was created before the previous exec time for the same
                // leaf event - we can deduplicate cause by the time of the prev execution
                // the template (root_event source) changes were already in the database.
                if (previousExecutionTime &&
                        message.root_event &&
                        new Date(previousExecutionTime) - 1000 >
                            new Date(message.root_event.dt)) {
                    hyper.metrics.increment(`${name}_dedupe`);
                    hyper.logger.log('trace/dedupe', () => ({
                        message: 'Event was deduplicated based on sha1 and root_event dt',
                        event_str: utils.stringify(message),
                        newer_dt: previousExecutionTime
                    }));
                    return DUPLICATE;
                }
                return this._redis.setAsync(messageKey, new Date().toISOString())
                .then(() => this._redis.expireAsync(messageKey,
                    Math.ceil(this._expire_timeout / 24)))
                .thenReturn(NOT_DUPLICATE);
            });
        })
        .then((sha1Duplicate) => {
            if (sha1Duplicate.body || !message.root_event) {
                // If the message was sha1-deduped or if it has no root event info,
                // don't use deduplication by the root event
                return sha1Duplicate;
            }

            const rootEventKey = `${this._prefix}_dedupe_${name}_${message.root_event.signature}`;
            return this._redis.getAsync(rootEventKey)
            .then((oldEventTimestamp) => {
                // If this event was caused by root event and there was a leaf event executed
                // already that belonged to a later root_event we can cut off this chain.
                if (oldEventTimestamp &&
                        new Date(oldEventTimestamp) > new Date(message.root_event.dt)) {
                    hyper.metrics.increment(`${name}_dedupe`);
                    hyper.logger.log('trace/dedupe', () => ({
                        message: 'Event was deduplicated based on root event',
                        event_str: utils.stringify(message),
                        signature: message.root_event.signature,
                        newer_dt: oldEventTimestamp
                    }));
                    return DUPLICATE;
                }
                return this._redis.setAsync(rootEventKey, message.root_event.dt)
                .then(() => this._redis.expireAsync(rootEventKey, this._expire_timeout))
                .thenReturn(NOT_DUPLICATE);
            });
        })
        .catch((e) => {
            hyper.logger.log('error/dedupe', {
                message: 'Error during deduplication',
                err_str: e.toString()
            });
            return NOT_DUPLICATE;
        });
    }
}

module.exports = (options) => {
    const ps = new Deduplicator(options);

    return {
        spec: {
            paths: {
                '/{name}': {
                    post: {
                        operationId: 'checkDuplicate'
                    }
                }
            }
        },
        operations: {
            checkDuplicate: ps.checkDuplicate.bind(ps)
        }
    };
};
<commit_msg>Take job domain into account when deduplicating.<commit_after>'use strict';

const mixins = require('../lib/mixins');
const utils = require('../lib/utils');

const DUPLICATE = { status: 200, body: true };
const NOT_DUPLICATE = { status: 200, body: false };

class Deduplicator extends mixins.mix(Object).with(mixins.Redis) {
    constructor(options) {
        super(options);

        this._options = options || {};
        this._expire_timeout = options.window || 86400;
        this._prefix = this._options.redis_prefix || 'CP';
    }

    /**
     * Checks whether the message is a duplicate
     * @param {HyperSwitch} hyper
     * @param {Object} req
     * @return {Promise} response status shows whether it's a duplicate or not.
     */
    checkDuplicate(hyper, req) {
        const name = req.params.name;
        const message = req.body;
        const prefix = `${this._prefix}_dedupe_${name}`;

        // First, look at the individual event duplication based on ID
        // This happens when we restart ChangeProp and reread some of the
        // exact same events which were executed but was not committed.
        const messageKey = `${prefix}_${message.meta.domain}_${message.meta.id}`;
        return this._redis.setnxAsync(messageKey, '1')
        // Expire the key or renew the expiration timestamp if the key existed
        .tap(() => this._redis.expireAsync(messageKey, Math.ceil(this._expire_timeout / 24)))
        // If that key already existed - that means it's a duplicate
        .then((setResult) => {
            if (setResult) {
                return NOT_DUPLICATE;
            }
            hyper.metrics.increment(`${name}_dedupe`);
            hyper.logger.log('trace/dedupe', () => ({
                message: 'Event was deduplicated based on id',
                event_str: utils.stringify(message)
            }));
            return DUPLICATE;
        })
        .then((individualDuplicate) => {
            if (individualDuplicate.body || !message.sha1) {
                // If the message was deduped based on its event ID or if it has no SHA-1 hash,
                // don't try to deduplicate by SHA-1
                return individualDuplicate;
            }
            const messageKey = `${prefix}_${message.meta.domain}_${message.sha1}`;
            return this._redis.getAsync(messageKey)
            .then((previousExecutionTime) => {
                // If the same event (by sha1) was created before the previous execution
                // time, the changes that caused it were already in the database, so it
                // will be a no-op and can be deduplicated.
                if (previousExecutionTime &&
                        // Give that the resolution of the event dt is 1 second, this could
                        // be false-positive when the job queue is so quick that it executes
                        // two jobs with the same SHA1 within a single second. To be on the safe
                        // side - subtract 1 second from the previous execution time to allow for
                        // some lag.
                        new Date(previousExecutionTime) - 1000 > new Date(message.meta.dt)) {
                    hyper.metrics.increment(`${name}_dedupe`);
                    hyper.logger.log('trace/dedupe', () => ({
                        message: 'Event was deduplicated based on sha1',
                        event_str: utils.stringify(message),
                        newer_dt: previousExecutionTime
                    }));
                    return DUPLICATE;
                }
                // If the root event was created before the previous exec time for the same
                // leaf event - we can deduplicate cause by the time of the prev execution
                // the template (root_event source) changes were already in the database.
                if (previousExecutionTime &&
                        message.root_event &&
                        new Date(previousExecutionTime) - 1000 >
                            new Date(message.root_event.dt)) {
                    hyper.metrics.increment(`${name}_dedupe`);
                    hyper.logger.log('trace/dedupe', () => ({
                        message: 'Event was deduplicated based on sha1 and root_event dt',
                        event_str: utils.stringify(message),
                        newer_dt: previousExecutionTime
                    }));
                    return DUPLICATE;
                }
                return this._redis.setAsync(messageKey, new Date().toISOString())
                .then(() => this._redis.expireAsync(messageKey,
                    Math.ceil(this._expire_timeout / 24)))
                .thenReturn(NOT_DUPLICATE);
            });
        })
        .then((sha1Duplicate) => {
            if (sha1Duplicate.body || !message.root_event) {
                // If the message was sha1-deduped or if it has no root event info,
                // don't use deduplication by the root event
                return sha1Duplicate;
            }

            const rootEventKey = `${prefix}_${message.root_event.signature}`;
            return this._redis.getAsync(rootEventKey)
            .then((oldEventTimestamp) => {
                // If this event was caused by root event and there was a leaf event executed
                // already that belonged to a later root_event we can cut off this chain.
                if (oldEventTimestamp &&
                        new Date(oldEventTimestamp) > new Date(message.root_event.dt)) {
                    hyper.metrics.increment(`${name}_dedupe`);
                    hyper.logger.log('trace/dedupe', () => ({
                        message: 'Event was deduplicated based on root event',
                        event_str: utils.stringify(message),
                        signature: message.root_event.signature,
                        newer_dt: oldEventTimestamp
                    }));
                    return DUPLICATE;
                }
                return this._redis.setAsync(rootEventKey, message.root_event.dt)
                .then(() => this._redis.expireAsync(rootEventKey, this._expire_timeout))
                .thenReturn(NOT_DUPLICATE);
            });
        })
        .catch((e) => {
            hyper.logger.log('error/dedupe', {
                message: 'Error during deduplication',
                err_str: e.toString()
            });
            return NOT_DUPLICATE;
        });
    }
}

module.exports = (options) => {
    const ps = new Deduplicator(options);

    return {
        spec: {
            paths: {
                '/{name}': {
                    post: {
                        operationId: 'checkDuplicate'
                    }
                }
            }
        },
        operations: {
            checkDuplicate: ps.checkDuplicate.bind(ps)
        }
    };
};
<|endoftext|>


<commit_before>var wsUri = "";
var output;

function set_ws_uri(){
    var scheme   = "ws://";
    wsUri =  scheme + window.document.location.host + "/socket"
}

function init()
{
    output = document.getElementById("output");
    set_ws_uri();
    testWebSocket();

}

function testWebSocket()
{

    websocket = new WebSocket(wsUri);
    websocket.onopen = function(evt) { onOpen(evt) };
    websocket.onclose = function(evt) { onClose(evt) };
    websocket.onmessage = function(evt) { onMessage(evt) };
    websocket.onerror = function(evt) { onError(evt) };
}

function onOpen(evt)
{
    //writeToScreen("CONNECTED");
    doSend(current_cell);
}

function onClose(evt)
{
    //writeToScreen("DISCONNECTED");
}

function onMessage(evt)
{
    current_matrix = evt.data;
    //writeToScreen('RESPONSE: ' + evt.data+'');
    websocket.close();
    showMatrix();
}

function onError(evt)
{
    writeToScreen('ERROR: ' + evt.data);
}

function doSend(message)
{
    //writeToScreen("SENT: " + message);
    websocket.send(message);
}

function writeToScreen(message)
{
    var pre = document.createElement("p");
    pre.style.wordWrap = "break-word";
    pre.innerHTML = message;
    output.appendChild(pre);
}

//window.addEventListener("load", init, false);
//window.addEventListener("click", init, false);
//window.addEventListener("click", function(){ alert("Hello World!"); });<commit_msg>Fix JavaScript<commit_after>var wsUri = "";
var output;

function set_ws_uri(){
    var scheme   = "wss://";
    wsUri =  scheme + window.document.location.host + "/socket"
}

function init()
{
    output = document.getElementById("output");
    set_ws_uri();
    testWebSocket();

}

function testWebSocket()
{

    websocket = new WebSocket(wsUri);
    websocket.onopen = function(evt) { onOpen(evt) };
    websocket.onclose = function(evt) { onClose(evt) };
    websocket.onmessage = function(evt) { onMessage(evt) };
    websocket.onerror = function(evt) { onError(evt) };
}

function onOpen(evt)
{
    //writeToScreen("CONNECTED");
    doSend(current_cell);
}

function onClose(evt)
{
    //writeToScreen("DISCONNECTED");
}

function onMessage(evt)
{
    current_matrix = evt.data;
    //writeToScreen('RESPONSE: ' + evt.data+'');
    websocket.close();
    showMatrix();
}

function onError(evt)
{
    writeToScreen('ERROR: ' + evt.data);
}

function doSend(message)
{
    //writeToScreen("SENT: " + message);
    websocket.send(message);
}

function writeToScreen(message)
{
    var pre = document.createElement("p");
    pre.style.wordWrap = "break-word";
    pre.innerHTML = message;
    output.appendChild(pre);
}

//window.addEventListener("load", init, false);
//window.addEventListener("click", init, false);
//window.addEventListener("click", function(){ alert("Hello World!"); });<|endoftext|>