<commit_before>/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
 * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */

/**
 * @requires OpenLayers/Layer/Markers.js
 * @requires OpenLayers/Ajax.js
 */

/**
 * Class: OpenLayers.Layer.Text
 * This layer creates markers given data in a text file.  The <location>
 *     property of the layer (specified as a property of the options argument
 *     in the <OpenLayers.Layer.Text> constructor) points to a tab delimited
 *     file with data used to create markers.
 *
 * The first row of the data file should be a header line with the column names
 *     of the data. Each column should be delimited by a tab space. The
 *     possible columns are:
 *      - *point* lat,lon of the point where a marker is to be placed
 *      - *lat*  Latitude of the point where a marker is to be placed
 *      - *lon*  Longitude of the point where a marker is to be placed
 *      - *iconURL* URL of marker icon to use.
 *      - *iconSize* Size of Icon to use.
 *      - *iconOffset* Where the top-left corner of the icon is to be placed
 *            relative to the latitude and longitude of the point.
 *      - *title* The text of the 'title' is placed inside an 'h2' marker
 *            inside a popup, which opens when the marker is clicked.
 *      - *description* The text of the 'description' is placed below the h2
 *            in the popup. this can be plain text or HTML.
 *
 * Example text file:
 * (code)
 * lat	lon	title	description	iconSize	iconOffset	icon
 * 10	20	title	description	21,25		-10,-25		http://www.openlayers.org/dev/img/marker.png
 * (end)
 *
 * Inherits from:
 *  - <OpenLayers.Layer.Markers>
 */
OpenLayers.Layer.Text = OpenLayers.Class(OpenLayers.Layer.Markers, {

    /**
     * APIProperty: location
     * {String} URL of text file.  Must be specified in the "options" argument
     *   of the constructor. Can not be changed once passed in.
     */
    location:null,

    /**
     * Property: features
     * {Array(<OpenLayers.Feature>)}
     */
    features: null,

    /**
     * APIProperty: formatOptions
     * {Object} Hash of options which should be passed to the format when it is
     * created. Must be passed in the constructor.
     */
    formatOptions: null,

    /**
     * Property: selectedFeature
     * {<OpenLayers.Feature>}
     */
    selectedFeature: null,

    /**
     * Constructor: OpenLayers.Layer.Text
     * Create a text layer.
     *
     * Parameters:
     * name - {String}
     * options - {Object} Object with properties to be set on the layer.
     *     Must include <location> property.
     */
    initialize: function(name, options) {
        OpenLayers.Layer.Markers.prototype.initialize.apply(this, arguments);
        this.features = new Array();
    },

    /**
     * APIMethod: destroy
     */
    destroy: function() {
        // Warning: Layer.Markers.destroy() must be called prior to calling
        // clearFeatures() here, otherwise we leak memory. Indeed, if
        // Layer.Markers.destroy() is called after clearFeatures(), it won't be
        // able to remove the marker image elements from the layer's div since
        // the markers will have been destroyed by clearFeatures().
        OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments);
        this.clearFeatures();
        this.features = null;
    },

    /**
     * Method: loadText
     * Start the load of the Text data. Don't do this when we first add the layer,
     * since we may not be visible at any point, and it would therefore be a waste.
     */
    loadText: function() {
        if (!this.loaded) {
            if (this.location != null) {

                var onFail = function(e) {
                    this.events.triggerEvent("loadend");
                };

                this.events.triggerEvent("loadstart");
                OpenLayers.loadURL(this.location, null,
                                   this, this.parseData, onFail);
                this.loaded = true;
            }
        }
    },

    /**
     * Method: moveTo
     * If layer is visible and Text has not been loaded, load Text.
     *
     * Parameters:
     * bounds - {Object}
     * zoomChanged - {Object}
     * minor - {Object}
     */
    moveTo:function(bounds, zoomChanged, minor) {
        OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments);
        if(this.visibility && !this.loaded){
            this.events.triggerEvent("loadstart");
            this.loadText();
        }
    },

    /**
     * Method: parseData
     *
     * Parameters:
     * ajaxRequest - {XMLHttpRequest}
     */
    parseData: function(ajaxRequest) {
        var text = ajaxRequest.responseText;

        var options = {};

        OpenLayers.Util.extend(options, this.formatOptions);

        if (this.map && !this.projection.equals(this.map.getProjectionObject())) {
            options.externalProjection = this.projection;
            options.internalProjection = this.map.getProjectionObject();
        }

        var parser = new OpenLayers.Format.Text(options);
        features = parser.read(text);
        for (var i = 0; i < features.length; i++) {
            var data = {};
            var feature = features[i];
            var location;
            var iconSize, iconOffset;

            location = new OpenLayers.LonLat(feature.geometry.x,
                                             feature.geometry.y);

            if (feature.style.graphicWidth
                && feature.style.graphicHeight) {
                iconSize = new OpenLayers.Size(
                    feature.style.graphicWidth,
                    feature.style.graphicHeight);
            }

            // FIXME: At the moment, we only use this if we have an
            // externalGraphic, because icon has no setOffset API Method.
            if (feature.style.graphicXOffset
                && feature.style.graphicYOffset) {
                iconOffset = new OpenLayers.Pixel(
                    feature.style.graphicXOffset,
                    feature.style.graphicYOffset);
            }

            if (feature.style.externalGraphic != null) {
                data.icon = new OpenLayers.Icon(feature.style.externalGraphic,
                                                iconSize,
                                                iconOffset);
            } else {
                data.icon = OpenLayers.Marker.defaultIcon();

                //allows for the case where the image url is not
                // specified but the size is. use a default icon
                // but change the size
                if (iconSize != null) {
                    data.icon.setSize(iconSize);
                }
            }

            if ((feature.attributes.title != null)
                && (feature.attributes.description != null)) {
                data['popupContentHTML'] =
                    '
'+feature.attributes.title+'
' +
                    '
'+feature.attributes.description+'
';
            }

            data['overflow'] = feature.attributes.overflow || "auto";

            var markerFeature = new OpenLayers.Feature(this, location, data);
            this.features.push(markerFeature);
            var marker = markerFeature.createMarker();
            if ((feature.attributes.title != null)
                && (feature.attributes.description != null)) {
              marker.events.register('click', markerFeature, this.markerClick);
            }
            this.addMarker(marker);
        }
        this.events.triggerEvent("loadend");
    },

    /**
     * Property: markerClick
     *
     * Parameters:
     * evt - {Event}
     */
    markerClick: function(evt) {
        var sameMarkerClicked = (this == this.layer.selectedFeature);
        this.layer.selectedFeature = (!sameMarkerClicked) ? this : null;
        for(var i=0; i < this.layer.map.popups.length; i++) {
            this.layer.map.removePopup(this.layer.map.popups[i]);
        }
        if (!sameMarkerClicked) {
            this.layer.map.addPopup(this.createPopup());
        }
        OpenLayers.Event.stop(evt);
    },

    /**
     * Method: clearFeatures
     */
    clearFeatures: function() {
        if (this.features != null) {
            while(this.features.length > 0) {
                var feature = this.features[0];
                OpenLayers.Util.removeItem(this.features, feature);
                feature.destroy();
            }
        }
    },

    CLASS_NAME: "OpenLayers.Layer.Text"
});
<commit_msg>Fix to Layer.Text to allow iconOffset of 0,0 from Edgemaster, r=me (Closes #1467)<commit_after>/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
 * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */

/**
 * @requires OpenLayers/Layer/Markers.js
 * @requires OpenLayers/Ajax.js
 */

/**
 * Class: OpenLayers.Layer.Text
 * This layer creates markers given data in a text file.  The <location>
 *     property of the layer (specified as a property of the options argument
 *     in the <OpenLayers.Layer.Text> constructor) points to a tab delimited
 *     file with data used to create markers.
 *
 * The first row of the data file should be a header line with the column names
 *     of the data. Each column should be delimited by a tab space. The
 *     possible columns are:
 *      - *point* lat,lon of the point where a marker is to be placed
 *      - *lat*  Latitude of the point where a marker is to be placed
 *      - *lon*  Longitude of the point where a marker is to be placed
 *      - *iconURL* URL of marker icon to use.
 *      - *iconSize* Size of Icon to use.
 *      - *iconOffset* Where the top-left corner of the icon is to be placed
 *            relative to the latitude and longitude of the point.
 *      - *title* The text of the 'title' is placed inside an 'h2' marker
 *            inside a popup, which opens when the marker is clicked.
 *      - *description* The text of the 'description' is placed below the h2
 *            in the popup. this can be plain text or HTML.
 *
 * Example text file:
 * (code)
 * lat	lon	title	description	iconSize	iconOffset	icon
 * 10	20	title	description	21,25		-10,-25		http://www.openlayers.org/dev/img/marker.png
 * (end)
 *
 * Inherits from:
 *  - <OpenLayers.Layer.Markers>
 */
OpenLayers.Layer.Text = OpenLayers.Class(OpenLayers.Layer.Markers, {

    /**
     * APIProperty: location
     * {String} URL of text file.  Must be specified in the "options" argument
     *   of the constructor. Can not be changed once passed in.
     */
    location:null,

    /**
     * Property: features
     * {Array(<OpenLayers.Feature>)}
     */
    features: null,

    /**
     * APIProperty: formatOptions
     * {Object} Hash of options which should be passed to the format when it is
     * created. Must be passed in the constructor.
     */
    formatOptions: null,

    /**
     * Property: selectedFeature
     * {<OpenLayers.Feature>}
     */
    selectedFeature: null,

    /**
     * Constructor: OpenLayers.Layer.Text
     * Create a text layer.
     *
     * Parameters:
     * name - {String}
     * options - {Object} Object with properties to be set on the layer.
     *     Must include <location> property.
     */
    initialize: function(name, options) {
        OpenLayers.Layer.Markers.prototype.initialize.apply(this, arguments);
        this.features = new Array();
    },

    /**
     * APIMethod: destroy
     */
    destroy: function() {
        // Warning: Layer.Markers.destroy() must be called prior to calling
        // clearFeatures() here, otherwise we leak memory. Indeed, if
        // Layer.Markers.destroy() is called after clearFeatures(), it won't be
        // able to remove the marker image elements from the layer's div since
        // the markers will have been destroyed by clearFeatures().
        OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments);
        this.clearFeatures();
        this.features = null;
    },

    /**
     * Method: loadText
     * Start the load of the Text data. Don't do this when we first add the layer,
     * since we may not be visible at any point, and it would therefore be a waste.
     */
    loadText: function() {
        if (!this.loaded) {
            if (this.location != null) {

                var onFail = function(e) {
                    this.events.triggerEvent("loadend");
                };

                this.events.triggerEvent("loadstart");
                OpenLayers.loadURL(this.location, null,
                                   this, this.parseData, onFail);
                this.loaded = true;
            }
        }
    },

    /**
     * Method: moveTo
     * If layer is visible and Text has not been loaded, load Text.
     *
     * Parameters:
     * bounds - {Object}
     * zoomChanged - {Object}
     * minor - {Object}
     */
    moveTo:function(bounds, zoomChanged, minor) {
        OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments);
        if(this.visibility && !this.loaded){
            this.events.triggerEvent("loadstart");
            this.loadText();
        }
    },

    /**
     * Method: parseData
     *
     * Parameters:
     * ajaxRequest - {XMLHttpRequest}
     */
    parseData: function(ajaxRequest) {
        var text = ajaxRequest.responseText;

        var options = {};

        OpenLayers.Util.extend(options, this.formatOptions);

        if (this.map && !this.projection.equals(this.map.getProjectionObject())) {
            options.externalProjection = this.projection;
            options.internalProjection = this.map.getProjectionObject();
        }

        var parser = new OpenLayers.Format.Text(options);
        features = parser.read(text);
        for (var i = 0; i < features.length; i++) {
            var data = {};
            var feature = features[i];
            var location;
            var iconSize, iconOffset;

            location = new OpenLayers.LonLat(feature.geometry.x,
                                             feature.geometry.y);

            if (feature.style.graphicWidth
                && feature.style.graphicHeight) {
                iconSize = new OpenLayers.Size(
                    feature.style.graphicWidth,
                    feature.style.graphicHeight);
            }

            // FIXME: At the moment, we only use this if we have an
            // externalGraphic, because icon has no setOffset API Method.
            if (feature.style.graphicXOffset !== null
                && feature.style.graphicYOffset !== null) {
                iconOffset = new OpenLayers.Pixel(
                    feature.style.graphicXOffset,
                    feature.style.graphicYOffset);
            }

            if (feature.style.externalGraphic != null) {
                data.icon = new OpenLayers.Icon(feature.style.externalGraphic,
                                                iconSize,
                                                iconOffset);
            } else {
                data.icon = OpenLayers.Marker.defaultIcon();

                //allows for the case where the image url is not
                // specified but the size is. use a default icon
                // but change the size
                if (iconSize != null) {
                    data.icon.setSize(iconSize);
                }
            }

            if ((feature.attributes.title != null)
                && (feature.attributes.description != null)) {
                data['popupContentHTML'] =
                    '
'+feature.attributes.title+'
' +
                    '
'+feature.attributes.description+'
';
            }

            data['overflow'] = feature.attributes.overflow || "auto";

            var markerFeature = new OpenLayers.Feature(this, location, data);
            this.features.push(markerFeature);
            var marker = markerFeature.createMarker();
            if ((feature.attributes.title != null)
                && (feature.attributes.description != null)) {
              marker.events.register('click', markerFeature, this.markerClick);
            }
            this.addMarker(marker);
        }
        this.events.triggerEvent("loadend");
    },

    /**
     * Property: markerClick
     *
     * Parameters:
     * evt - {Event}
     */
    markerClick: function(evt) {
        var sameMarkerClicked = (this == this.layer.selectedFeature);
        this.layer.selectedFeature = (!sameMarkerClicked) ? this : null;
        for(var i=0; i < this.layer.map.popups.length; i++) {
            this.layer.map.removePopup(this.layer.map.popups[i]);
        }
        if (!sameMarkerClicked) {
            this.layer.map.addPopup(this.createPopup());
        }
        OpenLayers.Event.stop(evt);
    },

    /**
     * Method: clearFeatures
     */
    clearFeatures: function() {
        if (this.features != null) {
            while(this.features.length > 0) {
                var feature = this.features[0];
                OpenLayers.Util.removeItem(this.features, feature);
                feature.destroy();
            }
        }
    },

    CLASS_NAME: "OpenLayers.Layer.Text"
});
<|endoftext|>


