<commit_before>import L from 'leaflet';
import { cors } from '../Support';
import { setEsriAttribution } from '../Util';

var Overlay = L.ImageOverlay.extend({
  onAdd: function (map) {
    this._topLeft = map.getPixelBounds().min;
    L.ImageOverlay.prototype.onAdd.call(this, map);
  },
  _reset: function () {
    if (this._map.options.crs === L.CRS.EPSG3857) {
      L.ImageOverlay.prototype._reset.call(this);
    } else {
      L.DomUtil.setPosition(this._image, this._topLeft.subtract(this._map.getPixelOrigin()));
    }
  }
});

export var RasterLayer = L.Layer.extend({

  options: {
    opacity: 1,
    position: 'front',
    f: 'image',
    useCors: cors,
    attribution: null,
    interactive: false,
    alt: ''
  },

  onAdd: function (map) {
    // include 'Powered by Esri' in map attribution
    setEsriAttribution(map);

    this._update = L.Util.throttle(this._update, this.options.updateInterval, this);

    map.on('moveend', this._update, this);

    // if we had an image loaded and it matches the
    // current bounds show the image otherwise remove it
    if (this._currentImage && this._currentImage._bounds.equals(this._map.getBounds())) {
      map.addLayer(this._currentImage);
    } else if (this._currentImage) {
      this._map.removeLayer(this._currentImage);
      this._currentImage = null;
    }

    this._update();

    if (this._popup) {
      this._map.on('click', this._getPopupData, this);
      this._map.on('dblclick', this._resetPopupState, this);
    }

    // add copyright text listed in service metadata
    this.metadata(function (err, metadata) {
      if (!err && !this.options.attribution && map.attributionControl && metadata.copyrightText) {
        this.options.attribution = metadata.copyrightText;
        map.attributionControl.addAttribution(this.getAttribution());
      }
    }, this);
  },

  onRemove: function (map) {
    if (this._currentImage) {
      this._map.removeLayer(this._currentImage);
    }

    if (this._popup) {
      this._map.off('click', this._getPopupData, this);
      this._map.off('dblclick', this._resetPopupState, this);
    }

    this._map.off('moveend', this._update, this);
  },

  bindPopup: function (fn, popupOptions) {
    this._shouldRenderPopup = false;
    this._lastClick = false;
    this._popup = L.popup(popupOptions);
    this._popupFunction = fn;
    if (this._map) {
      this._map.on('click', this._getPopupData, this);
      this._map.on('dblclick', this._resetPopupState, this);
    }
    return this;
  },

  unbindPopup: function () {
    if (this._map) {
      this._map.closePopup(this._popup);
      this._map.off('click', this._getPopupData, this);
      this._map.off('dblclick', this._resetPopupState, this);
    }
    this._popup = false;
    return this;
  },

  bringToFront: function () {
    this.options.position = 'front';
    if (this._currentImage) {
      this._currentImage.bringToFront();
    }
    return this;
  },

  bringToBack: function () {
    this.options.position = 'back';
    if (this._currentImage) {
      this._currentImage.bringToBack();
    }
    return this;
  },

  getAttribution: function () {
    return this.options.attribution;
  },

  getOpacity: function () {
    return this.options.opacity;
  },

  setOpacity: function (opacity) {
    this.options.opacity = opacity;
    if (this._currentImage) {
      this._currentImage.setOpacity(opacity);
    }
    return this;
  },

  getTimeRange: function () {
    return [this.options.from, this.options.to];
  },

  setTimeRange: function (from, to) {
    this.options.from = from;
    this.options.to = to;
    this._update();
    return this;
  },

  metadata: function (callback, context) {
    this.service.metadata(callback, context);
    return this;
  },

  authenticate: function (token) {
    this.service.authenticate(token);
    return this;
  },

  redraw: function () {
    this._update();
  },

  _renderImage: function (url, bounds, contentType) {
    if (this._map) {
      // if no output directory has been specified for a service, MIME data will be returned
      if (contentType) {
        url = 'data:' + contentType + ';base64,' + url;
      }
      // create a new image overlay and add it to the map
      // to start loading the image
      // opacity is 0 while the image is loading
      var image = new Overlay(url, bounds, {
        opacity: 0,
        crossOrigin: this.options.useCors,
        alt: this.options.alt,
        pane: this.options.pane || this.getPane(),
        interactive: this.options.interactive
      }).addTo(this._map);

      // once the image loads
      image.once('load', function (e) {
        if (this._map) {
          var newImage = e.target;
          var oldImage = this._currentImage;

          // if the bounds of this image matches the bounds that
          // _renderImage was called with and we have a map with the same bounds
          // hide the old image if there is one and set the opacity
          // of the new image otherwise remove the new image
          if (newImage._bounds.equals(bounds) && newImage._bounds.equals(this._map.getBounds())) {
            this._currentImage = newImage;

            if (this.options.position === 'front') {
              this.bringToFront();
            } else {
              this.bringToBack();
            }

            if (this._map && this._currentImage._map) {
              this._currentImage.setOpacity(this.options.opacity);
            } else {
              this._currentImage._map.removeLayer(this._currentImage);
            }

            if (oldImage && this._map) {
              this._map.removeLayer(oldImage);
            }

            if (oldImage && oldImage._map) {
              oldImage._map.removeLayer(oldImage);
            }
          } else {
            this._map.removeLayer(newImage);
          }
        }

        this.fire('load', {
          bounds: bounds
        });
      }, this);

      this.fire('loading', {
        bounds: bounds
      });
    }
  },

  _update: function () {
    if (!this._map) {
      return;
    }

    var zoom = this._map.getZoom();
    var bounds = this._map.getBounds();

    if (this._animatingZoom) {
      return;
    }

    if (this._map._panTransition && this._map._panTransition._inProgress) {
      return;
    }

    if (zoom > this.options.maxZoom || zoom < this.options.minZoom) {
      if (this._currentImage && this._currentImage._map) {
        this._currentImage._map.removeLayer(this._currentImage);
      }
      return;
    }

    var params = this._buildExportParams();

    this._requestExport(params, bounds);
  },

  _renderPopup: function (latlng, error, results, response) {
    latlng = L.latLng(latlng);
    if (this._shouldRenderPopup && this._lastClick.equals(latlng)) {
      // add the popup to the map where the mouse was clicked at
      var content = this._popupFunction(error, results, response);
      if (content) {
        this._popup.setLatLng(latlng).setContent(content).openOn(this._map);
      }
    }
  },

  _resetPopupState: function (e) {
    this._shouldRenderPopup = false;
    this._lastClick = e.latlng;
  }
});
<commit_msg>dont check for _map, nullify the variable<commit_after>import L from 'leaflet';
import { cors } from '../Support';
import { setEsriAttribution } from '../Util';

var Overlay = L.ImageOverlay.extend({
  onAdd: function (map) {
    this._topLeft = map.getPixelBounds().min;
    L.ImageOverlay.prototype.onAdd.call(this, map);
  },
  _reset: function () {
    if (this._map.options.crs === L.CRS.EPSG3857) {
      L.ImageOverlay.prototype._reset.call(this);
    } else {
      L.DomUtil.setPosition(this._image, this._topLeft.subtract(this._map.getPixelOrigin()));
    }
  }
});

export var RasterLayer = L.Layer.extend({

  options: {
    opacity: 1,
    position: 'front',
    f: 'image',
    useCors: cors,
    attribution: null,
    interactive: false,
    alt: ''
  },

  onAdd: function (map) {
    // include 'Powered by Esri' in map attribution
    setEsriAttribution(map);

    this._update = L.Util.throttle(this._update, this.options.updateInterval, this);

    map.on('moveend', this._update, this);

    // if we had an image loaded and it matches the
    // current bounds show the image otherwise remove it
    if (this._currentImage && this._currentImage._bounds.equals(this._map.getBounds())) {
      map.addLayer(this._currentImage);
    } else if (this._currentImage) {
      this._map.removeLayer(this._currentImage);
      this._currentImage = null;
    }

    this._update();

    if (this._popup) {
      this._map.on('click', this._getPopupData, this);
      this._map.on('dblclick', this._resetPopupState, this);
    }

    // add copyright text listed in service metadata
    this.metadata(function (err, metadata) {
      if (!err && !this.options.attribution && map.attributionControl && metadata.copyrightText) {
        this.options.attribution = metadata.copyrightText;
        map.attributionControl.addAttribution(this.getAttribution());
      }
    }, this);
  },

  onRemove: function (map) {
    if (this._currentImage) {
      this._map.removeLayer(this._currentImage);
    }

    if (this._popup) {
      this._map.off('click', this._getPopupData, this);
      this._map.off('dblclick', this._resetPopupState, this);
    }

    this._map.off('moveend', this._update, this);
  },

  bindPopup: function (fn, popupOptions) {
    this._shouldRenderPopup = false;
    this._lastClick = false;
    this._popup = L.popup(popupOptions);
    this._popupFunction = fn;
    if (this._map) {
      this._map.on('click', this._getPopupData, this);
      this._map.on('dblclick', this._resetPopupState, this);
    }
    return this;
  },

  unbindPopup: function () {
    if (this._map) {
      this._map.closePopup(this._popup);
      this._map.off('click', this._getPopupData, this);
      this._map.off('dblclick', this._resetPopupState, this);
    }
    this._popup = false;
    return this;
  },

  bringToFront: function () {
    this.options.position = 'front';
    if (this._currentImage) {
      this._currentImage.bringToFront();
    }
    return this;
  },

  bringToBack: function () {
    this.options.position = 'back';
    if (this._currentImage) {
      this._currentImage.bringToBack();
    }
    return this;
  },

  getAttribution: function () {
    return this.options.attribution;
  },

  getOpacity: function () {
    return this.options.opacity;
  },

  setOpacity: function (opacity) {
    this.options.opacity = opacity;
    if (this._currentImage) {
      this._currentImage.setOpacity(opacity);
    }
    return this;
  },

  getTimeRange: function () {
    return [this.options.from, this.options.to];
  },

  setTimeRange: function (from, to) {
    this.options.from = from;
    this.options.to = to;
    this._update();
    return this;
  },

  metadata: function (callback, context) {
    this.service.metadata(callback, context);
    return this;
  },

  authenticate: function (token) {
    this.service.authenticate(token);
    return this;
  },

  redraw: function () {
    this._update();
  },

  _renderImage: function (url, bounds, contentType) {
    if (this._map) {
      // if no output directory has been specified for a service, MIME data will be returned
      if (contentType) {
        url = 'data:' + contentType + ';base64,' + url;
      }
      // create a new image overlay and add it to the map
      // to start loading the image
      // opacity is 0 while the image is loading
      var image = new Overlay(url, bounds, {
        opacity: 0,
        crossOrigin: this.options.useCors,
        alt: this.options.alt,
        pane: this.options.pane || this.getPane(),
        interactive: this.options.interactive
      }).addTo(this._map);

      // once the image loads
      image.once('load', function (e) {
        if (this._map) {
          var newImage = e.target;
          var oldImage = this._currentImage;

          // if the bounds of this image matches the bounds that
          // _renderImage was called with and we have a map with the same bounds
          // hide the old image if there is one and set the opacity
          // of the new image otherwise remove the new image
          if (newImage._bounds.equals(bounds) && newImage._bounds.equals(this._map.getBounds())) {
            this._currentImage = newImage;

            if (this.options.position === 'front') {
              this.bringToFront();
            } else {
              this.bringToBack();
            }

            if (this._map && this._currentImage._map) {
              this._currentImage.setOpacity(this.options.opacity);
            } else {
              this._currentImage._map.removeLayer(this._currentImage);
            }

            if (oldImage && this._map) {
              this._map.removeLayer(oldImage);
            }

            if (oldImage && oldImage._map) {
              oldImage._map.removeLayer(oldImage);
            }
          } else {
            this._map.removeLayer(newImage);
          }
        }

        this.fire('load', {
          bounds: bounds
        });
      }, this);

      this.fire('loading', {
        bounds: bounds
      });
    }
  },

  _update: function () {
    if (!this._map) {
      return;
    }

    var zoom = this._map.getZoom();
    var bounds = this._map.getBounds();

    if (this._animatingZoom) {
      return;
    }

    if (this._map._panTransition && this._map._panTransition._inProgress) {
      return;
    }

    if (zoom > this.options.maxZoom || zoom < this.options.minZoom) {
      if (this._currentImage) {
        this._currentImage._map.removeLayer(this._currentImage);
        this._currentImage = null;
      }
      return;
    }

    var params = this._buildExportParams();

    this._requestExport(params, bounds);
  },

  _renderPopup: function (latlng, error, results, response) {
    latlng = L.latLng(latlng);
    if (this._shouldRenderPopup && this._lastClick.equals(latlng)) {
      // add the popup to the map where the mouse was clicked at
      var content = this._popupFunction(error, results, response);
      if (content) {
        this._popup.setLatLng(latlng).setContent(content).openOn(this._map);
      }
    }
  },

  _resetPopupState: function (e) {
    this._shouldRenderPopup = false;
    this._lastClick = e.latlng;
  }
});
<|endoftext|>


