<commit_before>  window.DynamicFields = {

    initialize: function() {
      /* Any fields marked with the class 'dynamic_field' will have an add button appended
       * to the DOM after the label */
      this.add_controls_to_label();
      this.add_remove_buttons_to_dynamic_fields();

      $(document).on('click', '.add-dynamic-field', function(event){

        // find all the input controls after the add button
        var fields = $(this).parent().parent().find('.controls.dynamic');
        var inputs = $(fields).find('input');
        var input_template = inputs.first()

	/*
	 * Make this simpler - store an attribute on the control container that keeps
	 * track of the index of the last input ID, increment it, and then put it back
	 * in the DOM
	 */
        var incremented_rails_id = parseInt($(fields).data('inputs')) + 1;
        $(fields).data('inputs', incremented_rails_id);
	var clone = $(input_template).clone().attr('id', incremented_rails_id).val('');

        // add input and remove button
        $(fields).append(clone);
        $(fields).append(DynamicFields.remove_button_html);

	// show the first remove dynamic field button
        // because we remove it when there is only one field
        if (inputs.length == 1) {
          $(inputs[0]).next('.remove-dynamic-field').show();
        }

      });

      $(document).on('click', '.remove-dynamic-field', function(event){

      	var node = $(this);
        input_fields_in_control_group = node.parent('.controls').find('input');

        /*
         * If there is only one item then hide the controls since you can't actually
         * click the button in that case. Reshow when there are two or more fields */
        if ( input_fields_in_control_group.length == 2 ) {
          abc = $(this);
         $(this).parent().find('.remove-dynamic-field').hide();
        }

        if (input_fields_in_control_group.length > 1 ) {
          //remove the input field
          node.prev().remove();
          //remove the remove button
          node.remove();
        }

      });
    },

    add_controls_to_label: function() {

      var labels = $('.controls.dynamic').parent('.control-group').children('label');

      var that = this;
      labels.each(function(index,label){
        $(label).append(that.add_button_html);
      });
    },

    add_remove_buttons_to_dynamic_fields: function(){
      $('.controls.dynamic > input').after(this.remove_button_html);
    },

    //makes an attempt at making sure the id's of each input are unique
    copy_and_increment_rails_collection_id: function( current_id ) {
      var match = current_id.match(/([a-z_]+)([0-9]+)/)
      var string_portion_of_id = match[1];
      var integer_portion_of_id = parseInt(match[2]);
      return string_portion_of_id + String(integer_portion_of_id + 1);
    },

    add_button_html: '',
    remove_button_html: ''

  }
<commit_msg>Refactored dynamic fields to match discussions about making it simpler (add only)<commit_after>  window.DynamicFields = {

    initialize: function() {
      /* Any fields marked with the class 'dynamic_field' will have an add button appended
       * to the DOM after the label */
      this.add_button_to_controls();

      $(document).on('click', '.add-dynamic-field', function(event){
        /* When we click the add button we need to manipulate the parent container, which
	 * is a
 wrapper */
	/* CSS selectors are faster than doing a last() call in jQuery */
        var input_template = $(this).parent().find('input:last');
	/* By doing this we should just keep pushing the add button down as the last
	 * element of the parent container */
	var new_input = $(input_template).clone();
        $(input_template).after(new_input);
      });
    },

    /* Simpler is better */
    add_button_to_controls: function() {
      var controls = $('.controls.dynamic').append(DynamicFields.add_input_html);
    },

    add_input_html: ''
  }
<|endoftext|>


<commit_before>// Leaflet Map js
var lats_longs;
function placeMarkers(dataArray) {
  lats_longs = dataArray;
  if(lats_longs.length < 30) {
    markerFeatureGroup = new L.FeatureGroup();
  }
  else {
    markerFeatureGroup = new L.MarkerClusterGroup({
      showCoverageOnHover: false,
      maxClusterRadius: 60,
      iconCreateFunction: function (cluster) {
        return L.divIcon({
          html: cluster.getChildCount(),
          className: 'marker-cluster',
          iconSize: L.point(40,40)
        });
      }
    });
  }
  for(var i = 0; i < dataArray.length; i++) {
    var subject = dataArray[i];
    var mapIcon = L.icon({
        iconUrl: '/assets/marker_icon_gray.png',
        iconAnchor: [12, 12],
        popupAnchor: [0, -4],
      });
    //var mapIcon = new MapIcon();
    // Turn on below once we've fixed the positioning and have implemented color icons
    //var marker = L.marker(new L.LatLng(a[1],a[2]) , {icon: mapIcon} , { address: address });
    if (subject.lat && subject.long) {
      var marker = L.marker(new L.LatLng(subject.lat,subject.long), { name: subject.name, icon: mapIcon });
      marker.bindPopup("" + subject.name + "");
      //marker.addTo(map);
      markerFeatureGroup.addLayer(marker);
    }
  }
  map.fitBounds(markerFeatureGroup.getBounds());
  markerFeatureGroup.addTo(map);
}

$(document).ready(function() {
  drawMap();
  audiojs.events.ready(function() {
    //var as = audiojs.createAll();
  });
});

function drawMap () {
  if(monroePilot) {
    window.map = L.mapbox.map('map',mapboxMapID).setView([41.6696, -86.246], 16);
  }
  else {
    window.map = L.mapbox.map('map',mapboxMapID).setView([41.665, -86.28], 13);
  }
  $.getJSON('/subjects.json', placeMarkers);
  $( "#dialog" ).dialog();
  $( "#dialog" ).dialog({ width: 295 });
  $( "#dialog" ).dialog({ position: { my: "left top", at: "left+50 bottom+60", of: "head"} });
}

// Expand Section js

(function($){"use strict";function e(){var e=this;e.defaults={hideMode:"fadeToggle",defaultSearchMode:"parent",defaultTarget:".content",throwOnMissingTarget:!0,keepStateInCookie:!1,cookieName:"simple-expand"},e.settings={},$.extend(e.settings,e.defaults),e.findLevelOneDeep=function(e,t,n){return e.find(t).filter(function(){return!$(this).parentsUntil(e,n).length})},e.setInitialState=function(t,n){var r=e.readState(t);r?(t.removeClass("collapsed").addClass("expanded"),e.show(n)):(t.removeClass("expanded").addClass("collapsed"),e.hide(n))},e.hide=function(t){e.settings.hideMode==="fadeToggle"?t.hide():e.settings.hideMode==="basic"&&t.hide()},e.show=function(t){e.settings.hideMode==="fadeToggle"?t.show():e.settings.hideMode==="basic"&&t.show()},e.checkKeepStateInCookiePreconditions=function(){if(e.settings.keepStateInCookie&&$.cookie===undefined)throw new Error("simple-expand: keepStateInCookie option requires $.cookie to be defined.")},e.readCookie=function(){var t=$.cookie(e.settings.cookieName);return t===null||t===""?{}:JSON.parse(t)},e.readState=function(t){if(!e.settings.keepStateInCookie)return!1;var n=t.attr("Id");if(n===undefined)return;var r=e.readCookie(),i=r[n]===!0||!1;return i},e.saveState=function(t,n){if(!e.settings.keepStateInCookie)return;var r=t.attr("Id");if(r===undefined)return;var i=e.readCookie();i[r]=n,$.cookie(e.settings.cookieName,JSON.stringify(i),{raw:!0,path:window.location.pathname})},e.toggle=function(t,n){var r=e.toggleCss(t);return e.settings.hideMode==="fadeToggle"?n.fadeToggle(150):e.settings.hideMode==="basic"?n.toggle():$.isFunction(e.settings.hideMode)&&e.settings.hideMode(t,n,r),e.saveState(t,r),!1},e.toggleCss=function(e){return e.hasClass("expanded")?(e.toggleClass("collapsed expanded"),!1):(e.toggleClass("expanded collapsed"),!0)},e.findTargets=function(t,n,r){var i=[];if(n==="absolute")i=$(r);else if(n==="relative")i=e.findLevelOneDeep(t,r,r);else if(n==="parent"){var s=t.parent();do i=e.findLevelOneDeep(s,r,r),i.length===0&&(s=s.parent());while(i.length===0&&s.length!==0)}return i},e.activate=function(t,n){$.extend(e.settings,n),e.checkKeepStateInCookiePreconditions(),t.each(function(){var t=$(this),n=t.attr("data-expander-target")||e.settings.defaultTarget,r=t.attr("data-expander-target-search")||e.settings.defaultSearchMode,i=e.findTargets(t,r,n);if(i.length===0){if(e.settings.throwOnMissingTarget)throw"simple-expand: Targets not found";return this}e.setInitialState(t,i),t.click(function(){return e.toggle(t,i)})})}}window.SimpleExpand=e,$.fn.simpleexpand=function(t){var n=new e;return n.activate(this,t),this}})(jQuery);

  $(function() {
    $('.expander').simpleexpand();
    $('.expander').click();
  });

<commit_msg>Fix JS for landing to deal with subject names that have apostrophes in them<commit_after>// Leaflet Map js
var lats_longs;
function placeMarkers(dataArray) {
  lats_longs = dataArray;
  if(lats_longs.length < 30) {
    markerFeatureGroup = new L.FeatureGroup();
  }
  else {
    markerFeatureGroup = new L.MarkerClusterGroup({
      showCoverageOnHover: false,
      maxClusterRadius: 60,
      iconCreateFunction: function (cluster) {
        return L.divIcon({
          html: cluster.getChildCount(),
          className: 'marker-cluster',
          iconSize: L.point(40,40)
        });
      }
    });
  }
  for(var i = 0; i < dataArray.length; i++) {
    var subject = dataArray[i];
    var mapIcon = L.icon({
        iconUrl: '/assets/marker_icon_gray.png',
        iconAnchor: [12, 12],
        popupAnchor: [0, -4],
      });
    //var mapIcon = new MapIcon();
    // Turn on below once we've fixed the positioning and have implemented color icons
    //var marker = L.marker(new L.LatLng(a[1],a[2]) , {icon: mapIcon} , { address: address });
    if (subject.lat && subject.long) {
      var marker = L.marker(new L.LatLng(subject.lat,subject.long), { name: subject.name, icon: mapIcon });
      marker.bindPopup("" + subject.name + "");
      if (subject.name.indexOf("O'Brien") != -1) {
        console.log("" + subject.name + "");
      }
      //marker.addTo(map);
      markerFeatureGroup.addLayer(marker);
    }
  }
  map.fitBounds(markerFeatureGroup.getBounds());
  markerFeatureGroup.addTo(map);
}

$(document).ready(function() {
  drawMap();
  audiojs.events.ready(function() {
    //var as = audiojs.createAll();
  });
});

function drawMap () {
  if(monroePilot) {
    window.map = L.mapbox.map('map',mapboxMapID).setView([41.6696, -86.246], 16);
  }
  else {
    window.map = L.mapbox.map('map',mapboxMapID).setView([41.665, -86.28], 13);
  }
  $.getJSON('/subjects.json', placeMarkers);
  $( "#dialog" ).dialog();
  $( "#dialog" ).dialog({ width: 295 });
  $( "#dialog" ).dialog({ position: { my: "left top", at: "left+50 bottom+60", of: "head"} });
}

// Expand Section js

