<commit_before>// Prevent double lazyload script on same page
// We NEED to use string as closure compiler would otherwise compile this statement badly
if (!window['Lazyload']) {
  (function(window, document){

    var pageHasLoaded = false;

    // retro compatibility old lazyload
    // will automatically create an instance at first lzld call
    window['lzld'] = (function() {
      var instance;
      return function() {
        if (instance === undefined) instance = new Lazyload;
        instance['lzld'].apply(instance, arguments)
      }
    }());

    window['Lazyload'] = Lazyload;

    addEvent(window, 'load', function onLoadFired() {
      pageHasLoaded = true;
    });

    /**
     * A new lazyloader, watching the whole window right now
     * @constructor
     * @param {Object=} opts Provide offset or lazyAttr or none
     */
    function Lazyload(opts) {
      this.opts = merge({
        offset: 200,
        lazyAttr: 'data-src'
      }, opts || {});

      this.imgs = [];
      this.listening = false;
      this.showImagesT = throttle(bind(this.showImages, this), 20);

      // init
      if (this.opts['container'] === document) {
        this.scrollContainer = window;
        domready(bind(this.setBodyContainer, this));
      } else {
        this.scrollContainer = this.opts['container'];
      }

      domready(bind(this.findImages, this));
      domready(bind(this.showImages, this));

      setTimeout(this.showImagesT, 25);

      addEvent(window, 'load', this.showImagesT);

      // Ok, cannot use setTimeout.apply in IE7/8 LOL, you don't wanna know why, wait 3 years
      // http://stackoverflow.com/questions/11619826/internet-explorer-7-8-and-window-functions-are-empty-objects
      addEvent(window, 'load', bind(function() {
        setTimeout(this.showImagesT, 25);
      }, this));

      // Bind events
      this.subscribe();

      this['lzld'] = bind(this.onDataSrcImgLoad, this);

      // Override image element .getAttribute globally so that we give the real src
      // does not works for ie < 8: http://perfectionkills.com/whats-wrong-with-extending-the-dom/
      // Internet Explorer 7 (and below) [...] does not expose global Node, Element, HTMLElement, HTMLParagraphElement
      if ('HTMLImageElement' in window) {
        this.replaceGetAttribute();
      }
    }

    Lazyload.prototype.replaceGetAttribute = function replaceGetAttribute() {
      var original = HTMLImageElement.prototype.getAttribute;
      var lazyload = this;
      HTMLImageElement.prototype.getAttribute = function(name) {
        if(name === 'src') {
          var realSrc = original.call(this, lazyload.opts.lazyAttr);
          return realSrc || original.call(this, name);
        } else {
          // our own lazyloader will go through theses lines
          // because we use getAttribute(opts.lazyAttr)
          return original.call(this, name);
        }
      }
    }

    // document.body is not available when Lazyload is in the <head> of the document
    // so fix it as asap: domready or first onload= event
    Lazyload.prototype.setBodyContainer = function setBodyContainer() {
      this.opts['container'] = document.body;
    }

    // called by img onload= or onerror= for IE6/7
    Lazyload.prototype.onDataSrcImgLoad = function onDataSrcImgLoad(img) {
      if (this.opts['container'] === document) {
        this.setBodyContainer();
      }
      // if image is not already in the imgs array
      // it can already be in it if domready was fast and img onload slow

      // For the first image of the stack, it is possible we already shown it
      // But we still got the onload event
      if (img.getAttribute(this.opts['lazyAttr']) === null) {
        return;
      }

      if (indexOf.call(this.imgs, img) === -1) {
        // this case happens when the page had loaded but we inserted more lazyload images with
        // javascript (ajax). We need to re-watch scroll/resize
        if (!this.listening) {
          this.subscribe();
        }
        this.showIfVisible(img, this.imgs.push(img) - 1);
      }
    }

    // find and merge images on domready with possibly already present onload= onerror= imgs
    Lazyload.prototype.findImages = function findImages() {
      var
        domreadyImgs = document.getElementsByTagName('img'),
        currentImg;

      // merge them with already self onload registered imgs
      for (var imgIndex = 0, max = domreadyImgs.length; imgIndex < max; imgIndex += 1) {
        currentImg = domreadyImgs[imgIndex];
        if (currentImg.getAttribute(this.opts.lazyAttr) && indexOf.call(this.imgs, currentImg) === -1) {
          this.imgs.push(currentImg);
        }
      }
    }

    // img = dom element
    // index = imgs array index
    Lazyload.prototype.showIfVisible = function showIfVisible(img, index) {
      // We have to check that the current node is in the DOM
      // It could be a detached() dom node
      // http://bugs.jquery.com/ticket/4996
      if (contains(document.documentElement, img)
        && hasScrolled(this.opts['container'], img, this.opts['offset'])) {
        // To avoid onload loop calls
        // removeAttribute on IE is not enough to prevent the event to fire
        img.onload = null;
        img.removeAttribute('onload');

        // on IE < 8 we get an onerror event instead of an onload event
        img.onerror = null;
        img.removeAttribute('onerror');

        img.src = img.getAttribute(this.opts.lazyAttr);
        img.removeAttribute(this.opts.lazyAttr);
        this.imgs[index] = null;

        return true; // img shown
      } else {
        return false; // img to be shown
      }
    }

    // Loop through an images array to find to-be-shown images
    Lazyload.prototype.showImages = function showImages() {
      var
        last = this.imgs.length,
        current,
        allImagesDone = true;

      for (current = 0; current < last; current++) {
        var img = this.imgs[current];
        // if showIfVisible is false, it means we have some waiting images to be
        // shown
        if(img !== null && !this.showIfVisible(img, current)) {
          allImagesDone = false;
        }
      }

      if (allImagesDone && pageHasLoaded) {
        this.unsubscribe();
      }
    }

    Lazyload.prototype.unsubscribe = function unsubscribe() {
      removeEvent(this.scrollContainer, 'scroll', this.showImagesT);
      this.listening = false;
      this.imgs = [];
    }

    Lazyload.prototype.subscribe = function subscribe() {
      addEvent(this.scrollContainer, 'scroll', this.showImagesT);
      this.listening = true;
    }

    /* Lazyload utility belt *\!/* SHINY *\!/* */
    function bind (method, context){
      return function(){
        method.apply(context, arguments);
      }
    }

    function merge(defaults, opts) {
      for (var name in defaults) {
        if (opts[name] === undefined) {
          opts[name] = defaults[name];
        }
      }

      return opts;
    }

    function throttle(fn, minDelay) {
      var lastCall = 0;
      return function() {
        var now = +new Date();
        if (now - lastCall < minDelay) {
          return;
        }
        lastCall = now;
        // we do not return anything as
        // https://github.com/documentcloud/underscore/issues/387
        fn.apply(this, arguments);
      }
    }

    // X-browser
    function addEvent( el, type, fn ) {
      if (el.attachEvent) {
        el.attachEvent && el.attachEvent( 'on' + type, fn );
      } else {
        el.addEventListener( type, fn, false );
      }
    }

    // X-browser
    function removeEvent( el, type, fn ) {
      if (el.detachEvent) {
        el.detachEvent && el.detachEvent( 'on' + type, fn );
      } else {
        el.removeEventListener( type, fn, false );
      }
    }

    // custom domready function
    // ripped from https://github.com/dperini/ContentLoaded/blob/master/src/contentloaded.js
    // http://javascript.nwbox.com/ContentLoaded/
    // http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE
    // kept the inner logic, merged with our helpers/variables
    function domready(callback) {
      var
        done = false,
        top = true;

      function init(e) {
        if (e.type === 'readystatechange' && document.readyState !== 'complete') return;
        removeEvent((e.type === 'load' ? window : document), e.type, init);
        if (!done) {
          done = true;
          callback();
        }
      }

      function poll() {
        try { document.documentElement.doScroll('left'); } catch(e) { setTimeout(poll, 50); return; }
        init('poll');
      }

      if (document.readyState === 'complete') callback();
      else {
        if (document.createEventObject && document.documentElement.doScroll) {
          try { top = !window.frameElement; } catch(e) { }
          if (top) poll();
        }
        addEvent(document, 'DOMContentLoaded', init);
        addEvent(document, 'readystatechange', init);
        addEvent(window, 'load', init);
      }

    }

    function hasScrolled(container, element, offset) {
      // when no offset given, default to plaholder height or width
      // it means you should set your width= height=
      if (!offset) offset = Math.max(element.clientHeight, element.clientWidth);

      var rect = element.getBoundingClientRect();
      var pos = {
        x: rect.left - offset,
        y: rect.top - offset
      }
      var viewport = {
        x: 0,
        y: 0
      }

      if (container === document.body) {
        viewport.x += document.documentElement.clientWidth;
        viewport.y += document.documentElement.clientHeight;
      } else {
        pos.x += scrollOffset().x;
        pos.y += scrollOffset().y;
        viewport.x += container.clientWidth;
        viewport.y += container.clientHeight;
      }

      return pos.y <= viewport.y && pos.x <= viewport.x;
    }

    function scrollOffset() {
      return {
        x: Math.max(window.pageXOffset || 0, document.body.scrollLeft, document.documentElement.scrollLeft),
        y: Math.max(window.pageYOffset || 0, document.body.scrollTop, document.documentElement.scrollTop)
      }
    }

    // https://github.com/jquery/sizzle/blob/3136f48b90e3edc84cbaaa6f6f7734ef03775a07/sizzle.js#L708
    var contains = document.documentElement.compareDocumentPosition ?
      function( a, b ) {
        return !!(a.compareDocumentPosition( b ) & 16);
      } :
      document.documentElement.contains ?
      function( a, b ) {
        return a !== b && ( a.contains ? a.contains( b ) : false );
      } :
      function( a, b ) {
        while ( (b = b.parentNode) ) {
          if ( b === a ) {
            return true;
          }
        }
        return false;
      };

    // as suggested by http://webreflection.blogspot.fr/2011/06/partial-polyfills.html
    var indexOf = [].indexOf || function (value) {
        for (var i = this.length; i-- && this[i] !== value;);
        return i;
    };

  }(this, document))
}
<commit_msg>Export params so that they won't get mangled by closure compiler<commit_after>// Prevent double lazyload script on same page
// We NEED to use string as closure compiler would otherwise compile this statement badly
if (!window['Lazyload']) {
  (function(window, document){

    var pageHasLoaded = false;

    // retro compatibility old lazyload
    // will automatically create an instance at first lzld call
    window['lzld'] = (function() {
      var instance;
      return function() {
        if (instance === undefined) instance = new Lazyload;
        instance['lzld'].apply(instance, arguments)
      }
    }());

    window['Lazyload'] = Lazyload;

    addEvent(window, 'load', function onLoadFired() {
      pageHasLoaded = true;
    });

    /**
     * Lazyload, defer image loading to visible images
     * @constructor
     * @param {Object=} opts Provide offset, lazyAttr, container or none
     */
    function Lazyload(opts) {
      this.opts = merge({
        'offset': 200,
        'lazyAttr': 'data-src',
        'container': document
      }, opts || {});

      this.imgs = [];
      this.listening = false;
      this.showImagesT = throttle(bind(this.showImages, this), 20);

      // init
      if (this.opts['container'] === document) {
        this.scrollContainer = window;
        domready(bind(this.setBodyContainer, this));
      } else {
        this.scrollContainer = this.opts['container'];
      }

      domready(bind(this.findImages, this));
      domready(bind(this.showImages, this));

      setTimeout(this.showImagesT, 25);

      addEvent(window, 'load', this.showImagesT);

      // Ok, cannot use setTimeout.apply in IE7/8 LOL, you don't wanna know why, wait 3 years
      // http://stackoverflow.com/questions/11619826/internet-explorer-7-8-and-window-functions-are-empty-objects
      addEvent(window, 'load', bind(function() {
        setTimeout(this.showImagesT, 25);
      }, this));

      // Bind events
      this.subscribe();

      this['lzld'] = bind(this.onDataSrcImgLoad, this);

      // Override image element .getAttribute globally so that we give the real src
      // does not works for ie < 8: http://perfectionkills.com/whats-wrong-with-extending-the-dom/
      // Internet Explorer 7 (and below) [...] does not expose global Node, Element, HTMLElement, HTMLParagraphElement
      if ('HTMLImageElement' in window) {
        this.replaceGetAttribute();
      }
    }

    Lazyload.prototype.replaceGetAttribute = function replaceGetAttribute() {
      var original = HTMLImageElement.prototype.getAttribute;
      var lazyload = this;
      HTMLImageElement.prototype.getAttribute = function(name) {
        if(name === 'src') {
          var realSrc = original.call(this, lazyload.opts.lazyAttr);
          return realSrc || original.call(this, name);
        } else {
          // our own lazyloader will go through theses lines
          // because we use getAttribute(opts.lazyAttr)
          return original.call(this, name);
        }
      }
    }

    // document.body is not available when Lazyload is in the <head> of the document
    // so fix it as asap: domready or first onload= event
    Lazyload.prototype.setBodyContainer = function setBodyContainer() {
      this.opts['container'] = document.body;
    }

    // called by img onload= or onerror= for IE6/7
    Lazyload.prototype.onDataSrcImgLoad = function onDataSrcImgLoad(img) {
      if (this.opts['container'] === document) {
        this.setBodyContainer();
      }
      // if image is not already in the imgs array
      // it can already be in it if domready was fast and img onload slow

      // For the first image of the stack, it is possible we already shown it
      // But we still got the onload event
      if (img.getAttribute(this.opts['lazyAttr']) === null) {
        return;
      }

      if (indexOf.call(this.imgs, img) === -1) {
        // this case happens when the page had loaded but we inserted more lazyload images with
        // javascript (ajax). We need to re-watch scroll/resize
        if (!this.listening) {
          this.subscribe();
        }
        this.showIfVisible(img, this.imgs.push(img) - 1);
      }
    }

    // find and merge images on domready with possibly already present onload= onerror= imgs
    Lazyload.prototype.findImages = function findImages() {
      var
        domreadyImgs = document.getElementsByTagName('img'),
        currentImg;

      // merge them with already self onload registered imgs
      for (var imgIndex = 0, max = domreadyImgs.length; imgIndex < max; imgIndex += 1) {
        currentImg = domreadyImgs[imgIndex];
        if (currentImg.getAttribute(this.opts['lazyAttr']) && indexOf.call(this.imgs, currentImg) === -1) {
          this.imgs.push(currentImg);
        }
      }
    }

    // img = dom element
    // index = imgs array index
    Lazyload.prototype.showIfVisible = function showIfVisible(img, index) {
      // We have to check that the current node is in the DOM
      // It could be a detached() dom node
      // http://bugs.jquery.com/ticket/4996
      if (contains(document.documentElement, img)
        && hasScrolled(this.opts['container'], img, this.opts['offset'])) {
        // To avoid onload loop calls
        // removeAttribute on IE is not enough to prevent the event to fire
        img.onload = null;
        img.removeAttribute('onload');

        // on IE < 8 we get an onerror event instead of an onload event
        img.onerror = null;
        img.removeAttribute('onerror');

        img.src = img.getAttribute(this.opts['lazyAttr']);
        img.removeAttribute(this.opts['lazyAttr']);
        this.imgs[index] = null;

        return true; // img shown
      } else {
        return false; // img to be shown
      }
    }

    // Loop through an images array to find to-be-shown images
    Lazyload.prototype.showImages = function showImages() {
      var
        last = this.imgs.length,
        current,
        allImagesDone = true;

      for (current = 0; current < last; current++) {
        var img = this.imgs[current];
        // if showIfVisible is false, it means we have some waiting images to be
        // shown
        if(img !== null && !this.showIfVisible(img, current)) {
          allImagesDone = false;
        }
      }

      if (allImagesDone && pageHasLoaded) {
        this.unsubscribe();
      }
    }

    Lazyload.prototype.unsubscribe = function unsubscribe() {
      removeEvent(this.scrollContainer, 'scroll', this.showImagesT);
      this.listening = false;
      this.imgs = [];
    }

    Lazyload.prototype.subscribe = function subscribe() {
      addEvent(this.scrollContainer, 'scroll', this.showImagesT);
      this.listening = true;
    }

    /* Lazyload utility belt *\!/* SHINY *\!/* */
    function bind (method, context){
      return function(){
        method.apply(context, arguments);
      }
    }

    function merge(defaults, opts) {
      for (var name in defaults) {
        if (opts[name] === undefined) {
          opts[name] = defaults[name];
        }
      }

      return opts;
    }

    function throttle(fn, minDelay) {
      var lastCall = 0;
      return function() {
        var now = +new Date();
        if (now - lastCall < minDelay) {
          return;
        }
        lastCall = now;
        // we do not return anything as
        // https://github.com/documentcloud/underscore/issues/387
        fn.apply(this, arguments);
      }
    }

    // X-browser
    function addEvent( el, type, fn ) {
      if (el.attachEvent) {
        el.attachEvent && el.attachEvent( 'on' + type, fn );
      } else {
        el.addEventListener( type, fn, false );
      }
    }

    // X-browser
    function removeEvent( el, type, fn ) {
      if (el.detachEvent) {
        el.detachEvent && el.detachEvent( 'on' + type, fn );
      } else {
        el.removeEventListener( type, fn, false );
      }
    }

    // custom domready function
    // ripped from https://github.com/dperini/ContentLoaded/blob/master/src/contentloaded.js
    // http://javascript.nwbox.com/ContentLoaded/
    // http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE
    // kept the inner logic, merged with our helpers/variables
    function domready(callback) {
      var
        done = false,
        top = true;

      function init(e) {
        if (e.type === 'readystatechange' && document.readyState !== 'complete') return;
        removeEvent((e.type === 'load' ? window : document), e.type, init);
        if (!done) {
          done = true;
          callback();
        }
      }

      function poll() {
        try { document.documentElement.doScroll('left'); } catch(e) { setTimeout(poll, 50); return; }
        init('poll');
      }

      if (document.readyState === 'complete') callback();
      else {
        if (document.createEventObject && document.documentElement.doScroll) {
          try { top = !window.frameElement; } catch(e) { }
          if (top) poll();
        }
        addEvent(document, 'DOMContentLoaded', init);
        addEvent(document, 'readystatechange', init);
        addEvent(window, 'load', init);
      }

    }

    function hasScrolled(container, element, offset) {
      // when no offset given, default to plaholder height or width
      // it means you should set your width= height=
      if (!offset) offset = Math.max(element.clientHeight, element.clientWidth);

      var rect = element.getBoundingClientRect();
      var pos = {
        x: rect.left - offset,
        y: rect.top - offset
      }
      var viewport = {
        x: 0,
        y: 0
      }

      if (container === document.body) {
        viewport.x += document.documentElement.clientWidth;
        viewport.y += document.documentElement.clientHeight;
      } else {
        pos.x += scrollOffset().x;
        pos.y += scrollOffset().y;
        viewport.x += container.clientWidth;
        viewport.y += container.clientHeight;
      }

      return pos.y <= viewport.y && pos.x <= viewport.x;
    }

    function scrollOffset() {
      return {
        x: Math.max(window.pageXOffset || 0, document.body.scrollLeft, document.documentElement.scrollLeft),
        y: Math.max(window.pageYOffset || 0, document.body.scrollTop, document.documentElement.scrollTop)
      }
    }

    // https://github.com/jquery/sizzle/blob/3136f48b90e3edc84cbaaa6f6f7734ef03775a07/sizzle.js#L708
    var contains = document.documentElement.compareDocumentPosition ?
      function( a, b ) {
        return !!(a.compareDocumentPosition( b ) & 16);
      } :
      document.documentElement.contains ?
      function( a, b ) {
        return a !== b && ( a.contains ? a.contains( b ) : false );
      } :
      function( a, b ) {
        while ( (b = b.parentNode) ) {
          if ( b === a ) {
            return true;
          }
        }
        return false;
      };

    // as suggested by http://webreflection.blogspot.fr/2011/06/partial-polyfills.html
    var indexOf = [].indexOf || function (value) {
        for (var i = this.length; i-- && this[i] !== value;);
        return i;
    };

  }(this, document))
}
<|endoftext|>