<commit_before>/**
 * Unobstrusive date picker widget using jQuery.
 * example : $('select.uo_widget_form_date_picker, :text.uo_widget_form_date_picker').uoWidgetFormDatePicker({});
 *
 * @author     François Béliveau <francois.beliveau@my-labz.com>
 */
;(function($) {

  $.fn.uoWidgetFormDatePicker = function(customConfiguration)
  {
    // default configuration
    var configuration = {
      showOn:          'button',
      buttonImageOnly: true,
      buttonImage:     '/sfUnobstrusiveWidgetPlugin/images/default/uo_widget_form_date_picker/calendar.gif',
      changeFirstDay:  false
    };

    // merge default and custom configuration
    $.extend(true, configuration, customConfiguration);

    return this.each(function(index)
    {
      var $widget       = $(this);
      var $rangeWidget  = false;
      var $baseId       = '';
      var $baseRangeId  = '';
      var $widgets      = {};
      var $rangeWidgets = {};

      /**
       * Initialize widget
       */
      function init()
      {
        // prevent initialize twice
        if ($widget.hasClass('uo_widget_form_date_picker_ON'))
        {
          return $widget;
        }

        var id   = $widget.attr('id') || '';
        $baseId  =  id.substr(0, id.lastIndexOf('_'));
        $widgets = initWidgets($widget, $baseId);
        initRange();

        if ($rangeWidget.length > 0)
        {
          for (var property in $widgets)
          {
            $widgets[property].change(dateUpdate);
          }

          for (var property in $rangeWidgets)
          {
            $rangeWidgets[property].change(dateUpdate);
          }
        }

        $widget.removeClass('uo_widget_form_date_picker');
        $widget.addClass('uo_widget_form_date_picker_ON');
        $('#' + $baseId).datepicker(getConfiguration());
        if ($widget.attr('disabled'))
        {
          $('#' + $baseId.replace('_from', '_to')).datepicker('disable');
        }

        if ($rangeWidget)
        {
          $rangeWidget.removeClass('uo_widget_form_date_picker');
          $rangeWidget.addClass('uo_widget_form_date_picker_ON');
          $('#' + $baseId.replace('_from', '_to')).datepicker(getConfiguration());
          if ($rangeWidget.attr('disabled'))
          {
            $('#' + $baseId.replace('_from', '_to')).datepicker('disable');
          }
        }
      }

      /**
       * Return widget's specific configuration
       */
      function getConfiguration()
      {
        var result = {};

        if (undefined == result.beforeShow)
        {
          result.beforeShow = readLinked;
        }

        if (undefined == result.onSelect)
        {
          result.onSelect = updateLinked;
        }

        return $.extend(true, configuration, result);
      }

      /**
       * Initialize range
       */
      function initRange()
      {
        var id   = $widget.attr('id') || '';
        var name = $widget.attr('name') || '';

        if (name.lastIndexOf('[from]') > 0)
        {
          $rangeWidget = $('#' + id.replace('_from', '_to'));
          if ($rangeWidget.length < 1)
          {
            $rangeWidget = false;
          }
          else
          {
            $baseRangeId  = $baseId.replace('_from', '_to');
            $rangeWidgets = initWidgets($rangeWidget, $baseRangeId);
          }
        }
      }

      /**
       * Initialize widgets
       */
      function initWidgets(elm, baseId)
      {
        var result   = {};
        var id       = elm.attr('id') || '';
        if (id == baseId)
        {
          return result;
        }

        var day   = $('#' + baseId + '_day');
        var month = $('#' + baseId + '_month');
        var year  = $('#' + baseId + '_year');

        if (day.length > 0 && month.length > 0 && year.length > 0)
        {
          result.day   = day;
          result.month = month;
          result.year  = year;

          elm.after('<input type="hidden" id="' + baseId  +'" />');
          result.month.change(checkLinkedDays);
          result.year.change(checkLinkedDays);
        }

        return result;
      }

      /**
       * Prepare to show a date picker linked to 3 controls
       */
      function readLinked(input, inst)
      {
        var objects = false;
        var minDate = null;
        var maxDate = null;
        if ($(this).attr('id') == $baseId)
        {
          objects = $widgets;
        }
        else if ($(this).attr('id') == $baseRangeId)
        {
          objects = $rangeWidgets;
        }

        if (objects)
        {
          $(this).val(objects.month.val() + '/' + objects.day.val() + '/' + objects.year.val());

          if ($('option', objects.year).length > 0)
          {
            minDate = new Date(($('option:eq(0)', objects.year).attr('value') != '') ? $('option:eq(0)', objects.year).attr('value') : $('option:eq(1)', objects.year).attr('value'), 1 - 1, 1);
            maxDate = new Date($('option:last', objects.year).attr('value'), 12 - 1, 31);
          }

          if ($rangeWidget)
          {
            if ($(this).attr('id') == $baseRangeId && $('#' + $baseId).datepicker("getDate") != null)
            {
              minDate = $('#' + $baseId).datepicker("getDate");
            }
            if ($(this).attr('id') == $baseId && $('#' + $baseRangeId).datepicker("getDate") != null)
            {
              maxDate = $('#' + $baseRangeId).datepicker("getDate");
            }
          }
        }

        if (inst.settings.maxDate && !maxDate)
        {
          maxDate = inst.settings.maxDate;
        }
        if (inst.settings.minDate && !minDate)
        {
          minDate = inst.settings.minDate;
        }

        if (minDate > maxDate)
        {
          minDate = maxDate;
        }

        return { minDate: minDate, maxDate: maxDate };
      }

      /**
       * Update 3 controls to match a date picker selection
       */
      function updateLinked(dateText, inst)
      {
        var objects = false;
        if ($(this).attr('id') == $baseId)
        {
          objects = $widgets;
        }
        else if ($(this).attr('id') == $baseRangeId)
        {
          objects = $rangeWidgets;
        }

        if (objects)
        {
          indexForDay   = $.datepicker._defaults.dateFormat.indexOf('dd');
          indexForMonth = $.datepicker._defaults.dateFormat.indexOf('mm');
          indexForYear  = $.datepicker._defaults.dateFormat.indexOf('yy');

          var offsetForYear;
          if (objects.year.attr('maxlength'))
          {
            offsetForYear = objects.year.attr('maxlength');
          }
          else
          {
            var lastYear = objects.year.find('option:last').attr('value');
            offsetForYear = lastYear.length;
          }

          objects.month.val(dateText.substring(indexForMonth, indexForMonth+2));
          objects.day.val(dateText.substring(indexForDay, indexForDay+2));
          objects.year.val(dateText.substring(indexForYear, indexForYear+offsetForYear));
        }
      }

      /**
       * Update date picker date (for date range)
       */
      function dateUpdate()
      {
        var id      = $(this).attr('id') || '';
        var baseId  = id.substr(0, id.lastIndexOf('_'));
        var objects = false;
        if (baseId == $baseId)
        {
          objects = $widgets;
        }
        else if (baseId == $baseRangeId)
        {
          objects = $rangeWidgets;
        }

        $('#'+baseId).val(objects.month.val() + '/' + objects.day.val() + '/' + objects.year.val());
      }

      /**
       * Prevent selection of invalid dates through the controls
       */
      function checkLinkedDays()
      {
        var id      = $(this).attr('id') || '';
        var baseId  = id.substr(0, id.lastIndexOf('_'));
        var objects = false;
        if (baseId == $baseId)
        {
          objects = $widgets;
        }
        else if (baseId == $baseRangeId)
        {
          objects = $rangeWidgets;
        }

        var daysInMonth = 32 - new Date(objects.year.val(), objects.month.val() - 1, 32).getDate();

        $('option', objects.day).removeAttr('disabled');
        var daysInMonthIndex = daysInMonth;
        if ('' != $('option:first-child', objects.day).val())
        {
          daysInMonthIndex--;
        }
        $('option:gt(' + daysInMonthIndex + ')', objects.day).attr("disabled", "disabled");

        if (objects.day.val() > daysInMonth)
        {
          objects.day.val(daysInMonth);
        }
      }

      init();
    });

  };

})(jQuery);
<commit_msg>[sfUnobstrusiveWidgetPlugin] fixed date picker to be able to use it with any date format<commit_after>/**
 * Unobstrusive date picker widget using jQuery.
 * example : $('select.uo_widget_form_date_picker, :text.uo_widget_form_date_picker').uoWidgetFormDatePicker({});
 *
 * @author     François Béliveau <francois.beliveau@my-labz.com>
 */