(function($){"use strict";function e(){var e=this;e.defaults={hideMode:"fadeToggle",defaultSearchMode:"parent",defaultTarget:".content",throwOnMissingTarget:!0,keepStateInCookie:!1,cookieName:"simple-expand"},e.settings={},$.extend(e.settings,e.defaults),e.findLevelOneDeep=function(e,t,n){return e.find(t).filter(function(){return!$(this).parentsUntil(e,n).length})},e.setInitialState=function(t,n){var r=e.readState(t);r?(t.removeClass("collapsed").addClass("expanded"),e.show(n)):(t.removeClass("expanded").addClass("collapsed"),e.hide(n))},e.hide=function(t){e.settings.hideMode==="fadeToggle"?t.hide():e.settings.hideMode==="basic"&&t.hide()},e.show=function(t){e.settings.hideMode==="fadeToggle"?t.show():e.settings.hideMode==="basic"&&t.show()},e.checkKeepStateInCookiePreconditions=function(){if(e.settings.keepStateInCookie&&$.cookie===undefined)throw new Error("simple-expand: keepStateInCookie option requires $.cookie to be defined.")},e.readCookie=function(){var t=$.cookie(e.settings.cookieName);return t===null||t===""?{}:JSON.parse(t)},e.readState=function(t){if(!e.settings.keepStateInCookie)return!1;var n=t.attr("Id");if(n===undefined)return;var r=e.readCookie(),i=r[n]===!0||!1;return i},e.saveState=function(t,n){if(!e.settings.keepStateInCookie)return;var r=t.attr("Id");if(r===undefined)return;var i=e.readCookie();i[r]=n,$.cookie(e.settings.cookieName,JSON.stringify(i),{raw:!0,path:window.location.pathname})},e.toggle=function(t,n){var r=e.toggleCss(t);return e.settings.hideMode==="fadeToggle"?n.fadeToggle(150):e.settings.hideMode==="basic"?n.toggle():$.isFunction(e.settings.hideMode)&&e.settings.hideMode(t,n,r),e.saveState(t,r),!1},e.toggleCss=function(e){return e.hasClass("expanded")?(e.toggleClass("collapsed expanded"),!1):(e.toggleClass("expanded collapsed"),!0)},e.findTargets=function(t,n,r){var i=[];if(n==="absolute")i=$(r);else if(n==="relative")i=e.findLevelOneDeep(t,r,r);else if(n==="parent"){var s=t.parent();do i=e.findLevelOneDeep(s,r,r),i.length===0&&(s=s.parent());while(i.length===0&&s.length!==0)}return i},e.activate=function(t,n){$.extend(e.settings,n),e.checkKeepStateInCookiePreconditions(),t.each(function(){var t=$(this),n=t.attr("data-expander-target")||e.settings.defaultTarget,r=t.attr("data-expander-target-search")||e.settings.defaultSearchMode,i=e.findTargets(t,r,n);if(i.length===0){if(e.settings.throwOnMissingTarget)throw"simple-expand: Targets not found";return this}e.setInitialState(t,i),t.click(function(){return e.toggle(t,i)})})}}window.SimpleExpand=e,$.fn.simpleexpand=function(t){var n=new e;return n.activate(this,t),this}})(jQuery);

  $(function() {
    $('.expander').simpleexpand();
    $('.expander').click();
  });

<|endoftext|>


<commit_before>/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

// TODO:  Add ajax function to load pictures based on properties object.

$(window).scroll(function () {
    if ($(window).scrollTop() > $('body').height() / 2) {
        $("div#page-scrollback-image").fadeIn();
    }
    else
    {
        $("div#page-scrollback-image").fadeOut();

    }
});

$(document).load(function(){
     if ($("#slider-nav").text() == "false"){
         $("a.slidesjs-navigation").hide();
         console.log("slider nav hidden.");
        };

});

$(document).ready(function(){
 call_document_ready_on_show_page();
});

function call_document_ready_on_show_page() {
           setupPagePopup();

    // update left to correct height.
    $("#page-middle-left").height($("#page-body").height() + parseInt($("#page-body").css("margin-top")))

    // check for full screen and adjust layout
    if ($("#full-screen").html() == "true")
    {
        $("div#page-middle-left").hide();
        $("div#content").width("100%");
        $('#Content').css('background',"white")

    }

    activate_slides();

}

function activate_slides() {

    if (($("div#slides3").length > 0))
    {
        $("#page-slider-gallary-page").show();
    }
    else
    {
        $("#page-slider-gallary-page").hide();

    }

    console.log($("div#slides3 > div").length);

    if ($("div#slides3 > div").length > 1)
    {
        slideshow_width = parseInt($("#slider-width").text());
        slideshow_height = parseInt($("#slider-height").text());
        slideshow_nav_pagination = $("#slider-nav").text();
        slideshow_effect = $("#slider-effect").text();
        slideshow_auto = $("#slider-auto").text() || "true"
        slideshow_speed = $("#slider-speed").text() || "5000"

        $('#slides3').slidesjs({
            width: slideshow_width,
            height: slideshow_height,
            pagination: {
                active: true,
                // [boolean] Create pagination items.
                // You cannot use your own pagination. Sorry.
                effect: slideshow_effect
                        // [string] Can be either "slide" or "fade".
            },
            play: {
                active: false,
                // [boolean] Generate the play and stop buttons.
                // You cannot use your own buttons. Sorry.
                effect: slideshow_effect,
                // [string] Can be either "slide" or "fade".
                interval: 5000,
                // [number] Time spent on each slide in milliseconds.
                auto: false,
                // [boolean] Start playing the slideshow on load.
                //swap: true,
                // [boolean] show/hide stop and play buttons
                pauseOnHover: true,
                // [boolean] pause a playing slideshow on hover
                //    restartDelay: 2500
                // [number] restart delay on inactive slideshow
            },
            navigation: {
                active: slideshow_nav_pagination,
                // [boolean] Generates next and previous buttons.
                // You can set to false and use your own buttons.
                // User defined buttons must have the following:
                // previous button: class="slidesjs-previous slidesjs-navigation"
                // next button: class="slidesjs-n           ext slidesjs-navigation"
                effect: slideshow_effect
                        // [string] Can be either "slide" or "fade".
            }

        });

        if (($("div#slides3 div.slidesjs-container").length > 0))
        {

            if ($("#slider-nav").text() == "false") {
                $("a.slidesjs-navigation").hide();
            }
            ;

            $("div#slides3 .slidesjs-container").width($("#slider-width").text());
            $("div#slides3 .slidesjs-container").height($("#slider-height").text());
            $("div#slides3 .slidesjs-container div.slides_control").width($("#slider-width").text());
            $("div#slides3 .slidesjs-container div.slides_control").height($("#slider-height").text());
            $("div#slides3 .slidesjs-container div.slider-content").width($("#slider-width").text());
            $("div#slides3 .slidesjs-container div.slider-content").height($("#slider-height").text());

            //  slideshow_width = $("#slides").width();
            //  slideshow_height =$("#slides").height();

            slideshow_width = parseInt($("#slider-width").text());
            slideshow_height = parseInt($("#slider-height").text());

            slideshow_offset = $("#slides3").offset();
            slideshow_middle = (slideshow_height / 2) - ($("#slides3 .next-slide").height() / 2);

            $("#slides3 a.slidesjs-next").offset({
                top: slideshow_middle + slideshow_offset.top,
                left: slideshow_width + slideshow_offset.left + 17
            });

            $("#slides3 a.slidesjs-previous").offset({
                top: slideshow_middle + slideshow_offset.top,
                left: slideshow_offset.left - $("#slides3 .prev-slide").width() - 30
            });

            $("#slides3").css("overflow", "visible");

        }
    $("#page-slider-gallary-page").css("position", "absolute");

    }
    else
    {
        $("#page-slider-gallary-page").css("top", "0px");
        $("#page-slider-gallary-page").css("overflow", "hidden");

    }

}

function setupPagePopup() {
    $.each($('.page-popup-link'),function(){
        var  page_to_open = $(this).attr('href');
        $(this).attr('href','#');
        $(this).attr('onClick','return(0);');
        $(this).attr("page-to-open",page_to_open);
    // console.log(this);
    });

    $('.page-popup-link').click( function(){
        var  page_to_open = $(this).attr('page-to-open');
        var  page_name = $(this).attr('title') || "popup-page";

        $.ajax({
            url: page_to_open,
            success: function(data)
            {
                pageViewDialog = createAppDialog(page_name,data);
                $("div.ui-dialog-titlebar").hide();
                $("div.ui-dialog .ui-dialog-buttonpane").css("border-width","0px");
                $(".ui-dialog .ui-dialog-buttonpane button span").html("X");

                dialogHeight = $(".ui-dialog").height();
                dialogWidth = $(".ui-dialog").width();
                $(".ui-dialog").css("background", "none");
                 $(".ui-dialog").css("border", "none");

                $(".ui-dialog .ui-dialog-buttonpane").css("background", "none");

                $(".ui-dialog .ui-dialog-buttonpane button").css("position", "absolute");
                $(".ui-dialog .ui-dialog-buttonpane button").css("top", "40px");
                $(".ui-dialog .ui-dialog-buttonpane button").css("right", "40px");
                $(".ui-dialog .ui-resizable-se").css("display", "none");

                pageViewDialog.dialog('open');
                pageViewDialog.dialog({
                    close: function( event, ui ) {
                        $('#app-dialog').html("");
                        $('#app-dialog').dialog( "destroy" );
                    }
                });
            // require("roles/update_rights.js");
            // update_rights_callDocumentReady();

            // setupRolesSelection();
            }
        });
    });
}

// ************************************
//
// Create Edit Dialog Box
//
// ************************************

function createAppDialog(theName, theContent) {

    console.log(theName);

    if ($("#app-dialog-" + theName).length == 0)
    {
        var dialogContainer =  "

";
        $("#page").append($(dialogContainer));
    }
    else
    {
        dialogContainer=$("#app-dialog-" + theName);
    }
    // $('#app-dialog').html(theContent);
    theContent = '<input type="hidden" autofocus="autofocus" />' + theContent
    theAppDialog =  $("#app-dialog-" + theName).dialog({
        autoOpen: false,
        modal: true,
        buttons: {
            "Close": function() {
                // Do what needs to be done to complete
                $(this).dialog("close");
            }
        },
        close: function( event, ui ) {
            $('#app-dialog-' + theName).html("");
            $('#app-dialog-' + theName).dialog( "destroy" );
        },
        open: function (event, ui)
        {
            popUpAlertifExists();
        }

    });

    $('#app-dialog-' + theName).html(theContent);

    theHeight= $('#app-dialog-' + theName+ ' #dialog-height').text() || "500";
    theWidth= $('#app-dialog-' + theName+ ' #dialog-width').text()  || "500";
    theTitle= $('#app-dialog-' + theName+ ' #dialog-name').text() || "Edit";

    theAppDialog.dialog({
        title:theTitle,
        width: theWidth,
        height:theHeight
    });

    return(theAppDialog)
}
<commit_msg>Update slider (flexslider) so its part of the rendering of the page (show_page.js)<commit_after>/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

// TODO:  Add ajax function to load pictures based on properties object.

$(window).scroll(function () {
    if ($(window).scrollTop() > $('body').height() / 2) {
        $("div#page-scrollback-image").fadeIn();
    }
    else
    {
        $("div#page-scrollback-image").fadeOut();

    }
});