<commit_before>import angular from 'angular';
import ngModule from '../module';
import { uuid } from '../../core/utils';
import '../../core/validation';
import Base from '../base';

class AvValFieldController extends Base {

  static $inject = ['$element', 'avValAdapter', 'avVal', '$log', '$timeout', '$scope', '$attrs'];

  constructor(...args) {

    super(...args);

    this.ngModel = null;
    this.rule = null;
    this.avValForm = null;
    this.avValInvalid = false;
    this.noEvent = {};
    this.placeholder = this.av.$element[0].placeholder;

  }

  init(options) {
    Object.assign(this, options);
    this.createId();
    this.setupValidators();
  }

  createId() {
    this.ngModel.avId = uuid('avVal');
  }

  isRadio() {
    return this.av.$element.is('input') && this.av.$attrs.type === 'radio';
  }

  isCheckbox() {
    return this.av.$element.is('input') && this.av.$attrs.type === 'checkbox';
  }

  updateElement() {

    this.av.avValAdapter.element({
      element: this.av.$element,
      ngModel: this.ngModel
    });

    this.av.avValAdapter.message({
      element: this.av.$element,
      ngModel: this.ngModel
    });

  }

  setupValidators() {

    const self = this;

    const schemaName = this.avValForm.rulesSchema;
    const ruleConfig = this.av.avVal.getRule(schemaName);

    if (!ruleConfig) {
      this.av.$log.error(`Failed to get rules schema named [${schemaName}].  Forms must be tagged with a rules schema name for validation to work.`);
      return;
    }

    let constraints = ruleConfig[this.ruleName];
    if (!constraints) {
      this.av.$log.info(`Rule named [${this.ruleName}] could not be found in the current schema.`);
      constraints = {};
    }

    Object.keys(constraints).forEach(constraintName => {
      const constraint = constraints[constraintName];
      if (!constraint) {

        // When extending rule sets, previous rules can be overridden with null so
        // delete the previous $validator
        delete self.ngModel.$validators[constraintName];
        return;
      }

      const validator = self.av.avVal.getService(constraintName);

      if (angular.isUndefined(validator)) {
        self.av.$log.warn(`No validator defined for ${constraintName}`);
        return;
      }

      self.ngModel.$validators[constraintName] = function contraintValidator(modelValue, viewValue) {

        const value = modelValue || viewValue;

        const valid = validator.validate({
          value,
          constraint,
          element: self.av.$element
        });

        return valid;

      };

      // Attach the constrain to the validator so that the message is available
      // to the validation container that is going to paint the message on screen.
      self.ngModel.$validators[constraintName].constraint = constraint;

    });

  }

  reset() {
    this.ngModel.$setPristine();
    this.ngModel.$setUntouched();
    this.ngModel.$error = {};
    this.av.avValAdapter.reset(this.av.$element);
  }

  onRunValidators() {

    if (this.ngModel.$dirty) {
      this.updateElement();
    }

  }

}

ngModule.controller('AvValFieldController', AvValFieldController);