;(function($) {

  $.fn.uoWidgetFormDatePicker = function(customConfiguration)
  {
    // default configuration
    var configuration = {
      showOn:          'button',
      buttonImageOnly: true,
      buttonImage:     '/sfUnobstrusiveWidgetPlugin/images/default/uo_widget_form_date_picker/calendar.gif',
      changeFirstDay:  false
    };

    // merge default and custom configuration
    $.extend(true, configuration, customConfiguration);

    return this.each(function(index)
    {
      var $widget       = $(this);
      var $rangeWidget  = false;
      var $baseId       = '';
      var $baseRangeId  = '';
      var $widgets      = {};
      var $rangeWidgets = {};

      /**
       * Initialize widget
       */
      function init()
      {
        // prevent initialize twice
        if ($widget.hasClass('uo_widget_form_date_picker_ON'))
        {
          return $widget;
        }

        var id   = $widget.attr('id') || '';
        $baseId  =  id.substr(0, id.lastIndexOf('_'));
        $widgets = initWidgets($widget, $baseId);
        initRange();

        if ($rangeWidget.length > 0)
        {
          for (var property in $widgets)
          {
            $widgets[property].change(dateUpdate);
          }

          for (var property in $rangeWidgets)
          {
            $rangeWidgets[property].change(dateUpdate);
          }
        }

        $widget.removeClass('uo_widget_form_date_picker');
        $widget.addClass('uo_widget_form_date_picker_ON');
        $('#' + $baseId).datepicker(getConfiguration());
        if ($widget.attr('disabled'))
        {
          $('#' + $baseId.replace('_from', '_to')).datepicker('disable');
        }

        if ($rangeWidget)
        {
          $rangeWidget.removeClass('uo_widget_form_date_picker');
          $rangeWidget.addClass('uo_widget_form_date_picker_ON');
          $('#' + $baseId.replace('_from', '_to')).datepicker(getConfiguration());
          if ($rangeWidget.attr('disabled'))
          {
            $('#' + $baseId.replace('_from', '_to')).datepicker('disable');
          }
        }
      }

      /**
       * Return widget's specific configuration
       */
      function getConfiguration()
      {
        var result = {};

        if (undefined == result.beforeShow)
        {
          result.beforeShow = readLinked;
        }

        if (undefined == result.onSelect)
        {
          result.onSelect = updateLinked;
        }

        return $.extend(true, configuration, result);
      }

      /**
       * Initialize range
       */
      function initRange()
      {
        var id   = $widget.attr('id') || '';
        var name = $widget.attr('name') || '';

        if (name.lastIndexOf('[from]') > 0)
        {
          $rangeWidget = $('#' + id.replace('_from', '_to'));
          if ($rangeWidget.length < 1)
          {
            $rangeWidget = false;
          }
          else
          {
            $baseRangeId  = $baseId.replace('_from', '_to');
            $rangeWidgets = initWidgets($rangeWidget, $baseRangeId);
          }
        }
      }

      /**
       * Initialize widgets
       */
      function initWidgets(elm, baseId)
      {
        var result   = {};
        var id       = elm.attr('id') || '';
        if (id == baseId)
        {
          return result;
        }

        var day   = $('#' + baseId + '_day');
        var month = $('#' + baseId + '_month');
        var year  = $('#' + baseId + '_year');

        if (day.length > 0 && month.length > 0 && year.length > 0)
        {
          result.day   = day;
          result.month = month;
          result.year  = year;

          elm.after('<input type="hidden" id="' + baseId  +'" />');
          result.month.change(checkLinkedDays);
          result.year.change(checkLinkedDays);
        }

        return result;
      }

      /**
       * Prepare to show a date picker linked to 3 controls
       * beforeshow
       */
      function readLinked(input, inst)
      {
        var objects = false;
        var minDate = null;
        var maxDate = null;
        if ($(this).attr('id') == $baseId)
        {
          objects = $widgets;
        }
        else if ($(this).attr('id') == $baseRangeId)
        {
          objects = $rangeWidgets;
        }

        if (objects)
        {
          var
              currentDay   = objects.day.val(),
              currentMonth = objects.month.val(),
              currentYear  = objects.year.val();

            if (!currentDay)
            {
              currentDay = $('option[value!=""]:first', '#jst_registration_born_at_day').attr('value');
            }

            if (!currentMonth)
            {
              currentMonth = $('option[value!=""]:first', '#jst_registration_born_at_month').attr('value');
            }

            if (!currentYear)
            {
              currentYear = $('option[value!=""]:first', '#jst_registration_born_at_year').attr('value');
            }

          if (currentDay && currentMonth && currentYear)
          {
            $(input).datepicker('setDate', new Date(currentYear, currentMonth -1, currentDay));
          }

          if ($('option', objects.year).length > 0)
          {
            minDate = new Date(($('option:eq(0)', objects.year).attr('value') != '') ? $('option:eq(0)', objects.year).attr('value') : $('option:eq(1)', objects.year).attr('value'), 1 - 1, 1);
            maxDate = new Date($('option:last', objects.year).attr('value'), 12 - 1, 31);
          }

          if ($rangeWidget)
          {
            if ($(this).attr('id') == $baseRangeId && $('#' + $baseId).datepicker("getDate") != null)
            {
              minDate = $('#' + $baseId).datepicker("getDate");
            }
            if ($(this).attr('id') == $baseId && $('#' + $baseRangeId).datepicker("getDate") != null)
            {
              maxDate = $('#' + $baseRangeId).datepicker("getDate");
            }
          }
        }

        if (inst.settings.maxDate && !maxDate)
        {
          maxDate = inst.settings.maxDate;
        }
        if (inst.settings.minDate && !minDate)
        {
          minDate = inst.settings.minDate;
        }

        if (minDate > maxDate)
        {
          minDate = maxDate;
        }

        return { minDate: minDate, maxDate: maxDate };
      }

      /**
       * Update 3 controls to match a date picker selection
       */
      function updateLinked(dateText, inst)
      {
        var objects = false;
        if ($(this).attr('id') == $baseId)
        {
          objects = $widgets;
        }
        else if ($(this).attr('id') == $baseRangeId)
        {
          objects = $rangeWidgets;
        }

        if (objects)
        {
          objects.month.val(inst.selectedMonth + 1);
          objects.day.val(inst.selectedDay);
          objects.year.val(inst.selectedYear);
        }
      }

      /**
       * Update date picker date (for date range)
       */
      function dateUpdate()
      {
        var id      = $(this).attr('id') || '';
        var baseId  = id.substr(0, id.lastIndexOf('_'));
        var objects = false;
        if (baseId == $baseId)
        {
          objects = $widgets;
        }
        else if (baseId == $baseRangeId)
        {
          objects = $rangeWidgets;
        }

        $(input).datepicker('setDate', new Date(objects.year.val(), objects.month.val() -1, objects.day.val()));
      }

      /**
       * Prevent selection of invalid dates through the controls
       */
      function checkLinkedDays()
      {
        var id      = $(this).attr('id') || '';
        var baseId  = id.substr(0, id.lastIndexOf('_'));
        var objects = false;
        if (baseId == $baseId)
        {
          objects = $widgets;
        }
        else if (baseId == $baseRangeId)
        {
          objects = $rangeWidgets;
        }

        var daysInMonth = 32 - new Date(objects.year.val(), objects.month.val() - 1, 32).getDate();

        $('option', objects.day).removeAttr('disabled');
        var daysInMonthIndex = daysInMonth;
        if ('' != $('option:first-child', objects.day).val())
        {
          daysInMonthIndex--;
        }
        $('option:gt(' + daysInMonthIndex + ')', objects.day).attr("disabled", "disabled");

        if (objects.day.val() > daysInMonth)
        {
          objects.day.val(daysInMonth);
        }
      }

      init();
    });

  };

})(jQuery);
<|endoftext|>


<commit_before>// Description:
//   Buy soda or list balance
//
// Configuration:
//   SODA_TOKEN,
//   SODA_URL,
//   MEMBERS_URL
//
// Commands
//   hubot kjøp <produkt_navn> - Purchase a product from Brus
//   hubot brus produkter - Get a list of products from brus.abakus.no
//   hubot saldo brus - Get your balance brus.abakus.no

const _ = require('lodash');
const fetch = require('node-fetch');
const members = require('../lib/members');

const { SODA_TOKEN, SODA_URL } = process.env;

const sodaMappings = {
  ':dahls:': 'beer_dahls_bottle'
};

function brus(path, options = {}) {
  return fetch(
    `${SODA_URL}/api/liste${path}`,
    Object.assign(
      {
        method: 'GET',
        headers: {
          Authorization: `Token ${SODA_TOKEN}`,
          'Content-Type': 'application/json'
        }
      },
      options
    )
  );
}