$(document).load(function(){
     if ($("#slider-nav").text() == "false"){
         $("a.slidesjs-navigation").hide();
         console.log("slider nav hidden.");
        };

});

$(document).ready(function(){
 call_document_ready_on_show_page();
});

function call_document_ready_on_show_page() {
           setupPagePopup();

    // update left to correct height.
    $("#page-middle-left").height($("#page-body").height() + parseInt($("#page-body").css("margin-top")))

    // check for full screen and adjust layout
    if ($("#full-screen").html() == "true")
    {
        $("div#page-middle-left").hide();
        $("div#content").width("100%");
        $('#Content').css('background',"white")

    }

    activate_slides();
   start_flex_sliders();
}

function start_flex_sliders() {

    if ($('.flexslider').length > 0) {
        require("jquery.flexslider.js");
        $('.flexslider').flexslider({start: function () {
                $('#page-slider-gallary-page').fadeIn();
            }, directionNav: true, animationSpeed: 2000, slideshowSpeed: 5000});

    }
}

function activate_slides() {

    if (($("div#slides3").length > 0))
    {
        $("#page-slider-gallary-page").show();
    }
    else
    {
        $("#page-slider-gallary-page").hide();

    }

    console.log($("div#slides3 > div").length);

    if ($("div#slides3 > div").length > 1)
    {
        slideshow_width = parseInt($("#slider-width").text());
        slideshow_height = parseInt($("#slider-height").text());
        slideshow_nav_pagination = $("#slider-nav").text();
        slideshow_effect = $("#slider-effect").text();
        slideshow_auto = $("#slider-auto").text() || "true"
        slideshow_speed = $("#slider-speed").text() || "5000"

        $('#slides3').slidesjs({
            width: slideshow_width,
            height: slideshow_height,
            pagination: {
                active: true,
                // [boolean] Create pagination items.
                // You cannot use your own pagination. Sorry.
                effect: slideshow_effect
                        // [string] Can be either "slide" or "fade".
            },
            play: {
                active: false,
                // [boolean] Generate the play and stop buttons.
                // You cannot use your own buttons. Sorry.
                effect: slideshow_effect,
                // [string] Can be either "slide" or "fade".
                interval: 5000,
                // [number] Time spent on each slide in milliseconds.
                auto: false,
                // [boolean] Start playing the slideshow on load.
                //swap: true,
                // [boolean] show/hide stop and play buttons
                pauseOnHover: true,
                // [boolean] pause a playing slideshow on hover
                //    restartDelay: 2500
                // [number] restart delay on inactive slideshow
            },
            navigation: {
                active: slideshow_nav_pagination,
                // [boolean] Generates next and previous buttons.
                // You can set to false and use your own buttons.
                // User defined buttons must have the following:
                // previous button: class="slidesjs-previous slidesjs-navigation"
                // next button: class="slidesjs-n           ext slidesjs-navigation"
                effect: slideshow_effect
                        // [string] Can be either "slide" or "fade".
            }

        });

        if (($("div#slides3 div.slidesjs-container").length > 0))
        {

            if ($("#slider-nav").text() == "false") {
                $("a.slidesjs-navigation").hide();
            }
            ;

            $("div#slides3 .slidesjs-container").width($("#slider-width").text());
            $("div#slides3 .slidesjs-container").height($("#slider-height").text());
            $("div#slides3 .slidesjs-container div.slides_control").width($("#slider-width").text());
            $("div#slides3 .slidesjs-container div.slides_control").height($("#slider-height").text());
            $("div#slides3 .slidesjs-container div.slider-content").width($("#slider-width").text());
            $("div#slides3 .slidesjs-container div.slider-content").height($("#slider-height").text());

            //  slideshow_width = $("#slides").width();
            //  slideshow_height =$("#slides").height();

            slideshow_width = parseInt($("#slider-width").text());
            slideshow_height = parseInt($("#slider-height").text());

            slideshow_offset = $("#slides3").offset();
            slideshow_middle = (slideshow_height / 2) - ($("#slides3 .next-slide").height() / 2);

            $("#slides3 a.slidesjs-next").offset({
                top: slideshow_middle + slideshow_offset.top,
                left: slideshow_width + slideshow_offset.left + 17
            });

            $("#slides3 a.slidesjs-previous").offset({
                top: slideshow_middle + slideshow_offset.top,
                left: slideshow_offset.left - $("#slides3 .prev-slide").width() - 30
            });

            $("#slides3").css("overflow", "visible");

        }
    $("#page-slider-gallary-page").css("position", "absolute");

    }
    else
    {
        $("#page-slider-gallary-page").css("top", "0px");
        $("#page-slider-gallary-page").css("overflow", "hidden");

    }

}

function setupPagePopup() {
    $.each($('.page-popup-link'),function(){
        var  page_to_open = $(this).attr('href');
        $(this).attr('href','#');
        $(this).attr('onClick','return(0);');
        $(this).attr("page-to-open",page_to_open);
    // console.log(this);
    });

    $('.page-popup-link').click( function(){
        var  page_to_open = $(this).attr('page-to-open');
        var  page_name = $(this).attr('title') || "popup-page";

        $.ajax({
            url: page_to_open,
            success: function(data)
            {
                pageViewDialog = createAppDialog(page_name,data);
                $("div.ui-dialog-titlebar").hide();
                $("div.ui-dialog .ui-dialog-buttonpane").css("border-width","0px");
                $(".ui-dialog .ui-dialog-buttonpane button span").html("X");

                dialogHeight = $(".ui-dialog").height();
                dialogWidth = $(".ui-dialog").width();
                $(".ui-dialog").css("background", "none");
                 $(".ui-dialog").css("border", "none");

                $(".ui-dialog .ui-dialog-buttonpane").css("background", "none");

                $(".ui-dialog .ui-dialog-buttonpane button").css("position", "absolute");
                $(".ui-dialog .ui-dialog-buttonpane button").css("top", "40px");
                $(".ui-dialog .ui-dialog-buttonpane button").css("right", "40px");
                $(".ui-dialog .ui-resizable-se").css("display", "none");

                pageViewDialog.dialog('open');
                pageViewDialog.dialog({
                    close: function( event, ui ) {
                        $('#app-dialog').html("");
                        $('#app-dialog').dialog( "destroy" );
                    }
                });
            // require("roles/update_rights.js");
            // update_rights_callDocumentReady();

            // setupRolesSelection();
            }
        });
    });
}

// ************************************
//
// Create Edit Dialog Box
//
// ************************************

function createAppDialog(theName, theContent) {

    console.log(theName);

    if ($("#app-dialog-" + theName).length == 0)
    {
        var dialogContainer =  "

";
        $("#page").append($(dialogContainer));
    }
    else
    {
        dialogContainer=$("#app-dialog-" + theName);
    }
    // $('#app-dialog').html(theContent);
    theContent = '<input type="hidden" autofocus="autofocus" />' + theContent
    theAppDialog =  $("#app-dialog-" + theName).dialog({
        autoOpen: false,
        modal: true,
        buttons: {
            "Close": function() {
                // Do what needs to be done to complete
                $(this).dialog("close");
            }
        },
        close: function( event, ui ) {
            $('#app-dialog-' + theName).html("");
            $('#app-dialog-' + theName).dialog( "destroy" );
        },
        open: function (event, ui)
        {
            popUpAlertifExists();
        }

    });

    $('#app-dialog-' + theName).html(theContent);

    theHeight= $('#app-dialog-' + theName+ ' #dialog-height').text() || "500";
    theWidth= $('#app-dialog-' + theName+ ' #dialog-width').text()  || "500";
    theTitle= $('#app-dialog-' + theName+ ' #dialog-name').text() || "Edit";

    theAppDialog.dialog({
        title:theTitle,
        width: theWidth,
        height:theHeight
    });

    return(theAppDialog)
}
<|endoftext|>


<commit_before>import React from 'react'
import { connect } from 'react-redux'
import { DragSource, DropTarget } from 'react-dnd'
import { NavLink, withRouter } from 'react-router-dom'

import { ItemTypes } from 'concerns/dndConfig.js'
import Icon from 'Icon.js'

import {
  updateCaseElement,
  persistCaseElementReordering,
} from 'redux/actions.js'

function getElementDataFrom(state) {
  return ({elementStore: store, elementId: id}) => {
    const {title, iconSlug} = state[store][id]
    const typeIcon = iconSlug && <Icon filename={iconSlug} />

    return { title, typeIcon }
  }
}

const TableOfContentsElement = ({position, element, connectDragSource,
  connectDropTarget, isDragging, editing}) =>
      <NavLink className="c-toc__link"
        activeClassName="c-toc__link--active"
        to={`/${position}`}
        style={{opacity: isDragging ? 0 : 1}}
      >
        { connectDragSource(connectDropTarget(

{editing ? ": : :" : position}

{element.title}

{element.typeIcon}

        )) }
      </NavLink>

const DraggableTableOfContentsElement = DropTarget(
  ItemTypes.CASE_ELEMENT,
  {
    canDrop() { return false },
    hover(props, monitor) {
      const { id: draggedId } = monitor.getItem()
      const { id: overId } = props

      if (draggedId !== overId) {
        const { index: overIndex } = props.findElement(overId)
        props.updateCaseElement(draggedId, overIndex)
      }
    },
  },
  connect => ({
    connectDropTarget: connect.dropTarget(),
  })
)(
  DragSource(
    ItemTypes.CASE_ELEMENT,
    {
      canDrag(props) {
        return props.editing && !props.readOnly
      },
      beginDrag(props) {
        return {
          id: props.id,
          originalIndex: props.findElement(props.id).index,
        }
      },
      endDrag(props, monitor) {
        const { id: droppedId, originalIndex } = monitor.getItem()
        const { index: droppedIndex } = props.findElement(droppedId)
        const didDrop = monitor.didDrop()

        if (didDrop) {
          props.persistCaseElementReordering(droppedId, droppedIndex)
        } else {
          props.updateCaseElement(droppedId, originalIndex)
        }
      },
    },
    (connect, monitor) => ({
      connectDragSource: connect.dragSource(),
      isDragging: monitor.isDragging(),
    })
  )(
    TableOfContentsElement
  )
)

export default withRouter(
  connect(
    (state, {element}) => ({
      ...element,
      element: getElementDataFrom(state)(element),
      findElement: (id) => {
        const { caseElements } = state.caseData
        return { element, index: caseElements.findIndex(e => e.id === id) }
      },
      editing: state.edit.inProgress,
    }),
    { updateCaseElement, persistCaseElementReordering },
  )(DraggableTableOfContentsElement)
)
<commit_msg>Doesn't show TOC drag handles on CaseElement pages since it's readonly<commit_after>import React from 'react'
import { connect } from 'react-redux'
import { DragSource, DropTarget } from 'react-dnd'
import { NavLink, withRouter } from 'react-router-dom'

import { ItemTypes } from 'concerns/dndConfig.js'
import Icon from 'Icon.js'

import {
  updateCaseElement,
  persistCaseElementReordering,
} from 'redux/actions.js'

function getElementDataFrom(state) {
  return ({elementStore: store, elementId: id}) => {
    const {title, iconSlug} = state[store][id]
    const typeIcon = iconSlug && <Icon filename={iconSlug} />

    return { title, typeIcon }
  }
}