ngModule.directive('avValField', ($log, $timeout, avVal, avValAdapter, AV_VAL) => {
  return {
    restrict: 'A',
    controller: 'AvValFieldController',
    require: ['^avValForm', 'ngModel', 'avValField'],
    scope: {
      avValDebounce: '<?',
      avValOn: '<?',
      avValShowOnLoad: '<?',
      avValInvalid: '<?'
    },
    link(scope, element, attrs, controllers) {

      const ruleName = attrs.avValField;

      const avValForm = controllers[0];
      const ngModel = controllers[1];
      const avValField = controllers[2];

      const avValOn = scope.avValOn || avValForm.avValOn || 'default';

      let avValDebounce;
      if (avValField.isCheckbox() || avValField.isRadio()) {
        avValDebounce = scope.avValDebounce || avValForm.avValDebounce || AV_VAL.DEBOUNCE_QUICK;
      } else {
        avValDebounce = scope.avValDebounce || avValForm.avValDebounce || AV_VAL.DEBOUNCE;
      }

      const avValInvalid = scope.avValInvalid || avValForm.avValInvalid || false;

      ngModel.$$setOptions({
        updateOnDefault: true,
        updateOn: avValOn,
        allowInvalid: avValInvalid,
        debounce: avValDebounce
      });

      // Wrap $$runValidators with our own function so we can intercept when the validation
      // pipeline finishes.
      const $$runValidators = ngModel.$$runValidators;
      const runValidators = (modelValue, viewValue, doneCallback) => {

        $$runValidators(modelValue, viewValue, (allValid) => {
          doneCallback(allValid);
          avValField.onRunValidators();
        });

      };

      ngModel.$$runValidators = runValidators;

      if (!ngModel && !ruleName) {
        $log.error('avValField requires ngModel and a validation rule name to run.');
        return;
      }

      avValField.init({
        ngModel,
        ruleName,
        avValForm
      });

      scope.$on(AV_VAL.EVENTS.REVALIDATE, () => {
        ngModel.$validate();
      });

      scope.$on(AV_VAL.EVENTS.SUBMITTED, () => {
        ngModel.$dirty = true;
        ngModel.$validate();
      });

      // - Removes all errors on page,
      // - Does not reset view or model values.  This should to be handled by the application.
      scope.$on(AV_VAL.EVENTS.RESET, () => {
        avValField.reset();
      });

    }
  };
});
<commit_msg>remove extend from Base<commit_after>import angular from 'angular';

import ngModule from '../module';
import { uuid } from '../../core/utils';
import '../../core/validation';

class AvValFieldController {

  constructor($element, avValAdapter, avVal, $log, $timeout, $scope, $attrs) {

    this.av = { $element, avValAdapter, avVal, $log, $timeout, $scope, $attrs };

    this.ngModel = null;
    this.rule = null;
    this.avValForm = null;
    this.avValInvalid = false;
    this.noEvent = {};
    this.placeholder = this.av.$element[0].placeholder;

  }

  init(options) {
    Object.assign(this, options);
    this.createId();
    this.setupValidators();
  }

  createId() {
    this.ngModel.avId = uuid('avVal');
  }

  isRadio() {
    return this.av.$element.is('input') && this.av.$attrs.type === 'radio';
  }

  isCheckbox() {
    return this.av.$element.is('input') && this.av.$attrs.type === 'checkbox';
  }

  updateElement() {

    this.av.avValAdapter.element({
      element: this.av.$element,
      ngModel: this.ngModel
    });

    this.av.avValAdapter.message({
      element: this.av.$element,
      ngModel: this.ngModel
    });

  }

  setupValidators() {

    const self = this;

    const schemaName = this.avValForm.rulesSchema;
    const ruleConfig = this.av.avVal.getRule(schemaName);

    if (!ruleConfig) {
      this.av.$log.error(`Failed to get rules schema named [${schemaName}].  Forms must be tagged with a rules schema name for validation to work.`);
      return;
    }

    let constraints = ruleConfig[this.ruleName];
    if (!constraints) {
      this.av.$log.info(`Rule named [${this.ruleName}] could not be found in the current schema.`);
      constraints = {};
    }

    Object.keys(constraints).forEach(constraintName => {

      const constraint = constraints[constraintName];
      if (!constraint) {

        // When extending rule sets, previous rules can be overridden with null so
        // delete the previous $validator
        delete self.ngModel.$validators[constraintName];
        return;
      }

      const validator = self.av.avVal.getService(constraintName);

      if (angular.isUndefined(validator)) {
        self.av.$log.warn(`No validator defined for ${constraintName}`);
        return;
      }

      self.ngModel.$validators[constraintName] = function contraintValidator(modelValue, viewValue) {

        const value = modelValue || viewValue;

        const valid = validator.validate({
          value,
          constraint,
          element: self.av.$element
        });

        return valid;

      };

      // Attach the constraint to the validator so that the message is available
      // to the validation container that is going to paint the message on screen.
      self.ngModel.$validators[constraintName].constraint = constraint;

    });

  }

  reset() {
    this.ngModel.$setPristine();
    this.ngModel.$setUntouched();
    this.ngModel.$error = {};
    this.av.avValAdapter.reset(this.av.$element);
  }

  onRunValidators() {
    if (this.ngModel.$dirty) {
      this.updateElement();
    }
  }

}

ngModule.controller('AvValFieldController', AvValFieldController);

ngModule.directive('avValField', ($log, $timeout, avVal, avValAdapter, AV_VAL) => {
  return {
    restrict: 'A',
    controller: 'AvValFieldController',
    require: ['^avValForm', 'ngModel', 'avValField', '?^ngModelOptions'],
    link(scope, element, attrs, controllers) {

      const ruleName = attrs.avValField;

      const avValForm = controllers[0];
      const ngModel = controllers[1];
      const avValField = controllers[2];
      const ngModelOptions = controllers[3];

      if (ngModelOptions) {
        avValField.$options = ngModelOptions.$options;
      }

      const avValOn = scope.avValOn || avValForm.avValOn || 'default';

      let avValDebounce;
      if (avValField.isCheckbox() || avValField.isRadio()) {
        avValDebounce = scope.avValDebounce || avValForm.avValDebounce || AV_VAL.DEBOUNCE_QUICK;
      } else {
        avValDebounce = scope.avValDebounce || avValForm.avValDebounce || AV_VAL.DEBOUNCE;
      }

      const avValInvalid = scope.avValInvalid || avValForm.avValInvalid || false;

      // ngModel.$$setOptions({
      //   updateOnDefault: true,
      //   updateOn: avValOn,
      //   allowInvalid: avValInvalid,
      //   debounce: avValDebounce
      // });

      // if (modelCtrl.$options.getOption('updateOn')) {
      //   element.on(modelCtrl.$options.getOption('updateOn'), function(ev) {
      //     modelCtrl.$$debounceViewValueCommit(ev && ev.type);
      //   });
      // }

      // Wrap $$runValidators with our own function so we can intercept when the validation
      // pipeline finishes.
      // const $$runValidators = ngModel.$$runValidators;
      // const runValidators = (modelValue, viewValue, doneCallback) => {

      //   $$runValidators(modelValue, viewValue, (allValid) => {
      //     doneCallback(allValid);
      //     avValField.onRunValidators();
      //   });

      // };

      // ngModel.$$runValidators = runValidators;

      if (!ngModel && !ruleName) {
        $log.error('avValField requires ngModel and a validation rule name to run.');
        return;
      }

      avValField.init({
        ngModel,
        ruleName,
        avValForm
      });

      const reValidateOff = scope.$on(AV_VAL.EVENTS.REVALIDATE, () => {
        ngModel.$validate();
      });

      const submittedOff = scope.$on(AV_VAL.EVENTS.SUBMITTED, () => {
        ngModel.$dirty = true;
        ngModel.$validate();
      });

      // - Removes all errors on page,
      // - Does not reset view or model values.  This should to be handled by the application.
      const resetOff = scope.$on(AV_VAL.EVENTS.RESET, () => {
        avValField.reset();
      });

      scope.$on('$destroy', () => {
        reValidateOff();
        submittedOff();
        resetOff();
      });

    }
  };
});
<|endoftext|>


<commit_before>/**
 * Scale 9 Container.
 * e.g. useful for scalable buttons.
 *
 * @class ScaleContainer
 * @extends PIXI.Container
 * @memberof PIXI_UI
 * @constructor
 */

function ScaleContainer(texture, rect) {
    PIXI.Container.call( this );

    this.rect = rect;
    this.baseTexture = texture.baseTexture;
    this.frame = texture.frame;

    this._width = this.frame.width;
    this._height = this.frame.height;

    // left / middle / right width
    var lw = rect.x;
    var mw = rect.width;
    var rw = this.frame.width - (mw + lw);

    // top / center / bottom height
    var th = rect.y;
    var ch = rect.height;
    var bh = this.frame.height - (ch + th);

    // top
    if (lw > 0 && th > 0) {
        this.tl = this._getTexture(0, 0, lw, th);
        this.addChild(this.tl);
    }
    if (mw > 0 && th > 0) {
        this.tm = this._getTexture(lw, 0, mw, th);
        this.addChild(this.tm);
        this.tm.x = lw;
    }
    if (rw > 0 && th > 0) {
        this.tr = this._getTexture(lw + mw, 0, rw, th);
        this.addChild(this.tr);
    }

    // center
    if (lw > 0 && ch > 0) {
        this.cl = this._getTexture(0, th, lw, ch);
        this.addChild(this.cl);
        this.cl.y = th;
    }
    if (mw > 0 && ch > 0) {
        this.cm = this._getTexture(lw, th, mw, ch);
        this.addChild(this.cm);
        this.cm.y = th;
        this.cm.x = lw;
    }
    if (rw > 0 && ch > 0) {
        this.cr = this._getTexture(lw + mw, th, rw, ch);
        this.addChild(this.cr);
        this.cr.y = th;
    }

    // bottom
    if (lw > 0 && bh > 0) {
        this.bl = this._getTexture(0, th + ch, lw, bh);
        this.addChild(this.bl);
    }
    if (mw > 0 && bh > 0) {
        this.bm = this._getTexture(lw, th + ch, mw, bh);
        this.addChild(this.bm);
        this.bm.x = lw;
    }
    if (rw > 0 && bh > 0) {
        this.br = this._getTexture(lw + mw, th + ch, rw, bh);
        this.addChild(this.br);
    }
}

// constructor
ScaleContainer.prototype = Object.create( PIXI.Container.prototype );
ScaleContainer.prototype.constructor = ScaleContainer;
module.exports = ScaleContainer;

/**
 * create a new texture from a base-texture by given dimensions
 *
 * @method _getTexture
 * @private
 */
ScaleContainer.prototype._getTexture = function(x, y, w, h) {
    var frame = new PIXI.math.Rectangle(this.frame.x+x, this.frame.y+y, w, h);
    var t = new PIXI.Texture(this.baseTexture, frame, frame.clone(), null);
    return new PIXI.Sprite(t);
};

/**
 * The width of the container, setting this will redraw the component.
 *
 * @property width
 * @type Number
 */
Object.defineProperty(ScaleContainer.prototype, 'width', {
    get: function() {
        return this._width;
    },
    set: function(value) {
        if (this._width !== value) {
            this._width = value;
            this.invalid = true;
        }
    }
});

/**
 * The height of the container, setting this will redraw the component.
 *
 * @property height
 * @type Number
 */
Object.defineProperty(ScaleContainer.prototype, 'height', {
    get: function() {
        return this._height;
    },
    set: function(value) {
        if (this._height !== value) {
            this._height = value;
            this.invalid = true;
        }
    }
});