<commit_before>import { GetFormattedTime } from "../../utils/time.js";
let sha1 = require('sha1');

class InfoContainer {
    constructor(annotator){
        this.annotator = annotator;
        this.$container = $("

").appendTo(this.annotator.$container);
    }

    Rebuild(annotations){
        let plural = annotations.length == 1 ? "" : "s";
        let totalAnnotations = this.annotator.annotationManager.annotations.length;
        this.$container.empty();
        this.$container.html("
Showing " + annotations.length + " annotation" + plural + " (" + totalAnnotations + " total).
");

        // Add each annotation to the readout
        for (let i = 0; i < annotations.length; i++){
            this.$container.append(this.MakeContainer(annotations[i], i));
        }
    }

    MakeContainer(annotation, index){
        let $panel = $("

").appendTo($("

").appendTo(this.$container));
        //let text = JSON.stringify(annotation.AsOpenAnnotation(), null, 2);

        let $header = $("Annotation " + (index + 1) + ":
");
        $panel.append($header);
        let $content = $("

");

        $content.append("Text:  " + annotation.data.text);
        $content.append("
");
        $content.append("Tags:  " + annotation.data.tags.join(", "));
        $content.append("
");
        $content.append("Time:  "
                + GetFormattedTime(annotation.data.beginTime / 1000)
                + " - "
                + GetFormattedTime(annotation.data.endTime / 1000));
        $content.append("
");

        $content.append("Submitted by:
"
                + (annotation.metadata.userEmail != null ? sha1(annotation.metadata.userEmail) : "unspecified")
                );

        //$paragraph.append("Annotation " + (index + 1) + ":

" + text.escapeHTML() + "
");

        $panel.append($content);
        return $panel;
    }

}

export { InfoContainer };<commit_msg>Add edit capability to info container entries (allow editing of annotations with no polygons)<commit_after>import { GetFormattedTime } from "../../utils/time.js";
let sha1 = require('sha1');

class InfoContainer {
    constructor(annotator){
        this.annotator = annotator;
        this.$container = $("

").appendTo(this.annotator.$container);
    }

    Rebuild(annotations){
        let plural = annotations.length == 1 ? "" : "s";
        let totalAnnotations = this.annotator.annotationManager.annotations.length;
        this.$container.empty();
        this.$container.html(`<p>Showing ${annotations.length} annotation${plural} (${totalAnnotations} total).</p>`);

        // Add each annotation to the readout
        for (let i = 0; i < annotations.length; i++){
            this.$container.append(this.MakeContainer(annotations[i], i));
        }
    }

    MakeContainer(annotation, index){
        let $panel = $("

").appendTo($("

").appendTo(this.$container));
        //let text = JSON.stringify(annotation.AsOpenAnnotation(), null, 2);

        // Add clickable header that brings up the edit interface.
        let $header = $(`<a href='' title='Edit Annotation'><b>Annotation ${index + 1}:</b><br></a>`);
        $header.click( (event) => {
            event.preventDefault();
            this.annotator.gui.BeginEditing(annotation);
        });

        $panel.append($header);
        let $content = $("

");

        $content.append("Text:  " + annotation.data.text);
        $content.append("
");
        $content.append("Tags:  " + annotation.data.tags.join(", "));
        $content.append("
");
        $content.append("Time:  "
                + GetFormattedTime(annotation.data.beginTime / 1000)
                + " - "
                + GetFormattedTime(annotation.data.endTime / 1000));
        $content.append("
");

        $content.append("Submitted by:
"
                + (annotation.metadata.userEmail != null ? sha1(annotation.metadata.userEmail) : "unspecified")
                );

        //$paragraph.append("Annotation " + (index + 1) + ":

" + text.escapeHTML() + "
");

        $panel.append($content);
        return $panel;
    }

}

export { InfoContainer };<|endoftext|>


<commit_before>function resize_main_div() {
    // Resize main_div to exactly take up remaining vertical space.
    var div = $('#main_div');
    div.height(Math.max(200, div.height() + $(window).height() - $('body').height()));
}
$(function () {
    resize_main_div();
    $(window).resize(resize_main_div);
    $('#zephyr-type-tabs a').on('shown', function (e) { resize_main_div(); });
});

$.ajaxSetup({
     beforeSend: function(xhr, settings) {
         function getCookie(name) {
             var cookieValue = null;
             if (document.cookie && document.cookie != '') {
                 var cookies = document.cookie.split(';');
                 for (var i = 0; i < cookies.length; i++) {
                     var cookie = jQuery.trim(cookies[i]);
                     // Does this cookie string begin with the name we want?
                 if (cookie.substring(0, name.length + 1) == (name + '=')) {
                     cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                     break;
                 }
             }
         }
         return cookieValue;
         }
         if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
             // Only send the token to relative URLs i.e. locally.
             xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
         }
     }
});

selected_tag = '
▶
'

function textarea_in_focus() {
    return $("#class").is(":focus") || $("#instance").is(":focus") || $("#new_zephyr").is(":focus") || $("#new_personal_zephyr").is("focus");
}

$(document).keydown(function(event) {
    if (event.keyCode == 38 || event.keyCode == 40) { // down or up arrow
	// Remove focus from zephyr creation.
	$("#new_zephyr").blur();
	$("#new_personal_zephyr").blur();

        p = $("#selected");
        tr = $(p).closest("tr");
        td = $(p).closest("td");

        if (event.keyCode == 40) { // down arrow
            // There are probably more verbose but more efficient ways to do this.
            next_zephyr = tr.nextAll(":not(:hidden):first");
        } else { // up arrow
            next_zephyr = tr.prevAll(":not(:hidden):first");
        }
        if (next_zephyr.length != 0) { // We are not at the bottom or top of the zephyrs.
            next_zephyr.children("td:first").html(selected_tag);
            td.empty(); // Clear the previous arrow.
            $.post("update", {pointer: next_zephyr.attr("id")});

            if ($(next_zephyr).offset().top < $("#main_div").offset().top) {
                $("#main_div").scrollTop($("#main_div").scrollTop() - 75);
            }

            if ($(next_zephyr).offset().top + $(next_zephyr).height() > $("#main_div").offset().top + $("#main_div").height()) {
                $("#main_div").scrollTop($("#main_div").scrollTop() + 75);
            }
        }
    } else if ((event.keyCode == 82) && !textarea_in_focus()) { // 'r' keypress, for responding to a zephyr
        var parent = $("#selected").parents("tr");
        var zephyr_class = parent.find("span.zephyr_class").text();
	var instance = parent.find("span.zephyr_instance").text();
        $("#class").val(zephyr_class);
        $("#instance").val(instance);
        $("#new_zephyr").focus();
    }
});

function scroll_to_zephyr(target_zephyr, old_offset) {
    // target_zephyr is an id.
    // old_offset is how far from the top of the scroll area the
    // zephyr was before any narrowing or unnarrowing happened.
    var height_above_zephyr = 0;
    $("#table tr:lt(" + $("#" + target_zephyr).index() + ")").each(function() {
        if (!$(this).is(":hidden")) {
            height_above_zephyr += $(this).height();
        }
    });
    $("#main_div").scrollTop(height_above_zephyr + old_offset);
}

function hide_personals() {
    $("span.zephyr_personal_recipient").each(
        function() {
            $(this).parents("tr").hide();
        }
    );
}

function narrow_personals(target_zephyr) {
    var old_top = $("#main_div").offset().top - $("#" + target_zephyr).offset().top;

    $("span.zephyr_personal_recipient").each(
        function() {
            $(this).parents("tr").show();
        }
    );
    $("span.zephyr_class").each(
        function() {
            $(this).parents("tr").hide();
        }
    );

    $("#selected").closest("td").empty();
    $("#" + target_zephyr).children("td:first").html(selected_tag);
    $.post("update", {pointer: target_zephyr});
    scroll_to_zephyr(target_zephyr, old_top);

    $("#unhide").removeAttr("disabled");
    $("#narrow_indicator").html("Showing personals");
}

function narrow(class_name, target_zephyr) {
    // We want the zephyr on which the narrow happened to stay in the same place if possible.
    var old_top = $("#main_div").offset().top - $("#" + target_zephyr).offset().top;
    $("span.zephyr_class").each(
        function() {
            if ($(this).text() != class_name) {
                $(this).parents("tr").hide();
            } else {
                // If you've narrowed on an instance and then click on the class, that should unhide the other instances on that class.
                $(this).parents("tr").show();
	    }
        }
    );
    hide_personals();
    $("#selected").closest("td").empty();
    $("#" + target_zephyr).children("td:first").html(selected_tag);
    $.post("update", {pointer: target_zephyr});

    // Try to keep the zephyr in the same place on the screen after narrowing.
    scroll_to_zephyr(target_zephyr, old_top);

    $("#unhide").removeAttr("disabled");
    $("#narrow_indicator").html("Showing " + class_name + "");
}

function narrow_instance(class_name, instance, target_zephyr) {
    var old_top = $("#main_div").offset().top - $("#" + target_zephyr).offset().top;
    $("tr").each(
        function() {
            if (($(this).find("span.zephyr_class").text() != class_name) ||
		($(this).find("span.zephyr_instance").text() != instance)) {
                $(this).hide();
	    }
        }
    );
    hide_personals();
    $("#selected").closest("td").empty();
    $("#" + target_zephyr).children("td:first").html(selected_tag);
    $.post("update", {pointer: target_zephyr});

    // Try to keep the zephyr in the same place on the screen after narrowing.
    scroll_to_zephyr(target_zephyr, old_top);

    $("#unhide").removeAttr("disabled");
    $("#narrow_indicator").html("Showing " + class_name
      + " " + instance + "");
}

function prepare_personal(username) {
    $('#zephyr-type-tabs a[href="#personal-message"]').tab('show');
    $("#recipient").val(username);
    $("#new_personal_zephyr").focus();
}

function unhide() {
    $("tr").show();

    p = $("#selected");
    tr = $(p).closest("tr");
    scroll_to_zephyr(tr.attr("id"), 0);

    $("#unhide").attr("disabled", "disabled");
    $("#narrow_indicator").html("");
}

$(function() {
  setInterval(get_updates, 1000);
});

function newline2br(content) {
    return content.replace(/\n/g, '
');
}

function add_message(index, zephyr) {
    var new_str = "
" +
	"

	" +
	"
";
    if (zephyr.type == "class") {
        new_str += "" + zephyr.display_recipient + " "
                +  "" +
                   zephyr.instance + " ";
    } else {
        new_str += "" +
                   zephyr.display_recipient + ""
                   + " ← ";
    }
    new_str += ""
        + zephyr.sender + "
"
	+ newline2br(zephyr.content) +
	"
	" +
	"
";
    $("#table tr:last").after(new_str);
}

function get_updates() {
    var last_received = $("tr:last").attr("id");
    $.post("get_updates", {last_received: last_received},
           function(data) {
               $.each(data, add_message);
    }, "json");
}
<commit_msg>Suppress displaying the 'r' in the content box on r-to-start-composing-zephyr.<commit_after>function resize_main_div() {
    // Resize main_div to exactly take up remaining vertical space.
    var div = $('#main_div');
    div.height(Math.max(200, div.height() + $(window).height() - $('body').height()));
}
$(function () {
    resize_main_div();
    $(window).resize(resize_main_div);
    $('#zephyr-type-tabs a').on('shown', function (e) { resize_main_div(); });
});

$.ajaxSetup({
     beforeSend: function(xhr, settings) {
         function getCookie(name) {
             var cookieValue = null;
             if (document.cookie && document.cookie != '') {
                 var cookies = document.cookie.split(';');
                 for (var i = 0; i < cookies.length; i++) {
                     var cookie = jQuery.trim(cookies[i]);
                     // Does this cookie string begin with the name we want?
                 if (cookie.substring(0, name.length + 1) == (name + '=')) {
                     cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                     break;
                 }
             }
         }
         return cookieValue;
         }
         if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
             // Only send the token to relative URLs i.e. locally.
             xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
         }
     }
});

selected_tag = '
▶
'

function textarea_in_focus() {
    return $("#class").is(":focus") || $("#instance").is(":focus") || $("#new_zephyr").is(":focus") || $("#new_personal_zephyr").is("focus");
}

$(document).keydown(function(event) {
    if (event.keyCode == 38 || event.keyCode == 40) { // down or up arrow
	// Remove focus from zephyr creation.
	$("#new_zephyr").blur();
	$("#new_personal_zephyr").blur();

        p = $("#selected");
        tr = $(p).closest("tr");
        td = $(p).closest("td");

        if (event.keyCode == 40) { // down arrow
            // There are probably more verbose but more efficient ways to do this.
            next_zephyr = tr.nextAll(":not(:hidden):first");
        } else { // up arrow
            next_zephyr = tr.prevAll(":not(:hidden):first");
        }
        if (next_zephyr.length != 0) { // We are not at the bottom or top of the zephyrs.
            next_zephyr.children("td:first").html(selected_tag);
            td.empty(); // Clear the previous arrow.
            $.post("update", {pointer: next_zephyr.attr("id")});

            if ($(next_zephyr).offset().top < $("#main_div").offset().top) {
                $("#main_div").scrollTop($("#main_div").scrollTop() - 75);
            }

            if ($(next_zephyr).offset().top + $(next_zephyr).height() > $("#main_div").offset().top + $("#main_div").height()) {
                $("#main_div").scrollTop($("#main_div").scrollTop() + 75);
            }
        }
    } else if ((event.keyCode == 82) && !textarea_in_focus()) { // 'r' keypress, for responding to a zephyr
        var parent = $("#selected").parents("tr");
        var zephyr_class = parent.find("span.zephyr_class").text();
	var instance = parent.find("span.zephyr_instance").text();
        $("#class").val(zephyr_class);
        $("#instance").val(instance);
        $("#new_zephyr").focus();
	event.preventDefault();
    }
});

function scroll_to_zephyr(target_zephyr, old_offset) {
    // target_zephyr is an id.
    // old_offset is how far from the top of the scroll area the
    // zephyr was before any narrowing or unnarrowing happened.
    var height_above_zephyr = 0;
    $("#table tr:lt(" + $("#" + target_zephyr).index() + ")").each(function() {
        if (!$(this).is(":hidden")) {
            height_above_zephyr += $(this).height();
        }
    });
    $("#main_div").scrollTop(height_above_zephyr + old_offset);
}

function hide_personals() {
    $("span.zephyr_personal_recipient").each(
        function() {
            $(this).parents("tr").hide();
        }
    );
}

function narrow_personals(target_zephyr) {
    var old_top = $("#main_div").offset().top - $("#" + target_zephyr).offset().top;

    $("span.zephyr_personal_recipient").each(
        function() {
            $(this).parents("tr").show();
        }
    );
    $("span.zephyr_class").each(
        function() {
            $(this).parents("tr").hide();
        }
    );

    $("#selected").closest("td").empty();
    $("#" + target_zephyr).children("td:first").html(selected_tag);
    $.post("update", {pointer: target_zephyr});
    scroll_to_zephyr(target_zephyr, old_top);

    $("#unhide").removeAttr("disabled");
    $("#narrow_indicator").html("Showing personals");
}

function narrow(class_name, target_zephyr) {
    // We want the zephyr on which the narrow happened to stay in the same place if possible.
    var old_top = $("#main_div").offset().top - $("#" + target_zephyr).offset().top;
    $("span.zephyr_class").each(
        function() {
            if ($(this).text() != class_name) {
                $(this).parents("tr").hide();
            } else {
                // If you've narrowed on an instance and then click on the class, that should unhide the other instances on that class.
                $(this).parents("tr").show();
	    }
        }
    );
    hide_personals();
    $("#selected").closest("td").empty();
    $("#" + target_zephyr).children("td:first").html(selected_tag);
    $.post("update", {pointer: target_zephyr});

    // Try to keep the zephyr in the same place on the screen after narrowing.
    scroll_to_zephyr(target_zephyr, old_top);

    $("#unhide").removeAttr("disabled");
    $("#narrow_indicator").html("Showing " + class_name + "");
}

function narrow_instance(class_name, instance, target_zephyr) {
    var old_top = $("#main_div").offset().top - $("#" + target_zephyr).offset().top;
    $("tr").each(
        function() {
            if (($(this).find("span.zephyr_class").text() != class_name) ||
		($(this).find("span.zephyr_instance").text() != instance)) {
                $(this).hide();
	    }
        }
    );
    hide_personals();
    $("#selected").closest("td").empty();
    $("#" + target_zephyr).children("td:first").html(selected_tag);
    $.post("update", {pointer: target_zephyr});

    // Try to keep the zephyr in the same place on the screen after narrowing.
    scroll_to_zephyr(target_zephyr, old_top);

    $("#unhide").removeAttr("disabled");
    $("#narrow_indicator").html("Showing " + class_name
      + " " + instance + "");
}

function prepare_personal(username) {
    $('#zephyr-type-tabs a[href="#personal-message"]').tab('show');
    $("#recipient").val(username);
    $("#new_personal_zephyr").focus();
}

function unhide() {
    $("tr").show();

    p = $("#selected");
    tr = $(p).closest("tr");
    scroll_to_zephyr(tr.attr("id"), 0);

    $("#unhide").attr("disabled", "disabled");
    $("#narrow_indicator").html("");
}

$(function() {
  setInterval(get_updates, 1000);
});

function newline2br(content) {
    return content.replace(/\n/g, '
');
}

function add_message(index, zephyr) {
    var new_str = "
" +
	"

	" +
	"
";
    if (zephyr.type == "class") {
        new_str += "" + zephyr.display_recipient + " "
                +  "" +
                   zephyr.instance + " ";
    } else {
        new_str += "" +
                   zephyr.display_recipient + ""
                   + " ← ";
    }
    new_str += ""
        + zephyr.sender + "
"
	+ newline2br(zephyr.content) +
	"
	" +
	"
";
    $("#table tr:last").after(new_str);
}

function get_updates() {
    var last_received = $("tr:last").attr("id");
    $.post("get_updates", {last_received: last_received},
           function(data) {
               $.each(data, add_message);
    }, "json");
}
<|endoftext|>


<commit_before>var DCRAW = "/home/view/current/bin/dcraw";
var UFRAW = "/usr/bin/ufraw-batch";
var TMPFOLDER = "/tmp/tlp";
var execFile = require('child_process').execFile;
var epeg = require('epeg');
var sharp = require('sharp');
var fs = require('fs');
//var pixelr = require('pixelr');
var luminance = require('jpeg-lum');
//var cv = require('opencv');
var jpegSize = require('jpeg-size');

var log2 = Math.log2 || function(x) {
    return Math.log(x) / Math.LN2;
};

if (!fs.existsSync(TMPFOLDER)) {
    fs.mkdirSync(TMPFOLDER);
}

var TMP_IMAGE_INPUT = TMPFOLDER + "/tmp_image_in";
var TMP_IMAGE_OUTPUT = TMPFOLDER + "/tmp_image_in.thumb.jpg";
var TMP_IMAGE_THUMB = TMPFOLDER + "/tmp_image_thm.jpg";

function getJpeg(path, crop, callback) {
    console.log("Processing photo...");
    try {
        console.log("Fetching JPEG from RAW photo...", path);
        var dcraw = execFile(DCRAW, ['-e', path], function(err, stdout, stderr) {
            if (err) console.log("DCRAW Error:", err);
            if (stderr) console.log("StdErr:", stderr);
            var size = {
                x: 840,
                q: 75
            };
            console.log("Downsizing JPEG...");
            if (path == TMP_IMAGE_INPUT || path.indexOf('.') === -1) path += ".X"; // this gets replaced
            var thmFile = path.replace(/\.([a-z0-9])+$/i, ".thumb.jpg");
            exports.downsizeJpeg(thmFile, size, crop, function(err2, thm) {
                fs.unlink(thmFile);
                if (!err && err2) err = err2;
                if (callback) callback(err, thm);
            });
        });
    } catch (e) {
        console.log("(getJpeg) ERROR: ", e);
        if (callback) callback(e);
    }
}

exports.writeXMP = function(fileName, exposureCompensation, description, name, lat, lon) {
    var template = '<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.5-c002 1.148022, 2012/07/15-18:06:45        ">\n\
 <rdf:RDF xmlns:rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" >\n\
  <rdf:Description rdf:about=""\n\
    xmlns:xmp="http://ns.adobe.com/xap/1.0/"\n\
    xmlns:tiff="http://ns.adobe.com/tiff/1.0/"\n\
    xmlns:exif="http://ns.adobe.com/exif/1.0/"\n\
    xmlns:dc="http://purl.org/dc/elements/1.1/"\n\
    xmlns:aux="http://ns.adobe.com/exif/1.0/aux/"\n\
    xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/"\n\
    xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"\n\
    xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#"\n\
    xmlns:crs="http://ns.adobe.com/camera-raw-settings/1.0/"\n\
    crs:Exposure2012="{{EXP}}">\n\
    <dc:subject>\n\
     <rdf:Bag>\n\
      <rdf:li>Timelapse+ VIEW</rdf:li>\n\
      <rdf:li>time-lapse</rdf:li>\n\
      <rdf:li>{{NAME}}</rdf:li>\n\
     </rdf:Bag>\n\
    </dc:subject>\n\
    <dc:description>\n\
     <rdf:Alt>\n\
      <rdf:li xml:lang="x-default">{{DESC}}</rdf:li>\n\
     </rdf:Alt>\n\
    </dc:description>\n\
  </rdf:Description>\n\
{{GPS}}  <rdf:Description rdf:about=""\n\
    xmlns:lrt="http://lrtimelapse.com/">\n\
    <lrt:ExternalExposureDefault>{{LRTEXP}}</lrt:ExternalExposureDefault>\n\
  </rdf:Description>\n\
  </rdf:RDF>\n\
</x:xmpmeta>';

    var gpsData = "";
    if(lat != null && lat != null) {
        var gpsData = '  <rdf:Description rdf:about="" xmlns:exif="http://ns.adobe.com/exif/1.0/">\n\
            <exif:GPSLatitude>{{LAT}}</exif:GPSLatitude>\n\
            <exif:GPSLongitude>{{LON}}</exif:GPSLongitude>\n\
          </rdf:Description>\n\
        ';
        gpsData = gpsData.replace("{{LAT}}", lat);
        gpsData = gpsData.replace("{{LON}}", lon);
    }

    var expString = (exposureCompensation >= 0 ? "+" : "") + exposureCompensation.toString();
    var xmpData = template.replace("{{EXP}}", expString);
    xmpData = xmpData.replace("{{LRTEXP}}", expString);
    xmpData = xmpData.replace("{{NAME}}", name);
    xmpData = xmpData.replace("{{DESC}}", description);
    xmpData = xmpData.replace("{{GPS}}", gpsData);

    console.log("writing XMP file");
    fs.writeFileSync(fileName.replace(/\.[0-9a-z]+$/i, '.xmp'), xmpData);
}

exports.convertRawToTiff = function(rawImagePath, tiffOutputPath, exposureCompensation, callback) {
    console.log("Processing RAW photo...");
    var ufraw = execFile(UFRAW, ['--out-depth=16', '--out-type=tiff', '--zip', '--exposure=' + exposureCompensation, '--output=' + tiffOutputPath, rawImagePath], function(err, stdout, stderr) {
        if (err) console.log("(ufraw) error:", err);
        if (stderr) console.log("(ufraw) stderr:", stderr);
        if (callback) callback();
    });
}

exports.getJpegFromRawBuffer = function(rawImageBuf, crop, callback) {
    fs.writeFile(TMP_IMAGE_INPUT, new Buffer(rawImageBuf), function() {
        getJpeg(TMP_IMAGE_INPUT, crop, callback);
    });
}

exports.saveTemp = function(name, buf, callback) {
    var file = name ? TMPFOLDER + "/" + name : TMP_IMAGE_INPUT;
    fs.writeFile(file, new Buffer(buf), function(err) {
        if (callback) callback(err, file);
    });
}

exports.getJpegFromRawFile = function(rawImagePath, crop, callback) {
    getJpeg(rawImagePath, crop, callback);
}

exports.downsizeJpeg = function(jpeg, size, crop, callback) {
    //console.log("Resizing photo...");
    if (!size) size = {};
    if (!size.x) x = (size.y > 0) ? size.y * 1.5 : 300;
    if (!size.y) size.y = size.x / 1.5;
    if (!size.q) size.q = 70;

    if (!jpeg) return;

    var jpegConfig = {};
    if (typeof jpeg == "string") {
        //console.log("downsizeJpeg: reading image file", jpeg);
        jpegBuf = fs.readFileSync(jpeg);
    } else {
        //console.log("downsizeJpeg: assuming image buffer");
        jpegBuf = jpeg;
    }

    var err = null;
    try {
        var img = new epeg.Image({
            data: jpegBuf
        });
        var thm;
        if (crop && crop.xPercent && crop.yPercent) {
            imgSize = jpegSize(jpegBuf);
            if (imgSize) {
                if (crop.xPercent > 1) crop.xPercent /= 100;
                if (crop.yPercent > 1) crop.yPercent /= 100;
                crop.x = imgSize.width * crop.xPercent - size.x / 2;
                crop.y = imgSize.height * crop.yPercent - size.y / 2;
                if (crop.x < 0) crop.x = 0;
                if (crop.y < 0) crop.y = 0;
                if (crop.x > imgSize.width - size.x) crop.x = imgSize.width - size.x;
                if (crop.y > imgSize.height - size.y) crop.y = imgSize.height - size.y;
                //console.log("cropping to ", crop);
                thm = img.crop(crop.x, crop.y, size.x, size.y, size.q).process();
            } else {
                console.log("failed to read image size; not cropping");
                thm = img.downsize(size.x, size.y, size.q).process();
            }
        } else {
            thm = img.downsize(size.x, size.y, size.q).process();
        }
        //console.log("downsizeJpeg: Done.");
    } catch (e) {
        console.log("Error resizing photo", e);
        err = e;
    }
    delete img;
    if (callback) callback(err, thm);
}

exports.downsizeJpegSharp = function(jpeg, size, crop, exposureCompensation, callback) {
    console.log("(sharp) Resizing photo...");
    if (!size) size = {};
    if (!size.x) x = (size.y > 0) ? size.y * 1.5 : 300;
    if (!size.y) size.y = size.x / 1.5;
    if (!size.q) size.q = 70;
    if (!jpeg) return;

    var jpegConfig = {};
    if (typeof jpeg == "string") {
        jpegBuf = fs.readFileSync(jpeg);
    } else {
        jpegBuf = jpeg;
    }

    var err = null;
    try {
        var img = sharp(jpegBuf);
        //var img = new epeg.Image({
        //    data: jpegBuf
        //});
        var thm;
        if (crop && crop.xPercent && crop.yPercent) {
            img.metadata(function(err, metadata) {
                if (!err && metadata) {
                    if (crop.xPercent > 1) crop.xPercent /= 100;
                    if (crop.yPercent > 1) crop.yPercent /= 100;
                    crop.x = metadata.width * crop.xPercent - size.x / 2;
                    crop.y = metadata.height * crop.yPercent - size.y / 2;
                    if (crop.x < 0) crop.x = 0;
                    if (crop.y < 0) crop.y = 0;
                    if (crop.x > metadata.width - size.x) crop.x = metadata.width - size.x;
                    if (crop.y > metadata.height - size.y) crop.y = metadata.height - size.y;
                    console.log("cropping to ", crop);
                    img.extract({
                        left: Math.round(crop.x),
                        top: Math.round(crop.y),
                        width: Math.round(size.x),
                        height: Math.round(size.y)
                    }).sharpen().jpeg().quality(size.q).toBuffer(callback);
                } else {
                    console.log("failed to read image size; not cropping");
                    img.resize(Math.round(size.x), Math.round(size.y)).sharpen().jpeg().quality(size.q).toBuffer(callback);
                }
            });
        } else {
            if (exposureCompensation) {
                img.resize(Math.round(size.x), Math.round(size.y)).raw().toBuffer(function(err, buf, info) {
                    if (!err && buf) {
                        console.log("adding exposure compensation of " + exposureCompensation);
                        for (var i = 0; i < buf.length; i++) {
                            // read 8-bit pixel val from buf
                            var val = buf.readUInt8(i, true);
                            if (val < 255) {
                                // convert to linear
                                val = Math.pow(val / 255, 2.2) * 255;
                                // add exposure compensation
                                val *= Math.pow(2, exposureCompensation);
                                // reapply gamma
                                val = Math.pow(val / 255, 1 / 2.2) * 255;
                                // coerce to 8-bit range
                                val = Math.round(Math.min(Math.max(val, 0), 255));
                                // save to buf
                            }
                            buf.writeUInt8(val, i, true);
                        }
                        console.log("exposure compensation done");
                        var out = sharp(buf, {
                            raw: info
                        }).gamma(2.2).sharpen().jpeg().quality(size.q).toBuffer(callback);
                    } else {
                        console.log("Error creating buffer", err);
                        if (callback) callback(err, null);
                    }
                });
            } else {
                img.resize(Math.round(size.x), Math.round(size.y)).sharpen().jpeg().quality(size.q).toBuffer(callback);
            }
        }
        console.log("Done.");
    } catch (e) {
        console.log("Error resizing photo", e);
        err = e;
        if (callback) callback(err, null);
    }
}

exports.getJpegBuffer = function(jpegPath, callback) {
    console.log("Loading JPEG as buffer...");
    var err = null;
    try {
        fs.readFile(jpegPath, function(err, jpg) {
            if (callback) callback(err, jpg);
        });
        console.log("Done.");
    } catch (e) {
        console.log("Error loading photo (" + jpegPath + ")", e);
        err = e;
        if (callback) callback(err, null);
    }
}

exports.histogramArray = function(jpegBuffer, callback) {
    fs.writeFile(TMP_IMAGE_THUMB, new Buffer(jpegBuffer), function() {
        luminance.read(TMP_IMAGE_THUMB, function(err, res) {
            var histArray = null;
            if(!err && res && res.histogram) histArray = res.histogram;
            if (callback) callback(err, histArray);
        });
        /*pixelr.read(TMP_IMAGE_THUMB, "jpeg", function(err, data) {
            if (err) console.log("Error:", err);
            var result = new Array(256);
            if (!err) {
                for (var i = 0; i < data.pixels.length; i += 3) {
                    pixelIndex = i / 3;
                    var val = Math.ceil((data.pixels[i + 0] + data.pixels[i + 1] + data.pixels[i + 2]) / 3);
                    if (val >= 0 && val <= 255) {
                        if (!result[val]) result[val] = 1;
                        else result[val] ++;
                    }
                }
            }
            if (callback) callback(err, result);
        });*/
    });
}

exports.exposureValue = function(jpegBuffer, callback) {
    var highlightProtection = 20;

    fs.writeFile(TMP_IMAGE_THUMB, jpegBuffer, function() {
        luminance.read(TMP_IMAGE_THUMB, function(err, res) {
            var lum = 0;
            if(!err && res && res.luminance) {
                lum = res.luminance;
                if(res.clipped && highlightProtection) {
                    console.log("Compensating for clipped highlights: ", res.clipped * highlightProtection);
                    lum += res.clipped * highlightProtection;
                }
            }
            if (callback) callback(err, lum);
        });
    });
}

exports.faceDetection = function(jpegBuffer, callback) {
    cv.readImage(jpegBuffer, function(err, im) {
        im.detectObject(cv.FACE_CASCADE, {}, function(err, faces) {
            if (!err && faces && faces.length > 0) {
                console.log("detected " + faces.length + " faces");
                for (var i = 0; i < faces.length; i++) {
                    var f = faces[i]
                    im.ellipse(f.x + f.width / 2, f.y + f.height / 2, f.width / 2, f.height / 2);
                }
                jpg = im.toBuffer('jpg');
                if (callback) callback(jpg);
            } else {
                if (callback) callback(jpegBuffer);
            }
        });
    });
}<commit_msg>fix geotagging data in xmps<commit_after>var DCRAW = "/home/view/current/bin/dcraw";
var UFRAW = "/usr/bin/ufraw-batch";
var TMPFOLDER = "/tmp/tlp";
var execFile = require('child_process').execFile;
var epeg = require('epeg');
var sharp = require('sharp');
var fs = require('fs');
//var pixelr = require('pixelr');
var luminance = require('jpeg-lum');
//var cv = require('opencv');
var jpegSize = require('jpeg-size');

var log2 = Math.log2 || function(x) {
    return Math.log(x) / Math.LN2;
};

if (!fs.existsSync(TMPFOLDER)) {
    fs.mkdirSync(TMPFOLDER);
}

var TMP_IMAGE_INPUT = TMPFOLDER + "/tmp_image_in";
var TMP_IMAGE_OUTPUT = TMPFOLDER + "/tmp_image_in.thumb.jpg";
var TMP_IMAGE_THUMB = TMPFOLDER + "/tmp_image_thm.jpg";

function getJpeg(path, crop, callback) {
    console.log("Processing photo...");
    try {
        console.log("Fetching JPEG from RAW photo...", path);
        var dcraw = execFile(DCRAW, ['-e', path], function(err, stdout, stderr) {
            if (err) console.log("DCRAW Error:", err);
            if (stderr) console.log("StdErr:", stderr);
            var size = {
                x: 840,
                q: 75
            };
            console.log("Downsizing JPEG...");
            if (path == TMP_IMAGE_INPUT || path.indexOf('.') === -1) path += ".X"; // this gets replaced
            var thmFile = path.replace(/\.([a-z0-9])+$/i, ".thumb.jpg");
            exports.downsizeJpeg(thmFile, size, crop, function(err2, thm) {
                fs.unlink(thmFile);
                if (!err && err2) err = err2;
                if (callback) callback(err, thm);
            });
        });
    } catch (e) {
        console.log("(getJpeg) ERROR: ", e);
        if (callback) callback(e);
    }
}

exports.writeXMP = function(fileName, exposureCompensation, description, name, lat, lon) {
    var template = '<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.5-c002 1.148022, 2012/07/15-18:06:45        ">\n\
 <rdf:RDF xmlns:rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" >\n\
  <rdf:Description rdf:about=""\n\
    xmlns:xmp="http://ns.adobe.com/xap/1.0/"\n\
    xmlns:tiff="http://ns.adobe.com/tiff/1.0/"\n\
    xmlns:exif="http://ns.adobe.com/exif/1.0/"\n\
    xmlns:dc="http://purl.org/dc/elements/1.1/"\n\
    xmlns:aux="http://ns.adobe.com/exif/1.0/aux/"\n\
    xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/"\n\
    xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"\n\
    xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#"\n\
    xmlns:crs="http://ns.adobe.com/camera-raw-settings/1.0/"\n\
    crs:Exposure2012="{{EXP}}">\n\
    <dc:subject>\n\
     <rdf:Bag>\n\
      <rdf:li>Timelapse+ VIEW</rdf:li>\n\
      <rdf:li>time-lapse</rdf:li>\n\
      <rdf:li>{{NAME}}</rdf:li>\n\
     </rdf:Bag>\n\
    </dc:subject>\n\
    <dc:description>\n\
     <rdf:Alt>\n\
      <rdf:li xml:lang="x-default">{{DESC}}</rdf:li>\n\
     </rdf:Alt>\n\
    </dc:description>\n\
  </rdf:Description>\n\
{{GPS}}  <rdf:Description rdf:about=""\n\
    xmlns:lrt="http://lrtimelapse.com/">\n\
    <lrt:ExternalExposureDefault>{{LRTEXP}}</lrt:ExternalExposureDefault>\n\
  </rdf:Description>\n\
  </rdf:RDF>\n\
</x:xmpmeta>';

    var gpsData = "";
    if(lat != null && lat != null) {
        if(lat < 0) {
            lat = 0 - lat;
            lat = "S" + lat.toString();
        } else {
            lat = "N" + lat.toString();
        }
        if(lon < 0) {
            lon = 0 - lon;
            lon = "W" + lon.toString();
        } else {
            lon = "E" + lon.toString();
        }
        var gpsData = '  <rdf:Description rdf:about="" xmlns:exif="http://ns.adobe.com/exif/1.0/">\n\
            <exif:GPSLatitude>{{LAT}}</exif:GPSLatitude>\n\
            <exif:GPSLongitude>{{LON}}</exif:GPSLongitude>\n\
          </rdf:Description>\n\
        ';
        gpsData = gpsData.replace("{{LAT}}", lat);
        gpsData = gpsData.replace("{{LON}}", lon);
    }

    var expString = (exposureCompensation >= 0 ? "+" : "") + exposureCompensation.toString();
    var xmpData = template.replace("{{EXP}}", expString);
    xmpData = xmpData.replace("{{LRTEXP}}", expString);
    xmpData = xmpData.replace("{{NAME}}", name);
    xmpData = xmpData.replace("{{DESC}}", description);
    xmpData = xmpData.replace("{{GPS}}", gpsData);

    console.log("writing XMP file");
    fs.writeFileSync(fileName.replace(/\.[0-9a-z]+$/i, '.xmp'), xmpData);
}

exports.convertRawToTiff = function(rawImagePath, tiffOutputPath, exposureCompensation, callback) {
    console.log("Processing RAW photo...");
    var ufraw = execFile(UFRAW, ['--out-depth=16', '--out-type=tiff', '--zip', '--exposure=' + exposureCompensation, '--output=' + tiffOutputPath, rawImagePath], function(err, stdout, stderr) {
        if (err) console.log("(ufraw) error:", err);
        if (stderr) console.log("(ufraw) stderr:", stderr);
        if (callback) callback();
    });
}

exports.getJpegFromRawBuffer = function(rawImageBuf, crop, callback) {
    fs.writeFile(TMP_IMAGE_INPUT, new Buffer(rawImageBuf), function() {
        getJpeg(TMP_IMAGE_INPUT, crop, callback);
    });
}

exports.saveTemp = function(name, buf, callback) {
    var file = name ? TMPFOLDER + "/" + name : TMP_IMAGE_INPUT;
    fs.writeFile(file, new Buffer(buf), function(err) {
        if (callback) callback(err, file);
    });
}

exports.getJpegFromRawFile = function(rawImagePath, crop, callback) {
    getJpeg(rawImagePath, crop, callback);
}

exports.downsizeJpeg = function(jpeg, size, crop, callback) {
    //console.log("Resizing photo...");
    if (!size) size = {};
    if (!size.x) x = (size.y > 0) ? size.y * 1.5 : 300;
    if (!size.y) size.y = size.x / 1.5;
    if (!size.q) size.q = 70;

    if (!jpeg) return;

    var jpegConfig = {};
    if (typeof jpeg == "string") {
        //console.log("downsizeJpeg: reading image file", jpeg);
        jpegBuf = fs.readFileSync(jpeg);
    } else {
        //console.log("downsizeJpeg: assuming image buffer");
        jpegBuf = jpeg;
    }

    var err = null;
    try {
        var img = new epeg.Image({
            data: jpegBuf
        });
        var thm;
        if (crop && crop.xPercent && crop.yPercent) {
            imgSize = jpegSize(jpegBuf);
            if (imgSize) {
                if (crop.xPercent > 1) crop.xPercent /= 100;
                if (crop.yPercent > 1) crop.yPercent /= 100;
                crop.x = imgSize.width * crop.xPercent - size.x / 2;
                crop.y = imgSize.height * crop.yPercent - size.y / 2;
                if (crop.x < 0) crop.x = 0;
                if (crop.y < 0) crop.y = 0;
                if (crop.x > imgSize.width - size.x) crop.x = imgSize.width - size.x;
                if (crop.y > imgSize.height - size.y) crop.y = imgSize.height - size.y;
                //console.log("cropping to ", crop);
                thm = img.crop(crop.x, crop.y, size.x, size.y, size.q).process();
            } else {
                console.log("failed to read image size; not cropping");
                thm = img.downsize(size.x, size.y, size.q).process();
            }
        } else {
            thm = img.downsize(size.x, size.y, size.q).process();
        }
        //console.log("downsizeJpeg: Done.");
    } catch (e) {
        console.log("Error resizing photo", e);
        err = e;
    }
    delete img;
    if (callback) callback(err, thm);
}

exports.downsizeJpegSharp = function(jpeg, size, crop, exposureCompensation, callback) {
    console.log("(sharp) Resizing photo...");
    if (!size) size = {};
    if (!size.x) x = (size.y > 0) ? size.y * 1.5 : 300;
    if (!size.y) size.y = size.x / 1.5;
    if (!size.q) size.q = 70;
    if (!jpeg) return;

    var jpegConfig = {};
    if (typeof jpeg == "string") {
        jpegBuf = fs.readFileSync(jpeg);
    } else {
        jpegBuf = jpeg;
    }

    var err = null;
    try {
        var img = sharp(jpegBuf);
        //var img = new epeg.Image({
        //    data: jpegBuf
        //});
        var thm;
        if (crop && crop.xPercent && crop.yPercent) {
            img.metadata(function(err, metadata) {
                if (!err && metadata) {
                    if (crop.xPercent > 1) crop.xPercent /= 100;
                    if (crop.yPercent > 1) crop.yPercent /= 100;
                    crop.x = metadata.width * crop.xPercent - size.x / 2;
                    crop.y = metadata.height * crop.yPercent - size.y / 2;
                    if (crop.x < 0) crop.x = 0;
                    if (crop.y < 0) crop.y = 0;
                    if (crop.x > metadata.width - size.x) crop.x = metadata.width - size.x;
                    if (crop.y > metadata.height - size.y) crop.y = metadata.height - size.y;
                    console.log("cropping to ", crop);
                    img.extract({
                        left: Math.round(crop.x),
                        top: Math.round(crop.y),
                        width: Math.round(size.x),
                        height: Math.round(size.y)
                    }).sharpen().jpeg().quality(size.q).toBuffer(callback);
                } else {
                    console.log("failed to read image size; not cropping");
                    img.resize(Math.round(size.x), Math.round(size.y)).sharpen().jpeg().quality(size.q).toBuffer(callback);
                }
            });
        } else {
            if (exposureCompensation) {
                img.resize(Math.round(size.x), Math.round(size.y)).raw().toBuffer(function(err, buf, info) {
                    if (!err && buf) {
                        console.log("adding exposure compensation of " + exposureCompensation);
                        for (var i = 0; i < buf.length; i++) {
                            // read 8-bit pixel val from buf
                            var val = buf.readUInt8(i, true);
                            if (val < 255) {
                                // convert to linear
                                val = Math.pow(val / 255, 2.2) * 255;
                                // add exposure compensation
                                val *= Math.pow(2, exposureCompensation);
                                // reapply gamma
                                val = Math.pow(val / 255, 1 / 2.2) * 255;
                                // coerce to 8-bit range
                                val = Math.round(Math.min(Math.max(val, 0), 255));
                                // save to buf
                            }
                            buf.writeUInt8(val, i, true);
                        }
                        console.log("exposure compensation done");
                        var out = sharp(buf, {
                            raw: info
                        }).gamma(2.2).sharpen().jpeg().quality(size.q).toBuffer(callback);
                    } else {
                        console.log("Error creating buffer", err);
                        if (callback) callback(err, null);
                    }
                });
            } else {
                img.resize(Math.round(size.x), Math.round(size.y)).sharpen().jpeg().quality(size.q).toBuffer(callback);
            }
        }
        console.log("Done.");
    } catch (e) {
        console.log("Error resizing photo", e);
        err = e;
        if (callback) callback(err, null);
    }
}

exports.getJpegBuffer = function(jpegPath, callback) {
    console.log("Loading JPEG as buffer...");
    var err = null;
    try {
        fs.readFile(jpegPath, function(err, jpg) {
            if (callback) callback(err, jpg);
        });
        console.log("Done.");
    } catch (e) {
        console.log("Error loading photo (" + jpegPath + ")", e);
        err = e;
        if (callback) callback(err, null);
    }
}

exports.histogramArray = function(jpegBuffer, callback) {
    fs.writeFile(TMP_IMAGE_THUMB, new Buffer(jpegBuffer), function() {
        luminance.read(TMP_IMAGE_THUMB, function(err, res) {
            var histArray = null;
            if(!err && res && res.histogram) histArray = res.histogram;
            if (callback) callback(err, histArray);
        });
        /*pixelr.read(TMP_IMAGE_THUMB, "jpeg", function(err, data) {
            if (err) console.log("Error:", err);
            var result = new Array(256);
            if (!err) {
                for (var i = 0; i < data.pixels.length; i += 3) {
                    pixelIndex = i / 3;
                    var val = Math.ceil((data.pixels[i + 0] + data.pixels[i + 1] + data.pixels[i + 2]) / 3);
                    if (val >= 0 && val <= 255) {
                        if (!result[val]) result[val] = 1;
                        else result[val] ++;
                    }
                }
            }
            if (callback) callback(err, result);
        });*/
    });
}

exports.exposureValue = function(jpegBuffer, callback) {
    var highlightProtection = 20;

    fs.writeFile(TMP_IMAGE_THUMB, jpegBuffer, function() {
        luminance.read(TMP_IMAGE_THUMB, function(err, res) {
            var lum = 0;
            if(!err && res && res.luminance) {
                lum = res.luminance;
                if(res.clipped && highlightProtection) {
                    console.log("Compensating for clipped highlights: ", res.clipped * highlightProtection);
                    lum += res.clipped * highlightProtection;
                }
            }
            if (callback) callback(err, lum);
        });
    });
}

exports.faceDetection = function(jpegBuffer, callback) {
    cv.readImage(jpegBuffer, function(err, im) {
        im.detectObject(cv.FACE_CASCADE, {}, function(err, faces) {
            if (!err && faces && faces.length > 0) {
                console.log("detected " + faces.length + " faces");
                for (var i = 0; i < faces.length; i++) {
                    var f = faces[i]
                    im.ellipse(f.x + f.width / 2, f.y + f.height / 2, f.width / 2, f.height / 2);
                }
                jpg = im.toBuffer('jpg');
                if (callback) callback(jpg);
            } else {
                if (callback) callback(jpegBuffer);
            }
        });
    });
}<|endoftext|>


<commit_before>function SocietiesCtrl($scope, searchModelService, LanguageClass) {
    $scope.results = searchModelService.getModel().getResults();
    console.log($scope.results);
    $scope.query = searchModelService.getModel().getQuery();
        console.log($scope.query);

    if ($scope.query.variable_codes) {
        $scope.code_ids = {};
        for (var i = 0; i < $scope.query.variable_codes.length; i++) {
            if ($scope.query.variable_codes[i].bf_id) {
                if ($scope.query.variable_codes[i].bf_id in $scope.code_ids)
                    $scope.code_ids[$scope.query.variable_codes[i].bf_id] = $scope.code_ids[$scope.query.variable_codes[i].bf_id].concat([$scope.query.variable_codes[i]]);
                else
                    $scope.code_ids[$scope.query.variable_codes[i].bf_id] = [$scope.query.variable_codes[i]];

            }
            else if ($scope.query.variable_codes[i].variable in $scope.code_ids)
                $scope.code_ids[$scope.query.variable_codes[i].variable] = $scope.code_ids[$scope.query.variable_codes[i].variable].concat([$scope.query.variable_codes[i]]);
            else
                $scope.code_ids[$scope.query.variable_codes[i].variable] = [$scope.query.variable_codes[i]];

        }

        if ($scope.results.variable_descriptions) {
            for (var i = 0; i < $scope.results.variable_descriptions.length; i++){
                if ($scope.results.variable_descriptions[i].data_type == 'CONTINUOUS') $scope.code_ids[$scope.results.variable_descriptions[i].id].name = $scope.results.variable_descriptions[i].name;
                if ($scope.code_ids[$scope.results.variable_descriptions[i].id].name) continue;
                else $scope.code_ids[$scope.results.variable_descriptions[i].id].name = $scope.results.variable_descriptions[i].name;

            }
        }
    }

    if ($scope.query.environmental_filters) {
        var extractedValues = $scope.results.societies.map(function(society) { return society.environmental_values[0].value; } );
        var min_value = Math.min.apply(null, extractedValues);
        var max_value = Math.max.apply(null, extractedValues);
        $scope.range = max_value - min_value;
    }

    if ($scope.query.language_classifications) {
        //get lang classifications in tree
        $scope.classifications = [];
        $scope.languageClasses = [];
        LanguageClass.query().$promise.then(function(result) {
            console.log(result);
             for (var i = 0; i < $scope.results.societies.length; i++) {
            for (var j = 0; j < $scope.results.societies[i].languages.length; j++) {
                classification = $scope.query.language_classifications.filter(function(l) { return l.language.id == $scope.results.societies[i].languages[j].id; });
                toAdd = result.filter(function(l) { return l.id == classification[0].class_subfamily; });
                if (toAdd[0] && $scope.classifications.indexOf(toAdd[0]) == -1)
                    $scope.classifications = $scope.classifications.concat(toAdd);
            }
        }
        });
    }

    $scope.setActive('societies');

    $scope.resizeMap = function() {
        $scope.$broadcast('mapTabActivated');
    };

    $scope.treeSelected = function() {
        $scope.$broadcast('treeSelected', {tree: $scope.results.selectedTree});
    };

    $scope.generateDownloadLinks = function() {
        // queryObject is the in-memory JS object representing the chosen search options
        var queryObject = searchModelService.getModel().getQuery();
        // the CSV download endpoint is a GET URL, so we must send the query object as a string.
        var queryString = encodeURIComponent(JSON.stringify(queryObject));
        // format (csv/svg/etc) should be an argument, and change the endpoint to /api/v1/download
        $scope.csvDownloadLink = "/api/v1/csv_download?query=" + queryString;
    };
}
<commit_msg>cleaning up societies.js<commit_after>function SocietiesCtrl($scope, searchModelService, LanguageClass) {
    $scope.results = searchModelService.getModel().getResults();
    console.log($scope.results);
    $scope.query = searchModelService.getModel().getQuery();
        console.log($scope.query);

    if ($scope.query.variable_codes) {
        $scope.code_ids = {};
        for (var i = 0; i < $scope.query.variable_codes.length; i++) {
            if ($scope.query.variable_codes[i].bf_id) {
                if ($scope.query.variable_codes[i].bf_id in $scope.code_ids)
                    $scope.code_ids[$scope.query.variable_codes[i].bf_id] = $scope.code_ids[$scope.query.variable_codes[i].bf_id].concat([$scope.query.variable_codes[i]]);
                else
                    $scope.code_ids[$scope.query.variable_codes[i].bf_id] = [$scope.query.variable_codes[i]];
            }
            else if ($scope.query.variable_codes[i].variable in $scope.code_ids)
                $scope.code_ids[$scope.query.variable_codes[i].variable] = $scope.code_ids[$scope.query.variable_codes[i].variable].concat([$scope.query.variable_codes[i]]);
            else
                $scope.code_ids[$scope.query.variable_codes[i].variable] = [$scope.query.variable_codes[i]];

        }

        if ($scope.results.variable_descriptions) {
            for (var i = 0; i < $scope.results.variable_descriptions.length; i++){
                if ($scope.results.variable_descriptions[i].data_type == 'CONTINUOUS') $scope.code_ids[$scope.results.variable_descriptions[i].id].name = $scope.results.variable_descriptions[i].name;
                if ($scope.code_ids[$scope.results.variable_descriptions[i].id].name) continue;
                else $scope.code_ids[$scope.results.variable_descriptions[i].id].name = $scope.results.variable_descriptions[i].name;

            }
        }
    }

    if ($scope.query.environmental_filters) {
        var extractedValues = $scope.results.societies.map(function(society) { return society.environmental_values[0].value; } );
        var min_value = Math.min.apply(null, extractedValues);
        var max_value = Math.max.apply(null, extractedValues);
        $scope.range = max_value - min_value;
    }

    if ($scope.query.language_classifications) {
        //get lang classifications in tree
        $scope.classifications = [];
        $scope.languageClasses = [];
        LanguageClass.query().$promise.then(function(result) {
            console.log(result);
             for (var i = 0; i < $scope.results.societies.length; i++) {
            for (var j = 0; j < $scope.results.societies[i].languages.length; j++) {
                classification = $scope.query.language_classifications.filter(function(l) { return l.language.id == $scope.results.societies[i].languages[j].id; });
                toAdd = result.filter(function(l) { return l.id == classification[0].class_subfamily; });
                if (toAdd[0] && $scope.classifications.indexOf(toAdd[0]) == -1)
                    $scope.classifications = $scope.classifications.concat(toAdd);
            }
        }
        });
    }

    $scope.setActive('societies');

    $scope.resizeMap = function() {
        $scope.$broadcast('mapTabActivated');
    };

    $scope.treeSelected = function() {
        $scope.$broadcast('treeSelected', {tree: $scope.results.selectedTree});
    };

    $scope.generateDownloadLinks = function() {
        // queryObject is the in-memory JS object representing the chosen search options
        var queryObject = searchModelService.getModel().getQuery();
        // the CSV download endpoint is a GET URL, so we must send the query object as a string.
        var queryString = encodeURIComponent(JSON.stringify(queryObject));
        // format (csv/svg/etc) should be an argument, and change the endpoint to /api/v1/download
        $scope.csvDownloadLink = "/api/v1/csv_download?query=" + queryString;
    };
}
<|endoftext|>


<commit_before>import {clone, uid, toCSS, findClassNames} from '../utils'

/**
 * Regular rules.
 *
 * @api public
 */
export default class Rule {
  constructor(selector, style, options) {
    this.id = uid.get()
    this.type = 'regular'
    this.options = options
    this.selectorText = selector || ''
    this.className = ''
    if (options.named) {
      this.name = selector
      const className = options.className || (this.name ? `${this.name}--${this.id}` : this.id)
      this.selectorText = `.${className}`
      this.className = className
    }
    this.originalStyle = style
    // We expect style to be plain object.
    this.style = clone(style)
  }

  /**
   * Set selector string.
   * Attenition: use this with caution. Most browser didn't implement selector
   * text setter, so this will result in rerendering of entire style sheet.
   *
   * @param {String} selector
   * @api public
   */
  set selector(selector = '') {
    const {Renderer, sheet} = this.options

    // After we modify selector, ref by old selector needs to be removed.
    if (sheet) sheet.unregisterRule(this)

    this.selectorText = selector
    this.className = findClassNames(selector)

    if (!this.renderable) {
      // Register the rule with new selector.
      if (sheet) sheet.registerRule(this)
      return
    }

    const changed = Renderer.setSelector(this.renderable, selector)

    if (changed) {
      sheet.registerRule(this)
      return
    }

    // If selector setter is not implemented, rerender the sheet.
    // We need to delete renderable from the rule, because when sheet.deploy()
    // calls rule.toString, it will get the old selector.
    delete this.renderable
    sheet
      .registerRule(this)
      .deploy()
      .link()
  }

  /**
   * Get selector string.
   *
   * @return {String}
   * @api public
   */
  get selector() {
    if (this.renderable) {
      return this.options.Renderer.getSelector(this.renderable)
    }

    return this.selectorText
  }

  /**
   * Get or set a style property.
   *
   * @param {String} name
   * @param {String|Number} [value]
   * @return {Rule|String|Number}
   * @api public
   */
  prop(name, value) {
    const {style} = this.options.Renderer
    // Its a setter.
    if (value != null) {
      this.style[name] = value
      // Only defined if option linked is true.
      if (this.renderable) style(this.renderable, name, value)
      return this
    }
    // Its a getter, read the value from the DOM if its not cached.
    if (this.renderable && this.style[name] == null) {
      // Cache the value after we have got it from the DOM once.
      this.style[name] = style(this.renderable, name)
    }
    return this.style[name]
  }

  /**
   * Apply rule to an element inline.
   *
   * @param {Element} renderable
   * @return {Rule}
   * @api public
   */
  applyTo(renderable) {
    for (const prop in this.style) {
      const value = this.style[prop]
      const {style} = this.options.Renderer
      if (Array.isArray(value)) {
        for (let index = 0; index < value.length; index++) {
          style(renderable, prop, value[index])
        }
      }
      else style(renderable, prop, value)
    }
    return this
  }

  /**
   * Returns JSON representation of the rule.
   * Array of values is not supported.
   *
   * @return {Object}
   * @api public
   */
  toJSON() {
    const style = Object.create(null)
    for (const prop in this.style) {
      if (typeof this.style[prop] != 'object') {
        style[prop] = this.style[prop]
      }
    }
    return style
  }

  /**
   * Generates a CSS string.
   *
   * @see toCSS
   * @api public
   */
  toString(options) {
    return toCSS(this.selector, this.style, options)
  }
}
<commit_msg>a bit better logic for options.named<commit_after>import {clone, uid, toCSS, findClassNames} from '../utils'

/**
 * Regular rules.
 *
 * @api public
 */
export default class Rule {
  constructor(selector, style, options) {
    this.id = uid.get()
    this.type = 'regular'
    this.options = options
    this.selectorText = selector || ''
    this.className = options.className || ''
    this.originalStyle = style
    // We expect style to be plain object.
    this.style = clone(style)
    if (options.named) {
      this.name = selector
      if (!this.className) {
        this.className = this.name ? `${this.name}--${this.id}` : this.id
      }
      this.selectorText = `.${this.className}`
    }
  }

  /**
   * Set selector string.
   * Attenition: use this with caution. Most browser didn't implement selector
   * text setter, so this will result in rerendering of entire style sheet.
   *
   * @param {String} selector
   * @api public
   */
  set selector(selector = '') {
    const {Renderer, sheet} = this.options

    // After we modify selector, ref by old selector needs to be removed.
    if (sheet) sheet.unregisterRule(this)

    this.selectorText = selector
    this.className = findClassNames(selector)

    if (!this.renderable) {
      // Register the rule with new selector.
      if (sheet) sheet.registerRule(this)
      return
    }

    const changed = Renderer.setSelector(this.renderable, selector)

    if (changed) {
      sheet.registerRule(this)
      return
    }

    // If selector setter is not implemented, rerender the sheet.
    // We need to delete renderable from the rule, because when sheet.deploy()
    // calls rule.toString, it will get the old selector.
    delete this.renderable
    sheet
      .registerRule(this)
      .deploy()
      .link()
  }

  /**
   * Get selector string.
   *
   * @return {String}
   * @api public
   */
  get selector() {
    if (this.renderable) {
      return this.options.Renderer.getSelector(this.renderable)
    }

    return this.selectorText
  }

  /**
   * Get or set a style property.
   *
   * @param {String} name
   * @param {String|Number} [value]
   * @return {Rule|String|Number}
   * @api public
   */
  prop(name, value) {
    const {style} = this.options.Renderer
    // Its a setter.
    if (value != null) {
      this.style[name] = value
      // Only defined if option linked is true.
      if (this.renderable) style(this.renderable, name, value)
      return this
    }
    // Its a getter, read the value from the DOM if its not cached.
    if (this.renderable && this.style[name] == null) {
      // Cache the value after we have got it from the DOM once.
      this.style[name] = style(this.renderable, name)
    }
    return this.style[name]
  }

  /**
   * Apply rule to an element inline.
   *
   * @param {Element} renderable
   * @return {Rule}
   * @api public
   */
  applyTo(renderable) {
    for (const prop in this.style) {
      const value = this.style[prop]
      const {style} = this.options.Renderer
      if (Array.isArray(value)) {
        for (let index = 0; index < value.length; index++) {
          style(renderable, prop, value[index])
        }
      }
      else style(renderable, prop, value)
    }
    return this
  }

  /**
   * Returns JSON representation of the rule.
   * Array of values is not supported.
   *
   * @return {Object}
   * @api public
   */
  toJSON() {
    const style = Object.create(null)
    for (const prop in this.style) {
      if (typeof this.style[prop] != 'object') {
        style[prop] = this.style[prop]
      }
    }
    return style
  }

  /**
   * Generates a CSS string.
   *
   * @see toCSS
   * @api public
   */
  toString(options) {
    return toCSS(this.selector, this.style, options)
  }
}
<|endoftext|>


<commit_before>import {Form, field, rule } from 'ember-input';

export default Form.extend({

  //form attributes go here.
  //e.g.
  // firstName: field(),
  // lastName: field()

  // validation rules go here. e.g.
  //rules: {
    // hasFullName: rule('firstName.value', 'lastName.value', function() {
    //   var first = this.get('firstName.value');
    //   var last = this.get('lastName.value');
    //   return !Ember.isEmpty(first) && !Ember.isEmpty(last);
    // })
  //}
});
<commit_msg>bring in Ember to form blueprint<commit_after>import Ember from 'ember';
import {Form, field, rule } from 'ember-input';

export default Form.extend({

  //form attributes go here.
  //e.g.
  // firstName: field(),
  // lastName: field()

  // validation rules go here. e.g.
  //rules: {
    // hasFullName: rule('firstName.value', 'lastName.value', function() {
    //   var first = this.get('firstName.value');
    //   var last = this.get('lastName.value');
    //   return !Ember.isEmpty(first) && !Ember.isEmpty(last);
    // })
  //}
});
<|endoftext|>


<commit_before>// (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP

import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { loadActivityItem, unloadActivityItem,
  clearAlert, activateAlert } from '../../actions/actions';
import Layer from 'grommet/components/Layer';
import Article from 'grommet/components/Article';
import Box from 'grommet/components/Box';
import Heading from 'grommet/components/Heading';
import StatusIcon from 'grommet/components/icons/Status';
import Footer from 'grommet/components/Footer';
import CheckBox from 'grommet/components/CheckBox';
import Meter from 'grommet/components/Meter';
import Value from 'grommet/components/Value';
import Paragraph from 'grommet/components/Paragraph';
import Timestamp from 'grommet/components/Timestamp';
import Duration from '../../utils/Duration';
import ActivityResourceLink from './ActivityResourceLink';

class ActivityItem extends Component {

  constructor () {
    super();
    this._onToggle = this._onToggle.bind(this);
    // this._onActivate = this._onActivate.bind(this);
  }

  componentDidMount () {
    this.props.dispatch(loadActivityItem(this.props.uri));
  }

  componentWillUnmount () {
    this.props.dispatch(unloadActivityItem());
  }

  _onToggle () {
    const item = this.props.activity.item;
    if ('Active' === item.state) {
      this.props.dispatch(clearAlert(this.props.activity.item));
    } else if ('Cleared' === item.state) {
      this.props.dispatch(activateAlert(this.props.activity.item));
    }
  }

  _renderTimestamp (item) {
    let result;
    if (item.created) {
      result = <Timestamp className="secondary" value={item.created} />;
    }
    return result;
  }

  _renderResource (item) {
    const { includeResource } = this.props;
    let result;
    if (includeResource && item.attributes) {
      result = <ActivityResourceLink item={item} />;
    }
    return result;
  }

  _renderOwner (item) {
    let result;
    if (item.owner || (item.attributes && item.attributes.owner)) {
      result = (

          by {item.owner || item.attributes.owner}

      );
    }
    return result;
  }

  _renderState (item) {
    let result;
    if ('Running' === item.state) {
      let duration;
      if (item.created && item.modified) {
        duration = Duration(item.created, item.modified);
      }
      result = (

          <Meter size="small"
            value={item.percentComplete || 0}
            a11yTitle="Progress bar" />
          <Value size="small" value={item.percentComplete || 0} units="%" />
          {duration}

      );
    }
    return result;
  }

  _renderDetails (item) {
    let result;
    if (item.taskErrors) {
      result = item.taskErrors.map((taskError, index) => {
        return (

            <Paragraph>{taskError.message}</Paragraph>
            <Heading tag="h3">Resolution</Heading>
            {taskError.recommendedActions}

        );
      });
    }
    return result;
  }

  _renderChild (child, index) {
    const separator = (0 === index ? 'horizontal' : 'bottom');
    let timestamp = this._renderTimestamp(child);
    let resource = this._renderResource(child);
    let state = this._renderState(child);
    let details = this._renderDetails(child);
    return (
      <Box key={child.uri} pad={{vertical: 'medium'}} separator={separator}>
        <Box direction="row" pad={{between: 'large'}}>
          <Box pad="small">
            <StatusIcon value={child.status} />
          </Box>
          <Box>
            <Heading tag="h3">{child.name}</Heading>
            {timestamp}
            {resource}
            {state}
            {details}
          </Box>
        </Box>
      </Box>
    );
  }

  render () {
    let { activity: {item, children}, role } = this.props;

    let timestamp = this._renderTimestamp(item);
    let owner = this._renderOwner(item);

    let sub;
    if (timestamp || owner) {
      sub = (
        <Box direction="row" justify="between" pad={{between: 'small'}}>
          {owner}{timestamp}
        </Box>
      );
    }

    let footer;
    if ('read only' !== role &&
      ('Active' === item.state || 'Cleared' === item.state)) {
      footer = (

          <CheckBox id="state" label={item.state} toggle={true}
            checked={'Active' === item.state}
            onChange={this._onToggle} />

      );
    }

    let resource = this._renderResource(item);
    let state = this._renderState(item);
    let details = this._renderDetails(item);

    let childTasks;
    if (children) {
      childTasks = children.items.map(this._renderChild, this);
    }

    return (
      <Layer align="center" closer={true} onClose={this.props.onClose}
        a11yTitle='Activity Item'>

          <Box pad={{between: 'large'}}
            direction="row">
            <StatusIcon value={item.status} size="large" />
            <Box>
              <Heading tag="h2" margin="none">{item.name}</Heading>
              {resource}
              {sub}
              {state}
              {details}
              {footer}
            </Box>
          </Box>

            {childTasks}

      </Layer>
    );
  }
}

ActivityItem.propTypes = {
  activity: PropTypes.object,
  includeResource: PropTypes.bool,
  onClose: PropTypes.func.isRequired,
  role: PropTypes.string,
  uri: PropTypes.string.isRequired
};

let select = (state, props) => {
  return {
    activity: state.activity,
    role: state.session.role
  };
};

export default connect(select)(ActivityItem);
<commit_msg>Fixed an issue with ActivityItem layout of progress bar annotations.<commit_after>// (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP

import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { loadActivityItem, unloadActivityItem,
  clearAlert, activateAlert } from '../../actions/actions';
import Layer from 'grommet/components/Layer';
import Article from 'grommet/components/Article';
import Box from 'grommet/components/Box';
import Heading from 'grommet/components/Heading';
import StatusIcon from 'grommet/components/icons/Status';
import Footer from 'grommet/components/Footer';
import CheckBox from 'grommet/components/CheckBox';
import Meter from 'grommet/components/Meter';
import Value from 'grommet/components/Value';
import Paragraph from 'grommet/components/Paragraph';
import Timestamp from 'grommet/components/Timestamp';
import Duration from '../../utils/Duration';
import ActivityResourceLink from './ActivityResourceLink';

class ActivityItem extends Component {

  constructor () {
    super();
    this._onToggle = this._onToggle.bind(this);
    // this._onActivate = this._onActivate.bind(this);
  }

  componentDidMount () {
    this.props.dispatch(loadActivityItem(this.props.uri));
  }

  componentWillUnmount () {
    this.props.dispatch(unloadActivityItem());
  }

  _onToggle () {
    const item = this.props.activity.item;
    if ('Active' === item.state) {
      this.props.dispatch(clearAlert(this.props.activity.item));
    } else if ('Cleared' === item.state) {
      this.props.dispatch(activateAlert(this.props.activity.item));
    }
  }

  _renderTimestamp (item) {
    let result;
    if (item.created) {
      result = <Timestamp className="secondary" value={item.created} />;
    }
    return result;
  }

  _renderResource (item) {
    const { includeResource } = this.props;
    let result;
    if (includeResource && item.attributes) {
      result = <ActivityResourceLink item={item} />;
    }
    return result;
  }

  _renderOwner (item) {
    let result;
    if (item.owner || (item.attributes && item.attributes.owner)) {
      result = (

          by {item.owner || item.attributes.owner}

      );
    }
    return result;
  }

  _renderState (item) {
    let result;
    if ('Running' === item.state) {
      let duration;
      if (item.created && item.modified) {
        duration = Duration(item.created, item.modified);
      }
      result = (
        <Box direction='row' pad={{ between: 'small' }}>
          <Meter size="small"
            value={item.percentComplete || 0}
            a11yTitle="Progress bar" />
          <Value size="small" value={item.percentComplete || 0} units="%" />
          {duration}
        </Box>
      );
    }
    return result;
  }

  _renderDetails (item) {
    let result;
    if (item.taskErrors) {
      result = item.taskErrors.map((taskError, index) => {
        return (

            <Paragraph>{taskError.message}</Paragraph>
            <Heading tag="h3">Resolution</Heading>
            {taskError.recommendedActions}

        );
      });
    }
    return result;
  }

  _renderChild (child, index) {
    const separator = (0 === index ? 'horizontal' : 'bottom');
    let timestamp = this._renderTimestamp(child);
    let resource = this._renderResource(child);
    let state = this._renderState(child);
    let details = this._renderDetails(child);
    return (
      <Box key={child.uri} pad={{vertical: 'medium'}} separator={separator}>
        <Box direction="row" pad={{between: 'large'}}>
          <Box pad="small">
            <StatusIcon value={child.status} />
          </Box>
          <Box>
            <Heading tag="h3">{child.name}</Heading>
            {timestamp}
            {resource}
            {state}
            {details}
          </Box>
        </Box>
      </Box>
    );
  }

  render () {
    let { activity: {item, children}, role } = this.props;

    let timestamp = this._renderTimestamp(item);
    let owner = this._renderOwner(item);

    let sub;
    if (timestamp || owner) {
      sub = (
        <Box direction="row" justify="between" pad={{between: 'small'}}>
          {owner}{timestamp}
        </Box>
      );
    }

    let footer;
    if ('read only' !== role &&
      ('Active' === item.state || 'Cleared' === item.state)) {
      footer = (

          <CheckBox id="state" label={item.state} toggle={true}
            checked={'Active' === item.state}
            onChange={this._onToggle} />

      );
    }

    let resource = this._renderResource(item);
    let state = this._renderState(item);
    let details = this._renderDetails(item);

    let childTasks;
    if (children) {
      childTasks = children.items.map(this._renderChild, this);
    }

    return (
      <Layer align="center" closer={true} onClose={this.props.onClose}
        a11yTitle='Activity Item'>

          <Box pad={{between: 'large'}}
            direction="row">
            <StatusIcon value={item.status} size="large" />
            <Box>
              <Heading tag="h2" margin="none">{item.name}</Heading>
              {resource}
              {sub}
              {state}
              {details}
              {footer}
            </Box>
          </Box>

            {childTasks}

      </Layer>
    );
  }
}

ActivityItem.propTypes = {
  activity: PropTypes.object,
  includeResource: PropTypes.bool,
  onClose: PropTypes.func.isRequired,
  role: PropTypes.string,
  uri: PropTypes.string.isRequired
};

let select = (state, props) => {
  return {
    activity: state.activity,
    role: state.session.role
  };
};

export default connect(select)(ActivityItem);
<|endoftext|>


<commit_before><commit_msg>Add squash feature.<commit_after><|endoftext|>