const TableOfContentsElement = ({position, element, connectDragSource,
  connectDropTarget, isDragging, editing, readOnly}) =>
      <NavLink className="c-toc__link"
        activeClassName="c-toc__link--active"
        to={`/${position}`}
        style={{opacity: isDragging ? 0 : 1}}
      >
        { connectDragSource(connectDropTarget(

              {editing && !readOnly ? ": : :" : position}

{element.title}

{element.typeIcon}

        )) }
      </NavLink>

const DraggableTableOfContentsElement = DropTarget(
  ItemTypes.CASE_ELEMENT,
  {
    canDrop() { return false },
    hover(props, monitor) {
      const { id: draggedId } = monitor.getItem()
      const { id: overId } = props

      if (draggedId !== overId) {
        const { index: overIndex } = props.findElement(overId)
        props.updateCaseElement(draggedId, overIndex)
      }
    },
  },
  connect => ({
    connectDropTarget: connect.dropTarget(),
  })
)(
  DragSource(
    ItemTypes.CASE_ELEMENT,
    {
      canDrag(props) {
        return props.editing && !props.readOnly
      },
      beginDrag(props) {
        return {
          id: props.id,
          originalIndex: props.findElement(props.id).index,
        }
      },
      endDrag(props, monitor) {
        const { id: droppedId, originalIndex } = monitor.getItem()
        const { index: droppedIndex } = props.findElement(droppedId)
        const didDrop = monitor.didDrop()

        if (didDrop) {
          props.persistCaseElementReordering(droppedId, droppedIndex)
        } else {
          props.updateCaseElement(droppedId, originalIndex)
        }
      },
    },
    (connect, monitor) => ({
      connectDragSource: connect.dragSource(),
      isDragging: monitor.isDragging(),
    })
  )(
    TableOfContentsElement
  )
)

export default withRouter(
  connect(
    (state, {element}) => ({
      ...element,
      element: getElementDataFrom(state)(element),
      findElement: (id) => {
        const { caseElements } = state.caseData
        return { element, index: caseElements.findIndex(e => e.id === id) }
      },
      editing: state.edit.inProgress,
    }),
    { updateCaseElement, persistCaseElementReordering },
  )(DraggableTableOfContentsElement)
)
<|endoftext|>


<commit_before>function ProjectFile(params) {
    params = params || {};

    this.name = params.name || "New Project";
    this.settings = params.settings || {};
    this.editor = params.editor || {
            lastScene: null,
            layout: null
        };
    this.content = params.content || {};
}

ProjectFile.restore = function (data) {
    return new ProjectFile(data);
};

<commit_msg>+ matrix4 implementation<commit_after>/**
 * Project File class
 */
class ProjectFile {
    /**
     *
     * @param params
     */
    constructor(params) {
        params = params || {};

        this.name = params.name || "New Project";
        this.settings = params.settings || {};
        this.editor = params.editor || {
                lastScene: null,
                layout: null
            };
        this.content = params.content || {};
    }

    /**
     *
     * @param data
     * @returns {ProjectFile}
     */
    static restore(data) {
        return new ProjectFile(data);
    }
}<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import {
  Image,
  Text,
  TouchableHighlight,
  View
} from 'react-native';
import Theme from 'config/theme';

import AreaCache from 'containers/dashboard/area-cache';
import styles from './styles';

const nextIcon = require('assets/next.png');
const downloadedIcon = require('assets/downloaded.png');

function AreaList(props) {
  const { areas, onAreaPress, showCache } = props;
  if (!areas) return null;

  return (
    <View>
      {areas.map((area, index) => (
        <View key={`${area.id}-area-list`} style={styles.container}>
          <TouchableHighlight
            activeOpacity={0.5}
            underlayColor="transparent"
            onPress={() => onAreaPress(area.id, area.name, index)}
          >
            <View style={styles.item}>
              <View style={styles.imageContainer}>
                {area.image
                  ? <Image style={styles.image} source={{ uri: area.image }} />
                  : null
                }
              </View>
              <View style={styles.titleContainer}>
                <Text style={styles.title} numberOfLines={2}> {area.name} </Text>
                {showCache && area.cacheComplete &&
                  <Image style={[Theme.icon, styles.downloadedIcon]} source={downloadedIcon} />
                }
              </View>
              <TouchableHighlight
                activeOpacity={0.5}
                underlayColor="transparent"
                onPress={() => onAreaPress(area.id, area.name)}
              >
                <Image style={Theme.icon} source={nextIcon} />
              </TouchableHighlight>
            </View>
          </TouchableHighlight>
          {showCache && !area.cacheComplete &&
            <AreaCache areaId={area.id} />
          }
        </View>
      ))}
    </View>
  );
}

AreaList.propTypes = {
  areas: PropTypes.arrayOf(
    PropTypes.shape({
      id: PropTypes.string.isRequired,
      name: PropTypes.string.isRequired,
      image: PropTypes.string,
      cacheComplete: PropTypes.bool
    })
  ),
  onAreaPress: PropTypes.func,
  showCache: PropTypes.bool
};

AreaList.defaultProps = {
  showCache: false
};

export default AreaList;
<commit_msg>feat: changes AreaList to set a delay on progress bar<commit_after>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import {
  Image,
  Text,
  TouchableHighlight,
  View
} from 'react-native';
import Theme from 'config/theme';
import isEqual from 'lodash/isEqual';

import AreaCache from 'containers/dashboard/area-cache';
import styles from './styles';

const Timer = require('react-native-timer');

const nextIcon = require('assets/next.png');
const downloadedIcon = require('assets/downloaded.png');

class AreaList extends PureComponent {

  static propTypes = {
    areas: PropTypes.arrayOf(
      PropTypes.shape({
        id: PropTypes.string.isRequired,
        name: PropTypes.string.isRequired,
        image: PropTypes.string,
        cacheComplete: PropTypes.bool
      })
    ),
    onAreaPress: PropTypes.func,
    showCache: PropTypes.bool
  };

  static defaultProps = {
    showCache: false
  };

  state = {
    areasToCache: this.props.areas.map(area => area.cacheComplete)
  };

  componentWillReceiveProps(nextProps) {
    const areasToCache = nextProps.areas.map(area => area.cacheComplete);
    if (!isEqual(areasToCache, this.state.areasToCache)) {
      this.updateAreasToCache(areasToCache);
    }
  }

  componentWillUnmount() {
    Timer.clearTimeout(this, 'updateAreasToCache');
  }

  updateAreasToCache(areasToCache) {
    Timer.setTimeout(this, 'updateAreasToCache', () => this.setState({ areasToCache }), 350);
  }

  render() {
    const { areas, onAreaPress, showCache } = this.props;
    const { areasToCache } = this.state;
    if (!areas) return null;

    return (
      <View>
        {areas.map((area, index) => (
          <View key={`${area.id}-area-list`} style={styles.container}>
            <TouchableHighlight
              activeOpacity={0.5}
              underlayColor="transparent"
              onPress={() => onAreaPress(area.id, area.name, index)}
            >
              <View style={styles.item}>
                <View style={styles.imageContainer}>
                  {area.image
                    ? <Image style={styles.image} source={{ uri: area.image }} />
                    : null
                  }
                </View>
                <View style={styles.titleContainer}>
                  <Text style={styles.title} numberOfLines={2}> {area.name} </Text>
                  {showCache && area.cacheComplete &&
                    <Image style={[Theme.icon, styles.downloadedIcon]} source={downloadedIcon} />
                  }
                </View>
                <TouchableHighlight
                  activeOpacity={0.5}
                  underlayColor="transparent"
                  onPress={() => onAreaPress(area.id, area.name)}
                >
                  <Image style={Theme.icon} source={nextIcon} />
                </TouchableHighlight>
              </View>
            </TouchableHighlight>
            {showCache && !areasToCache[index] &&
              <AreaCache areaId={area.id} />
            }
          </View>
        ))}
      </View>
    );
  }
}

export default AreaList;
<|endoftext|>


<commit_before>const semver = require('semver')
const request = require('request')
const express = require('express')
const serviceRegistry = require('../models/service-registry')
// const users = require('../models/users')

// Handler for UDP service registration
module.exports.registryHandler = function (msg, rinfo) {
  console.log(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`)
  const instance = JSON.parse(msg)
  // The most important thing is the ip address, and we need to set that
  // property on the object before setting it in storage
  instance.ipAddr = rinfo.address
  serviceRegistry.add(instance)
}

// The main router for the API
module.exports.Router = () => {
  const router = express.Router()

  // Get list of microservice instances with registered name
  router.get('/:name', (req, res) => {
    serviceRegistry.getAll(req.params.name)
      .then(services => {
        res.json(services)
      })
      .catch(err => {
        res.status(500).json(err)
      })
  })

  // Make is so that only 'admins' can do this in the future
  // See who's authorized to use a given service
  router.get('/:name/:id/authentication')
  // Authorize a user
  router.post('/:name/:id/authentication/:userId')
  // Deauthorize a user
  router.delete('/:name/:id/authentication/:userId')

  // This is where we will perform forwarding and do service lookups
  router.all('/forward/:name/:version/*', (req, res) => {
    if (!semver.valid(req.params.version)) {
      res.status(400).send(`Supplied invalid version string: ${req.params.version}`)
    }
    // IP Lookup for service
    serviceRegistry.get(req.params.name, req.params.version)
      .then(({ipAddr, port}) => {
        // Port is optional
        port = port || 80
        const idx = `/forward/${req.params.name}/${req.params.version}`.length
        const forwardedPath = req.url.substring(idx)
        const uri = `http://${ipAddr}:${port}${forwardedPath}`
        // Proxy the reqest
        req.pipe(request(uri)).pipe(res)
      }).catch(err => {
        res.status(404).send(`Service '${req.params.name}' not found :(.\nError details: ${err.toString()}`)
      })
  })

  return router
}
<commit_msg>Custom Header Test<commit_after>const semver = require('semver')
const request = require('request')
const express = require('express')
const serviceRegistry = require('../models/service-registry')
// const users = require('../models/users')

// Handler for UDP service registration
module.exports.registryHandler = function (msg, rinfo) {
  console.log(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`)
  const instance = JSON.parse(msg)
  // The most important thing is the ip address, and we need to set that
  // property on the object before setting it in storage
  instance.ipAddr = rinfo.address
  serviceRegistry.add(instance)
}

// The main router for the API
module.exports.Router = () => {
  const router = express.Router()

  // Get list of microservice instances with registered name
  router.get('/:name', (req, res) => {
    serviceRegistry.getAll(req.params.name)
      .then(services => {
        res.json(services)
      })
      .catch(err => {
        res.status(500).json(err)
      })
  })

  // Make is so that only 'admins' can do this in the future
  // See who's authorized to use a given service
  router.get('/:name/:id/authentication')
  // Authorize a user
  router.post('/:name/:id/authentication/:userId')
  // Deauthorize a user
  router.delete('/:name/:id/authentication/:userId')

  // This is where we will perform forwarding and do service lookups
  router.all('/forward/:name/:version/*', (req, res) => {
    if (!semver.valid(req.params.version)) {
      res.status(400).send(`Supplied invalid version string: ${req.params.version}`)
    }
    // IP Lookup for service
    serviceRegistry.get(req.params.name, req.params.version)
      .then(({ipAddr, port}) => {
        // Port is optional
        port = port || 80
        const idx = `/forward/${req.params.name}/${req.params.version}`.length
        const forwardedPath = req.url.substring(idx)
        const uri = `http://${ipAddr}:${port}${forwardedPath}`
        const options = {
          url: uri,
          headers: {
            'X-User': '1234'
          }
        }
        // Proxy the reqest
        req.pipe(request(options)).pipe(res)
      }).catch(err => {
        res.status(404).send(`Service '${req.params.name}' not found :(.\nError details: ${err.toString()}`)
      })
  })

  return router
}
<|endoftext|>