/**
 * update before draw call (reposition textures)
 *
 * @method redraw
 */
ScaleContainer.prototype.redraw = function() {
    if (this.invalid) {
        this._positionTilable();
        this.invalid = false;
    }
};

/**
 * recalculate the position of the tiles (every time width/height changes)
 *
 * @method _positionTilable
 * @private
 */
ScaleContainer.prototype._positionTilable = function() {
    // left / middle / right width
    var lw = this.rect.x;
    var mw = this.rect.width;
    var rw = this.frame.width - (mw + lw);

    // top / center / bottom height
    var th = this.rect.y;
    var ch = this.rect.height;
    var bh = this.frame.height - (ch + th);

    var rightX = this._width - rw;
    var bottomY = this._height - bh;
    if (this.cr) {
        this.cr.x = rightX;
    }
    if (this.br) {
        this.br.x = rightX;
        this.br.y = bottomY;
    }
    if (this.tr) {
        this.tr.x = rightX;
    }

    var middleWidth = this._width - (lw + rw);
    var centerHeight = this._height - (th + bh);
    if (this.cm) {
        this.cm.width = middleWidth;
        this.cm.height = centerHeight;
    }
    if (this.bm) {
        this.bm.width = middleWidth;
        this.bm.y = bottomY;
    }
    if (this.tm) {
        this.tm.width = middleWidth;
    }
    if (this.cl) {
        this.cl.height = centerHeight;
    }
    if (this.cr) {
        this.cr.height = centerHeight;
    }

    if (this.bl) {
        this.bl.y = bottomY;
    }
};

/**
 *
 * Helper function that creates a sprite that will contain a texture from the TextureCache based on the frameId
 * The frame ids are created when a Texture packer file has been loaded
 *
 * @method fromFrame
 * @static
 * @param frameId {String} The frame Id of the texture in the cache
 * @param rect {Rectangle} defines tilable area
 * @return {ScaleTexture} A new Scalable Texture (e.g. a button) using a texture from the texture cache matching the frameId
 */
ScaleContainer.fromFrame = function(frameId, rect) {
    var texture = PIXI.util.TextureCache[frameId];
    if(!texture) {
        throw new Error('The frameId "' + frameId + '" does not exist ' +
                        'in the texture cache');
    }
    return new ScaleContainer(texture, rect);
};

/**
 * Renders the object using the WebGL renderer
 *
 * @method _renderWebGL
 * @param renderSession {RenderSession}
 * @private
 */
/* istanbul ignore next */
ScaleContainer.prototype._renderWebGL = function(renderSession) {
    this.redraw();
    return PIXI.Container.prototype._renderWebGL.call(this, renderSession);
};

/**
 * Renders the object using the Canvas renderer
 *
 * @method _renderWebGL
 * @param renderSession {RenderSession}
 * @private
 */
/* istanbul ignore next */
ScaleContainer.prototype._renderCanvas = function(renderSession) {
    this.redraw();
    return PIXI.Container.prototype._renderCanvas.call(this, renderSession);
};
<commit_msg>typo fix: util -> utils<commit_after>/**
 * Scale 9 Container.
 * e.g. useful for scalable buttons.
 *
 * @class ScaleContainer
 * @extends PIXI.Container
 * @memberof PIXI_UI
 * @constructor
 */

function ScaleContainer(texture, rect) {
    PIXI.Container.call( this );

    this.rect = rect;
    this.baseTexture = texture.baseTexture;
    this.frame = texture.frame;

    this._width = this.frame.width;
    this._height = this.frame.height;

    // left / middle / right width
    var lw = rect.x;
    var mw = rect.width;
    var rw = this.frame.width - (mw + lw);

    // top / center / bottom height
    var th = rect.y;
    var ch = rect.height;
    var bh = this.frame.height - (ch + th);

    // top
    if (lw > 0 && th > 0) {
        this.tl = this._getTexture(0, 0, lw, th);
        this.addChild(this.tl);
    }
    if (mw > 0 && th > 0) {
        this.tm = this._getTexture(lw, 0, mw, th);
        this.addChild(this.tm);
        this.tm.x = lw;
    }
    if (rw > 0 && th > 0) {
        this.tr = this._getTexture(lw + mw, 0, rw, th);
        this.addChild(this.tr);
    }

    // center
    if (lw > 0 && ch > 0) {
        this.cl = this._getTexture(0, th, lw, ch);
        this.addChild(this.cl);
        this.cl.y = th;
    }
    if (mw > 0 && ch > 0) {
        this.cm = this._getTexture(lw, th, mw, ch);
        this.addChild(this.cm);
        this.cm.y = th;
        this.cm.x = lw;
    }
    if (rw > 0 && ch > 0) {
        this.cr = this._getTexture(lw + mw, th, rw, ch);
        this.addChild(this.cr);
        this.cr.y = th;
    }

    // bottom
    if (lw > 0 && bh > 0) {
        this.bl = this._getTexture(0, th + ch, lw, bh);
        this.addChild(this.bl);
    }
    if (mw > 0 && bh > 0) {
        this.bm = this._getTexture(lw, th + ch, mw, bh);
        this.addChild(this.bm);
        this.bm.x = lw;
    }
    if (rw > 0 && bh > 0) {
        this.br = this._getTexture(lw + mw, th + ch, rw, bh);
        this.addChild(this.br);
    }
}

// constructor
ScaleContainer.prototype = Object.create( PIXI.Container.prototype );
ScaleContainer.prototype.constructor = ScaleContainer;
module.exports = ScaleContainer;

/**
 * create a new texture from a base-texture by given dimensions
 *
 * @method _getTexture
 * @private
 */
ScaleContainer.prototype._getTexture = function(x, y, w, h) {
    var frame = new PIXI.math.Rectangle(this.frame.x+x, this.frame.y+y, w, h);
    var t = new PIXI.Texture(this.baseTexture, frame, frame.clone(), null);
    return new PIXI.Sprite(t);
};

/**
 * The width of the container, setting this will redraw the component.
 *
 * @property width
 * @type Number
 */
Object.defineProperty(ScaleContainer.prototype, 'width', {
    get: function() {
        return this._width;
    },
    set: function(value) {
        if (this._width !== value) {
            this._width = value;
            this.invalid = true;
        }
    }
});

/**
 * The height of the container, setting this will redraw the component.
 *
 * @property height
 * @type Number
 */
Object.defineProperty(ScaleContainer.prototype, 'height', {
    get: function() {
        return this._height;
    },
    set: function(value) {
        if (this._height !== value) {
            this._height = value;
            this.invalid = true;
        }
    }
});

/**
 * update before draw call (reposition textures)
 *
 * @method redraw
 */
ScaleContainer.prototype.redraw = function() {
    if (this.invalid) {
        this._positionTilable();
        this.invalid = false;
    }
};

/**
 * recalculate the position of the tiles (every time width/height changes)
 *
 * @method _positionTilable
 * @private
 */
ScaleContainer.prototype._positionTilable = function() {
    // left / middle / right width
    var lw = this.rect.x;
    var mw = this.rect.width;
    var rw = this.frame.width - (mw + lw);

    // top / center / bottom height
    var th = this.rect.y;
    var ch = this.rect.height;
    var bh = this.frame.height - (ch + th);

    var rightX = this._width - rw;
    var bottomY = this._height - bh;
    if (this.cr) {
        this.cr.x = rightX;
    }
    if (this.br) {
        this.br.x = rightX;
        this.br.y = bottomY;
    }
    if (this.tr) {
        this.tr.x = rightX;
    }

    var middleWidth = this._width - (lw + rw);
    var centerHeight = this._height - (th + bh);
    if (this.cm) {
        this.cm.width = middleWidth;
        this.cm.height = centerHeight;
    }
    if (this.bm) {
        this.bm.width = middleWidth;
        this.bm.y = bottomY;
    }
    if (this.tm) {
        this.tm.width = middleWidth;
    }
    if (this.cl) {
        this.cl.height = centerHeight;
    }
    if (this.cr) {
        this.cr.height = centerHeight;
    }

    if (this.bl) {
        this.bl.y = bottomY;
    }
};

/**
 *
 * Helper function that creates a sprite that will contain a texture from the TextureCache based on the frameId
 * The frame ids are created when a Texture packer file has been loaded
 *
 * @method fromFrame
 * @static
 * @param frameId {String} The frame Id of the texture in the cache
 * @param rect {Rectangle} defines tilable area
 * @return {ScaleTexture} A new Scalable Texture (e.g. a button) using a texture from the texture cache matching the frameId
 */
ScaleContainer.fromFrame = function(frameId, rect) {
    var texture = PIXI.utils.TextureCache[frameId];
    if(!texture) {
        throw new Error('The frameId "' + frameId + '" does not exist ' +
                        'in the texture cache');
    }
    return new ScaleContainer(texture, rect);
};

/**
 * Renders the object using the WebGL renderer
 *
 * @method _renderWebGL
 * @param renderSession {RenderSession}
 * @private
 */
/* istanbul ignore next */
ScaleContainer.prototype._renderWebGL = function(renderSession) {
    this.redraw();
    return PIXI.Container.prototype._renderWebGL.call(this, renderSession);
};

/**
 * Renders the object using the Canvas renderer
 *
 * @method _renderWebGL
 * @param renderSession {RenderSession}
 * @private
 */
/* istanbul ignore next */
ScaleContainer.prototype._renderCanvas = function(renderSession) {
    this.redraw();
    return PIXI.Container.prototype._renderCanvas.call(this, renderSession);
};
<|endoftext|>


<commit_before>/*eslint-env node, es6 */
/*eslint-disable no-magic-numbers, camelcase, no-process-exit, global-require, no-process-env */
"use strict";

const path = require("path");
const crypto = require("crypto");
const fs = require("fs");
const url = require("url");
const ProxyAgent = require("https-proxy-agent");

const chalk = require("chalk");

const pkg = require(path.resolve(path.join(__dirname, "..", "..", "package.json")));

let instance = null;