function getSodaName(slackName) {
  return members(`?slack=${slackName}`).then(body => {
    const user = body[0];

    if (!user || !user.brus) {
      throw new Error(`Fant ikke ${slackName} på brus.`);
    }

    return user.brus;
  });
}
function getProducts() {
  return brus(`/products/`, {
    method: 'GET'
  })
    .then(response => {
      if (!response.ok) {
        throw new Error(`Jeg klarte ikke hente produktene fra brus`);
      }
      return response.json();
    })
    .then(body => {
      return body
        .map(product => `- \`${product.key}\`: ${product.current_price} kr`)
        .join('\n');
    });
}

function purchaseSoda(slackName, sodaType) {
  return getSodaName(slackName).then(name => {
    return brus(`/purchase/`, {
      method: 'POST',
      body: JSON.stringify({
        name,
        shopping_cart: [
          {
            product_name: sodaMappings[sodaType] || sodaType,
            count: 1
          }
        ]
      })
    }).then(response => {
      if (!response.ok) {
        if (response.status === 404) {
          throw new Error(
            `Jeg klarte ikke å kjøpe brusen: fant ikke noe produkt med navnet \`${sodaType}\`\nSkriv \`hubot brus produkter\` for å se listen`
          );
        } else {
          throw new Error(`Jeg klarte ikke å kjøpe brusen: ${response.status}`);
        }
      }

      return response.json();
    });
  });
}

module.exports = robot => {
  robot.respond(/kjøp (.*)?/i, msg => {
    const send = msg.send.bind(msg);
    const productName = msg.match[1].trim();
    purchaseSoda(msg.message.user.name, productName).catch(error =>
      send(error.message)
    );
  });

  robot.respond(/brus produkter/i, msg => {
    const send = msg.send.bind(msg);
    getProducts()
      .then(send)
      .catch(error => send(error.message));
  });

  robot.respond(/saldo brus( .*)?/i, msg => {
    const send = msg.send.bind(msg);
    const slackName = msg.match[1]
      ? msg.match[1].trim()
      : msg.message.user.name;

    getSodaName(slackName)
      .then(name => {
        return brus(`/${name}/`)
          .then(response => {
            if (response.status !== 200) {
              throw new Error(
                `Jeg klarte ikke hente info fra brus (${response.status}).`
              );
            }

            return response.json();
          })
          .then(
            // TODO: list products
            body =>
              `${body.name} sin saldo er ${
                body.balance
              } spenn. (TODO: produktliste, @noen fix)`
          );
      })
      .then(send)
      .catch(error => send(error.message));
  });
};
<commit_msg>Add dahls jul short-thing<commit_after>// Description:
//   Buy soda or list balance
//
// Configuration:
//   SODA_TOKEN,
//   SODA_URL,
//   MEMBERS_URL
//
// Commands
//   hubot kjøp <produkt_navn> - Purchase a product from Brus
//   hubot brus produkter - Get a list of products from brus.abakus.no
//   hubot saldo brus - Get your balance brus.abakus.no

const _ = require('lodash');
const fetch = require('node-fetch');
const members = require('../lib/members');

const { SODA_TOKEN, SODA_URL } = process.env;

const sodaMappings = {
  ':dahls:': 'beer_dahls_bottle',
  ':dahls-jul:': 'beer_dahls_jul_bottle'
};

function brus(path, options = {}) {
  return fetch(
    `${SODA_URL}/api/liste${path}`,
    Object.assign(
      {
        method: 'GET',
        headers: {
          Authorization: `Token ${SODA_TOKEN}`,
          'Content-Type': 'application/json'
        }
      },
      options
    )
  );
}

function getSodaName(slackName) {
  return members(`?slack=${slackName}`).then(body => {
    const user = body[0];

    if (!user || !user.brus) {
      throw new Error(`Fant ikke ${slackName} på brus.`);
    }

    return user.brus;
  });
}
function getProducts() {
  return brus(`/products/`, {
    method: 'GET'
  })
    .then(response => {
      if (!response.ok) {
        throw new Error(`Jeg klarte ikke hente produktene fra brus`);
      }
      return response.json();
    })
    .then(body => {
      return body
        .map(product => `- \`${product.key}\`: ${product.current_price} kr`)
        .join('\n');
    });
}

function purchaseSoda(slackName, sodaType) {
  return getSodaName(slackName).then(name => {
    return brus(`/purchase/`, {
      method: 'POST',
      body: JSON.stringify({
        name,
        shopping_cart: [
          {
            product_name: sodaMappings[sodaType] || sodaType,
            count: 1
          }
        ]
      })
    }).then(response => {
      if (!response.ok) {
        if (response.status === 404) {
          throw new Error(
            `Jeg klarte ikke å kjøpe brusen: fant ikke noe produkt med navnet \`${sodaType}\`\nSkriv \`hubot brus produkter\` for å se listen`
          );
        } else {
          throw new Error(`Jeg klarte ikke å kjøpe brusen: ${response.status}`);
        }
      }

      return response.json();
    });
  });
}

module.exports = robot => {
  robot.respond(/kjøp (.*)?/i, msg => {
    const send = msg.send.bind(msg);
    const productName = msg.match[1].trim();
    purchaseSoda(msg.message.user.name, productName).catch(error =>
      send(error.message)
    );
  });

  robot.respond(/brus produkter/i, msg => {
    const send = msg.send.bind(msg);
    getProducts()
      .then(send)
      .catch(error => send(error.message));
  });

  robot.respond(/saldo brus( .*)?/i, msg => {
    const send = msg.send.bind(msg);
    const slackName = msg.match[1]
      ? msg.match[1].trim()
      : msg.message.user.name;

    getSodaName(slackName)
      .then(name => {
        return brus(`/${name}/`)
          .then(response => {
            if (response.status !== 200) {
              throw new Error(
                `Jeg klarte ikke hente info fra brus (${response.status}).`
              );
            }

            return response.json();
          })
          .then(
            // TODO: list products
            body =>
              `${body.name} sin saldo er ${
                body.balance
              } spenn. (TODO: produktliste, @noen fix)`
          );
      })
      .then(send)
      .catch(error => send(error.message));
  });
};
<|endoftext|>