<commit_before>sharingController.$inject = ['$scope'];

export default function sharingController($scope) {
    $scope.fate = '';
    $scope.percentage = 60;

    if($scope.percentage <= 10) {
        $scope.fate = 'The wagon\'s occupants accuse you of miserliness and kill you.';
    } else if($scope.percentage > 10 && $scope.percentage <= 50) {
        $scope.fate = 'The wagon\'s occupants don\'t want another mouth to feed, so they kill you.';
    } else {
        $scope.fate = 'You were too generous. Your food eventually spoiled and you all died.';
    }
}
<commit_msg>sharing functions back<commit_after>sharingController.$inject = ['$scope'];

export default function sharingController($scope) {
    $scope.fate = '';

  $scope.submit = function () {
    if($scope.percentage <= 10) {
        $scope.fate = 'The wagon\'s occupants accuse you of miserliness and kill you.';
    } else if($scope.percentage > 10 && $scope.percentage <= 50) {
        $scope.fate = 'The wagon\'s occupants don\'t want another mouth to feed, so they kill you.';
    } else {
        $scope.fate = 'You were too generous. Your food eventually spoiled and you all died.';
    }
  }
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { validate } from 'parameter-validator';
import { color1 } from '../../style-variables';
import { MusicNoteEventType } from 'react-native-voxophone-engine';
import delay from '../../utils/delay';
import Ring from '../music-note-meter-ring';

const NUMBER_OF_RINGS = 8;
const NOTE_ON_TRANSITION_MILLISECONDS = 40;
const NOTE_OFF_TRANSITION_MILLISECONDS = 100;
const TOTAL_HUE_LIGHTNESS_CHANGE = 0.5;
const RANDOM_COLORS_ENABLED = true;

const meterCenterDiameter = 140;

const styles = StyleSheet.create({

    musicNoteMeter: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
        // backgroundColor: 'green',
        // borderRadius: 170
    },
    meterCenter: {
        flexGrow: 0,
        flexShrink: 0,
        flexBasis: 'auto',
        height: meterCenterDiameter,
        width: meterCenterDiameter,
        borderRadius: meterCenterDiameter / 2,
        backgroundColor: 'white',
        alignItems: 'center',
        justifyContent: 'center',
    },
    meterCenterText: {
        color: color1,
        fontSize: 72,
        fontWeight: 'bold'
    }
});

/**
* Illustrates the volume envelope of a note played using concentric circles and
* displays the name of the note being played (e.g. "C#").
*/
export default class MusicNoteMeter extends Component {

    constructor(props) {

        super(props);
        validate(props.dependencies, [ 'logger', 'voxophone' ], this, { addPrefix: '_' });
        this._voxophone.addMusicNoteListener(this._handleMusicNoteEvent.bind(this));
        this.state = { note: '' };

        // return this._createAndConfigureRings()
        // .then(rings => {
        //     this._rings = rings;
        //     this._noteOff();
        // });
    }

    render() {
        return (
            <View style={styles.musicNoteMeter}>

                {this._renderRings(NUMBER_OF_RINGS,
                    <View style={styles.meterCenter}>
                        <Text style={styles.meterCenterText}>C#</Text>
                    </View>
                )}
            </View>
        );
    }

    _renderRings(numberOfRingsLeft, center) {

        return (
            <Ring backgroundColor={this._getRandomColor()} diameter={Math.max(this.props.diameter - ((NUMBER_OF_RINGS - numberOfRingsLeft) * 25), 0)}>
                {--numberOfRingsLeft > 0 ? this._renderRings(numberOfRingsLeft, center) : center}
            </Ring>
        );
    }

    _handleMusicNoteEvent(event) {

        if (event.type === MusicNoteEventType.NOTE_ON) {

            this.setState({ note: event.note });
            // this._noteOn(event.note);
        } else {
            // this._noteOff();
        }
    }

    /* eslint-disable */

    /**
    * Illustrates that a given note has been played
    *
    * @param {string} note - e.g. 'C#'
    */
    _noteOn(note) {

        let delayPerRing = NOTE_ON_TRANSITION_MILLISECONDS / this._rings.length;
        let promisedDisplayUpdate = Promise.resolve().then(() => this.set('note', note));

        // Sequentially render each ring, adding a delay between each to stretch it out to the desired time.
        return this._rings.reduce((promise, ring) => {
            return promise
            .then(() => this._setRingVisibility(ring, true))
            .then(() => delay(delayPerRing));
        }, promisedDisplayUpdate);
    }

    /**
    * Updates the display when a note has stopped being played.
    */
    _noteOff() {

        let reversedRings = [ ...this._rings ].reverse();
        let delayPerRing = NOTE_OFF_TRANSITION_MILLISECONDS / this._rings.length;

        // Sequentially erase each ring, adding a delay between each to stretch it out to the desired time.
        return reversedRings.reduce((promise, ring) => {
            return promise
            .then(() => this._setRingVisibility(ring, false))
            .then(() => delay(delayPerRing));
        }, Promise.resolve());
    }

    /**
    * Draws or hides the given ring.
    *
    * @param {ui/View} ring
    * @param {boolean} isVisible
    */
    _setRingVisibility(ring, isVisible) {

        ring.backgroundColor = isVisible ? this._getColorForRing(ring) : this.view.page.backgroundColor;
    }

    /**
    * Creates and hooks up the ring-shaped views arranged in concentric circles that are used in the UI.
    *
    * @returns {Promise.<Array.<View>>} - Array where each item is a View that is a ring in the music note meter's UI.
    *                                     The rings go from the center to the circumference as the index increases.
    */
    _createAndConfigureRings() {

        return this._getOuterRing()
        .then(outerRing => {

            let center = this.view.getViewById('meter-center');
            this.view.removeChild(center);

            let radiusLengthToDivide = outerRing.borderRadius - center.borderRadius;
            let radiusStepSize = radiusLengthToDivide / NUMBER_OF_RINGS;

            let numberOfRingsToCreate = NUMBER_OF_RINGS - 1; // Subtract one, since the outer ring already exists.
            let rings = this._createRings(center, numberOfRingsToCreate, radiusStepSize);
            rings.push(outerRing);

            // Link the rings together in a parent-child hierarchy.
            this._linkRingsTogether(rings);
            rings[0].addChild(center);

            this._setRingColors(rings);
            return rings;
        })
        .catch(error => this._logger.error(`An error occurred during ring creation.`, { error }));
    }

    /**
    * @param   {ui/View}        centerRing     - The initial, center ring on which the size of the other rings will be based.
    * @param   {int}            numberOfRings  - Total number of rings to render
    * @param   {int}            radiusStepSize - The distance in pixels between the border of a ring and the border of the ring
    *                                            immediately outside of it.
    * @returns {Array.<ui/View}
    */
    _createRings(centerRing, numberOfRings, radiusStepSize) {

        let previousRing = centerRing,
            rings = [];

        for (let i = 0; i < numberOfRings; i++) {

            let radius = previousRing.borderRadius + radiusStepSize;
            let ring = this._createRing(radius);
            rings.push(ring);
            previousRing = ring;
        }
        return rings;
    }

    _createRing(radius) {

        let ring = new FlexboxLayout();
        ring.height = ring.width = radius * 2;
        ring.borderRadius = radius;
        ring.alignItems = AlignItems.CENTER;
        ring.justifyContent = JustifyContent.CENTER;
        FlexboxLayout.setFlexGrow(ring, 0);
        FlexboxLayout.setFlexShrink(ring, 0);
        return ring;
    }

    /**
    * Gets a reference to the existing view which will serve as the outermost ring and
    * then configures and returns it.
    *
    * @returns {Promise.<ui/View>}
    */
    _getOuterRing() {

        return Promise.resolve()
        .then(() => {

            let outerRing = this.view;
            let outerRingSize = outerRing.getActualSize();
            let outerRingRadius = Math.min(outerRingSize.height, outerRingSize.width) / 2;

            if (outerRingRadius === 0) {
                // The view hasn't been fully initialized. Let's try again in 1 millisecond.
                return delay(1).then(() => this._getOuterRing());
            }
            // Set the height and width equal to each other, because this view is initially just a rectangle.
            outerRing.height = this.view.width = outerRingRadius * 2;
            outerRing.borderRadius = outerRingRadius;
            return outerRing;
        });
    }

    _getRandomColor() {

        let num = Math.floor(Math.random() * 0xFFFFFF);
        let hex = num.toString(16).padStart(6, '0');
        return '#' + hex;
    }

    _linkRingsTogether(rings) {

        rings.forEach((ring, index) => {
            let parentRing = rings[index + 1];

            if (parentRing) {
                parentRing.addChild(ring);
            }
        });
    }

    _setRingColors(rings) {

        rings.forEach((ring, index) => {
            ring.backgroundColor = this._getColorForRingIndex(index);
        });
    }

    _getColorForRing(ring) {

        let ringIndex = this._rings.indexOf(ring);
        return this._getColorForRingIndex(ringIndex);
    }

    _getColorForRingIndex(ringIndex) {

        if (RANDOM_COLORS_ENABLED) {
            return this._getRandomColor();
        }

        let lightnessStepSize = TOTAL_HUE_LIGHTNESS_CHANGE / NUMBER_OF_RINGS;
        let rootColor = '#ff871e';
        let { r, g, b } = ColorEditor(rootColor).darken(ringIndex * lightnessStepSize).rgb().object();
        return new Color(255, r, g, b);
    }
}
<commit_msg>Updated MusicNoteMeter._renderRings() so that the ring thicknesses are determined correctly.<commit_after>import React, { Component } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { validate } from 'parameter-validator';
import { color1 } from '../../style-variables';
import { MusicNoteEventType } from 'react-native-voxophone-engine';
import delay from '../../utils/delay';
import Ring from '../music-note-meter-ring';

const NUMBER_OF_RINGS = 8;
const NOTE_ON_TRANSITION_MILLISECONDS = 40;
const NOTE_OFF_TRANSITION_MILLISECONDS = 100;
const TOTAL_HUE_LIGHTNESS_CHANGE = 0.5;
const RANDOM_COLORS_ENABLED = true;

const meterCenterDiameter = 140;

const styles = StyleSheet.create({

    musicNoteMeter: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
        // backgroundColor: 'green',
        // borderRadius: 170
    },
    meterCenter: {
        flexGrow: 0,
        flexShrink: 0,
        flexBasis: 'auto',
        height: meterCenterDiameter,
        width: meterCenterDiameter,
        borderRadius: meterCenterDiameter / 2,
        backgroundColor: 'white',
        alignItems: 'center',
        justifyContent: 'center',
    },
    meterCenterText: {
        color: color1,
        fontSize: 72,
        fontWeight: 'bold'
    }
});