class COSI {
    constructor() {
        if (instance !== null) {
            return instance;
        }

        instance = this;  //eslint-disable-line consistent-this

        instance.app_name = pkg.name;
        instance.app_version = pkg.version;
        instance.description = pkg.description;
        instance.bug_url = pkg.bugs.url;
        instance.support_url = "https://support.circonus.com/";

        instance.cosi_dir = path.resolve(path.join(__dirname, "..", ".."));
        instance.lib_dir = __dirname;
        instance.etc_dir = path.resolve(path.join(instance.cosi_dir, "etc"));
        instance.reg_dir = path.resolve(path.join(instance.cosi_dir, "registration"));
        instance.ruleset_dir = path.resolve(path.join(instance.cosi_dir, "rulesets"));

        const configFile = path.resolve(path.join(instance.etc_dir, "cosi.json"));
        let cfg = {};

        try {
            cfg = require(configFile);
        }
        catch (err) {
            if (err.code === "MODULE_NOT_FOUND") {
                console.error(chalk.red(`Configuration file '${configFile}' not found!`));
                process.exit(1);
            }
            else {
                throw err;
            }
        }

        const requiredSettings = [
            "api_key",
            "api_app",
            "api_url",
            "cosi_url",
            "agent_mode",
            "agent_url",
            "statsd",
            "statsd_port",
            "cosi_os_type",
            "cosi_os_dist",
            "cosi_os_vers",
            "cosi_os_arch"
        ];

        //for (const prop of requiredSettings) {
        for (let i = 0; i < requiredSettings.length; i++) {
            const prop = requiredSettings[i];

            if (cfg.hasOwnProperty(prop)) {
                instance[prop] = cfg[prop];
            }
            else {
                console.error(chalk.red("ERROR"), "configuration missing required setting", prop);
                process.exit(1);
            }
        }

        const optionalSettings = [
            "cosi_host_target",
            "cosi_broker_id"
        ];

        for (let i = 0; i < optionalSettings.length; i++) {
            const prop = optionalSettings[i];

            if (cfg.hasOwnProperty(prop) && cfg[prop] !== "") {
                instance[prop] = cfg[prop];
            }
        }

        // used for aws public hostname detection for check target
        if (cfg.hasOwnProperty("cosi_os_dmi") && cfg.cosi_os_dmi !== "") {
            instance.dmi_bios_ver = cfg.cosi_os_dmi;
        }

        const idFile = path.resolve(path.join(instance.etc_dir, ".cosi_id"));

        try {
            const cosi_id = fs.readFileSync(idFile, { encoding: "utf8" });

            instance.cosi_id = cosi_id.trim();
        }
        catch (readError) {
            if (readError.code !== "ENOENT") {
                console.error("Unable to read", idFile, readError);
                process.exit(1);
            }

            instance.cosi_id = crypto.createHash("sha256").update(crypto.randomBytes(2048)).digest("hex");
            try {
                fs.writeFileSync(idFile, instance.cosi_id);
            }
            catch (writeError) {
                console.error("Unable to save", idFile, writeError);
            }
        }

        instance.custom_options = {};
        if (cfg.hasOwnProperty("custom_options_file") && cfg.custom_options_file.length > 0) {
            const custCfgFile = path.resolve(cfg.custom_options_file);

            try {
                instance.custom_options = require(custCfgFile);
            }
            catch (custCfgErr) {
                console.error(chalk.red("ERROR"), "unable to load specified custom options file", custCfgErr);
                process.exit(1);
            }
        }

        instance.ui_url = null;
        try {
            const regInfoFile = path.resolve(path.join(__dirname, "..", "..", "registration", "setup-config.json"));
            const info = require(regInfoFile);

            instance.ui_url = info.account.uiUrl;
        }
        catch (err) {
            // ignore
        }

        return instance;
    }

    getProxySettings(reqUrl) {
        const reqOptions = url.parse(reqUrl);
        const proxyServer = this._getProtocolProxyUrl(reqOptions.protocol);

        reqOptions.agent = false;
        if (proxyServer !== null) {
            reqOptions.agent = new ProxyAgent(proxyServer);
        }

        return reqOptions;
    }

    // extract proxy setting from environment for a specific protocol
    _getProtocolProxyUrl(urlProtocol) {
        let proxyServer = null;

        if (urlProtocol === "http:") {
            if (process.env.hasOwnProperty("http_proxy")) {
                proxyServer = process.env.http_proxy;
            }
            else if (process.env.hasOwnProperty("HTTP_PROXY")) {
                proxyServer = process.env.HTTP_PROXY;
            }
        }
        else if (urlProtocol === "https:") {
            if (process.env.hasOwnProperty("https_proxy")) {
                proxyServer = process.env.https_proxy;
            }
            else if (process.env.hasOwnProperty("HTTPS_PROXY")) {
                proxyServer = process.env.HTTPS_PROXY;
            }
        }
        if (proxyServer !== null && proxyServer !== "") {
            if (!proxyServer.match(/^http[s]?:\/\//)) {
                proxyServer = `http://${proxyServer}`;
            }
        }

        return proxyServer;
    }
}

module.exports = new COSI();
<commit_msg>backfill statsd and statsd_port settings in config reader<commit_after>/*eslint-env node, es6 */
/*eslint-disable no-magic-numbers, camelcase, no-process-exit, global-require, no-process-env */
"use strict";

const path = require("path");
const crypto = require("crypto");
const fs = require("fs");
const url = require("url");
const ProxyAgent = require("https-proxy-agent");

const chalk = require("chalk");

const pkg = require(path.resolve(path.join(__dirname, "..", "..", "package.json")));

let instance = null;

class COSI {
    constructor() {
        if (instance !== null) {
            return instance;
        }

        instance = this;  //eslint-disable-line consistent-this

        instance.app_name = pkg.name;
        instance.app_version = pkg.version;
        instance.description = pkg.description;
        instance.bug_url = pkg.bugs.url;
        instance.support_url = "https://support.circonus.com/";

        instance.cosi_dir = path.resolve(path.join(__dirname, "..", ".."));
        instance.lib_dir = __dirname;
        instance.etc_dir = path.resolve(path.join(instance.cosi_dir, "etc"));
        instance.reg_dir = path.resolve(path.join(instance.cosi_dir, "registration"));
        instance.ruleset_dir = path.resolve(path.join(instance.cosi_dir, "rulesets"));

        const configFile = path.resolve(path.join(instance.etc_dir, "cosi.json"));
        let cfg = {};

        try {
            cfg = require(configFile);
        }
        catch (err) {
            if (err.code === "MODULE_NOT_FOUND") {
                console.error(chalk.red(`Configuration file '${configFile}' not found!`));
                process.exit(1);
            }
            else {
                throw err;
            }
        }

        const requiredSettings = [
            "api_key",
            "api_app",
            "api_url",
            "cosi_url",
            "agent_mode",
            "agent_url",
            "cosi_os_type",
            "cosi_os_dist",
            "cosi_os_vers",
            "cosi_os_arch"
        ];

        //for (const prop of requiredSettings) {
        for (let i = 0; i < requiredSettings.length; i++) {
            const prop = requiredSettings[i];

            if (cfg.hasOwnProperty(prop)) {
                instance[prop] = cfg[prop];
            }
            else {
                console.error(chalk.red("ERROR"), "configuration missing required setting", prop);
                process.exit(1);
            }
        }

        // additional settings (previous installs may not have these settings on a cosi re-run)
        instance.statsd = cfg.statsd || 0;
        instance.statsd_port = cfg.statsd_port || 8125;

        const optionalSettings = [
            "cosi_host_target",
            "cosi_broker_id"
        ];

        for (let i = 0; i < optionalSettings.length; i++) {
            const prop = optionalSettings[i];

            if (cfg.hasOwnProperty(prop) && cfg[prop] !== "") {
                instance[prop] = cfg[prop];
            }
        }

        // used for aws public hostname detection for check target
        if (cfg.hasOwnProperty("cosi_os_dmi") && cfg.cosi_os_dmi !== "") {
            instance.dmi_bios_ver = cfg.cosi_os_dmi;
        }

        const idFile = path.resolve(path.join(instance.etc_dir, ".cosi_id"));

        try {
            const cosi_id = fs.readFileSync(idFile, { encoding: "utf8" });

            instance.cosi_id = cosi_id.trim();
        }
        catch (readError) {
            if (readError.code !== "ENOENT") {
                console.error("Unable to read", idFile, readError);
                process.exit(1);
            }

            instance.cosi_id = crypto.createHash("sha256").update(crypto.randomBytes(2048)).digest("hex");
            try {
                fs.writeFileSync(idFile, instance.cosi_id);
            }
            catch (writeError) {
                console.error("Unable to save", idFile, writeError);
            }
        }

        instance.custom_options = {};
        if (cfg.hasOwnProperty("custom_options_file") && cfg.custom_options_file.length > 0) {
            const custCfgFile = path.resolve(cfg.custom_options_file);

            try {
                instance.custom_options = require(custCfgFile);
            }
            catch (custCfgErr) {
                console.error(chalk.red("ERROR"), "unable to load specified custom options file", custCfgErr);
                process.exit(1);
            }
        }

        instance.ui_url = null;
        try {
            const regInfoFile = path.resolve(path.join(__dirname, "..", "..", "registration", "setup-config.json"));
            const info = require(regInfoFile);

            instance.ui_url = info.account.uiUrl;
        }
        catch (err) {
            // ignore
        }

        return instance;
    }

    getProxySettings(reqUrl) {
        const reqOptions = url.parse(reqUrl);
        const proxyServer = this._getProtocolProxyUrl(reqOptions.protocol);

        reqOptions.agent = false;
        if (proxyServer !== null) {
            reqOptions.agent = new ProxyAgent(proxyServer);
        }

        return reqOptions;
    }