<commit_before>/*global base64, config, Prism, Konami, translations, START, END, shortcuts, shortcut_names */
(function() {
	'use strict';

	var debounceInput = false,
		regexParts = [];

	jQuery(function($) {
		var placeholder = '',
			placeholderItems = 2,
			placeholderStart = false,
			maxSeed = translations.length-1;

		// Make sure we don't make this placeholder too long.
		while (placeholderItems > 0) {
			var lastNum = false,
				seeded = '';

			// If this is the first item, randomly choose whether to show "beginning of the line" or not.
			if (placeholderItems === 2 && doIt()) {
				// START will be in the 'expanded' translations file.
				placeholder+= START+', ';
				placeholderStart = true;
				placeholderItems--;
			}

			seeded = translations[randomInterval(0, maxSeed)];

			// Make sure this isn't one of our catchAll translations as they won't make sense as a placeholder.
			if (seeded.catchAll) {
				continue;
			}

			seeded = seeded.name;

			// If the placeholder has any ? symbols, replace these all with random numbers
			while (/\?/.test(seeded)) {
				// Each part will only ever have max 2 numbers
				lastNum = lastNum === false ? randomInterval(2,5) : randomInterval(6,9);
				// Use normal string replace to only replace first instance each time.
				seeded = seeded.replace('?', lastNum);
			}

			placeholder += seeded+', ';
			placeholderItems--;

			// If there's a space left, it's randomly decided that we want to add the "end", and there's no start of line item.
			if (placeholderItems === 1 && doIt() && !placeholderStart) {
				// END will be in the 'expanded' translations file.
				placeholder+= END;
				placeholderItems--;
			}
		}

		// Prepend our configured text to the placeholder (for example: "Try: ")
		placeholder = config.placeHolderPrepend + placeholder.replace(/, $/, '');

		$('.verbose').keydown(function(){
			// hide any visible warning about noticed regex
			if ( $('.noticed-regex').is('.is-visible') ) {
				$('.noticed-regex').removeClass('is-visible');
			}
		}).keyup(function(e) {
			// If the user presses enter (13), or types a comma (188)
			if (e.keyCode === 13 || e.keyCode === 188) {
				parseInput.call(this, this); // Pass this in as an argument to get around a jshint strict issue in the parseInput function
			}
		}).change(function() {
			parseInput.call(this, this);
		}).attr('placeholder', placeholder);

		$('.result, .copy-result').live('click', function() {
			var height = Number($('.result').outerHeight())+Number($('.result > .part').css('padding-bottom').replace('px', ''))+Number($('.result > .part').css('padding-top').replace('px', ''));

			$('.result-container').addClass('busy-copying');
			$('.copy-me').height(height).select();
		});
		$('.copy-me').live('blur', function() {
			$('.result-container').removeClass('busy-copying');
		});
	});

	/**
	 * Dynmaically add the shortcuts to the help panel
	 * on click, add them to the verbose input, trigger change
	 * and hide the help panel. Replace all ? with a random number.
	 */
	(function helpShortcuts(){
		var current,
			i,
			shortcutItem = '',
			shortcutsList = '';

		for (i = 0; i < shortcut_names.length; i++) {
			shortcutsList += '
' + shortcut_names[i] + '
';
		}

		$('#shortcuts-list').append(shortcutsList);

		$('#shortcuts-list a').on('click', function(e){
			var shortcut = $(this).text();

			current = $.trim($('.verbose').val());

			// If we already have some entered value
			if (current !== '') {
				shortcutItem = current;

				// If it doesn't end in a `,` add one.
				if (/[^,]$/.test(current)) {
					shortcutItem+=',';
				}
			}

			shortcutItem+= shortcut;

			$('.verbose').val(shortcutItem).focus().trigger('change');
			$('.help-tab').trigger('click');

			e.preventDefault();
			return false;
		});

	})();

	/**
	 *	This function receives a string that it parses into a regex Object.
	 */
	function parseInput(input) {
		var parts = input.value.replace(/, /g, ',').split(','),
			regex = strToRegex(parts),
			regexString = '',
			regexStringCopy = '';

		if (!debounceInput) {
			debounceInput = true;

			setTimeout(function() {
				debounceInput = false;
			}, 250);
		} else {
			return false;
		}

		// If this looks like a regex,
		// i.e.: It looks like a range [a-z]
		// or it looks like a JS formatted regex
		// or there seems to be one of the character classes you escape in regex (eg: \s)
		if (/([\[\/][^,]+[\]\/]|\\[bdnrstw]|\{[0-9]+,?([0-9]+)?\})/.test(input.value)) {
			$('.noticed-regex').addClass('is-visible');
		} else {
			$('.noticed-regex').removeClass('is-visible');
		}

		for (var i=regex.length; i > 0; i--) {
			regexString+= ''+regex[regex.length-i]+'';
			regexStringCopy+= regex[regex.length-i];
		}

		// If the regex isn't empty, show the result, otherwise empty
		// the result and hide the container
		if ( regex[0] !== '' ) {
			$('.result').html(regexString);
			$('.copy-me').html(regexStringCopy);
			$('.result-container').slideDown(500, function(){
				// after slide down, set visible overflow to ensure
				// that the tooltips are visible above the container
				$('.result-container').css('overflow', 'visible');
			});

			$('.regexplained').attr('href', 'http://regexplained.co.uk/#' + base64.encode(JSON.stringify({pattern: regexStringCopy})));
		} else {
			$('.result').empty();
			$('.copy-me').empty();
			$('.result-container').slideUp();
		}
	}

	/**
	 *	This function receives a string that it parses into a regex Object.
	 *
	 *	@param parts An array of the individual bits of the string to parse
	 *	@returns regexParts The regex parts representing the regex string passed in. Use by doing `regexParts.join()`
	 */
	function strToRegex(parts) {
		// Reset the array.
		regexParts.length = 0;

		for (var i=parts.length; i > 0; i--) {
			var compareParts = [],
				comparisons,
				part = $.trim(parts[parts.length - i]),
				latest = '',
				negation = config.negation.test(part),
				optional = config.optionals.test(part),
				partSolved = false;

			if (optional) {
				part = $.trim(part.replace(config.optionals, ''));
			}
			if (negation) {
				part = $.trim(part.replace(config.negation, ''));
			}

			partSolved = probe(translations, part);

			latest = regexParts[regexParts.length-1];

			// If this part has a regex match AND is a negation AND is a range that doesn't already have a negation in it.
			if (partSolved && negation && /\[[^\^]/.test(regexParts[regexParts.length-1])) {
				// Add the ^ symbol to the start of any range that doesn't already have it.
				regexParts[regexParts.length-1] = latest.replace(/\[/, '[^');
			}
			if (optional && /^(\[|\()([^\]]*)(\]|\))(\+|\*|\{[^\}]*\})?$/.test(latest)) {
				regexParts[regexParts.length-1] = '('+latest+')?';
			}

			// Check for comparisons (i.e.: "foo or bar" = (foo|bar))
			if (!partSolved && config.comparator.test(part)) {
				comparisons = part.split(config.comparator);

				for (var j=comparisons.length; j > 0; j--) {
					// Only compare translations and NOT shortcuts as those are a little too advanced.
					compareParts.push(probe(translations,comparisons[comparisons.length - j], true));
				}

				regexParts.push('('+compareParts.join('|')+')');
			// If none of the translations matched, and this part isn't a shortcut then just give back the same as was input.
			} else if (!partSolved && !probe(shortcuts, part)) {
				regexParts.push(escapeRegExp(part));
			}
		}

		return regexParts;
	}

	/**
	 *	This function probes the given list for the given part.
	 *
	 *	@param list The array of translations/shortcuts we're probing.
	 *	@param part The particular string we're probing for.
	 *	@param returnPart Whether or not to rather return the part than automatically add it to regexParts.
	 *	@returns partSolved Either whether this particular part was found (boolean), or the part that was found if returnPart is true.
	 */
	function probe(list, part, returnPart) {
		for (var j=list.length; j > 0; j--) {
			var catchAll,
				newPart,
				regex = new RegExp('^'+list[list.length-j].input+'$');

			// If this part matches this translation, we have a winner.
			if ( regex.test(part.toLowerCase()) ) {
				if (list[list.length-j].catchAll) {
					// Don't lowercase as the user might expect capitals as input
					catchAll = part.replace(regex, list[list.length-j].output);

					// If the catch all doesn't begin with `[` or `(`
					if (!/^\[/.test(catchAll)) {
						catchAll = escapeRegExp(catchAll);
					}

					newPart = catchAll.replace(/\[\-\]/g, '[\\-]');
				} else {
					newPart = part.toLowerCase().replace(regex, list[list.length-j].output);
				}

				if (returnPart) {
					return newPart;
				} else {
					regexParts.push(newPart);
					return true;
				}
			}
		}

		if (returnPart) {
			// Return the unmodified part.
			return part;
		} else {
			return false;
		}
	}

	// This function was modified, but originally found here: http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
	function escapeRegExp(str) {
		return str.replace(/[\-\[\/\{\(\)\*\+\?\.\\\^\$\|\>]/g, "\\$&");
	}

	/**
	 *	Simple function that picks a random number between the given range.
	 *
	 *	@param from The beginning of the range.
	 *	@param to The end of the range.
	 *	@returns A number between `from` and `to`.
	 */
	function randomInterval(from,to) {
		return Math.floor(Math.random()*(to-from+1)+from);
	}

	/**
	 *	This function simply makes a binary decision and returns true/false as required.
	 *
	 *	@returns boolean
	 */
	function doIt() {
		return randomInterval(0, 1) === 1;
	}

	/**
	 * No widows in running text
	 */
	$('p').each(function() {
		$(this).html(function(i, html){
			return html.replace(/\s([\S]+)$/,' $1');
		});
	});

	Prism.highlightAll();

	/*===== Just a little bit of fun. =====*/
	var konami = new Konami();
	konami.code = function() {
		if ($('body').hasClass('excavating')) {
			$('body').removeClass('excavating');
		} else {
			$('body').addClass('excavating');
		}
	};
	konami.load();
})();
<commit_msg>Optionals now work with comparisons too.<commit_after>/*global base64, config, Prism, Konami, translations, START, END, shortcuts, shortcut_names */
(function() {
	'use strict';

	var debounceInput = false,
		regexParts = [];

	jQuery(function($) {
		var placeholder = '',
			placeholderItems = 2,
			placeholderStart = false,
			maxSeed = translations.length-1;

		// Make sure we don't make this placeholder too long.
		while (placeholderItems > 0) {
			var lastNum = false,
				seeded = '';

			// If this is the first item, randomly choose whether to show "beginning of the line" or not.
			if (placeholderItems === 2 && doIt()) {
				// START will be in the 'expanded' translations file.
				placeholder+= START+', ';
				placeholderStart = true;
				placeholderItems--;
			}

			seeded = translations[randomInterval(0, maxSeed)];

			// Make sure this isn't one of our catchAll translations as they won't make sense as a placeholder.
			if (seeded.catchAll) {
				continue;
			}

			seeded = seeded.name;

			// If the placeholder has any ? symbols, replace these all with random numbers
			while (/\?/.test(seeded)) {
				// Each part will only ever have max 2 numbers
				lastNum = lastNum === false ? randomInterval(2,5) : randomInterval(6,9);
				// Use normal string replace to only replace first instance each time.
				seeded = seeded.replace('?', lastNum);
			}

			placeholder += seeded+', ';
			placeholderItems--;

			// If there's a space left, it's randomly decided that we want to add the "end", and there's no start of line item.
			if (placeholderItems === 1 && doIt() && !placeholderStart) {
				// END will be in the 'expanded' translations file.
				placeholder+= END;
				placeholderItems--;
			}
		}

		// Prepend our configured text to the placeholder (for example: "Try: ")
		placeholder = config.placeHolderPrepend + placeholder.replace(/, $/, '');

		$('.verbose').keydown(function(){
			// hide any visible warning about noticed regex
			if ( $('.noticed-regex').is('.is-visible') ) {
				$('.noticed-regex').removeClass('is-visible');
			}
		}).keyup(function(e) {
			// If the user presses enter (13), or types a comma (188)
			if (e.keyCode === 13 || e.keyCode === 188) {
				parseInput.call(this, this); // Pass this in as an argument to get around a jshint strict issue in the parseInput function
			}
		}).change(function() {
			parseInput.call(this, this);
		}).attr('placeholder', placeholder);

		$('.result, .copy-result').live('click', function() {
			var height = Number($('.result').outerHeight())+Number($('.result > .part').css('padding-bottom').replace('px', ''))+Number($('.result > .part').css('padding-top').replace('px', ''));

			$('.result-container').addClass('busy-copying');
			$('.copy-me').height(height).select();
		});
		$('.copy-me').live('blur', function() {
			$('.result-container').removeClass('busy-copying');
		});
	});

	/**
	 * Dynmaically add the shortcuts to the help panel
	 * on click, add them to the verbose input, trigger change
	 * and hide the help panel. Replace all ? with a random number.
	 */
	(function helpShortcuts(){
		var current,
			i,
			shortcutItem = '',
			shortcutsList = '';

		for (i = 0; i < shortcut_names.length; i++) {
			shortcutsList += '
' + shortcut_names[i] + '
';
		}

		$('#shortcuts-list').append(shortcutsList);

		$('#shortcuts-list a').on('click', function(e){
			var shortcut = $(this).text();

			current = $.trim($('.verbose').val());

			// If we already have some entered value
			if (current !== '') {
				shortcutItem = current;

				// If it doesn't end in a `,` add one.
				if (/[^,]$/.test(current)) {
					shortcutItem+=',';
				}
			}

			shortcutItem+= shortcut;

			$('.verbose').val(shortcutItem).focus().trigger('change');
			$('.help-tab').trigger('click');

			e.preventDefault();
			return false;
		});

	})();

	/**
	 *	This function receives a string that it parses into a regex Object.
	 */
	function parseInput(input) {
		var parts = input.value.replace(/, /g, ',').split(','),
			regex = strToRegex(parts),
			regexString = '',
			regexStringCopy = '';

		if (!debounceInput) {
			debounceInput = true;

			setTimeout(function() {
				debounceInput = false;
			}, 250);
		} else {
			return false;
		}

		// If this looks like a regex,
		// i.e.: It looks like a range [a-z]
		// or it looks like a JS formatted regex
		// or there seems to be one of the character classes you escape in regex (eg: \s)
		if (/([\[\/][^,]+[\]\/]|\\[bdnrstw]|\{[0-9]+,?([0-9]+)?\})/.test(input.value)) {
			$('.noticed-regex').addClass('is-visible');
		} else {
			$('.noticed-regex').removeClass('is-visible');
		}

		for (var i=regex.length; i > 0; i--) {
			regexString+= ''+regex[regex.length-i]+'';
			regexStringCopy+= regex[regex.length-i];
		}

		// If the regex isn't empty, show the result, otherwise empty
		// the result and hide the container
		if ( regex[0] !== '' ) {
			$('.result').html(regexString);
			$('.copy-me').html(regexStringCopy);
			$('.result-container').slideDown(500, function(){
				// after slide down, set visible overflow to ensure
				// that the tooltips are visible above the container
				$('.result-container').css('overflow', 'visible');
			});

			$('.regexplained').attr('href', 'http://regexplained.co.uk/#' + base64.encode(JSON.stringify({pattern: regexStringCopy})));
		} else {
			$('.result').empty();
			$('.copy-me').empty();
			$('.result-container').slideUp();
		}
	}

	/**
	 *	This function receives a string that it parses into a regex Object.
	 *
	 *	@param parts An array of the individual bits of the string to parse
	 *	@returns regexParts The regex parts representing the regex string passed in. Use by doing `regexParts.join()`
	 */
	function strToRegex(parts) {
		// Reset the array.
		regexParts.length = 0;

		for (var i=parts.length; i > 0; i--) {
			var compareParts = [],
				comparisons,
				part = $.trim(parts[parts.length - i]),
				latest = '',
				negation = config.negation.test(part),
				optional = config.optionals.test(part),
				partSolved = false;

			if (optional) {
				part = $.trim(part.replace(config.optionals, ''));
			}
			if (negation) {
				part = $.trim(part.replace(config.negation, ''));
			}

			partSolved = probe(translations, part);

			latest = regexParts[regexParts.length-1];

			// If this part has a regex match AND is a negation AND is a range that doesn't already have a negation in it.
			if (partSolved && negation && /\[[^\^]/.test(regexParts[regexParts.length-1])) {
				// Add the ^ symbol to the start of any range that doesn't already have it.
				regexParts[regexParts.length-1] = latest.replace(/\[/, '[^');
			}
			if (optional && /^(\[|\()([^\]]*)(\]|\))(\+|\*|\{[^\}]*\})?$/.test(latest)) {
				regexParts[regexParts.length-1] = '('+latest+')?';
			}

			// Check for comparisons (i.e.: "foo or bar" = (foo|bar))
			if (!partSolved && config.comparator.test(part)) {
				comparisons = part.split(config.comparator);

				for (var j=comparisons.length; j > 0; j--) {
					// Only compare translations and NOT shortcuts as those are a little too advanced.
					compareParts.push(probe(translations,comparisons[comparisons.length - j], true));
				}

				regexParts.push('('+compareParts.join('|')+')'+(optional ? '?' : ''));
			// If none of the translations matched, and this part isn't a shortcut then just give back the same as was input.
			} else if (!partSolved && !probe(shortcuts, part)) {
				regexParts.push(escapeRegExp(part));
			}
		}

		return regexParts;
	}

	/**
	 *	This function probes the given list for the given part.
	 *
	 *	@param list The array of translations/shortcuts we're probing.
	 *	@param part The particular string we're probing for.
	 *	@param returnPart Whether or not to rather return the part than automatically add it to regexParts.
	 *	@returns partSolved Either whether this particular part was found (boolean), or the part that was found if returnPart is true.
	 */
	function probe(list, part, returnPart) {
		for (var j=list.length; j > 0; j--) {
			var catchAll,
				newPart,
				regex = new RegExp('^'+list[list.length-j].input+'$');

			// If this part matches this translation, we have a winner.
			if ( regex.test(part.toLowerCase()) ) {
				if (list[list.length-j].catchAll) {
					// Don't lowercase as the user might expect capitals as input
					catchAll = part.replace(regex, list[list.length-j].output);

					// If the catch all doesn't begin with `[` or `(`
					if (!/^\[/.test(catchAll)) {
						catchAll = escapeRegExp(catchAll);
					}

					newPart = catchAll.replace(/\[\-\]/g, '[\\-]');
				} else {
					newPart = part.toLowerCase().replace(regex, list[list.length-j].output);
				}

				if (returnPart) {
					return newPart;
				} else {
					regexParts.push(newPart);
					return true;
				}
			}
		}

		if (returnPart) {
			// Return the unmodified part.
			return part;
		} else {
			return false;
		}
	}

	// This function was modified, but originally found here: http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
	function escapeRegExp(str) {
		return str.replace(/[\-\[\/\{\(\)\*\+\?\.\\\^\$\|\>]/g, "\\$&");
	}

	/**
	 *	Simple function that picks a random number between the given range.
	 *
	 *	@param from The beginning of the range.
	 *	@param to The end of the range.
	 *	@returns A number between `from` and `to`.
	 */
	function randomInterval(from,to) {
		return Math.floor(Math.random()*(to-from+1)+from);
	}

	/**
	 *	This function simply makes a binary decision and returns true/false as required.
	 *
	 *	@returns boolean
	 */
	function doIt() {
		return randomInterval(0, 1) === 1;
	}

	/**
	 * No widows in running text
	 */
	$('p').each(function() {
		$(this).html(function(i, html){
			return html.replace(/\s([\S]+)$/,' $1');
		});
	});

	Prism.highlightAll();

	/*===== Just a little bit of fun. =====*/
	var konami = new Konami();
	konami.code = function() {
		if ($('body').hasClass('excavating')) {
			$('body').removeClass('excavating');
		} else {
			$('body').addClass('excavating');
		}
	};
	konami.load();
})();
<|endoftext|>


<commit_before>Utils_Toltip__showTip = function(tip, my_event) {
	var div_tip = $('tooltip_div');
	var tooltip_text = $('tooltip_text');
	if(!div_tip || !tooltip_text) return;
	tooltip_text.innerHTML = tip;
	var dimensions = div_tip.getDimensions();

	var curPosx = ((my_event.clientX) ? parseInt(my_event.clientX) : parseInt(my_event.x));
	var curPosy = ((my_event.clientY) ? parseInt(my_event.clientY) : parseInt(my_event.y));

	if(document.body.scrollLeft + curPosx + 20 + dimensions.width < document.body.clientWidth - 10) {
		var pos = document.body.scrollLeft + curPosx + 20;
		div_tip.style.left = pos + 'px';
	} else {
		var pos = document.body.scrollLeft + curPosx - (dimensions.width) - 10;
		div_tip.style.left = pos + 'px';//$('ev').style.width;
	}

	var ch = (document.documentElement.clientHeight < document.body.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight)
	var scrollTop = (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
	if(navigator.appName.indexOf('Explorer') != -1 ) {
		scrollTop = document.documentElement.scrollTop;
	}

	//tooltip_text.innerHTML += ' ' + scrollTop + ' ' + ch;

	if(curPosy + 20 + dimensions.height < ch - 10) {
		var pos = scrollTop + curPosy + 20;
		div_tip.style.top = pos + "px";
	} else {
		var pos = scrollTop + curPosy - (dimensions.height) - 10;
		div_tip.style.top = pos + "px";
	}

	div_tip.style.display = 'block';
}

Utils_Toltip__hideTip = function() {
	$('tooltip_div').style.display = 'none';
} <commit_msg>tooltip fix<commit_after>Utils_Toltip__showTip = function(tip, my_event) {
	var div_tip = $('tooltip_div');
	var tooltip_text = $('tooltip_text');
	if(!div_tip || !tooltip_text) return;
	tooltip_text.innerHTML = tip;
	var dimensions = div_tip.getDimensions();

	var curPosx = ((my_event.clientX) ? parseInt(my_event.clientX) : parseInt(my_event.x));
	var curPosy = ((my_event.clientY) ? parseInt(my_event.clientY) : parseInt(my_event.y));

	if(document.body.scrollLeft + curPosx + 20 + dimensions.width < document.body.clientWidth - 10) {
		var pos = document.body.scrollLeft + curPosx + 20;
		div_tip.style.left = pos + 'px';
	} else {
		var pos = document.body.scrollLeft + curPosx - (dimensions.width) - 10;
		if(pos<0) pos=0;
		div_tip.style.left = pos + 'px';//$('ev').style.width;
	}

	var ch = (document.documentElement.clientHeight < document.body.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight)
	var scrollTop = (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
	if(navigator.appName.indexOf('Explorer') != -1 ) {
		scrollTop = document.documentElement.scrollTop;
	}

	//tooltip_text.innerHTML += ' ' + scrollTop + ' ' + ch;

	if(curPosy + 20 + dimensions.height < ch - 10) {
		var pos = scrollTop + curPosy + 20;
		div_tip.style.top = pos + "px";
	} else {
		var pos = scrollTop + curPosy - (dimensions.height) - 10;
		if(pos<0) pos=0;
		div_tip.style.top = pos + "px";
	}

	div_tip.style.display = 'block';
}

Utils_Toltip__hideTip = function() {
	$('tooltip_div').style.display = 'none';
} <|endoftext|>


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

/**
 * Checks if the given account ID appears to be a valid Analyics account.
 *
 * @param {(string|number)} accountID Account ID to test.
 * @return {boolean} Whether or not the given account ID is valid.
 */
export function isValidAccountID( accountID ) {
	const accountInt = parseInt( accountID ) || 0;

	return accountInt > 0;
}

/**
 * Checks whether the given property ID appears to be valid.
 *
 * @param {*} propertyID Property ID to check.
 * @return {boolean} Whether or not the given property ID is valid.
 */
export function isValidPropertyID( propertyID ) {
	return typeof propertyID === 'string' && propertyID.match( /^UA-\d+-\d+$/ );
}
<commit_msg>Add validation utilities for profile and internal web property IDs.<commit_after>/**
 * Validation utilities.
 *
 * Site Kit by Google, Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Checks the given value to see if it is a positive integer.
 *
 * @param {*} input Value to check.
 * @return {boolean} Validity.
 */
const isValidNumericID = function( input ) {
	const id = parseInt( input ) || 0;

	return id > 0;
};

/**
 * Checks if the given account ID appears to be a valid Analyics account.
 *
 * @param {(string|number)} accountID Account ID to test.
 * @return {boolean} Whether or not the given account ID is valid.
 */
export { isValidNumericID as isValidAccountID };

/**
 * Checks whether the given property ID appears to be valid.
 *
 * @param {*} propertyID Property ID to check.
 * @return {boolean} Whether or not the given property ID is valid.
 */
export function isValidPropertyID( propertyID ) {
	return typeof propertyID === 'string' && propertyID.match( /^UA-\d+-\d+$/ );
}

/**
 * Checks if the given profile ID appears to be valid.
 *
 * @param {(string|number)} accountID Account ID to test.
 * @return {boolean} Whether or not the given account ID is valid.
 */
export { isValidNumericID as isValidProfileID };

/**
 * Checks if the given internal web property ID appears to be valid.
 *
 * @param {(string|number)} accountID Account ID to test.
 * @return {boolean} Whether or not the given account ID is valid.
 */
export { isValidNumericID as isValidInternalWebPropertyID };
<|endoftext|>


<commit_before>/**
 * Created by tobias on 14.12.2015.
 */
var express = require('express');
var router = express.Router();

// connect to a local database. We assume that we do not need a user name / password
var db = require('monk')('localhost/mmn');

// this collection holds our notes
var notesCollection = db.get('notes');

// we enable updates / removals of multiple documents on collection-level.
notesCollection.options.multi = true;

/**
 * simply return all the notes in the database collection "notes"
 * The query params could be passed as GET parameters.
 */
router.get('/', function (req, res) {
    // find all notes, unless we find mongo selection parameters in the get request.
    // TODO
    // 1. query the database using the notesCollection
    // 2. respond to the client with a JSON object
    /*
         The response should look like this in case of success:
         {
            status : 'success',
            message : 'fetched notes',
            notes : ... // array containing the fetched notes.
         }

         In case of an error, adjust the response accordingly. The status and message fields are mandatory.
     */
});

/**
 * this route is used to insert notes into the notes collection.
 * it accepts both a single Object and an array of notes in req.body.notes
 */
router.post('/insert', function (req, res) {
    var notes;
    // make sure the parsing succeeded and notes is not null.
    if (req.body && req.body.notes) {
        // TODO
        // 1. use the right method on notesCollection to insert the data
        // 2. provide a callback function that is used when the insertion is done
        // 3. make sure to send a JSON as response.
        /*
            The response should look like this in case of success:
            {
                status : 'success',
                message : 'successfully inserted the note(s)',
                inserted : ... // array containing the inserted notes.
            }

            In case of an error, adjust the response accordingly. The status and message fields are mandatory.
         */
    }
    // either the body-parser failed or the parameter "notes" is missing in the request.
    else {
        res.json({
            status: 'error',
            code: 1000,
            message: 'missing parameter \'notes\''
        })
    }
});

/**
 * this route can be used to delete notes from the database.
 * req.body.notes is expected to be an array of document-ids (hex-value)
 * eg.
 * {
 *   notes :  ["566fdb2c9b8629381cfff85e","566fdb279b8629381cfff85d"]
 * }
 *
 */
router.post('/delete', function (req, res) {
    var notes;
    // make sure the POST parameter is present.
    if (req.body && req.body.notes) {

        // use whatever we get, but we need an array
        if (req.body.notes instanceof Array) {
            // it already is an array, so we use it.
            notes = req.body.notes;
        }
        else if(req.body.notes instanceof Object){
            // it is an object, so it should contain the _id field. Wrap it in a 1-element array.
            notes = [req.body.notes._id];
        }
        else if(req.body.notes instanceof String){
            // it is a string, so we assume it contains the id as hex-value
            notes = [req.body.notes];
        }

        // now we have to "cast" all the ids to real ObjectId objects.
        // to speed this up without for loops, we use the .map() function
        notes = notes.map(function(i){
            return notesCollection.id(i);
        });

        // notes now contains an array of ObjectIds.

        notesCollection.remove({
            _id: {
                // the $in operator is kind of slow, but does the job.
                // it takes each item in the notes array and checks if there is an object with such an id.
                $in: notes
            }
        }, function (e) {
            // remove does not return a docs array, only an error (if any)
            if (!e) {
                // everything went fine, let's inform the client
                res.json({
                    status: 'success',
                    code: 200,
                    message: 'removed ' + notes.length + ' notes.' // this is not accurate, but rather an upper boundary.
                })
            }
            else {
                // somehow, the removal failed, inform the client.
                res.json({
                    status: 'error',
                    code: 1002,
                    message: 'There was an error removing the data'
                })
            }
        })
    }
    else {
        // the notes parameter is missing in the request or the body parser failed.
        res.json({
            status: 'error',
            code: 1000,
            message: 'missing parameter \'notes\''
        })
    }
});

module.exports = router;
<commit_msg>TASK-09 Implement create- and delete-routes<commit_after>/**
 * Created by tobias on 14.12.2015.
 */
var express = require('express');
var router = express.Router();

// connect to a local database. We assume that we do not need a user name / password
var db = require('monk')('localhost/mmn');

// this collection holds our notes
var notesCollection = db.get('notes');

// we enable updates / removals of multiple documents on collection-level.
notesCollection.options.multi = true;

/**
 * simply return all the notes in the database collection "notes"
 * The query params could be passed as GET parameters.
 */
router.get('/', function (req, res) {
    // find all notes, unless we find mongo selection parameters in the get request.

    // response-dummy, will be modified within monk-callback
    var response = {
        status: '',
        message: '',
        notes: []
    };

    // selection parameters, expected to be
    var where = {};

    // if we were passed selection parameters in the request: use them!
    if (req.query.title) {
        where.extend({title: req.query.title});
    }

    if (req.query.content) {
        where.extend({content: req.query.content});
    }

    notesCollection.find(where, function (err, docs) {
        if (err) {
            response.status = 'failure';
            response.message = err.message;

        } else {
            response.status = 'success';
            response.message = 'inserted notes';
            response.notes = docs;
        }

        res.json(response);
    });

});

/**
 * this route is used to insert notes into the notes collection.
 * it accepts both a single Object and an array of notes in req.body.notes
 */
router.post('/insert', function (req, res) {
    var notes;
    var response = {
        status: '',
        message: '',
        inserted: []
    };

    // make sure the parsing succeeded and notes is not null.
    if (req.body && req.body.notes) {

        if (req.body.notes instanceof Array) {
            notes = req.body.notes;
        } else if (req.body.notes instanceof Object) {
            notes = [req.body.notes];
        }

        notesCollection.insert(notes, function (err, docs) {
            if (err) {
                response.status = 'failure';
                response.message = err.message;

            } else {
                response.status = 'success';
                response.message = 'successfully inserted the note(s)';
                response.inserted = docs;
            }

            res.json(response);
        });
    }
    // either the body-parser failed or the parameter "notes" is missing in the request.
    else {
        res.json({
            status: 'error',
            code: 1000,
            message: 'missing parameter \'notes\''
        })
    }
});

/**
 * this route can be used to delete notes from the database.
 * req.body.notes is expected to be an array of document-ids (hex-value)
 * eg.
 * {
 *   notes :  ["566fdb2c9b8629381cfff85e","566fdb279b8629381cfff85d"]
 * }
 *
 */
router.post('/delete', function (req, res) {
    var notes;
    // make sure the POST parameter is present.
    if (req.body && req.body.notes) {

        // use whatever we get, but we need an array
        if (req.body.notes instanceof Array) {
            // it already is an array, so we use it.
            notes = req.body.notes;
        }
        else if(req.body.notes instanceof Object){
            // it is an object, so it should contain the _id field. Wrap it in a 1-element array.
            notes = [req.body.notes._id];
        }
        else if(req.body.notes instanceof String){
            // it is a string, so we assume it contains the id as hex-value
            notes = [req.body.notes];
        }

        // now we have to "cast" all the ids to real ObjectId objects.
        // to speed this up without for loops, we use the .map() function
        notes = notes.map(function(i){
            return notesCollection.id(i);
        });

        // notes now contains an array of ObjectIds.

        notesCollection.remove({
            _id: {
                // the $in operator is kind of slow, but does the job.
                // it takes each item in the notes array and checks if there is an object with such an id.
                $in: notes
            }
        }, function (e) {
            // remove does not return a docs array, only an error (if any)
            if (!e) {
                // everything went fine, let's inform the client
                res.json({
                    status: 'success',
                    code: 200,
                    message: 'removed ' + notes.length + ' notes.' // this is not accurate, but rather an upper boundary.
                })
            }
            else {
                // somehow, the removal failed, inform the client.
                res.json({
                    status: 'error',
                    code: 1002,
                    message: 'There was an error removing the data'
                })
            }
        })
    }
    else {
        // the notes parameter is missing in the request or the body parser failed.
        res.json({
            status: 'error',
            code: 1000,
            message: 'missing parameter \'notes\''
        })
    }
});

module.exports = router;
<|endoftext|>


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

/**
 * Statistic functions for {@link DataFrame}s.
 * @constructor
 * @since EclairJS 0.1 Spark  1.4.0
 * @classdesc
 */

var DataFrameStatFunctions = function(jvmObject) {

	 this.logger = Logger.getLogger("DataFrameStatFunctions_js");
	 JavaWrapper.call(this, jvmObject);

};

DataFrameStatFunctions.prototype = Object.create(JavaWrapper.prototype);

DataFrameStatFunctions.prototype.constructor = DataFrameStatFunctions;

/**
 * Calculate the sample covariance of two numerical columns of a DataFrame.
 * @param {string} col1  the name of the first column
 * @param {string} col2  the name of the second column
 *
 * @example
 *    var stat = peopleDataFrame.stat().cov("income", "networth");
 *
 *
 * @since EclairJS 0.1 Spark  1.4.0
 * @returns {number}  the covariance of the two columns.
 */
DataFrameStatFunctions.prototype.cov = function(col1,col2) {
	return this.getJavaObject().cov(col1,col2);
}

/**
 * Calculates the correlation of two columns of a DataFrame. Currently only supports the Pearson
 * Correlation Coefficient. For Spearman Correlation, consider using RDD methods found in
 * MLlib's Statistics.
 *
 * @param {string} col1  the name of the column
 * @param {string} col2  the name of the column to calculate the correlation against
 * @param {string} method Optional currently only supports the "pearson"
 * @example
 *    var stat = peopleDataFrame.stat().cov("income", "networth", "pearson");
 *
 *
 * @since EclairJS 0.1 Spark  1.4.0
 * @returns {number}  The Pearson Correlation Coefficient.
 */
DataFrameStatFunctions.prototype.corr = function(col1,col2,method) {
	if (method) {
		return  this.getJavaObject().corr(col1,col2,method);
	} else {
		return  this.getJavaObject().corr(col1,col2);
	}

}

/**
 * Computes a pair-wise frequency table of the given columns. Also known as a contingency table.
 * The number of distinct values for each column should be less than 1e4. At most 1e6 non-zero
 * pair frequencies will be returned.
 * The first column of each row will be the distinct values of `col1` and the column names will
 * be the distinct values of `col2`. The name of the first column will be `$col1_$col2`. Counts
 * will be returned as `Long`s. Pairs that have no occurrences will have zero as their counts.
 * Null elements will be replaced by "null", and back ticks will be dropped from elements if they
 * exist.
 *
 *
 * @param {string} col1  The name of the first column. Distinct items will make the first item of
 *             each row.
 * @param {string} col2  The name of the second column. Distinct items will make the column names
 *             of the DataFrame.
 *
 * @example
 *   var df = sqlContext.createDataFrame([[1,1], [1,2], [2,1], [2,1], [2,3], [3,2], [3,3]], schema);
 *   var ct = df.stat().crosstab("key", "value");
 *   ct.show();
 *    +---------+---+---+---+
 *    |key_value|  1|  2|  3|
 *    +---------+---+---+---+
 *    |        2|  2|  0|  1|
 *    |        1|  1|  1|  0|
 *    |        3|  0|  1|  1|
 *    +---------+---+---+---+
 *
 *
 * @since EclairJS 0.1 Spark  1.4.0
 * @returns {DataFrame}  A DataFrame containing for the contingency table.
 */
DataFrameStatFunctions.prototype.crosstab = function(col1,col2) {
   var javaObject =  this.getJavaObject().crosstab(col1,col2);
   return new DataFrame(javaObject);
}

/**
 * Finding frequent items for columns, possibly with false positives. Using the
 * frequent element count algorithm described in
 * [[http://dx.doi.org/10.1145/762471.762473, proposed by Karp, Schenker, and Papadimitriou]].
 * The `support` should be greater than 1e-4.
 *
 * This function is meant for exploratory data analysis, as we make no guarantee about the
 * backward compatibility of the schema of the resulting {@link DataFrame}.
 *
 * @param {string[]} cols  the names of the columns to search frequent items in.
 * @param {number} support  The minimum frequency for an item to be considered `frequent`. Should be greater
 *                than 1e-4. defaults to 1% (0.01)
 *
 * @example
 *    // find the items with a frequency greater than 0.4 (observed 40% of the time) for columns
 *    // "a" and "b"
 *    var freqSingles = df.stat.freqItems(["a", "b"]), 0.4)
 *    freqSingles.show()
 *    +-----------+-------------+
 *    |a_freqItems|  b_freqItems|
 *    +-----------+-------------+
 *    |    [1, 99]|[-1.0, -99.0]|
 *    +-----------+-------------+
 *
 *
 * @since EclairJS 0.1 Spark  1.4.0
 * @returns {DataFrame}  A Local DataFrame with the Array of frequent items for each column.
 */
DataFrameStatFunctions.prototype.freqItems = function(cols,support) {
   var javaObject;
   if (support) {
	   javaObject =  this.getJavaObject().freqItems(cols,support);
   } else {
	   javaObject =  this.getJavaObject().freqItems(cols);
   }

   return new DataFrame(javaObject);
}

/**
 * Returns a stratified sample without replacement based on the fraction given on each stratum.
 * @param {string} col  column that defines strata
 * @param {object} fractions is expected to be a HashMap, the key of the map is the column name, and the value of the map is the replacement value.
 * The value must be of the following type: `number`or `String`.
 * @param {integer} seed  random seed
 *
 * @example
 *    var df = sqlContext.createDataFrame([[1,1], [1,2], [2,1], [2,1], [2,3], [3,2], [3,3]], schema).toDF("key", "value");
 *    var fractions = {"1": 1.0, "3": 0.5);
 *    df.stat.sampleBy("key", fractions, 36L).show()
 *    +---+-----+
 *    |key|value|
 *    +---+-----+
 *    |  1|    1|
 *    |  1|    2|
 *    |  3|    2|
 *    +---+-----+
 *
 *
 * @since EclairJS 0.1 Spark  1.5.0
 * @returns {DataFrame}  a new [[DataFrame]] that represents the stratified sample
 */
DataFrameStatFunctions.prototype.sampleBywithnumber = function(col,fractions,seed) {
	var fractions_uw = Utils.createJavaHashMap(fractions);
	var javaObject =  this.getJavaObject().sampleBy(col,fractions_uw,seed);
	return new DataFrame(javaObject);
}
<commit_msg>DataFrameStatFunctions.sampleBy was named wrongly<commit_after>/*
* Copyright 2015 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
 * Statistic functions for {@link DataFrame}s.
 * @constructor
 * @since EclairJS 0.1 Spark  1.4.0
 * @classdesc
 */

var DataFrameStatFunctions = function(jvmObject) {

	 this.logger = Logger.getLogger("DataFrameStatFunctions_js");
	 JavaWrapper.call(this, jvmObject);

};

DataFrameStatFunctions.prototype = Object.create(JavaWrapper.prototype);

DataFrameStatFunctions.prototype.constructor = DataFrameStatFunctions;

/**
 * Calculate the sample covariance of two numerical columns of a DataFrame.
 * @param {string} col1  the name of the first column
 * @param {string} col2  the name of the second column
 *
 * @example
 *    var stat = peopleDataFrame.stat().cov("income", "networth");
 *
 *
 * @since EclairJS 0.1 Spark  1.4.0
 * @returns {number}  the covariance of the two columns.
 */
DataFrameStatFunctions.prototype.cov = function(col1,col2) {
	return this.getJavaObject().cov(col1,col2);
}

/**
 * Calculates the correlation of two columns of a DataFrame. Currently only supports the Pearson
 * Correlation Coefficient. For Spearman Correlation, consider using RDD methods found in
 * MLlib's Statistics.
 *
 * @param {string} col1  the name of the column
 * @param {string} col2  the name of the column to calculate the correlation against
 * @param {string} method Optional currently only supports the "pearson"
 * @example
 *    var stat = peopleDataFrame.stat().cov("income", "networth", "pearson");
 *
 *
 * @since EclairJS 0.1 Spark  1.4.0
 * @returns {number}  The Pearson Correlation Coefficient.
 */
DataFrameStatFunctions.prototype.corr = function(col1,col2,method) {
	if (method) {
		return  this.getJavaObject().corr(col1,col2,method);
	} else {
		return  this.getJavaObject().corr(col1,col2);
	}

}

/**
 * Computes a pair-wise frequency table of the given columns. Also known as a contingency table.
 * The number of distinct values for each column should be less than 1e4. At most 1e6 non-zero
 * pair frequencies will be returned.
 * The first column of each row will be the distinct values of `col1` and the column names will
 * be the distinct values of `col2`. The name of the first column will be `$col1_$col2`. Counts
 * will be returned as `Long`s. Pairs that have no occurrences will have zero as their counts.
 * Null elements will be replaced by "null", and back ticks will be dropped from elements if they
 * exist.
 *
 *
 * @param {string} col1  The name of the first column. Distinct items will make the first item of
 *             each row.
 * @param {string} col2  The name of the second column. Distinct items will make the column names
 *             of the DataFrame.
 *
 * @example
 *   var df = sqlContext.createDataFrame([[1,1], [1,2], [2,1], [2,1], [2,3], [3,2], [3,3]], schema);
 *   var ct = df.stat().crosstab("key", "value");
 *   ct.show();
 *    +---------+---+---+---+
 *    |key_value|  1|  2|  3|
 *    +---------+---+---+---+
 *    |        2|  2|  0|  1|
 *    |        1|  1|  1|  0|
 *    |        3|  0|  1|  1|
 *    +---------+---+---+---+
 *
 *
 * @since EclairJS 0.1 Spark  1.4.0
 * @returns {DataFrame}  A DataFrame containing for the contingency table.
 */
DataFrameStatFunctions.prototype.crosstab = function(col1,col2) {
   var javaObject =  this.getJavaObject().crosstab(col1,col2);
   return new DataFrame(javaObject);
}

/**
 * Finding frequent items for columns, possibly with false positives. Using the
 * frequent element count algorithm described in
 * [[http://dx.doi.org/10.1145/762471.762473, proposed by Karp, Schenker, and Papadimitriou]].
 * The `support` should be greater than 1e-4.
 *
 * This function is meant for exploratory data analysis, as we make no guarantee about the
 * backward compatibility of the schema of the resulting {@link DataFrame}.
 *
 * @param {string[]} cols  the names of the columns to search frequent items in.
 * @param {number} support  The minimum frequency for an item to be considered `frequent`. Should be greater
 *                than 1e-4. defaults to 1% (0.01)
 *
 * @example
 *    // find the items with a frequency greater than 0.4 (observed 40% of the time) for columns
 *    // "a" and "b"
 *    var freqSingles = df.stat.freqItems(["a", "b"]), 0.4)
 *    freqSingles.show()
 *    +-----------+-------------+
 *    |a_freqItems|  b_freqItems|
 *    +-----------+-------------+
 *    |    [1, 99]|[-1.0, -99.0]|
 *    +-----------+-------------+
 *
 *
 * @since EclairJS 0.1 Spark  1.4.0
 * @returns {DataFrame}  A Local DataFrame with the Array of frequent items for each column.
 */
DataFrameStatFunctions.prototype.freqItems = function(cols,support) {
   var javaObject;
   if (support) {
	   javaObject =  this.getJavaObject().freqItems(cols,support);
   } else {
	   javaObject =  this.getJavaObject().freqItems(cols);
   }

   return new DataFrame(javaObject);
}

/**
 * Returns a stratified sample without replacement based on the fraction given on each stratum.
 * @param {string} col  column that defines strata
 * @param {object} fractions is expected to be a HashMap, the key of the map is the column name, and the value of the map is the replacement value.
 * The value must be of the following type: `number`or `String`.
 * @param {integer} seed  random seed
 *
 * @example
 *    var df = sqlContext.createDataFrame([[1,1], [1,2], [2,1], [2,1], [2,3], [3,2], [3,3]], schema).toDF("key", "value");
 *    var fractions = {"1": 1.0, "3": 0.5);
 *    df.stat.sampleBy("key", fractions, 36L).show()
 *    +---+-----+
 *    |key|value|
 *    +---+-----+
 *    |  1|    1|
 *    |  1|    2|
 *    |  3|    2|
 *    +---+-----+
 *
 *
 * @since EclairJS 0.1 Spark  1.5.0
 * @returns {DataFrame}  a new [[DataFrame]] that represents the stratified sample
 */
DataFrameStatFunctions.prototype.sampleBy = function(col,fractions,seed) {
	var fractions_uw = Utils.createJavaHashMap(fractions);
	var javaObject =  this.getJavaObject().sampleBy(col,fractions_uw,seed);
	return new DataFrame(javaObject);
}
<|endoftext|>