/**
* Illustrates the volume envelope of a note played using concentric circles and
* displays the name of the note being played (e.g. "C#").
*/
export default class MusicNoteMeter extends Component {

    constructor(props) {

        super(props);
        validate(props.dependencies, [ 'logger', 'voxophone' ], this, { addPrefix: '_' });
        this._voxophone.addMusicNoteListener(this._handleMusicNoteEvent.bind(this));
        this.state = { note: '' };

        // return this._createAndConfigureRings()
        // .then(rings => {
        //     this._rings = rings;
        //     this._noteOff();
        // });
    }

    render() {
        return (
            <View style={styles.musicNoteMeter}>

                {this._renderRings(NUMBER_OF_RINGS, this.props.diameter, meterCenterDiameter,
                    <View style={styles.meterCenter}>
                        <Text style={styles.meterCenterText}>C#</Text>
                    </View>
                )}
            </View>
        );
    }

    _renderRings(numberOfRingsLeft, diameter, centerDiameter, center) {

        let radius = diameter / 2,
            centerRadius = centerDiameter / 2,
            distanceToCenter = radius - centerRadius,
            ringThickness = Math.floor(distanceToCenter / numberOfRingsLeft),
            nextRingDiameter = diameter - (ringThickness * 2);

        return (
            <Ring backgroundColor={this._getRandomColor()} diameter={diameter}>
                {--numberOfRingsLeft > 0 ? this._renderRings(numberOfRingsLeft, nextRingDiameter, centerDiameter, center) : center}
            </Ring>
        );
    }

    _handleMusicNoteEvent(event) {

        if (event.type === MusicNoteEventType.NOTE_ON) {

            this.setState({ note: event.note });
            // this._noteOn(event.note);
        } else {
            // this._noteOff();
        }
    }

    /* eslint-disable */

    /**
    * Illustrates that a given note has been played
    *
    * @param {string} note - e.g. 'C#'
    */
    _noteOn(note) {

        let delayPerRing = NOTE_ON_TRANSITION_MILLISECONDS / this._rings.length;
        let promisedDisplayUpdate = Promise.resolve().then(() => this.set('note', note));

        // Sequentially render each ring, adding a delay between each to stretch it out to the desired time.
        return this._rings.reduce((promise, ring) => {
            return promise
            .then(() => this._setRingVisibility(ring, true))
            .then(() => delay(delayPerRing));
        }, promisedDisplayUpdate);
    }

    /**
    * Updates the display when a note has stopped being played.
    */
    _noteOff() {

        let reversedRings = [ ...this._rings ].reverse();
        let delayPerRing = NOTE_OFF_TRANSITION_MILLISECONDS / this._rings.length;

        // Sequentially erase each ring, adding a delay between each to stretch it out to the desired time.
        return reversedRings.reduce((promise, ring) => {
            return promise
            .then(() => this._setRingVisibility(ring, false))
            .then(() => delay(delayPerRing));
        }, Promise.resolve());
    }

    /**
    * Draws or hides the given ring.
    *
    * @param {ui/View} ring
    * @param {boolean} isVisible
    */
    _setRingVisibility(ring, isVisible) {

        ring.backgroundColor = isVisible ? this._getColorForRing(ring) : this.view.page.backgroundColor;
    }

    /**
    * Creates and hooks up the ring-shaped views arranged in concentric circles that are used in the UI.
    *
    * @returns {Promise.<Array.<View>>} - Array where each item is a View that is a ring in the music note meter's UI.
    *                                     The rings go from the center to the circumference as the index increases.
    */
    _createAndConfigureRings() {

        return this._getOuterRing()
        .then(outerRing => {

            let center = this.view.getViewById('meter-center');
            this.view.removeChild(center);

            let radiusLengthToDivide = outerRing.borderRadius - center.borderRadius;
            let radiusStepSize = radiusLengthToDivide / NUMBER_OF_RINGS;

            let numberOfRingsToCreate = NUMBER_OF_RINGS - 1; // Subtract one, since the outer ring already exists.
            let rings = this._createRings(center, numberOfRingsToCreate, radiusStepSize);
            rings.push(outerRing);

            // Link the rings together in a parent-child hierarchy.
            this._linkRingsTogether(rings);
            rings[0].addChild(center);

            this._setRingColors(rings);
            return rings;
        })
        .catch(error => this._logger.error(`An error occurred during ring creation.`, { error }));
    }

    /**
    * @param   {ui/View}        centerRing     - The initial, center ring on which the size of the other rings will be based.
    * @param   {int}            numberOfRings  - Total number of rings to render
    * @param   {int}            radiusStepSize - The distance in pixels between the border of a ring and the border of the ring
    *                                            immediately outside of it.
    * @returns {Array.<ui/View}
    */
    _createRings(centerRing, numberOfRings, radiusStepSize) {

        let previousRing = centerRing,
            rings = [];

        for (let i = 0; i < numberOfRings; i++) {

            let radius = previousRing.borderRadius + radiusStepSize;
            let ring = this._createRing(radius);
            rings.push(ring);
            previousRing = ring;
        }
        return rings;
    }

    _createRing(radius) {

        let ring = new FlexboxLayout();
        ring.height = ring.width = radius * 2;
        ring.borderRadius = radius;
        ring.alignItems = AlignItems.CENTER;
        ring.justifyContent = JustifyContent.CENTER;
        FlexboxLayout.setFlexGrow(ring, 0);
        FlexboxLayout.setFlexShrink(ring, 0);
        return ring;
    }

    /**
    * Gets a reference to the existing view which will serve as the outermost ring and
    * then configures and returns it.
    *
    * @returns {Promise.<ui/View>}
    */
    _getOuterRing() {

        return Promise.resolve()
        .then(() => {

            let outerRing = this.view;
            let outerRingSize = outerRing.getActualSize();
            let outerRingRadius = Math.min(outerRingSize.height, outerRingSize.width) / 2;

            if (outerRingRadius === 0) {
                // The view hasn't been fully initialized. Let's try again in 1 millisecond.
                return delay(1).then(() => this._getOuterRing());
            }
            // Set the height and width equal to each other, because this view is initially just a rectangle.
            outerRing.height = this.view.width = outerRingRadius * 2;
            outerRing.borderRadius = outerRingRadius;
            return outerRing;
        });
    }

    _getRandomColor() {

        let num = Math.floor(Math.random() * 0xFFFFFF);
        let hex = num.toString(16).padStart(6, '0');
        return '#' + hex;
    }

    _linkRingsTogether(rings) {

        rings.forEach((ring, index) => {
            let parentRing = rings[index + 1];

            if (parentRing) {
                parentRing.addChild(ring);
            }
        });
    }

    _setRingColors(rings) {

        rings.forEach((ring, index) => {
            ring.backgroundColor = this._getColorForRingIndex(index);
        });
    }

    _getColorForRing(ring) {

        let ringIndex = this._rings.indexOf(ring);
        return this._getColorForRingIndex(ringIndex);
    }

    _getColorForRingIndex(ringIndex) {

        if (RANDOM_COLORS_ENABLED) {
            return this._getRandomColor();
        }

        let lightnessStepSize = TOTAL_HUE_LIGHTNESS_CHANGE / NUMBER_OF_RINGS;
        let rootColor = '#ff871e';
        let { r, g, b } = ColorEditor(rootColor).darken(ringIndex * lightnessStepSize).rgb().object();
        return new Color(255, r, g, b);
    }
}
<|endoftext|>


<commit_before>var AudioletOutput = new Class({
    initialize: function(node, index) {
        this.node = node;
        this.index = index;
        this.connectedTo = [];
        // External buffer where data pulled from the graph is stored
        this.buffer = new AudioletBuffer(1, 0);
        // Internal buffer for if we are in a feedback loop
        this.feedbackBuffer = new AudioletBuffer(1, 0);
        // Buffer to shift data into if we are in a feedback loop
        this.outputBuffer = new AudioletBuffer(1, 0);

        this.linkedInput = null;
        this.numberOfChannels = 1;

        this.suppliesFeedbackLoop = false;
        this.timestamp = null;
    },

    connect: function(input) {
        this.connectedTo.push(input);
    },

    disconnect: function(input) {
        var numberOfStreams = this.connectedTo.length;
        for (var i = 0; i < numberOfStreams; i++) {
            if (input == this.connectedTo[i]) {
                this.connectedTo.splice(i, 1);
                break;
            }
        }
    },

    isConnected: function() {
        return (this.connectedTo.length > 0);
    },

    link: function(input) {
        this.linkedInput = input;
    },

    unlink: function() {
        this.linkedInput = null;
    },

    getNumberOfChannels: function() {
        if (this.linkedInput && this.linkedInput.isConnected()) {
            return (this.linkedInput.buffer.numberOfChannels);
        }
        return (this.numberOfChannels);
    },

    getBuffer: function(length) {
        var buffer = this.buffer;
        if (buffer.length == length && !this.suppliesFeedbackLoop) {
            // Buffer not part of a feedback loop, so just return it
            return buffer;
        }
        else {
            // Buffer is part of a feedback loop, so we need to take care
            // of overflows.
            // Because feedback loops have to be connected to more than one
            // node, getBuffer will be called more than once.  To make sure
            // we only generate the output buffer once, store a timestamp.
            if (this.node.timestamp == this.timestamp) {
                // Buffer already generated by a previous getBuffer call
                return this.outputBuffer;
            }
            else {
                this.timestamp = this.node.timestamp;

                var feedbackBuffer = this.feedbackBuffer;
                var outputBuffer = this.outputBuffer;

                if (!this.suppliesFeedbackLoop) {
                    this.suppliesFeedbackLoop = true;
                    var limiter = this.node.audiolet.blockSizeLimiter;
                    feedbackBuffer.resize(this.getNumberOfChannels(),
                                          limiter.maximumBlockSize, true);
                }

                // Resize feedback buffer to the correct number of channels
                feedbackBuffer.resize(this.getNumberOfChannels(),
                                      feedbackBuffer.length);

                // Resize output buffer to the correct size
                outputBuffer.resize(this.getNumberOfChannels(), length, true);

                // Buffer the output, so nodes on a later timestamp (i.e. nodes
                // in a feedback loop connected to this output) can pull
                // any amount up to maximumBlockSize without fear of overflow
                feedbackBuffer.push(buffer);
                feedbackBuffer.shift(outputBuffer);

                return outputBuffer;
            }
        }
    }
});