    // extract proxy setting from environment for a specific protocol
    _getProtocolProxyUrl(urlProtocol) {
        let proxyServer = null;

        if (urlProtocol === "http:") {
            if (process.env.hasOwnProperty("http_proxy")) {
                proxyServer = process.env.http_proxy;
            }
            else if (process.env.hasOwnProperty("HTTP_PROXY")) {
                proxyServer = process.env.HTTP_PROXY;
            }
        }
        else if (urlProtocol === "https:") {
            if (process.env.hasOwnProperty("https_proxy")) {
                proxyServer = process.env.https_proxy;
            }
            else if (process.env.hasOwnProperty("HTTPS_PROXY")) {
                proxyServer = process.env.HTTPS_PROXY;
            }
        }
        if (proxyServer !== null && proxyServer !== "") {
            if (!proxyServer.match(/^http[s]?:\/\//)) {
                proxyServer = `http://${proxyServer}`;
            }
        }

        return proxyServer;
    }
}

module.exports = new COSI();
<|endoftext|>


<commit_before>
// Since not all browser support URLSearchParams we implement it here
export function getUrlSearchParams(locationSearch = window.location.search) {
  return locationSearch.substr(1).split('&').reduce(function (q, query) {
    const chunks = query.split('=');
    const key = chunks[0];
    if(!chunks[1]) {
      return {};
    }
    const values = decodeURI(chunks[1]).split(','); //We want to support value=123,555
    const value = (values.length > 1 ) ? values : values[0];
    return (q[key] = value, q);
  }, {});
}

// Takes the { param=value, param2=value} and export it as a string to be used as a query param
export function urlSearchParamsToString(paramObject) {
  let result = '';
  if(!paramObject) {
    return '';
  }
  Object.keys(paramObject).forEach(e => {
    if (e == null || e === '') return;
    result+=`${e}=${paramObject[e]}&`;
  });

  // Remove the last '&' char
  if (result.length > 0) {
    result = result.slice(0, result.length-1);
  }

  return result
}

// Array of params [{name:name,value:value}] to set in query url
export function setQueryParams(params) {
  let currentSearchParams = getUrlSearchParams();
  const paramsObj = getUrlSearchParams('?' + params);
  Object.keys(paramsObj).forEach(param => {
      if (param == null || param === '' || !currentSearchParams) return;
      currentSearchParams[param] = paramsObj[param];
    });
  return urlSearchParamsToString(currentSearchParams);
}

/*
 This function handles replacing / concatting params to location
 Can receive complete for example will remove complete
 value - Optional value if it's a multi value like labels=label1,label2 then value=label2 can remove that label
 Apparently URLSearchParams doesn't handle delete for a single value
*/
export function removeQueryParam(paramsToRemove, value) {
  let currentQueryParams = getUrlSearchParams();

  if(!currentQueryParams) { return {}}
  paramsToRemove.forEach( param => {
    // Handle case of label=['label1','label2']

    if(Array.isArray(currentQueryParams[param]) && value) {
      currentQueryParams[param] = currentQueryParams[param].filter((val) => { return val !== value });
    }else {
      delete currentQueryParams[param];
    }
  });
  return urlSearchParamsToString(currentQueryParams);
}

// Get a given cookie from document.cookie
export function getCookie(cookieName) {
  const name = cookieName + "=";
  const decodedCookie = decodeURIComponent(document.cookie);
  const ca = decodedCookie.split(';');
  for(let i = 0; i <ca.length; i++) {
    let c = ca[i];
    while (c.charAt(0) === ' ') {
      c = c.substring(1);
    }
    if (c.indexOf(name) === 0) {
      return c.substring(name.length, c.length);
    }
  }
  return '';
}

export function setCookie(name, value,years=10) {
  let date = new Date();
  date.setTime(date.getTime()+(years*365*24*60*60*1000));
  var expires = "expires="+date.toGMTString();
  document.cookie = name+"=" + value + "; " + expires+"; path=/";
}

export const isMobile = window.innerWidth < 480;
export const isTablet = (window.innerWidth < 768  && window.innerWidth > 480);
<commit_msg>Fixed an issue with infrastructure that prevented storing query= empty string<commit_after>
// Since not all browser support URLSearchParams we implement it here
export function getUrlSearchParams(locationSearch = window.location.search) {
  return locationSearch.substr(1).split('&').reduce(function (q, query) {
    const chunks = query.split('=');
    const key = chunks[0];
    if(!chunks[1]) {
      return {[key]: ''};
    }
    const values = decodeURI(chunks[1]).split(','); //We want to support value=123,555
    const value = (values.length > 1 ) ? values : values[0];
    return (q[key] = value, q);
  }, {});
}

// Takes the { param=value, param2=value} and export it as a string to be used as a query param
export function urlSearchParamsToString(paramObject) {
  let result = '';
  if(!paramObject) {
    return '';
  }
  Object.keys(paramObject).forEach(e => {
    if (e == null || e === '') return;
    result+=`${e}=${paramObject[e]}&`;
  });

  // Remove the last '&' char
  if (result.length > 0) {
    result = result.slice(0, result.length-1);
  }

  return result
}

// Array of params [{name:name,value:value}] to set in query url
export function setQueryParams(params) {
  let currentSearchParams = getUrlSearchParams();
  const paramsObj = getUrlSearchParams('?' + params);
  Object.keys(paramsObj).forEach(param => {
      if (param == null || param === '' || !currentSearchParams) return;
      currentSearchParams[param] = paramsObj[param];
    });
  return urlSearchParamsToString(currentSearchParams);
}

/*
 This function handles replacing / concatting params to location
 Can receive complete for example will remove complete
 value - Optional value if it's a multi value like labels=label1,label2 then value=label2 can remove that label
 Apparently URLSearchParams doesn't handle delete for a single value
*/
export function removeQueryParam(paramsToRemove, value) {
  let currentQueryParams = getUrlSearchParams();

  if(!currentQueryParams) { return {}}
  paramsToRemove.forEach( param => {
    // Handle case of label=['label1','label2']

    if(Array.isArray(currentQueryParams[param]) && value) {
      currentQueryParams[param] = currentQueryParams[param].filter((val) => { return val !== value });
    }else {
      delete currentQueryParams[param];
    }
  });
  return urlSearchParamsToString(currentQueryParams);
}

// Get a given cookie from document.cookie
export function getCookie(cookieName) {
  const name = cookieName + "=";
  const decodedCookie = decodeURIComponent(document.cookie);
  const ca = decodedCookie.split(';');
  for(let i = 0; i <ca.length; i++) {
    let c = ca[i];
    while (c.charAt(0) === ' ') {
      c = c.substring(1);
    }
    if (c.indexOf(name) === 0) {
      return c.substring(name.length, c.length);
    }
  }
  return '';
}

export function setCookie(name, value,years=10) {
  let date = new Date();
  date.setTime(date.getTime()+(years*365*24*60*60*1000));
  var expires = "expires="+date.toGMTString();
  document.cookie = name+"=" + value + "; " + expires+"; path=/";
}

export const isMobile = window.innerWidth < 480;
export const isTablet = (window.innerWidth < 768  && window.innerWidth > 480);
<|endoftext|>


<commit_before>// import { baseURL } from './constants.js'
// import * as types from '../../core/types.js'
import ENDPOINTS from '../../config.js'

import request from 'request'
require('dotenv').config()

/***
 * !This is an internal function that should not be called by the end user!

 * Builds a URL for HTTP request
 * @param {object} anonymous: anonyous object with arguments:
 * @param {string} type: type of HTTP request (GET, POST, etc). Used for validation of parameters
 * @param {string} AMaaSClass: class being requested/sent (e.g. Transaction) (required)
 * @param {string} AMId: Asset Manager Id (required)
 * @param {string} resourceId: Id of the resource being requested (e.g. book_id)
*/
export function buildURL({ AMaaSClass, AMId, resourceId }) {
  let baseURL;
  switch (AMaaSClass) {
    case 'book':
      // baseURL = process.env.booksURL
      baseURL = `${ENDPOINTS.books}/books`
      break
    case 'parties':
      // baseURL = process.env.partiesURL
      baseURL = `${ENDPOINTS.parties}/parties`
      break
    case 'assetManagers':
      baseURL = `${ENDPOINTS.assetManagers}/asset_managers`
      break
    case 'assets':
      baseURL = `${ENDPOINTS.assets}/assets`
      break
    case 'positions':
      baseURL = `${ENDPOINTS.transactions}/positions`
      break
    default:
      // baseURL = process.env.booksURL
      baseURL = `${ENDPOINTS.books}/books`
  }
  if (!AMaaSClass) {
    throw new Error('Class is required to build URL')
  } else if (!AMId) {
    return `${baseURL}/`
  } else if (!resourceId) {
    return `${baseURL}/${AMId}`
  } else {
    return `${baseURL}/${AMId}/${resourceId}`
  }
}

/***
 * !This is an internal function that should not be called by the end user!
 * !Wrapper functions are exposed for the individual asset classes for consumption!

 * Base function for retrieval of data from the database (GET request)
 * @param {object} anonymous: anonymous object with arguments:
 * @param {string} AMaaSClass: class being requested/sent (e.g. Transaction) (required)
 * @param {string} AMId: Asset Manager Id (required)
 * @param {string} resourceId: Id of the resource being requested (e.g. book_id)
*/
export function retrieveData({ AMaaSClass, AMId, resourceId }, callback) {
  // callback(err, result)
  // Class and AMId needed to build the Url and for authorization
  if (!AMaaSClass || !AMId) {
    throw new Error('Both class and AMId are required')
  }
  // If resourceId is supplied, append to url. Otherwise, return all data for AMId
  const url = buildURL({ AMaaSClass, AMId, resourceId })
  // const url = resourceId ? `${baseURL}${AMaaSClass}/${AMId}/${resourceId}` : `${baseURL}${AMaaSClass}/${AMId}/`
  request(url, (error, response, body) => {
    if (!error && response.statusCode == 200) {
      callback(null, JSON.parse(body))
    } else {
      const statusCode = response ? response.statusCode : ''
      const requestError = {
        statusCode,
        error
      }
      callback(requestError)
    }
  })
}

/***
 * !This is an internal function that should not be called by the end user!
 * !Wrapper functions are exposed for the individual asset classes for consumption!

 * Base function for insertion of data to the database (POST request)
 * @param {object} anonymous: anonymous object with arguments:
 * @param {string} AMaaSClass: class being requested/sent (e.g. Transaction) (required)
 * @param {string} AMId: Asset Manager Id (required)
 * @param {string} data: data to insert into database
*/
export function insertData({ AMaaSClass, AMId, data }, callback) {
  // if (!AMaaSClass || !AMId || !data) {
  //   throw new Error('Class, AMId and data to insert are required')
  // }
  const url = buildURL({
    AMaaSClass,
    AMId
  })
  // Data is object with required key value pairs for that class
  // const am = 'asset_manager_id'
  // data[am] = AMId
  const params = {
    url,
    json: data
  }
  request.post(params, (error, response, body) => {
    _networkCallback(error, response, body, callback)
  })
}

export function putData({ AMaaSClass, AMId, resourceId, data }, callback) {
  const url = buildURL({
    AMaaSClass,
    AMId,
    resourceId
  })
  const params = {
    url,
    json: data
  }
  request.put(params, (error, response, body) => {
    _networkCallback(error, response, body, callback)
  })
}

export function patchData({ AMaaSClass, AMId, resourceId, data }, callback) {
  const url = buildURL({
    AMaaSClass,
    AMId,
    resourceId
  })
  const params = {
    url,
    json: data
  }
  request.patch(params, (error, response, body) => {
    _networkCallback(error, response, body, callback)
  })
}

export function deleteData({ AMaaSClass, AMId, resourceId }, callback) {
  const url = buildURL({
    AMaaSClass,
    AMId,
    resourceId
  })
  request.delete(url, (error, response, body) => {
    _networkCallback(error, response, body, callback)
  })
}

export function searchData({ AMaaSClass, queryKey, queryValue }, callback) {
  const url = buildURL({
    AMaaSClass
  })
  let qString = {}
  const qValueString = queryValue.join()
  qString[queryKey] = qValueString
  const params = {
    url,
    qs: qString
  }
  request.get(params, (error, response, body) => {
    _networkCallback(error, response, body, callback)
  })
}

function _networkCallback(error, response, body, callback) {
  if (!error && response.statusCode === 200) {
    callback(null, body)
  } else if (error) {
    callback(error)
  } else {
    callback({ response, body })
  }
}
<commit_msg>Replace request with superagent to support node and browser env<commit_after>// import { baseURL } from './constants.js'
// import * as types from '../../core/types.js'
import ENDPOINTS from '../../config.js'

import request from 'superagent'
require('dotenv').config()

/***
 * !This is an internal function that should not be called by the end user!

 * Builds a URL for HTTP request
 * @param {object} anonymous: anonyous object with arguments:
 * @param {string} type: type of HTTP request (GET, POST, etc). Used for validation of parameters
 * @param {string} AMaaSClass: class being requested/sent (e.g. Transaction) (required)
 * @param {string} AMId: Asset Manager Id (required)
 * @param {string} resourceId: Id of the resource being requested (e.g. book_id)
*/
export function buildURL({ AMaaSClass, AMId, resourceId }) {
  let baseURL;
  switch (AMaaSClass) {
    case 'book':
      // baseURL = process.env.booksURL
      baseURL = `${ENDPOINTS.books}/books`
      break
    case 'parties':
      // baseURL = process.env.partiesURL
      baseURL = `${ENDPOINTS.parties}/parties`
      break
    case 'assetManagers':
      baseURL = `${ENDPOINTS.assetManagers}/asset_managers`
      break
    case 'assets':
      baseURL = `${ENDPOINTS.assets}/assets`
      break
    case 'positions':
      baseURL = `${ENDPOINTS.transactions}/positions`
      break
    default:
      // baseURL = process.env.booksURL
      baseURL = `${ENDPOINTS.books}/books`
  }
  if (!AMaaSClass) {
    throw new Error('Class is required to build URL')
  } else if (!AMId) {
    return `${baseURL}/`
  } else if (!resourceId) {
    return `${baseURL}/${AMId}`
  } else {
    return `${baseURL}/${AMId}/${resourceId}`
  }
}

/***
 * !This is an internal function that should not be called by the end user!
 * !Wrapper functions are exposed for the individual asset classes for consumption!

 * Base function for retrieval of data from the database (GET request)
 * @param {object} anonymous: anonymous object with arguments:
 * @param {string} AMaaSClass: class being requested/sent (e.g. Transaction) (required)
 * @param {string} AMId: Asset Manager Id (required)
 * @param {string} resourceId: Id of the resource being requested (e.g. book_id)
*/
export function retrieveData({ AMaaSClass, AMId, resourceId }, callback) {
  // callback(err, result)
  // Class and AMId needed to build the Url and for authorization
  if (!AMaaSClass || !AMId) {
    throw new Error('Both class and AMId are required')
  }
  // If resourceId is supplied, append to url. Otherwise, return all data for AMId
  const url = buildURL({ AMaaSClass, AMId, resourceId })
  // const url = resourceId ? `${baseURL}${AMaaSClass}/${AMId}/${resourceId}` : `${baseURL}${AMaaSClass}/${AMId}/`

  request.get(url).end((error, response) => {
    if (!error && response.status == 200) {
      let body = response.body
      if (body == null || body.length <= 0) {
        body = {}
      } else {
        body = JSON.parse(body)
      }
      callback(null, body)
    } else {
      const statusCode = response ? response.status : ''
      const requestError = {
        statusCode,
        error
      }
      callback(requestError)
    }
  })
}

/***
 * !This is an internal function that should not be called by the end user!
 * !Wrapper functions are exposed for the individual asset classes for consumption!

 * Base function for insertion of data to the database (POST request)
 * @param {object} anonymous: anonymous object with arguments:
 * @param {string} AMaaSClass: class being requested/sent (e.g. Transaction) (required)
 * @param {string} AMId: Asset Manager Id (required)
 * @param {string} data: data to insert into database
*/
export function insertData({ AMaaSClass, AMId, data }, callback) {
  // if (!AMaaSClass || !AMId || !data) {
  //   throw new Error('Class, AMId and data to insert are required')
  // }
  const url = buildURL({
    AMaaSClass,
    AMId
  })
  // Data is object with required key value pairs for that class
  // const am = 'asset_manager_id'
  // data[am] = AMId
  const params = {
    url,
    json: data
  }
  request.post(url).send(data).end((error, response) => {
    _networkCallback(error, response, response.body, callback)
  })
}

export function putData({ AMaaSClass, AMId, resourceId, data }, callback) {
  const url = buildURL({
    AMaaSClass,
    AMId,
    resourceId
  })
  const params = {
    url,
    json: data
  }
  request.put(url).send(data).end((error, response) => {
    _networkCallback(error, response, response.body, callback)
  })
}

export function patchData({ AMaaSClass, AMId, resourceId, data }, callback) {
  const url = buildURL({
    AMaaSClass,
    AMId,
    resourceId
  })
  const params = {
    url,
    json: data
  }
  request.patch(url).send(data).end((error, response) => {
    _networkCallback(error, response, response.body, callback)
  })
}

export function deleteData({ AMaaSClass, AMId, resourceId }, callback) {
  const url = buildURL({
    AMaaSClass,
    AMId,
    resourceId
  })
  request.delete(url).end((error, response) => {
    _networkCallback(error, response, response.body, callback)
  })
}

export function searchData({ AMaaSClass, queryKey, queryValue }, callback) {
  const url = buildURL({
    AMaaSClass
  })
  let qString = {}
  const qValueString = queryValue.join()
  qString[queryKey] = qValueString
  const params = {
    url,
    qs: qString
  }
  request.get(url).query(qString).end((error, response) => {
    _networkCallback(error, response, response.body, callback)
  })
}

function _networkCallback(error, response, body, callback) {
  if (!error && response.status === 200) {
    callback(null, body)
  } else if (error) {
    callback(error)
  } else {
    callback({ response, body })
  }
}
<|endoftext|>


<commit_before>import { extend, intersection, merge, partial, isFunction, isEmpty, property } from "lodash";