<commit_msg>Forgot to rename output.link and unlink<commit_after>var AudioletOutput = new Class({
    initialize: function(node, index) {
        this.node = node;
        this.index = index;
        this.connectedTo = [];
        // External buffer where data pulled from the graph is stored
        this.buffer = new AudioletBuffer(1, 0);
        // Internal buffer for if we are in a feedback loop
        this.feedbackBuffer = new AudioletBuffer(1, 0);
        // Buffer to shift data into if we are in a feedback loop
        this.outputBuffer = new AudioletBuffer(1, 0);

        this.linkedInput = null;
        this.numberOfChannels = 1;

        this.suppliesFeedbackLoop = false;
        this.timestamp = null;
    },

    connect: function(input) {
        this.connectedTo.push(input);
    },

    disconnect: function(input) {
        var numberOfStreams = this.connectedTo.length;
        for (var i = 0; i < numberOfStreams; i++) {
            if (input == this.connectedTo[i]) {
                this.connectedTo.splice(i, 1);
                break;
            }
        }
    },

    isConnected: function() {
        return (this.connectedTo.length > 0);
    },

    linkNumberOfChannels: function(input) {
        this.linkedInput = input;
    },

    unlinkNumberOfChannels: function() {
        this.linkedInput = null;
    },

    getNumberOfChannels: function() {
        if (this.linkedInput && this.linkedInput.isConnected()) {
            return (this.linkedInput.buffer.numberOfChannels);
        }
        return (this.numberOfChannels);
    },

    getBuffer: function(length) {
        var buffer = this.buffer;
        if (buffer.length == length && !this.suppliesFeedbackLoop) {
            // Buffer not part of a feedback loop, so just return it
            return buffer;
        }
        else {
            // Buffer is part of a feedback loop, so we need to take care
            // of overflows.
            // Because feedback loops have to be connected to more than one
            // node, getBuffer will be called more than once.  To make sure
            // we only generate the output buffer once, store a timestamp.
            if (this.node.timestamp == this.timestamp) {
                // Buffer already generated by a previous getBuffer call
                return this.outputBuffer;
            }
            else {
                this.timestamp = this.node.timestamp;

                var feedbackBuffer = this.feedbackBuffer;
                var outputBuffer = this.outputBuffer;

                if (!this.suppliesFeedbackLoop) {
                    this.suppliesFeedbackLoop = true;
                    var limiter = this.node.audiolet.blockSizeLimiter;
                    feedbackBuffer.resize(this.getNumberOfChannels(),
                                          limiter.maximumBlockSize, true);
                }

                // Resize feedback buffer to the correct number of channels
                feedbackBuffer.resize(this.getNumberOfChannels(),
                                      feedbackBuffer.length);

                // Resize output buffer to the correct size
                outputBuffer.resize(this.getNumberOfChannels(), length, true);

                // Buffer the output, so nodes on a later timestamp (i.e. nodes
                // in a feedback loop connected to this output) can pull
                // any amount up to maximumBlockSize without fear of overflow
                feedbackBuffer.push(buffer);
                feedbackBuffer.shift(outputBuffer);

                return outputBuffer;
            }
        }
    }
});

<|endoftext|>


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

/**
  Imports and Exports provide implicit Context dependency management.

  A class can list which values it requires from the Context, and then
  these values will be added to the object itself so that it doesn't need
  to explicitly work with the Context.

  A class can list which values (properties, methods, or method-like axioms)
  that it exports, and these will automatically be added to the object's
  sub-Context. The object's sub-Context is the context that is used when
  new objects are created by the object.

  Ex.:

foam.CLASS({
  name: 'ImportsTest',

  imports: [ 'log', 'warn' ],

  methods: [ function foo() {
    this.log('log foo from ImportTest');
    this.warn('warn foo from ImportTest');
  } ]
});

foam.CLASS({
  name: 'ExportsTest',
  requires: [ 'ImportsTest' ],

  exports: [ 'log', 'log as warn' ],

  methods: [
    function init() {
      // ImportsTest will be created in ExportTest's
      // sub-Context, which will have 'log' and 'warn'
      // exported.
      this.ImportsTest.create().foo();
    },
    function log(msg) {
      console.log('log:', msg);
    }
  ]
});

  Aliasing:
    Bindings can be renamed or aliased when they're imported or exported using
    'as alias'.

  Examples:
    // import 'userDAO' from the Context and make available as this.dao
    imports: [ 'userDAO as dao' ]

    // export my log method as 'warn'
    exports: [ 'log as warn' ]

    // If the axiom to be exported isn't named, but just aliased, then 'this'
    // is exported as the named alias.  This is how objects export themselves.
    exports: [ 'as Controller' ]

  See Context.js.
 */