  /* Example Event Prop
    [
      {
        childName: "firstBar",
        target: "data",
        eventKey: 1,
        eventKey: "thisOne",
        eventHandlers: {
          onClick: () => {},
          ...
        }
      },
      {
        target: "labels",
        eventHandlers: {
          onClick: () => {}
        }
      }
    ]

  */

  /* Example Event handler return
  [
    {
      childName: "fistBar",
      target: "data",
      eventKey: 1,
      mutation: (propsForTarget) => {
        return {style: merge({}, propsForTarget.style, {fill: "red"})}
      }
    },
    {
      target: "labels",
      eventKey: 2,
      mutation: () => { return {text: "hello"}; }
    }
  ]
  */

export default {
  getPartialEvents(events, eventKey, childProps) {
    return events ?
      Object.keys(events).reduce((memo, eventName) => {
        /* eslint max-params: 0 */
        memo[eventName] = partial(
          events[eventName],
          partial.placeholder, // evt will still be the first argument for event handlers
          childProps, // event handlers will have access to data component props, including data
          eventKey, // used in setting a unique state property
          eventName // used in setting a unique state property
        );
        return memo;
      }, {}) :
      {};
  },

  getScopedEvents(events, namespace, childType, baseProps) {
    baseProps = baseProps || this.baseProps;
    const getTargetProps = (identifier, type) => {
      const { childName, target, key } = identifier;
      const baseType = type === "props" ? baseProps : this.state;
      const base = (!childName || !baseType[childName]) ? baseType : baseType[childName];
      return key === "parent" ? base.parent : base[key] && base[key][target];
    };

    const parseEvent = (eventReturn, eventKey) => {
      const nullFunction = () => null;
      const childName = eventReturn.childName || childType;
      const target = eventReturn.target || namespace;

      const getKeys = () => {
        if (baseProps.all || baseProps[childName] && baseProps[childName].all) {
          return "all";
        } else if (eventReturn.eventKey === "all") {
          return baseProps[childName] ?
            Object.keys(baseProps[childName]) : Object.keys(baseProps);
        } else if (!eventReturn.eventKey && eventKey === "parent") {
          return baseProps[childName] ?
            Object.keys(baseProps[childName]) : Object.keys(baseProps);
        }
        return eventReturn.eventKey || eventKey;
      };
      const mutationKeys = getKeys();

      const getMutationObject = (key) => {
        const mutationTargetProps = getTargetProps({childName, key, target}, "props");
        const mutationTargetState = getTargetProps({childName, key, target}, "state");
        const mutation = eventReturn.mutation || nullFunction;
        const mutatedProps = mutation(
          Object.assign({}, mutationTargetProps, mutationTargetState), baseProps
        );
        const childState = this.state[childName] || {};
        return childName ?
          extend(this.state, {
            [childName]: extend(childState, {
              [key]: extend(childState[key], {[target]: mutatedProps})
            })
          }) :
          extend(this.state, {
            [key]: extend(this.state[key], {[target]: mutatedProps})
          });
      };
      return Array.isArray(mutationKeys) ?
        mutationKeys.reduce((memo, k) => {
          return Object.assign(memo, getMutationObject(k));
        }, {}) :
        getMutationObject(mutationKeys);

    };

    const parseEventReturn = (eventReturn, eventKey) => {
      return Array.isArray(eventReturn) ?
        eventReturn.reduce((memo, props) => {
          memo = merge({}, memo, parseEvent(props, eventKey));
          return memo;
        }, {}) :
        parseEvent(eventReturn, eventKey);
    };

    const onEvent = (evt, childProps, eventKey, eventName) => {
      const eventReturn = events[eventName](evt, childProps, eventKey);
      if (eventReturn) {
        this.setState(parseEventReturn(eventReturn, eventKey));
      }
    };

    return !isEmpty(events) ?
      Object.keys(events).reduce((memo, event) => {
        memo[event] = onEvent;
        return memo;
      }, {}) : {};
  },

  getEvents(props, target, eventKey, getScopedEvents) {
    const getEventsFromProps = (events) => {
      const getSelectedEvents = () => {
        const findEventsWith = (name, value) => {
          return events.reduce((memo, event) => {
            if (event[name] !== undefined) {
              return `${event[name]}` === `${value}` ? memo.concat(event) : memo;
            }
            return memo.concat(event);
          }, []);
        };
        const keyEvents = findEventsWith("eventKey", eventKey);
        const targetEvents = findEventsWith("target", target);
        if (keyEvents.length && targetEvents.length) {
          return intersection([...keyEvents, ...targetEvents]);
        }
        return [];
      };
      const selectedEvents = getSelectedEvents();
      return Array.isArray(selectedEvents) && selectedEvents.reduce((memo, event) => {
        return event ? Object.assign(memo, event.eventHandlers) : memo;
      }, {});
    };

    const ownEvents = props.events && getScopedEvents(getEventsFromProps(props.events), target);
    if (!props.sharedEvents) {
      return ownEvents;
    }
    const getSharedEvents = props.sharedEvents.getEvents;
    const sharedEvents = props.sharedEvents.events &&
      getSharedEvents(getEventsFromProps(props.sharedEvents.events), target);
    return Object.assign({}, sharedEvents, ownEvents);
  },

  getEventState(eventKey, namespace, childType) {
    if (!childType) {
      return this.state[eventKey] && this.state[eventKey][namespace];
    }
    return this.state[childType] &&
      this.state[childType][eventKey] &&
      this.state[childType][eventKey][namespace];
  },

  getEventKey(key) {
    // creates a data accessor function
    // given a property key, path, array index, or null for identity.
    if (isFunction(key)) {
      return key;
    } else if (key === null || typeof key === "undefined") {
      return () => undefined;
    }
    // otherwise, assume it is an array index, property key or path (_.property handles all three)
    return property(key);
  },

  addEventKeys(props, data) {
    const eventKeyAccessor = this.getEventKey(props.eventKey);
    return data.map((datum, index) => {
      const eventKey = datum.eventKey || eventKeyAccessor(datum) || index;
      return Object.assign({eventKey}, datum);
    });
  }
};
<commit_msg>check for undefined<commit_after>import { extend, intersection, merge, partial, isFunction, isEmpty, property } from "lodash";

  /* Example Event Prop
    [
      {
        childName: "firstBar",
        target: "data",
        eventKey: 1,
        eventKey: "thisOne",
        eventHandlers: {
          onClick: () => {},
          ...
        }
      },
      {
        target: "labels",
        eventHandlers: {
          onClick: () => {}
        }
      }
    ]

  */