foam.CLASS({
  package: 'foam.core',
  name: 'Import',

  // documentation: 'Import Context Value Axiom',

  properties: [
    'name',
    'key',
    {
      name: 'slotName_',
      factory: function() { return this.name + '$'; }
    }
  ],

  methods: [
    function installInProto(proto) {
      var name     = this.name;
      var key      = this.key;
      var slotName = this.slotName_;

      Object.defineProperty(proto, slotName, {
        get: function importsSlotGetter() {
          if ( ! this.hasOwnPrivate_(slotName) ) {
            var ctx = this.__context__ || foam.__context__;
            this.setPrivate_(slotName, ctx[key + '$']);
          }

          return this.getPrivate_(slotName);
        },
        configurable: true,
        enumerable: false
      });

      Object.defineProperty(proto, name, {
        get: function importsGetter()  {
          var slot = this[slotName];
          if ( slot ) return slot.get();
          console.warn('Access missing import:', name);
          return undefined;
        },
        set: function importsSetter(v) {
          var slot = this[slotName];
          if ( slot ) slot.set(v);
          console.warn('Attempt to set missing import:', name);
        },
        configurable: true,
        enumerable: false
      });
    },

    function toSlot(obj) {
      return obj[this.slotName_];
    }
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'Export',

  // documentation: 'Export Sub-Context Value Axiom',

  properties: [
    'name',
    {
      name: 'exportName',
      postSet: function(_, name) {
        this.name = 'export_' + name;
      }
    },
    'key'
  ],

  methods: [
    function installInProto(proto) {
      if ( Object.prototype.hasOwnProperty.call(proto, '__subContext__' ) ) {
        return;
      }

      Object.defineProperty(proto, '__subContext__', {
        get: function YGetter() {
          if ( ! this.hasOwnPrivate_('__subContext__') ) {
            var ctx = this.__context__ || foam.__context__;
            var m = {};
            var bs = proto.cls_.getAxiomsByClass(foam.core.Export);
            for ( var i = 0 ; i < bs.length ; i++ ) {
              var b = bs[i];

              if ( b.key ) {
                var a = this.cls_.getAxiomByName(b.key);

                if ( ! a ) {
                  console.error(
                    'Unknown export: "' +
                      b.key +
                      '" in model: ' +
                      this.cls_.id);
                }

                // Axioms have an option of wrapping a value for export.
                // This could be used to bind a method to 'this', for example.
                m[b.exportName] = a.exportAs ? a.exportAs(this) : this[b.key] ;
              } else {
                // Ex. 'as Bank', which exports an implicit 'this'
                m[b.exportName] = this;
              }
            }
            this.setPrivate_('__subContext__', ctx.createSubContext(m));
          }

          return this.getPrivate_('__subContext__');
        },
        set: function() {
          throw new Error('Attempted to set unsettable __subContext__ in ' + this.cls_.id);
        },
        configurable: true,
        enumerable: false
      });
    }
  ]
});

foam.CLASS({
  refines: 'foam.core.Model',
  properties: [
    {
      class: 'AxiomArray',
      of: 'Import',
      name: 'imports',
      adaptArrayElement: function(o) {
        if ( typeof o === 'string' ) {
          var a = o.split(' as ');
          return foam.core.Import.create({name: a[1] || a[0], key: a[0]});
        }

        return foam.core.Import.create(o);
      }
    },
    {
      class: 'AxiomArray',
      of: 'Export',
      name: 'exports',
      adaptArrayElement: function(o) {
        if ( typeof o === 'string' ) {
          var a = o.split(' ');

          switch ( a.length ) {
            case 1:
              return foam.core.Export.create({exportName: a[0], key: a[0]});

            case 2:
              // Export 'this'
              console.assert(
                  a[0] === 'as',
                  'Invalid export syntax: key [as value] | as value');
              return foam.core.Export.create({exportName: a[1], key: null});

            case 3:
              console.assert(
                  a[1] === 'as',
                  'Invalid export syntax: key [as value] | as value');
              return foam.core.Export.create({exportName: a[2], key: a[0]});

            default:
              console.error(
                  'Invalid export syntax: key [as value] | as value');
          }
        }

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

/**
  Imports and Exports provide implicit Context dependency management.

  A class can list which values it requires from the Context, and then
  these values will be added to the object itself so that it doesn't need
  to explicitly work with the Context.

  A class can list which values (properties, methods, or method-like axioms)
  that it exports, and these will automatically be added to the object's
  sub-Context. The object's sub-Context is the context that is used when
  new objects are created by the object.

  Ex.:

foam.CLASS({
  name: 'ImportsTest',

  imports: [ 'log', 'warn' ],

  methods: [ function foo() {
    this.log('log foo from ImportTest');
    this.warn('warn foo from ImportTest');
  } ]
});

foam.CLASS({
  name: 'ExportsTest',
  requires: [ 'ImportsTest' ],

  exports: [ 'log', 'log as warn' ],

  methods: [
    function init() {
      // ImportsTest will be created in ExportTest's
      // sub-Context, which will have 'log' and 'warn'
      // exported.
      this.ImportsTest.create().foo();
    },
    function log(msg) {
      console.log('log:', msg);
    }
  ]
});

  Aliasing:
    Bindings can be renamed or aliased when they're imported or exported using
    'as alias'.

  Examples:
    // import 'userDAO' from the Context and make available as this.dao
    imports: [ 'userDAO as dao' ]

    // export my log method as 'warn'
    exports: [ 'log as warn' ]

    // If the axiom to be exported isn't named, but just aliased, then 'this'
    // is exported as the named alias.  This is how objects export themselves.
    exports: [ 'as Controller' ]

  See Context.js.
 */
foam.CLASS({
  package: 'foam.core',
  name: 'Import',

  // documentation: 'Import Context Value Axiom',

  properties: [
    'name',
    'key',
    {
      name: 'slotName_',
      factory: function() { return this.name + '$'; }
    }
  ],

  methods: [
    function installInProto(proto) {
      var name     = this.name;
      var key      = this.key + '$';
      var slotName = this.slotName_;

      Object.defineProperty(proto, slotName, {
        get: function importsSlotGetter() {
          if ( ! this.hasOwnPrivate_(slotName) ) {
            var ctx = this.__context__ || foam.__context__;
            var val = ctx[key];
            this.setPrivate_(slotName, val);
            return val;
          }

          return this.getPrivate_(slotName);
        },
        configurable: true,
        enumerable: false
      });

      Object.defineProperty(proto, name, {
        get: function importsGetter()  {
          var slot = this[slotName];
          if ( slot ) return slot.get();
          console.warn('Access missing import:', name);
          return undefined;
        },
        set: function importsSetter(v) {
          var slot = this[slotName];
          if ( slot ) slot.set(v);
          console.warn('Attempt to set missing import:', name);
        },
        configurable: true,
        enumerable: false
      });
    },

    function toSlot(obj) {
      return obj[this.slotName_];
    }
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'Export',

  // documentation: 'Export Sub-Context Value Axiom',

  properties: [
    'name',
    {
      name: 'exportName',
      postSet: function(_, name) {
        this.name = 'export_' + name;
      }
    },
    'key'
  ],

  methods: [
    function installInProto(proto) {
      if ( Object.prototype.hasOwnProperty.call(proto, '__subContext__' ) ) {
        return;
      }

      Object.defineProperty(proto, '__subContext__', {
        get: function YGetter() {
          if ( ! this.hasOwnPrivate_('__subContext__') ) {
            var ctx = this.__context__ || foam.__context__;
            var m = {};
            var bs = proto.cls_.getAxiomsByClass(foam.core.Export);
            for ( var i = 0 ; i < bs.length ; i++ ) {
              var b = bs[i];

              if ( b.key ) {
                var a = this.cls_.getAxiomByName(b.key);

                if ( ! a ) {
                  console.error(
                    'Unknown export: "' +
                      b.key +
                      '" in model: ' +
                      this.cls_.id);
                }

                // Axioms have an option of wrapping a value for export.
                // This could be used to bind a method to 'this', for example.
                m[b.exportName] = a.exportAs ? a.exportAs(this) : this[b.key] ;
              } else {
                // Ex. 'as Bank', which exports an implicit 'this'
                m[b.exportName] = this;
              }
            }
            this.setPrivate_('__subContext__', ctx.createSubContext(m));
          }

          return this.getPrivate_('__subContext__');
        },
        set: function() {
          throw new Error('Attempted to set unsettable __subContext__ in ' + this.cls_.id);
        },
        configurable: true,
        enumerable: false
      });
    }
  ]
});

foam.CLASS({
  refines: 'foam.core.Model',
  properties: [
    {
      class: 'AxiomArray',
      of: 'Import',
      name: 'imports',
      adaptArrayElement: function(o) {
        if ( typeof o === 'string' ) {
          var a = o.split(' as ');
          return foam.core.Import.create({name: a[1] || a[0], key: a[0]});
        }

        return foam.core.Import.create(o);
      }
    },
    {
      class: 'AxiomArray',
      of: 'Export',
      name: 'exports',
      adaptArrayElement: function(o) {
        if ( typeof o === 'string' ) {
          var a = o.split(' ');

          switch ( a.length ) {
            case 1:
              return foam.core.Export.create({exportName: a[0], key: a[0]});

            case 2:
              // Export 'this'
              console.assert(
                  a[0] === 'as',
                  'Invalid export syntax: key [as value] | as value');
              return foam.core.Export.create({exportName: a[1], key: null});

            case 3:
              console.assert(
                  a[1] === 'as',
                  'Invalid export syntax: key [as value] | as value');
              return foam.core.Export.create({exportName: a[2], key: a[0]});

            default:
              console.error(
                  'Invalid export syntax: key [as value] | as value');
          }
        }

        return foam.core.Export.create(o);
      }
    }
  ]
});
<|endoftext|>


<commit_before>'use strict'

const promisify = require('promisify-es6')
const every = require('async/every')
const PeerId = require('peer-id')
const CID = require('cids')
const each = require('async/each')
// const bsplit = require('buffer-split')

module.exports = (self) => {
  return {
    /**
     * Given a key, query the DHT for its best value.
     *
     * @param {Buffer} key
     * @param {function(Error)} [callback]
     * @returns {Promise|void}
     */
    get: promisify((key, options, callback) => {
      if (!Buffer.isBuffer(key)) {
        return callback(new Error('Not valid key'))
      }

      if (typeof options === 'function') {
        callback = options
        options = {}
      }

      self._libp2pNode.dht.get(key, options.timeout, callback)
    }),

    /**
     * Write a key/value pair to the DHT.
     *
     * Given a key of the form /foo/bar and a value of any
     * form, this will write that value to the DHT with
     * that key.
     *
     * @param {Buffer} key
     * @param {Buffer} value
     * @param {function(Error)} [callback]
     * @returns {Promise|void}
     */
    put: promisify((key, value, callback) => {
      if (!Buffer.isBuffer(key)) {
        return callback(new Error('Not valid key'))
      }

      self._libp2pNode.dht.put(key, value, callback)
    }),

    /**
     * Find peers in the DHT that can provide a specific value, given a key.
     *
     * @param {CID} key - They key to find providers for.
     * @param {function(Error, Array<PeerInfo>)} [callback]
     * @returns {Promise<PeerInfo>|void}
     */
    findprovs: promisify((key, callback) => {
      if (typeof key === 'string') {
        key = new CID(key)
      }

      self._libp2pNode.contentRouting.findProviders(key, callback)
    }),

    /**
     * Query the DHT for all multiaddresses associated with a `PeerId`.
     *
     * @param {PeerId} peer - The id of the peer to search for.
     * @param {function(Error, Array<Multiaddr>)} [callback]
     * @returns {Promise<Array<Multiaddr>>|void}
     */
    findpeer: promisify((peer, callback) => {
      if (typeof peer === 'string') {
        peer = PeerId.createFromB58String(peer)
      }

      self._libp2pNode.peerRouting.findPeer(peer, (err, info) => {
        if (err) {
          return callback(err)
        }

        // convert to go-ipfs return value, we need to revisit
        // this. For now will just conform.
        const goResult = [
          {
            Responses: [{
              ID: info.id.toB58String(),
              Addresses: info.multiaddrs.toArray().map((a) => a.toString())
            }]
          }
        ]

        callback(null, goResult)
      })
    }),

    /**
     * Announce to the network that we are providing given values.
     *
     * @param {CID|Array<CID>} keys - The keys that should be announced.
     * @param {Object} [options={}]
     * @param {bool} [options.recursive=false] - Provide not only the given object but also all objects linked from it.
     * @param {function(Error)} [callback]
     * @returns {Promise|void}
     */
    provide: promisify((keys, options, callback) => {
      if (!Array.isArray(keys)) {
        keys = [keys]
      }
      if (typeof options === 'function') {
        callback = options
        options = {}
      }

      // ensure blocks are actually local
      every(keys, (key, cb) => {
        self._repo.blocks.has(key, cb)
      }, (err, has) => {
        if (err) {
          return callback(err)
        }

        if (!has) {
          return callback(new Error('block(s) not found locally, cannot provide'))
        }

        if (options.recursive) {
          // TODO: Implement recursive providing
        } else {
          each(keys, (cid, cb) => {
            self._libp2pNode.contentRouting.provide(cid, cb)
          }, callback)
        }
      })
    }),

    /**
     * Find the closest peers to a given `PeerId`, by querying the DHT.
     *
     * @param {PeerId} peer - The `PeerId` to run the query agains.
     * @param {function(Error, Array<PeerId>)} [callback]
     * @returns {Promise<Array<PeerId>>|void}
     */
    query: promisify((peerId, callback) => {
      if (typeof peerId === 'string') {
        peerId = PeerId.createFromB58String(peerId)
      }

      // TODO expose this method in peerRouting
      self._libp2pNode._dht.getClosestPeers(peerId.toBytes(), (err, peerIds) => {
        if (err) {
          return callback(err)
        }
        callback(null, peerIds.map((id) => {
          return { ID: id.toB58String() }
        }))
      })
    })
  }
}
<commit_msg>fix(dht): allow for options object in `findProvs()` API (#1457)<commit_after>'use strict'

const promisify = require('promisify-es6')
const every = require('async/every')
const PeerId = require('peer-id')
const CID = require('cids')
const each = require('async/each')
// const bsplit = require('buffer-split')

module.exports = (self) => {
  return {
    /**
     * Given a key, query the DHT for its best value.
     *
     * @param {Buffer} key
     * @param {function(Error)} [callback]
     * @returns {Promise|void}
     */
    get: promisify((key, options, callback) => {
      if (!Buffer.isBuffer(key)) {
        return callback(new Error('Not valid key'))
      }

      if (typeof options === 'function') {
        callback = options
        options = {}
      }

      self._libp2pNode.dht.get(key, options.timeout, callback)
    }),

    /**
     * Write a key/value pair to the DHT.
     *
     * Given a key of the form /foo/bar and a value of any
     * form, this will write that value to the DHT with
     * that key.
     *
     * @param {Buffer} key
     * @param {Buffer} value
     * @param {function(Error)} [callback]
     * @returns {Promise|void}
     */
    put: promisify((key, value, callback) => {
      if (!Buffer.isBuffer(key)) {
        return callback(new Error('Not valid key'))
      }

      self._libp2pNode.dht.put(key, value, callback)
    }),

    /**
     * Find peers in the DHT that can provide a specific value, given a key.
     *
     * @param {CID} key - They key to find providers for.
     * @param {function(Error, Array<PeerInfo>)} [callback]
     * @returns {Promise<PeerInfo>|void}
     */
    findprovs: promisify((key, opts, callback) => {
      if (typeof key === 'string') {
        key = new CID(key)
      }

      if (typeof opts === 'function') {
        callback = opts
        opts = {}
      }

      opts = opts || {}

      self._libp2pNode.contentRouting.findProviders(key, opts.timeout || null, callback)
    }),

    /**
     * Query the DHT for all multiaddresses associated with a `PeerId`.
     *
     * @param {PeerId} peer - The id of the peer to search for.
     * @param {function(Error, Array<Multiaddr>)} [callback]
     * @returns {Promise<Array<Multiaddr>>|void}
     */
    findpeer: promisify((peer, callback) => {
      if (typeof peer === 'string') {
        peer = PeerId.createFromB58String(peer)
      }

      self._libp2pNode.peerRouting.findPeer(peer, (err, info) => {
        if (err) {
          return callback(err)
        }

        // convert to go-ipfs return value, we need to revisit
        // this. For now will just conform.
        const goResult = [
          {
            Responses: [{
              ID: info.id.toB58String(),
              Addresses: info.multiaddrs.toArray().map((a) => a.toString())
            }]
          }
        ]

        callback(null, goResult)
      })
    }),

    /**
     * Announce to the network that we are providing given values.
     *
     * @param {CID|Array<CID>} keys - The keys that should be announced.
     * @param {Object} [options={}]
     * @param {bool} [options.recursive=false] - Provide not only the given object but also all objects linked from it.
     * @param {function(Error)} [callback]
     * @returns {Promise|void}
     */
    provide: promisify((keys, options, callback) => {
      if (!Array.isArray(keys)) {
        keys = [keys]
      }
      if (typeof options === 'function') {
        callback = options
        options = {}
      }

      // ensure blocks are actually local
      every(keys, (key, cb) => {
        self._repo.blocks.has(key, cb)
      }, (err, has) => {
        if (err) {
          return callback(err)
        }

        if (!has) {
          return callback(new Error('block(s) not found locally, cannot provide'))
        }

        if (options.recursive) {
          // TODO: Implement recursive providing
        } else {
          each(keys, (cid, cb) => {
            self._libp2pNode.contentRouting.provide(cid, cb)
          }, callback)
        }
      })
    }),

    /**
     * Find the closest peers to a given `PeerId`, by querying the DHT.
     *
     * @param {PeerId} peer - The `PeerId` to run the query agains.
     * @param {function(Error, Array<PeerId>)} [callback]
     * @returns {Promise<Array<PeerId>>|void}
     */
    query: promisify((peerId, callback) => {
      if (typeof peerId === 'string') {
        peerId = PeerId.createFromB58String(peerId)
      }

      // TODO expose this method in peerRouting
      self._libp2pNode._dht.getClosestPeers(peerId.toBytes(), (err, peerIds) => {
        if (err) {
          return callback(err)
        }
        callback(null, peerIds.map((id) => {
          return { ID: id.toB58String() }
        }))
      })
    })
  }
}
<|endoftext|>