  /* Example Event handler return
  [
    {
      childName: "fistBar",
      target: "data",
      eventKey: 1,
      mutation: (propsForTarget) => {
        return {style: merge({}, propsForTarget.style, {fill: "red"})}
      }
    },
    {
      target: "labels",
      eventKey: 2,
      mutation: () => { return {text: "hello"}; }
    }
  ]
  */

export default {
  getPartialEvents(events, eventKey, childProps) {
    return events ?
      Object.keys(events).reduce((memo, eventName) => {
        /* eslint max-params: 0 */
        memo[eventName] = partial(
          events[eventName],
          partial.placeholder, // evt will still be the first argument for event handlers
          childProps, // event handlers will have access to data component props, including data
          eventKey, // used in setting a unique state property
          eventName // used in setting a unique state property
        );
        return memo;
      }, {}) :
      {};
  },

  getScopedEvents(events, namespace, childType, baseProps) {
    baseProps = baseProps || this.baseProps;
    const getTargetProps = (identifier, type) => {
      const { childName, target, key } = identifier;
      const baseType = type === "props" ? baseProps : this.state;
      const base = (!childName || !baseType[childName]) ? baseType : baseType[childName];
      return key === "parent" ? base.parent : base[key] && base[key][target];
    };

    const parseEvent = (eventReturn, eventKey) => {
      const nullFunction = () => null;
      const childName = eventReturn.childName || childType;
      const target = eventReturn.target || namespace;

      const getKeys = () => {
        if (baseProps.all || baseProps[childName] && baseProps[childName].all) {
          return "all";
        } else if (eventReturn.eventKey === "all") {
          return baseProps[childName] ?
            Object.keys(baseProps[childName]) : Object.keys(baseProps);
        } else if (eventReturn.eventKey === undefined && eventKey === "parent") {
          return baseProps[childName] ?
            Object.keys(baseProps[childName]) : Object.keys(baseProps);
        }
        return eventReturn.eventKey !== undefined ? eventReturn.eventKey : eventKey;
      };
      const mutationKeys = getKeys();

      const getMutationObject = (key) => {
        const mutationTargetProps = getTargetProps({childName, key, target}, "props");
        const mutationTargetState = getTargetProps({childName, key, target}, "state");
        const mutation = eventReturn.mutation || nullFunction;
        const mutatedProps = mutation(
          Object.assign({}, mutationTargetProps, mutationTargetState), baseProps
        );
        const childState = this.state[childName] || {};
        return childName ?
          extend(this.state, {
            [childName]: extend(childState, {
              [key]: extend(childState[key], {[target]: mutatedProps})
            })
          }) :
          extend(this.state, {
            [key]: extend(this.state[key], {[target]: mutatedProps})
          });
      };
      return Array.isArray(mutationKeys) ?
        mutationKeys.reduce((memo, k) => {
          return Object.assign(memo, getMutationObject(k));
        }, {}) :
        getMutationObject(mutationKeys);

    };

    const parseEventReturn = (eventReturn, eventKey) => {
      return Array.isArray(eventReturn) ?
        eventReturn.reduce((memo, props) => {
          memo = merge({}, memo, parseEvent(props, eventKey));
          return memo;
        }, {}) :
        parseEvent(eventReturn, eventKey);
    };

    const onEvent = (evt, childProps, eventKey, eventName) => {
      const eventReturn = events[eventName](evt, childProps, eventKey);
      if (eventReturn) {
        this.setState(parseEventReturn(eventReturn, eventKey));
      }
    };

    return !isEmpty(events) ?
      Object.keys(events).reduce((memo, event) => {
        memo[event] = onEvent;
        return memo;
      }, {}) : {};
  },

  getEvents(props, target, eventKey, getScopedEvents) {
    const getEventsFromProps = (events) => {
      const getSelectedEvents = () => {
        const findEventsWith = (name, value) => {
          return events.reduce((memo, event) => {
            if (event[name] !== undefined) {
              return `${event[name]}` === `${value}` ? memo.concat(event) : memo;
            }
            return memo.concat(event);
          }, []);
        };
        const keyEvents = findEventsWith("eventKey", eventKey);
        const targetEvents = findEventsWith("target", target);
        if (keyEvents.length && targetEvents.length) {
          return intersection([...keyEvents, ...targetEvents]);
        }
        return [];
      };
      const selectedEvents = getSelectedEvents();
      return Array.isArray(selectedEvents) && selectedEvents.reduce((memo, event) => {
        return event ? Object.assign(memo, event.eventHandlers) : memo;
      }, {});
    };

    const ownEvents = props.events && getScopedEvents(getEventsFromProps(props.events), target);
    if (!props.sharedEvents) {
      return ownEvents;
    }
    const getSharedEvents = props.sharedEvents.getEvents;
    const sharedEvents = props.sharedEvents.events &&
      getSharedEvents(getEventsFromProps(props.sharedEvents.events), target);
    return Object.assign({}, sharedEvents, ownEvents);
  },

  getEventState(eventKey, namespace, childType) {
    if (!childType) {
      return this.state[eventKey] && this.state[eventKey][namespace];
    }
    return this.state[childType] &&
      this.state[childType][eventKey] &&
      this.state[childType][eventKey][namespace];
  },

  getEventKey(key) {
    // creates a data accessor function
    // given a property key, path, array index, or null for identity.
    if (isFunction(key)) {
      return key;
    } else if (key === null || typeof key === "undefined") {
      return () => undefined;
    }
    // otherwise, assume it is an array index, property key or path (_.property handles all three)
    return property(key);
  },

  addEventKeys(props, data) {
    const eventKeyAccessor = this.getEventKey(props.eventKey);
    return data.map((datum, index) => {
      const eventKey = datum.eventKey || eventKeyAccessor(datum) || index;
      return Object.assign({eventKey}, datum);
    });
  }
};
<|endoftext|>


<commit_before>/**
 * An AMD used to display the (up to) 5 occurrences defining the selected admin unit's disease extent class.
 * Copyright (c) 2014 University of Oxford
 * - Events subscribed to:
 * -- 'admin-unit-selected'        - published by MapView.
 */
define([
    "ko",
    "jquery",
    "underscore"
], function (ko, $, _) {
    "use strict";

    return function (baseUrl) {
        var self = this;
        var DISEASE_EXTENT = "disease extent";

        self.count = ko.observable(0);
        self.occurrences = ko.observableArray([]);
        self.showOccurrences = ko.observable(true);

        self.toggle = function () {
            self.showOccurrences(!self.showOccurrences());
        };

        var ajax;
        var diseaseGroupId;

        ko.postbox.subscribe("admin-unit-selected", function (adminUnit) {
            self.occurrences([]);
            self.count(0);

            if (adminUnit && adminUnit.count > 0) {
                self.count(adminUnit.count);
                if (ajax) {
                    ajax.abort();
                }
                ajax = $.getJSON(baseUrl + "datavalidation/diseases/" + diseaseGroupId + "/adminunits/" + adminUnit.id + "/occurrences")
                    .done(function (data) {
                        var properties = _(data.features).pluck("properties");
                        var sortedProperties = _(properties).sortBy("occurrenceDate").reverse();
                        self.occurrences(sortedProperties);
                    });
            }
        });

        ko.postbox.subscribe("layers-changed", function (layer) {
            diseaseGroupId = (layer.type === DISEASE_EXTENT) ? layer.diseaseId : undefined;
        });
    };
});
<commit_msg>Long line in PublicSite<commit_after>/**
 * An AMD used to display the (up to) 5 occurrences defining the selected admin unit's disease extent class.
 * Copyright (c) 2014 University of Oxford
 * - Events subscribed to:
 * -- 'admin-unit-selected'        - published by MapView.
 */
define([
    "ko",
    "jquery",
    "underscore"
], function (ko, $, _) {
    "use strict";

    return function (baseUrl) {
        var self = this;
        var DISEASE_EXTENT = "disease extent";

        self.count = ko.observable(0);
        self.occurrences = ko.observableArray([]);
        self.showOccurrences = ko.observable(true);

        self.toggle = function () {
            self.showOccurrences(!self.showOccurrences());
        };

        var ajax;
        var diseaseGroupId;

        ko.postbox.subscribe("admin-unit-selected", function (adminUnit) {
            self.occurrences([]);
            self.count(0);

            if (adminUnit && adminUnit.count > 0) {
                self.count(adminUnit.count);
                if (ajax) {
                    ajax.abort();
                }
                ajax = $.getJSON(
                baseUrl + "datavalidation/diseases/" + diseaseGroupId + "/adminunits/" + adminUnit.id + "/occurrences")
                    .done(function (data) {
                        var properties = _(data.features).pluck("properties");
                        var sortedProperties = _(properties).sortBy("occurrenceDate").reverse();
                        self.occurrences(sortedProperties);
                    });
            }
        });

        ko.postbox.subscribe("layers-changed", function (layer) {
            diseaseGroupId = (layer.type === DISEASE_EXTENT) ? layer.diseaseId : undefined;
        });
    };
});
<|endoftext|>


<commit_before>var sfa = sfa || {};

sfa.homePage = {
    init: function () {
        this.startButton();
        this.toggleRadios();
    },
    startButton: function () {
        var that = this;
        $('#create_account').on('click touchstart', function (e) {
            var isYesClicked = $('#everything-yes').prop('checked'),
                errorShown = $('body').data('shownError') || false;
            if (!isYesClicked && !errorShown) {
                e.preventDefault();
                that.showError();
            }
        });
    },
    showError: function() {
        $('#have-not-got-everything').removeClass("js-hidden").attr("aria-hidden");
        $('body').data('shownError', true);
    },
    toggleRadios: function () {
        var radios = $('input[type=radio][name=everything-you-need]');
        radios.on('change', function () {

            radios.each(function () {
                if ($(this).prop('checked')) {
                    var target = $(this).parent().data("target");
                    $("#" + target).removeClass("js-hidden").attr("aria-hidden");
                } else {
                    var target = $(this).parent().data("target");
                    $("#" + target).addClass("js-hidden").attr("aria-hidden", "true");
                }
            });

        });
    }
}

var selectionButtons = new GOVUK.SelectionButtons("label input[type='radio'], label input[type='checkbox']");

// cohorts bingo balls - clickable block
$(".clickable").on('click touchstart', (function () {
    window.location = $(this).find("a").attr("href");
    return false;
}));

// character limitation script
$('#charCount').show(); // javascript enabled version only
$('#charCount-noJS').hide(); // javascript disabled version only

var totalChars = 20; //Total characters allowed in textarea
var countTextBox = $('#ProviderRef') // Textarea input box
var charsCountEl = $('#countchars'); // Remaining characters
charsCountEl.text(totalChars); //initial value of countchars element

countTextBox.keyup(function () { //user releases a key on the keyboard
    var thisChars = this.value.replace(/{.*}/g, '').length; //get chars count in textarea
    if (thisChars > totalChars) //if we have more chars than it should be
        {
            var CharsToDel = (thisChars - totalChars); // total extra chars to delete
            this.value = this.value.substring(0, this.value.length - CharsToDel); //remove excess chars from textarea
            $("#charCount").addClass('limit-reached');
    }
    else {
            charsCountEl.text(totalChars - thisChars); //count remaining chars
            $("#charCount").removeClass('limit-reached');
        }
});
<commit_msg>script debug<commit_after>var sfa = sfa || {};

sfa.homePage = {
    init: function () {
        this.startButton();
        this.toggleRadios();
    },
    startButton: function () {
        var that = this;
        $('#create_account').on('click touchstart', function (e) {
            var isYesClicked = $('#everything-yes').prop('checked'),
                errorShown = $('body').data('shownError') || false;
            if (!isYesClicked && !errorShown) {
                e.preventDefault();
                that.showError();
            }
        });
    },
    showError: function() {
        $('#have-not-got-everything').removeClass("js-hidden").attr("aria-hidden");
        $('body').data('shownError', true);
    },
    toggleRadios: function () {
        var radios = $('input[type=radio][name=everything-you-need]');
        radios.on('change', function () {

            radios.each(function () {
                if ($(this).prop('checked')) {
                    var target = $(this).parent().data("target");
                    $("#" + target).removeClass("js-hidden").attr("aria-hidden");
                } else {
                    var target = $(this).parent().data("target");
                    $("#" + target).addClass("js-hidden").attr("aria-hidden", "true");
                }
            });

        });
    }
}

var selectionButtons = new GOVUK.SelectionButtons("label input[type='radio'], label input[type='checkbox']");

// cohorts bingo balls - clickable block
$(".clickable").on('click touchstart', (function () {
    window.location = $(this).find("a").attr("href");
    return false;
}));

// character limitation script
$('#charCount').show(); // javascript enabled version only
$('#charCount-noJS').hide(); // javascript disabled version only

var totalChars = 20; //Total characters allowed in textarea
var countTextBox = $('#ProviderRef'); // Textarea input box
var charsCountEl = $('#countchars'); // Remaining characters
charsCountEl.text(totalChars); //initial value of countchars element

countTextBox.keyup(function () { //user releases a key on the keyboard
    var thisChars = this.value.replace(/{.*}/g, '').length; //get chars count in textarea
    if (thisChars > totalChars) //if we have more chars than it should be
        {
            var CharsToDel = (thisChars - totalChars); // total extra chars to delete
            this.value = this.value.substring(0, this.value.length - CharsToDel); //remove excess chars from textarea
            $("#charCount").addClass('limit-reached');
    }
    else {
            charsCountEl.text(totalChars - thisChars); //count remaining chars
            $("#charCount").removeClass('limit-reached');
        }
});
<|endoftext|>