<commit_before>// Initialize all modules by requiring them. Also makes sure they get bundled (see gulpfile.js).
var $ = require('jquery-detached').getJQuery();

var getItems = function(){
  var d = $.Deferred();
  $.get('categories?depth=3').done(
      function(data){
        d.resolve(data);
      }
  );
  return d.promise();
};

var jRoot = $('head').attr('data-rooturl');

$.when(getItems()).done(function(data){
  $(function() {

    // The main panel content is hidden by default via an
    // inline style. We're ready to remove that now.
    $('#create-item-panel').removeAttr('style');

    //////////////////////////////
    // helpful reference DOM

    var defaultMinToShow = 2;
    var defaultLooseItems = 'jenkins.category.uncategorized';
    var $root = $('#main-panel');
    var $form = $root.find('form[name="createItem"]').addClass('jenkins-config new-view');
    var $newView = $('
')
      .attr('name','createItem')
      .attr('action','createItem')
      .prependTo($form);
    var $navBox = $('');
    var $tabs = $('
').appendTo($newView);
    var $categories = $('
').appendTo($newView);
    var $subBtn = $('#bottom-sticker .yui-submit-button');
    var sectionsToShow = [];

    $tabs.prepend($navBox);

    ////////////////////////////////
    // submit button click

    function makeButtonWrapper(){
      var $p = window.$; // jshint ignore:line
      var btn = $p('ok');
      var okButton = window.makeButton(btn, null); // jshint ignore:line

      $subBtn = $('#bottom-sticker .yui-submit-button');

      checkFormReady();

      $subBtn.on('click',function() {
        $(this).addClass('yui-button-disabled yui-submit-button-disabled')
          .find('button')
            .attr('disabled','disabled')
            .text('. . .');
      });

    }

    ////////////////////////////////
    // scroll action......

    function watchScroll(){
      var $window = $(window);
      var $jenkTools = $('#breadcrumbBar');
      var winScoll = $window.scrollTop();
      var jenkToolOffset = $jenkTools.height() + $jenkTools.offset().top + 15;

      $tabs.find('.active').removeClass('active');
      $.each(data.categories,function(i,cat){
        var domId = '#j-add-item-type-'+cat.id;
        var $cat = $(domId);
        var catHeight = ($cat.length > 0)?
            $cat.offset().top + $cat.outerHeight() - (jenkToolOffset + 100):
              0;

        if(winScoll < catHeight){
          var $thisTab = $tabs.find(['[href="',cleanHref(domId),'"]'].join(''));
          resetActiveTab($thisTab);
          return false;
        }
      });

      if(winScoll > $('#page-head').height() - 5 ){
        $tabs.width($tabs.width()).css({
          'position':'fixed',
          'top':($jenkTools.height() - 5 )+'px'});
        $categories.css({'margin-top':$tabs.outerHeight()+'px'});
      }
      else{
        $tabs.add($categories).removeAttr('style');
      }
    }

    //////////////////////////
    // helper functions...

    function checkFormReady(){
      //make sure everyone has changed and gotten attached...
      setTimeout(function(){
        var $name = $form.removeClass('no-select').find('input[name="name"]').removeClass('no-val');

        function checkItems(){
          var selected = $form.find('input[type="radio"]:checked').length > 0;
          var named = $.trim($name.val()).length > 0;
          return {selected:selected,named:named};
        }
        if(checkItems().selected && checkItems().named){
          $subBtn.removeClass('yui-button-disabled').find('button').removeAttr('disabled');
        }
        else{
          $subBtn.addClass('yui-button-disabled').find('button').attr('disabled','disabled');
        }
      },10);
    }

    function addCopyOption(data){
      var $copy = $('#copy').closest('tr');
      if($copy.length === 0) {return data;} // exit if copy should not be added to page. Jelly page holds that logic.
      var copyTitle = $copy.find('label').text();
      var copyDom = $copy.next().find('.setting-main').html();
      var copy = {
          name:'Copy',
          id:'copy',
          minToShow:0,
          items:[
            {
              class:"copy",
              description:copyDom,
              displayName:copyTitle,
              iconFilePathPattern:'images/48x48/copy.png'
            }
          ]
      };
      var newData = [];

      $.each(data,function(i,elem){
        if(elem.id !== "category-id-copy")
          { newData.push(elem); }
      });

      newData.push(copy);

      return newData;
    }
    function checkForLink(desc){
      if(desc.indexOf('<a href="') === -1) {
        return false;
      }
      var newDesc = desc.replace(/\</g,'<').replace(/\>/g,'>');
      return newDesc;
    }
    function sortItemsByOrder(itemTypes) {
      function sortByOrder(a, b) {
        var aOrder = a.weight;
        var bOrder = b.weight;
        return ( (aOrder < bOrder) ? -1 : ( (aOrder === bOrder) ? 1 : 0));
      }
      return itemTypes.sort(sortByOrder);
    }

    function checkCatCount(elem){
      var minToShow = (typeof elem.minToShow === 'number')? elem.minToShow : defaultMinToShow;
      var showIt = ($.isArray(elem.items) && elem.items.length >= minToShow);
      return showIt;
    }

    function cleanClassName(className){
      return className.replace(/\./g,'_');
    }

    function cleanHref(id,reverse){
      if(reverse){
        var gotHash = (id.indexOf('#') === 0)?
           '#j-add-item-type-'+ id.substring(1).replace(/\./g,'_'):
             'j-add-item-type-'+ id.replace(/\./g,'_');
        return gotHash;
      }
      else{
        return id.replace('j-add-item-type-','');
      }
    }

    function cleanLayout(){
      // Do a little shimmy-hack to force legacy code to resize correctly and set tab state.
      $('html,body').animate({scrollTop: 1}, 1);
      $('html,body').animate({scrollTop: 0}, 10);

      setTimeout(fireBottomStickerAdjustEvent,410);
    }

    function resetActiveTab($this){
      var $nav = $this.closest('.nav');
      $nav.find('.active').removeClass('active');
      $this.addClass('active');
    }

    //////////////////////////////////
    // Draw functions

    function drawName() {
      var $name = $('
');

      var $input = $('<input type="text" name="name" class="name" id="name" placeholder="New item name..." />')
        .change(function(){
          $form.find('input[name="name"]').val($(this).val());
          checkFormReady();
        })
        .appendTo($name);

      $tabs.prepend($name);
      setTimeout(function(){$input.focus();},100);
    }

    function drawTabs(data){
      $('#main-panel').addClass('container');
      var $nav = $('
');

      $.each(data,function(i,elem){

        // little bit hacky here... need to keep track if I have tabs to show, so if there is just 1, I can hide it later....
        if (elem.minToShow !== 0 && checkCatCount(elem)) {sectionsToShow.push(elem.id);}

        var $tab = drawTab(i,elem);
        var $items = drawCategory(elem);
        var $cat = $items.parent();

        $.each(elem.items,function(i,elem){
          var $item = drawItem(elem);
          $items.append($item);
        });

        if(checkCatCount(elem)) {$nav.append($tab);}
        $categories.append($cat);

      });
      $(window).on('scroll',watchScroll);

      if(sectionsToShow.length > 1){
        $navBox.append($nav);
      }else{
        $categories.find('.category-header').hide();
      }
      drawName();
      cleanLayout();
    }

    function drawTab(i,elem){
      if(!elem) {elem = i;}
      var $tab = $(['
',elem.name,'
'].join(''))
        .click(function(){
          //e.preventDefault(e);
          var $this = $(this).children('a');

          var tab = $this.attr('href');
          var scrollTop = $(cleanHref(tab,true)).offset().top - ($newView.children('.jenkins-config-widgets').height() + 15);

          setTimeout(function(){resetActiveTab($this);},510);

          $('html,body').animate({
            scrollTop: scrollTop
          }, 500);
        });
      return $tab;
    }

    function drawCategory(i,elem){
      // categories are smart, so this is a little tricky....
      if (!elem) {
        elem = i;
      }
      var $category = $('
').addClass('category jenkins-config hide-cat').attr('id', 'j-add-item-type-'+cleanClassName(elem.id));
      var $items = $('
').addClass('j-item-options').appendTo($category);

      // if there are enough items for a category, attach the category and its header...
      if(checkCatCount(elem)){
        var $catHeader = $('
').prependTo($category);
        var catheader = ['
', elem.name, '
'].join('');
        var catDesc = ['
', elem.description, '
'].join('');

        if((elem.minToShow > 0)){
          $(catheader).appendTo($catHeader);
          $(catDesc).appendTo($catHeader);
        }
        $category.removeClass('hide-cat');
      }
      else{
        var targ = elem.remainders || defaultLooseItems;
        $items = $('#'+cleanHref(targ,true)).find('.j-item-options');
      }

      return $items;
    }

    function drawItem(elem){
      var desc = (checkForLink(elem.description))? checkForLink(elem.description):elem.description;
      var $item = $([
          '
<input name="mode" value="',elem.class,'" type="radio" /> ', elem.displayName, '
'
      ].join('')).append([
          '
', desc, '
'
      ].join('')).append(drawIcon(elem));

      function setSelectState(e){
        e.preventDefault();
        var href = $(e.target).attr('href');
        if(href) {
          window.open(href);
        }

        var $this = $(this).closest('li');
        $this.closest('.categories').find('input[type="radio"][name="mode"]').removeAttr('checked');
        //if this is a hyperlink, don't move the selection.
        if($this.find('a:focus').length === 1) {return false;}
        $this.closest('.categories').find('.active').removeClass('active');
        $this.addClass('active');
        $this.find('input[type="radio"]').prop('checked', true);
        checkFormReady();

        $('html, body').animate({
          scrollTop:$this.offset().top - 200
        },50);

      }

      $item.click(setSelectState);

      return $item;
    }

    function drawIcon(elem){
      var $icn = $('
');
      if (!elem.iconFilePathPattern) {
        var colors = ['c-49728B','c-335061','c-D33833','c-6D6B6D','c-DCD9D8','other'];
        var desc = elem.description || '';
        var name = elem.displayName;
        var colorClass= colors[(desc.length) % 6];
        var aName = name.split(' ');
        var a = name.substring(0,1);
        var b = ((aName.length === 1)?
            name.substring(1,2):
              aName[1].substring(0,1));
        $([
          '',a,'',b,''
         ].join(''))
          .appendTo($icn);
        return $icn.addClass('df').addClass(colorClass);
      }

      var iconFilePath = jRoot + '/' + elem.iconFilePathPattern.replace(":size", "48x48");
      $([''].join(''))
        .appendTo($icn);

      return $icn;
    }

    // initialize
    var sortedDCategories = sortItemsByOrder(data.categories);
    var sortedDCategoriesWithCopy = addCopyOption(sortedDCategories);
    makeButtonWrapper();
    drawTabs(sortedDCategoriesWithCopy);

  });
});

function fireBottomStickerAdjustEvent() {
  Event.fire(window, 'jenkins:bottom-sticker-adjust'); // jshint ignore:line
}<commit_msg>Check if we can enable the ok button on keyup event (Vs change)<commit_after>// Initialize all modules by requiring them. Also makes sure they get bundled (see gulpfile.js).
var $ = require('jquery-detached').getJQuery();

var getItems = function(){
  var d = $.Deferred();
  $.get('categories?depth=3').done(
      function(data){
        d.resolve(data);
      }
  );
  return d.promise();
};

var jRoot = $('head').attr('data-rooturl');

$.when(getItems()).done(function(data){
  $(function() {

    // The main panel content is hidden by default via an
    // inline style. We're ready to remove that now.
    $('#create-item-panel').removeAttr('style');

    //////////////////////////////
    // helpful reference DOM

    var defaultMinToShow = 2;
    var defaultLooseItems = 'jenkins.category.uncategorized';
    var $root = $('#main-panel');
    var $form = $root.find('form[name="createItem"]').addClass('jenkins-config new-view');
    var $newView = $('
')
      .attr('name','createItem')
      .attr('action','createItem')
      .prependTo($form);
    var $navBox = $('');
    var $tabs = $('
').appendTo($newView);
    var $categories = $('
').appendTo($newView);
    var $subBtn = $('#bottom-sticker .yui-submit-button');
    var sectionsToShow = [];

    $tabs.prepend($navBox);

    ////////////////////////////////
    // submit button click

    function makeButtonWrapper(){
      var $p = window.$; // jshint ignore:line
      var btn = $p('ok');
      var okButton = window.makeButton(btn, null); // jshint ignore:line

      $subBtn = $('#bottom-sticker .yui-submit-button');

      checkFormReady();

      $subBtn.on('click',function() {
        $(this).addClass('yui-button-disabled yui-submit-button-disabled')
          .find('button')
            .attr('disabled','disabled')
            .text('. . .');
      });

    }

    ////////////////////////////////
    // scroll action......

    function watchScroll(){
      var $window = $(window);
      var $jenkTools = $('#breadcrumbBar');
      var winScoll = $window.scrollTop();
      var jenkToolOffset = $jenkTools.height() + $jenkTools.offset().top + 15;

      $tabs.find('.active').removeClass('active');
      $.each(data.categories,function(i,cat){
        var domId = '#j-add-item-type-'+cat.id;
        var $cat = $(domId);
        var catHeight = ($cat.length > 0)?
            $cat.offset().top + $cat.outerHeight() - (jenkToolOffset + 100):
              0;

        if(winScoll < catHeight){
          var $thisTab = $tabs.find(['[href="',cleanHref(domId),'"]'].join(''));
          resetActiveTab($thisTab);
          return false;
        }
      });

      if(winScoll > $('#page-head').height() - 5 ){
        $tabs.width($tabs.width()).css({
          'position':'fixed',
          'top':($jenkTools.height() - 5 )+'px'});
        $categories.css({'margin-top':$tabs.outerHeight()+'px'});
      }
      else{
        $tabs.add($categories).removeAttr('style');
      }
    }

    //////////////////////////
    // helper functions...

    function checkFormReady(){
      //make sure everyone has changed and gotten attached...
      setTimeout(function(){
        var $name = $form.removeClass('no-select').find('input[name="name"]').removeClass('no-val');

        function checkItems(){
          var selected = $form.find('input[type="radio"]:checked').length > 0;
          var named = $.trim($name.val()).length > 0;
          return {selected:selected,named:named};
        }
        if(checkItems().selected && checkItems().named){
          $subBtn.removeClass('yui-button-disabled').find('button').removeAttr('disabled');
        }
        else{
          $subBtn.addClass('yui-button-disabled').find('button').attr('disabled','disabled');
        }
      },10);
    }

    function addCopyOption(data){
      var $copy = $('#copy').closest('tr');
      if($copy.length === 0) {return data;} // exit if copy should not be added to page. Jelly page holds that logic.
      var copyTitle = $copy.find('label').text();
      var copyDom = $copy.next().find('.setting-main').html();
      var copy = {
          name:'Copy',
          id:'copy',
          minToShow:0,
          items:[
            {
              class:"copy",
              description:copyDom,
              displayName:copyTitle,
              iconFilePathPattern:'images/48x48/copy.png'
            }
          ]
      };
      var newData = [];

      $.each(data,function(i,elem){
        if(elem.id !== "category-id-copy")
          { newData.push(elem); }
      });

      newData.push(copy);

      return newData;
    }
    function checkForLink(desc){
      if(desc.indexOf('<a href="') === -1) {
        return false;
      }
      var newDesc = desc.replace(/\</g,'<').replace(/\>/g,'>');
      return newDesc;
    }
    function sortItemsByOrder(itemTypes) {
      function sortByOrder(a, b) {
        var aOrder = a.weight;
        var bOrder = b.weight;
        return ( (aOrder < bOrder) ? -1 : ( (aOrder === bOrder) ? 1 : 0));
      }
      return itemTypes.sort(sortByOrder);
    }

    function checkCatCount(elem){
      var minToShow = (typeof elem.minToShow === 'number')? elem.minToShow : defaultMinToShow;
      var showIt = ($.isArray(elem.items) && elem.items.length >= minToShow);
      return showIt;
    }

    function cleanClassName(className){
      return className.replace(/\./g,'_');
    }

    function cleanHref(id,reverse){
      if(reverse){
        var gotHash = (id.indexOf('#') === 0)?
           '#j-add-item-type-'+ id.substring(1).replace(/\./g,'_'):
             'j-add-item-type-'+ id.replace(/\./g,'_');
        return gotHash;
      }
      else{
        return id.replace('j-add-item-type-','');
      }
    }

    function cleanLayout(){
      // Do a little shimmy-hack to force legacy code to resize correctly and set tab state.
      $('html,body').animate({scrollTop: 1}, 1);
      $('html,body').animate({scrollTop: 0}, 10);

      setTimeout(fireBottomStickerAdjustEvent,410);
    }

    function resetActiveTab($this){
      var $nav = $this.closest('.nav');
      $nav.find('.active').removeClass('active');
      $this.addClass('active');
    }

    //////////////////////////////////
    // Draw functions

    function drawName() {
      var $name = $('
');

      var $input = $('<input type="text" name="name" class="name" id="name" placeholder="New item name..." />')
        .keyup(function(){
          $form.find('input[name="name"]').val($(this).val());
          checkFormReady();
        })
        .appendTo($name);

      $tabs.prepend($name);
      setTimeout(function(){$input.focus();},100);
    }

    function drawTabs(data){
      $('#main-panel').addClass('container');
      var $nav = $('
');

      $.each(data,function(i,elem){

        // little bit hacky here... need to keep track if I have tabs to show, so if there is just 1, I can hide it later....
        if (elem.minToShow !== 0 && checkCatCount(elem)) {sectionsToShow.push(elem.id);}

        var $tab = drawTab(i,elem);
        var $items = drawCategory(elem);
        var $cat = $items.parent();

        $.each(elem.items,function(i,elem){
          var $item = drawItem(elem);
          $items.append($item);
        });

        if(checkCatCount(elem)) {$nav.append($tab);}
        $categories.append($cat);

      });
      $(window).on('scroll',watchScroll);

      if(sectionsToShow.length > 1){
        $navBox.append($nav);
      }else{
        $categories.find('.category-header').hide();
      }
      drawName();
      cleanLayout();
    }

    function drawTab(i,elem){
      if(!elem) {elem = i;}
      var $tab = $(['
',elem.name,'
'].join(''))
        .click(function(){
          //e.preventDefault(e);
          var $this = $(this).children('a');

          var tab = $this.attr('href');
          var scrollTop = $(cleanHref(tab,true)).offset().top - ($newView.children('.jenkins-config-widgets').height() + 15);

          setTimeout(function(){resetActiveTab($this);},510);

          $('html,body').animate({
            scrollTop: scrollTop
          }, 500);
        });
      return $tab;
    }

    function drawCategory(i,elem){
      // categories are smart, so this is a little tricky....
      if (!elem) {
        elem = i;
      }
      var $category = $('
').addClass('category jenkins-config hide-cat').attr('id', 'j-add-item-type-'+cleanClassName(elem.id));
      var $items = $('
').addClass('j-item-options').appendTo($category);

      // if there are enough items for a category, attach the category and its header...
      if(checkCatCount(elem)){
        var $catHeader = $('
').prependTo($category);
        var catheader = ['
', elem.name, '
'].join('');
        var catDesc = ['
', elem.description, '
'].join('');

        if((elem.minToShow > 0)){
          $(catheader).appendTo($catHeader);
          $(catDesc).appendTo($catHeader);
        }
        $category.removeClass('hide-cat');
      }
      else{
        var targ = elem.remainders || defaultLooseItems;
        $items = $('#'+cleanHref(targ,true)).find('.j-item-options');
      }

      return $items;
    }

    function drawItem(elem){
      var desc = (checkForLink(elem.description))? checkForLink(elem.description):elem.description;
      var $item = $([
          '
<input name="mode" value="',elem.class,'" type="radio" /> ', elem.displayName, '
'
      ].join('')).append([
          '
', desc, '
'
      ].join('')).append(drawIcon(elem));

      function setSelectState(e){
        e.preventDefault();
        var href = $(e.target).attr('href');
        if(href) {
          window.open(href);
        }

        var $this = $(this).closest('li');
        $this.closest('.categories').find('input[type="radio"][name="mode"]').removeAttr('checked');
        //if this is a hyperlink, don't move the selection.
        if($this.find('a:focus').length === 1) {return false;}
        $this.closest('.categories').find('.active').removeClass('active');
        $this.addClass('active');
        $this.find('input[type="radio"]').prop('checked', true);
        checkFormReady();

        $('html, body').animate({
          scrollTop:$this.offset().top - 200
        },50);

      }

      $item.click(setSelectState);

      return $item;
    }

    function drawIcon(elem){
      var $icn = $('
');
      if (!elem.iconFilePathPattern) {
        var colors = ['c-49728B','c-335061','c-D33833','c-6D6B6D','c-DCD9D8','other'];
        var desc = elem.description || '';
        var name = elem.displayName;
        var colorClass= colors[(desc.length) % 6];
        var aName = name.split(' ');
        var a = name.substring(0,1);
        var b = ((aName.length === 1)?
            name.substring(1,2):
              aName[1].substring(0,1));
        $([
          '',a,'',b,''
         ].join(''))
          .appendTo($icn);
        return $icn.addClass('df').addClass(colorClass);
      }

      var iconFilePath = jRoot + '/' + elem.iconFilePathPattern.replace(":size", "48x48");
      $([''].join(''))
        .appendTo($icn);

      return $icn;
    }

    // initialize
    var sortedDCategories = sortItemsByOrder(data.categories);
    var sortedDCategoriesWithCopy = addCopyOption(sortedDCategories);
    makeButtonWrapper();
    drawTabs(sortedDCategoriesWithCopy);

  });
});

function fireBottomStickerAdjustEvent() {
  Event.fire(window, 'jenkins:bottom-sticker-adjust'); // jshint ignore:line
}<|endoftext|>


<commit_before>var Crafty = require('./core.js'),
    document = window.document;

Crafty.extend({
    /**@
     * #Crafty.audio
     * @category Audio
     *
     * Add sound files and play them. Chooses best format for browser support.
     * Due to the nature of HTML5 audio, three types of audio files will be
     * required for cross-browser capabilities. These formats are MP3, Ogg and WAV.
     * When sound was not muted on before pause, sound will be unmuted after unpause.
     * When sound is muted Crafty.pause() does not have any effect on sound
     *
     * The maximum number of sounds that can be played simultaneously is defined by Crafty.audio.maxChannels.  The default value is 7.
     */
    audio: {

        sounds: {},
        supported: null,
        codecs: { // Chart from jPlayer
            ogg: 'audio/ogg; codecs="vorbis"', //OGG
            wav: 'audio/wav; codecs="1"', // PCM
            webma: 'audio/webm; codecs="vorbis"', // WEBM
            mp3: 'audio/mpeg; codecs="mp3"', //MP3
            m4a: 'audio/mp4; codecs="mp4a.40.2"' // AAC / MP4
        },
        volume: 1, //Global Volume
        muted: false,
        paused: false,
        playCheck: null,
        /**
         * Function to setup supported formats
         **/
        _canPlay: function () {
            this.supported = {};
            // Without support, no formats are supported
            if (!Crafty.support.audio)
                return;
            var audio = this.audioElement(),
                canplay;
            for (var i in this.codecs) {
                canplay = audio.canPlayType(this.codecs[i]);
                if (canplay !== "" && canplay !== "no") {
                    this.supported[i] = true;
                } else {
                    this.supported[i] = false;
                }
            }

        },

        /**@
         * #Crafty.audio.supports
         * @comp Crafty.audio
         * @sign public this Crafty.audio.supports(String extension)
         * @param extension - A file extension to check audio support for
         *
         * Return true if the browser thinks it can play the given file type, otherwise false
         */
        supports: function (extension) {
            // Build cache of supported formats, if necessary
            if (this.supported === null)
                this._canPlay();

            if (this.supported[extension])
                return true;
            else
                return false;
        },

        /**
         * Function to get an Audio Element
         **/
        audioElement: function () {
            //IE does not support Audio Object
            return typeof Audio !== 'undefined' ? new Audio("") : document.createElement('audio');
        },

        /**@
         * #Crafty.audio.create
         * @comp Crafty.audio
         * @sign public this Crafty.audio.create(String id, String url)
         * @param id - A string to refer to sounds
         * @param url - A string pointing to the sound file
         *
         * Creates an audio asset with the given id and resource.  `Crafty.audio.add` is a more flexible interface that allows cross-browser compatibility.
         *
         * If the sound file extension is not supported, returns false; otherwise, returns the audio asset.
         */
        create: function (id, path) {
            //check extension, return if not supported
            var ext = path.substr(path.lastIndexOf('.') + 1).toLowerCase();
            if (!this.supports(ext))
                return false;

            //initiate the audio element
            var audio = this.audioElement();
            audio.id = id;
            audio.preload = "auto";
            audio.volume = Crafty.audio.volume;
            audio.src = path;

            //create an asset and metadata for the audio element
            Crafty.asset(path, audio);
            this.sounds[id] = {
                obj: audio,
                played: 0,
                volume: Crafty.audio.volume
            };
            return this.sounds[id];

        },

        /**@
         * #Crafty.audio.add
         * @comp Crafty.audio
         * @sign public this Crafty.audio.add(String id, String url)
         * @param id - A string to refer to sounds
         * @param url - A string pointing to the sound file
         * @sign public this Crafty.audio.add(String id, Array urls)
         * @param urls - Array of urls pointing to different format of the same sound, selecting the first that is playable
         * @sign public this Crafty.audio.add(Object map)
         * @param map - key-value pairs where the key is the `id` and the value is either a `url` or `urls`
         *
         * Loads a sound to be played. Due to the nature of HTML5 audio,
         * three types of audio files will be required for cross-browser capabilities.
         * These formats are MP3, Ogg and WAV.
         *
         * Passing an array of URLs will determine which format the browser can play and select it over any other.
         *
         * Accepts an object where the key is the audio name and
         * either a URL or an Array of URLs (to determine which type to use).
         *
         * The ID you use will be how you refer to that sound when using `Crafty.audio.play`.
         *
         * @example
         * ~~~
         * //adding audio from an object
         * Crafty.audio.add({
         * shoot: ["sounds/shoot.wav",
         * "sounds/shoot.mp3",
         * "sounds/shoot.ogg"],
         *
         * coin: "sounds/coin.mp3"
         * });
         *
         * //adding a single sound
         * Crafty.audio.add("walk", [
         * "sounds/walk.mp3",
         * "sounds/walk.ogg",
         * "sounds/walk.wav"
         * ]);
         *
         * //only one format
         * Crafty.audio.add("jump", "sounds/jump.mp3");
         * ~~~
         */
        add: function (id, url) {
            if (!Crafty.support.audio)
                return;

            var src;

            if (arguments.length === 1 && typeof id === "object") {
                for (var i in id) {
                    for (src in id[i]) {
                        if (Crafty.audio.create(i, id[i][src]))
                            break;
                    }
                }
            }
            if (typeof id === "string") {
                if (typeof url === "string") {
                    Crafty.audio.create(id, url);
                }

                if (typeof url === "object") {
                    for (src in url) {
                        if (Crafty.audio.create(id, url[src]))
                            break;
                    }
                }

            }
        },
        /**@
         * #Crafty.audio.play
         * @comp Crafty.audio
         * @sign public this Crafty.audio.play(String id)
         * @sign public this Crafty.audio.play(String id, Number repeatCount)
         * @sign public this Crafty.audio.play(String id, Number repeatCount, Number volume)
         * @param id - A string to refer to sounds
         * @param repeatCount - Repeat count for the file, where -1 stands for repeat forever.
         * @param volume - volume can be a number between 0.0 and 1.0
         * @returns The audio element used to play the sound.  Null if the call failed due to a lack of open channels.
         *
         * Will play a sound previously added by using the ID that was used in `Crafty.audio.add`.
         * Has a default maximum of 5 channels so that the same sound can play simultaneously unless all of the channels are playing.

         * *Note that the implementation of HTML5 Audio is buggy at best.*
         *
         * @example
         * ~~~
         * Crafty.audio.play("walk");
         *
         * //play and repeat forever
         * Crafty.audio.play("backgroundMusic", -1);
         * Crafty.audio.play("explosion",1,0.5); //play sound once with volume of 50%
         * ~~~
         */
        play: function (id, repeat, volume) {
            if (repeat === 0 || !Crafty.support.audio || !this.sounds[id])
                return;
            var s = this.sounds[id];
            var c = this.getOpenChannel();
            if (!c)
                return null;
            c.id = id;
            var a = c.obj;

            c.volume = s.volume = s.obj.volume = volume || Crafty.audio.volume;

            a.volume = s.volume;
            a.src = s.obj.src;

            if (this.muted)
                a.volume = 0;
            a.play();
            s.played++;
            c.onEnd = function () {
                if (s.played < repeat || repeat == -1) {
                    if (this.currentTime)
                        this.currentTime = 0;
                    this.play();
                    s.played++;
                } else {
                    c.active = false;
                    this.pause();
                    this.removeEventListener("ended", c.onEnd, true);
                    this.currentTime = 0;
                    Crafty.trigger("SoundComplete", {
                        id: c.id
                    });
                }

            };
            a.addEventListener("ended", c.onEnd, true);

            return a;
        },

        /**@
         * #Crafty.audio.setChannels
         * @comp Crafty.audio
         * @sign public this Crafty.audio.setChannels(Number n)
         * @param n - The maximum number of channels
         */
        maxChannels: 7,
        setChannels: function (n) {
            this.maxChannels = n;
            if (n > channels.length)
                this.channels.length = n;

        },

        channels: [],
        // Finds an unused audio element, marks it as in use, and return it.
        getOpenChannel: function () {
            for (var i = 0; i < this.channels.length; i++) {
                if (this.channels[i].active === false) {
                    this.channels[i].active = true;
                    return this.channels[i];
                }
            }
            // If necessary, create a new element, unless we've already reached the max limit
            if (i <= this.maxChannels) {
                var c = {
                    obj: this.audioElement(),
                    active: true,
                    // Checks that the channel is being used to play sound id
                    _is: function (id) {
                        return this.id === id && this.active;
                    }
                };
                this.channels.push(c);
                return c;
            }
            // In that case, return null
            return null;
        },

        /**@
         * #Crafty.audio.remove
         * @comp Crafty.audio
         * @sign public this Crafty.audio.remove([String id])
         * @param id - A string to refer to sounds
         *
         * Will stop the sound and remove all references to the audio object allowing the browser to free the memory.
         * If no id is given, all sounds will be removed.
         *
         * @example
         * ~~~
         * Crafty.audio.remove("walk");
         * ~~~
         */
        remove: function (id) {
            if (!Crafty.support.audio)
                return;

            var s;

            if (!id) {
                for (var i in this.sounds) {
                    s = this.sounds[i];
                    Crafty.audio.stop(id);
                    delete Crafty.assets[s.obj.src];
                    delete Crafty.audio.sounds[id];
                }
                return;
            }
            if (!this.sounds[id])
                return;

            s = this.sounds[id];
            Crafty.audio.stop(id);
            delete Crafty.assets[s.obj.src];
            delete Crafty.audio.sounds[id];
        },
        /**@
         * #Crafty.audio.stop
         * @comp Crafty.audio
         * @sign public this Crafty.audio.stop([Number ID])
         *
         * Stops any playing sound. if id is not set, stop all sounds which are playing
         *
         * @example
         * ~~~
         * //all sounds stopped playing now
         * Crafty.audio.stop();
         *
         * ~~~
         */
        stop: function (id) {
            if (!Crafty.support.audio)
                return;
            for (var i in this.channels) {
                c = this.channels[i];
                if ( (!id && c.active) || c._is(id) ) {
                    c.active = false;
                    c.obj.pause();
                }
            }
            return;
        },
        /**
         * #Crafty.audio._mute
         * @comp Crafty.audio
         * @sign public this Crafty.audio._mute([Boolean mute])
         *
         * Mute or unmute every Audio instance that is playing.
         */
        _mute: function (mute) {
            if (!Crafty.support.audio)
                return;
            var c;
            for (var i in this.channels) {
                c = this.channels[i];
                c.obj.volume = mute ? 0 : c.volume;
            }
            this.muted = mute;
        },
        /**@
         * #Crafty.audio.toggleMute
         * @comp Crafty.audio
         * @sign public this Crafty.audio.toggleMute()
         *
         * Mute or unmute every Audio instance that is playing. Toggles between
         * pausing or playing depending on the state.
         *
         * @example
         * ~~~
         * //toggle mute and unmute depending on current state
         * Crafty.audio.toggleMute();
         * ~~~
         */
        toggleMute: function () {
            if (!this.muted) {
                this._mute(true);
            } else {
                this._mute(false);
            }

        },
        /**@
         * #Crafty.audio.mute
         * @comp Crafty.audio
         * @sign public this Crafty.audio.mute()
         *
         * Mute every Audio instance that is playing.
         *
         * @example
         * ~~~
         * Crafty.audio.mute();
         * ~~~
         */
        mute: function () {
            this._mute(true);
        },
        /**@
         * #Crafty.audio.unmute
         * @comp Crafty.audio
         * @sign public this Crafty.audio.unmute()
         *
         * Unmute every Audio instance that is playing.
         *
         * @example
         * ~~~
         * Crafty.audio.unmute();
         * ~~~
         */
        unmute: function () {
            this._mute(false);
        },

        /**@
         * #Crafty.audio.pause
         * @comp Crafty.audio
         * @sign public this Crafty.audio.pause(string ID)
         *
         * Pause the Audio instance specified by id param.
         *
         * @example
         * ~~~
         * Crafty.audio.pause('music');
         * ~~~
         *
         * @param {string} id The id of the audio object to pause
         */
        pause: function (id) {
            if (!Crafty.support.audio || !id || !this.sounds[id])
                return;
            var c;
            for (var i in this.channels) {
                c = this.channels[i];
                if (c._is(id) && !c.obj.paused)
                    c.obj.pause();
            }

        },

        /**@
         * #Crafty.audio.unpause
         * @comp Crafty.audio
         * @sign public this Crafty.audio.unpause(string ID)
         *
         * Resume playing the Audio instance specified by id param.
         *
         * @example
         * ~~~
         * Crafty.audio.unpause('music');
         * ~~~
         *
         * @param {string} id The id of the audio object to unpause
         */
        unpause: function (id) {
            if (!Crafty.support.audio || !id || !this.sounds[id])
                return;
            var c;
            for (var i in this.channels) {
                c = this.channels[i];
                if (c._is(id) && c.obj.paused)
                    c.obj.play();
            }
        },

        /**@
         * #Crafty.audio.togglePause
         * @comp Crafty.audio
         * @sign public this Crafty.audio.togglePause(string ID)
         *
         * Toggle the pause status of the Audio instance specified by id param.
         *
         * @example
         * ~~~
         * Crafty.audio.togglePause('music');
         * ~~~
         *
         * @param {string} id The id of the audio object to pause/unpause
         */
        togglePause: function (id) {
            if (!Crafty.support.audio || !id || !this.sounds[id])
                return;
            var c;
            for (var i in this.channels) {
                c = this.channels[i];
                if (c._is(id)) {
                    if (c.obj.paused) {
                        c.obj.play();
                    } else {
                        c.obj.pause();
                    }
                }
            }
        }
    }
});<commit_msg>Reversed compare in setChannels, corrected variable reference. Also fixed off-by-one creating channels (cherry picked from commit 5a1dd4b8d902333e690773e48de37117c0561cb9)<commit_after>var Crafty = require('./core.js'),
    document = window.document;

Crafty.extend({
    /**@
     * #Crafty.audio
     * @category Audio
     *
     * Add sound files and play them. Chooses best format for browser support.
     * Due to the nature of HTML5 audio, three types of audio files will be
     * required for cross-browser capabilities. These formats are MP3, Ogg and WAV.
     * When sound was not muted on before pause, sound will be unmuted after unpause.
     * When sound is muted Crafty.pause() does not have any effect on sound
     *
     * The maximum number of sounds that can be played simultaneously is defined by Crafty.audio.maxChannels.  The default value is 7.
     */
    audio: {

        sounds: {},
        supported: null,
        codecs: { // Chart from jPlayer
            ogg: 'audio/ogg; codecs="vorbis"', //OGG
            wav: 'audio/wav; codecs="1"', // PCM
            webma: 'audio/webm; codecs="vorbis"', // WEBM
            mp3: 'audio/mpeg; codecs="mp3"', //MP3
            m4a: 'audio/mp4; codecs="mp4a.40.2"' // AAC / MP4
        },
        volume: 1, //Global Volume
        muted: false,
        paused: false,
        playCheck: null,
        /**
         * Function to setup supported formats
         **/
        _canPlay: function () {
            this.supported = {};
            // Without support, no formats are supported
            if (!Crafty.support.audio)
                return;
            var audio = this.audioElement(),
                canplay;
            for (var i in this.codecs) {
                canplay = audio.canPlayType(this.codecs[i]);
                if (canplay !== "" && canplay !== "no") {
                    this.supported[i] = true;
                } else {
                    this.supported[i] = false;
                }
            }

        },

        /**@
         * #Crafty.audio.supports
         * @comp Crafty.audio
         * @sign public this Crafty.audio.supports(String extension)
         * @param extension - A file extension to check audio support for
         *
         * Return true if the browser thinks it can play the given file type, otherwise false
         */
        supports: function (extension) {
            // Build cache of supported formats, if necessary
            if (this.supported === null)
                this._canPlay();

            if (this.supported[extension])
                return true;
            else
                return false;
        },

        /**
         * Function to get an Audio Element
         **/
        audioElement: function () {
            //IE does not support Audio Object
            return typeof Audio !== 'undefined' ? new Audio("") : document.createElement('audio');
        },

        /**@
         * #Crafty.audio.create
         * @comp Crafty.audio
         * @sign public this Crafty.audio.create(String id, String url)
         * @param id - A string to refer to sounds
         * @param url - A string pointing to the sound file
         *
         * Creates an audio asset with the given id and resource.  `Crafty.audio.add` is a more flexible interface that allows cross-browser compatibility.
         *
         * If the sound file extension is not supported, returns false; otherwise, returns the audio asset.
         */
        create: function (id, path) {
            //check extension, return if not supported
            var ext = path.substr(path.lastIndexOf('.') + 1).toLowerCase();
            if (!this.supports(ext))
                return false;

            //initiate the audio element
            var audio = this.audioElement();
            audio.id = id;
            audio.preload = "auto";
            audio.volume = Crafty.audio.volume;
            audio.src = path;

            //create an asset and metadata for the audio element
            Crafty.asset(path, audio);
            this.sounds[id] = {
                obj: audio,
                played: 0,
                volume: Crafty.audio.volume
            };
            return this.sounds[id];

        },

        /**@
         * #Crafty.audio.add
         * @comp Crafty.audio
         * @sign public this Crafty.audio.add(String id, String url)
         * @param id - A string to refer to sounds
         * @param url - A string pointing to the sound file
         * @sign public this Crafty.audio.add(String id, Array urls)
         * @param urls - Array of urls pointing to different format of the same sound, selecting the first that is playable
         * @sign public this Crafty.audio.add(Object map)
         * @param map - key-value pairs where the key is the `id` and the value is either a `url` or `urls`
         *
         * Loads a sound to be played. Due to the nature of HTML5 audio,
         * three types of audio files will be required for cross-browser capabilities.
         * These formats are MP3, Ogg and WAV.
         *
         * Passing an array of URLs will determine which format the browser can play and select it over any other.
         *
         * Accepts an object where the key is the audio name and
         * either a URL or an Array of URLs (to determine which type to use).
         *
         * The ID you use will be how you refer to that sound when using `Crafty.audio.play`.
         *
         * @example
         * ~~~
         * //adding audio from an object
         * Crafty.audio.add({
         * shoot: ["sounds/shoot.wav",
         * "sounds/shoot.mp3",
         * "sounds/shoot.ogg"],
         *
         * coin: "sounds/coin.mp3"
         * });
         *
         * //adding a single sound
         * Crafty.audio.add("walk", [
         * "sounds/walk.mp3",
         * "sounds/walk.ogg",
         * "sounds/walk.wav"
         * ]);
         *
         * //only one format
         * Crafty.audio.add("jump", "sounds/jump.mp3");
         * ~~~
         */
        add: function (id, url) {
            if (!Crafty.support.audio)
                return;

            var src;

            if (arguments.length === 1 && typeof id === "object") {
                for (var i in id) {
                    for (src in id[i]) {
                        if (Crafty.audio.create(i, id[i][src]))
                            break;
                    }
                }
            }
            if (typeof id === "string") {
                if (typeof url === "string") {
                    Crafty.audio.create(id, url);
                }

                if (typeof url === "object") {
                    for (src in url) {
                        if (Crafty.audio.create(id, url[src]))
                            break;
                    }
                }

            }
        },
        /**@
         * #Crafty.audio.play
         * @comp Crafty.audio
         * @sign public this Crafty.audio.play(String id)
         * @sign public this Crafty.audio.play(String id, Number repeatCount)
         * @sign public this Crafty.audio.play(String id, Number repeatCount, Number volume)
         * @param id - A string to refer to sounds
         * @param repeatCount - Repeat count for the file, where -1 stands for repeat forever.
         * @param volume - volume can be a number between 0.0 and 1.0
         * @returns The audio element used to play the sound.  Null if the call failed due to a lack of open channels.
         *
         * Will play a sound previously added by using the ID that was used in `Crafty.audio.add`.
         * Has a default maximum of 5 channels so that the same sound can play simultaneously unless all of the channels are playing.

         * *Note that the implementation of HTML5 Audio is buggy at best.*
         *
         * @example
         * ~~~
         * Crafty.audio.play("walk");
         *
         * //play and repeat forever
         * Crafty.audio.play("backgroundMusic", -1);
         * Crafty.audio.play("explosion",1,0.5); //play sound once with volume of 50%
         * ~~~
         */
        play: function (id, repeat, volume) {
            if (repeat === 0 || !Crafty.support.audio || !this.sounds[id])
                return;
            var s = this.sounds[id];
            var c = this.getOpenChannel();
            if (!c)
                return null;
            c.id = id;
            var a = c.obj;

            c.volume = s.volume = s.obj.volume = volume || Crafty.audio.volume;

            a.volume = s.volume;
            a.src = s.obj.src;

            if (this.muted)
                a.volume = 0;
            a.play();
            s.played++;
            c.onEnd = function () {
                if (s.played < repeat || repeat == -1) {
                    if (this.currentTime)
                        this.currentTime = 0;
                    this.play();
                    s.played++;
                } else {
                    c.active = false;
                    this.pause();
                    this.removeEventListener("ended", c.onEnd, true);
                    this.currentTime = 0;
                    Crafty.trigger("SoundComplete", {
                        id: c.id
                    });
                }

            };
            a.addEventListener("ended", c.onEnd, true);

            return a;
        },

        /**@
         * #Crafty.audio.setChannels
         * @comp Crafty.audio
         * @sign public this Crafty.audio.setChannels(Number n)
         * @param n - The maximum number of channels
         */
        maxChannels: 7,
        setChannels: function (n) {
            this.maxChannels = n;
            if (n < this.channels.length)
                this.channels.length = n;
        },

        channels: [],
        // Finds an unused audio element, marks it as in use, and return it.
        getOpenChannel: function () {
            for (var i = 0; i < this.channels.length; i++) {
                if (this.channels[i].active === false) {
                    this.channels[i].active = true;
                    return this.channels[i];
                }
            }
            // If necessary, create a new element, unless we've already reached the max limit
            if (i < this.maxChannels) {
                var c = {
                    obj: this.audioElement(),
                    active: true,
                    // Checks that the channel is being used to play sound id
                    _is: function (id) {
                        return this.id === id && this.active;
                    }
                };
                this.channels.push(c);
                return c;
            }
            // In that case, return null
            return null;
        },

        /**@
         * #Crafty.audio.remove
         * @comp Crafty.audio
         * @sign public this Crafty.audio.remove([String id])
         * @param id - A string to refer to sounds
         *
         * Will stop the sound and remove all references to the audio object allowing the browser to free the memory.
         * If no id is given, all sounds will be removed.
         *
         * @example
         * ~~~
         * Crafty.audio.remove("walk");
         * ~~~
         */
        remove: function (id) {
            if (!Crafty.support.audio)
                return;

            var s;

            if (!id) {
                for (var i in this.sounds) {
                    s = this.sounds[i];
                    Crafty.audio.stop(id);
                    delete Crafty.assets[s.obj.src];
                    delete Crafty.audio.sounds[id];
                }
                return;
            }
            if (!this.sounds[id])
                return;

            s = this.sounds[id];
            Crafty.audio.stop(id);
            delete Crafty.assets[s.obj.src];
            delete Crafty.audio.sounds[id];
        },
        /**@
         * #Crafty.audio.stop
         * @comp Crafty.audio
         * @sign public this Crafty.audio.stop([Number ID])
         *
         * Stops any playing sound. if id is not set, stop all sounds which are playing
         *
         * @example
         * ~~~
         * //all sounds stopped playing now
         * Crafty.audio.stop();
         *
         * ~~~
         */
        stop: function (id) {
            if (!Crafty.support.audio)
                return;
            for (var i in this.channels) {
                c = this.channels[i];
                if ( (!id && c.active) || c._is(id) ) {
                    c.active = false;
                    c.obj.pause();
                }
            }
            return;
        },
        /**
         * #Crafty.audio._mute
         * @comp Crafty.audio
         * @sign public this Crafty.audio._mute([Boolean mute])
         *
         * Mute or unmute every Audio instance that is playing.
         */
        _mute: function (mute) {
            if (!Crafty.support.audio)
                return;
            var c;
            for (var i in this.channels) {
                c = this.channels[i];
                c.obj.volume = mute ? 0 : c.volume;
            }
            this.muted = mute;
        },
        /**@
         * #Crafty.audio.toggleMute
         * @comp Crafty.audio
         * @sign public this Crafty.audio.toggleMute()
         *
         * Mute or unmute every Audio instance that is playing. Toggles between
         * pausing or playing depending on the state.
         *
         * @example
         * ~~~
         * //toggle mute and unmute depending on current state
         * Crafty.audio.toggleMute();
         * ~~~
         */
        toggleMute: function () {
            if (!this.muted) {
                this._mute(true);
            } else {
                this._mute(false);
            }

        },
        /**@
         * #Crafty.audio.mute
         * @comp Crafty.audio
         * @sign public this Crafty.audio.mute()
         *
         * Mute every Audio instance that is playing.
         *
         * @example
         * ~~~
         * Crafty.audio.mute();
         * ~~~
         */
        mute: function () {
            this._mute(true);
        },
        /**@
         * #Crafty.audio.unmute
         * @comp Crafty.audio
         * @sign public this Crafty.audio.unmute()
         *
         * Unmute every Audio instance that is playing.
         *
         * @example
         * ~~~
         * Crafty.audio.unmute();
         * ~~~
         */
        unmute: function () {
            this._mute(false);
        },

        /**@
         * #Crafty.audio.pause
         * @comp Crafty.audio
         * @sign public this Crafty.audio.pause(string ID)
         *
         * Pause the Audio instance specified by id param.
         *
         * @example
         * ~~~
         * Crafty.audio.pause('music');
         * ~~~
         *
         * @param {string} id The id of the audio object to pause
         */
        pause: function (id) {
            if (!Crafty.support.audio || !id || !this.sounds[id])
                return;
            var c;
            for (var i in this.channels) {
                c = this.channels[i];
                if (c._is(id) && !c.obj.paused)
                    c.obj.pause();
            }

        },

        /**@
         * #Crafty.audio.unpause
         * @comp Crafty.audio
         * @sign public this Crafty.audio.unpause(string ID)
         *
         * Resume playing the Audio instance specified by id param.
         *
         * @example
         * ~~~
         * Crafty.audio.unpause('music');
         * ~~~
         *
         * @param {string} id The id of the audio object to unpause
         */
        unpause: function (id) {
            if (!Crafty.support.audio || !id || !this.sounds[id])
                return;
            var c;
            for (var i in this.channels) {
                c = this.channels[i];
                if (c._is(id) && c.obj.paused)
                    c.obj.play();
            }
        },

        /**@
         * #Crafty.audio.togglePause
         * @comp Crafty.audio
         * @sign public this Crafty.audio.togglePause(string ID)
         *
         * Toggle the pause status of the Audio instance specified by id param.
         *
         * @example
         * ~~~
         * Crafty.audio.togglePause('music');
         * ~~~
         *
         * @param {string} id The id of the audio object to pause/unpause
         */
        togglePause: function (id) {
            if (!Crafty.support.audio || !id || !this.sounds[id])
                return;
            var c;
            for (var i in this.channels) {
                c = this.channels[i];
                if (c._is(id)) {
                    if (c.obj.paused) {
                        c.obj.play();
                    } else {
                        c.obj.pause();
                    }
                }
            }
        }
    }
});
<|endoftext|>


<commit_before>import React from "react"

const NotFoundPage = () => (

404: Not Found

You just hit a route that doesn't exist... the sadness.

)

export default NotFoundPage
<commit_msg>add navigation to 404 page<commit_after>import React from "react"

import Header from "../components/header"

const NotFoundPage = () => (

404: Not Found

You just hit a route that doesn't exist... the sadness.

)

export default NotFoundPage
<|endoftext|>


<commit_before>'use strict';

const storageHelper = require('../storage-helper');

module.exports = (function () {
    return {
        init(options) {
            const mergeButton = document.getElementById('fulfill-pullrequest');
            mergeButton.addEventListener('click', handleApproval);
            shouldMergeBeDisabled().then(disable => {
                mergeButton.disabled = options.mergeButtonStartsDisabled && disable;
            });
        }
    };
})();

function handleApproval() {
    // timeout because it takes some time for the approvals counter to update
    setTimeout(() => {
        const mergeButton = document.getElementById('fulfill-pullrequest');
        mergeButton.disabled = shouldMergeBeDisabled();
    }, 200);
}

function shouldMergeBeDisabled() {
    const numberOfApprovals = parseInt(document.getElementsByClassName('approvals')[0].textContent, 10);
    return storageHelper.getConfig().then(config => {
        const minimumNumberOfApprovals = config.minimumNumberOfApprovals;
        const mergeRequiresApproval = minimumNumberOfApprovals > 0;
        return mergeRequiresApproval && numberOfApprovals < minimumNumberOfApprovals;
    });
}
<commit_msg>Fixes async code call<commit_after>'use strict';

const storageHelper = require('../storage-helper');

module.exports = (function () {
    return {
        init(options) {
            const mergeButton = document.getElementById('fulfill-pullrequest');
            mergeButton.addEventListener('click', handleApproval);
            shouldMergeBeDisabled().then(disable => {
                mergeButton.disabled = options.mergeButtonStartsDisabled && disable;
            });
        }
    };
})();

function handleApproval() {
    // timeout because it takes some time for the approvals counter to update
    setTimeout(() => {
        const mergeButton = document.getElementById('fulfill-pullrequest');
        shouldMergeBeDisabled().then(disable => {
            mergeButton.disabled = disable;
        });
    }, 200);
}

function shouldMergeBeDisabled() {
    const numberOfApprovals = parseInt(document.getElementsByClassName('approvals')[0].textContent, 10);
    return storageHelper.getConfig().then(config => {
        const minimumNumberOfApprovals = config.minimumNumberOfApprovals;
        const mergeRequiresApproval = minimumNumberOfApprovals > 0;
        return mergeRequiresApproval && numberOfApprovals < minimumNumberOfApprovals;
    });
}
<|endoftext|>


<commit_before>const FileUpload = require('../../../../app/services/domain/file-upload')
const ValidationError = require('../../../../app/services/errors/validation-error')
const expect = require('chai').expect
// const documentTypeEnum = require('../../../../app/constants/document-type-enum')
const UploadError = require('../../../../app/services/errors/upload-error')

describe('services/domain/file-upload', function () {
  const VALID_ID = '1'
  const VALID_DOCUMENT_TYPE = 'VISIT_CONFIRMATION' // documentTypeEnum['VISIT_CONFIRMATION'].documentType
  const VALID_FILE = {path: 'path'}
  const VALID_DOCUMENT_STATUS = 'uploaded'
  const UPLOAD_ERROR = new UploadError('File type error')

  it('should construct a domain object given valid input', function () {
    var fileUpload = new FileUpload(
      VALID_ID,
      VALID_DOCUMENT_TYPE,
      VALID_ID,
      VALID_FILE,
      undefined,
      undefined
    )

    expect(fileUpload.path).to.equal(VALID_FILE.path)
    expect(fileUpload.claimId).to.equal(VALID_ID)
    expect(fileUpload.documentStatus).to.equal(VALID_DOCUMENT_STATUS)
  })

  it('should throw an error if passed invalid data', function () {
    expect(function () {
      new FileUpload(
        VALID_ID,
        VALID_DOCUMENT_TYPE,
        VALID_ID,
        undefined,
        undefined,
        undefined
      ).isValid()
    }).to.throw(ValidationError)
  })

  it('should throw an error if passed UploadError', function () {
    expect(function () {
      new FileUpload(
        VALID_ID,
        VALID_DOCUMENT_TYPE,
        VALID_ID,
        VALID_FILE,
        UPLOAD_ERROR,
        undefined
      ).isValid()
    }).to.throw(ValidationError)
  })
})
<commit_msg>Removed commented out code<commit_after>const FileUpload = require('../../../../app/services/domain/file-upload')
const ValidationError = require('../../../../app/services/errors/validation-error')
const expect = require('chai').expect
const UploadError = require('../../../../app/services/errors/upload-error')

describe('services/domain/file-upload', function () {
  const VALID_ID = '1'
  const VALID_DOCUMENT_TYPE = 'VISIT_CONFIRMATION'
  const VALID_FILE = {path: 'path'}
  const VALID_DOCUMENT_STATUS = 'uploaded'
  const UPLOAD_ERROR = new UploadError('File type error')

  it('should construct a domain object given valid input', function () {
    var fileUpload = new FileUpload(
      VALID_ID,
      VALID_DOCUMENT_TYPE,
      VALID_ID,
      VALID_FILE,
      undefined,
      undefined
    )

    expect(fileUpload.path).to.equal(VALID_FILE.path)
    expect(fileUpload.claimId).to.equal(VALID_ID)
    expect(fileUpload.documentStatus).to.equal(VALID_DOCUMENT_STATUS)
  })

  it('should throw an error if passed invalid data', function () {
    expect(function () {
      new FileUpload(
        VALID_ID,
        VALID_DOCUMENT_TYPE,
        VALID_ID,
        undefined,
        undefined,
        undefined
      ).isValid()
    }).to.throw(ValidationError)
  })

  it('should throw an error if passed UploadError', function () {
    expect(function () {
      new FileUpload(
        VALID_ID,
        VALID_DOCUMENT_TYPE,
        VALID_ID,
        VALID_FILE,
        UPLOAD_ERROR,
        undefined
      ).isValid()
    }).to.throw(ValidationError)
  })
})
<|endoftext|>


<commit_before>module.exports = function(grunt) {

};
<commit_msg>Added grunt npm tasks<commit_after>module.exports = function(grunt) {

  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-contrib-watch');

};
<|endoftext|>


<commit_before>var webpack = require('webpack');

// postcss plugins
var cssimport = require('postcss-import');
var customProperties = require('postcss-custom-properties');
var autoprefixer = require('autoprefixer');
var csswring = require('csswring');
var cssnested = require('postcss-nested');

module.exports = {
  entry: {
    app : ['./src/index.js']
  },
  output: {
    path: __dirname + './dist/',
    filename: 'index.js'
  },
  devtool: 'eval',
  debug: true,
  plugins: [
    new webpack.ProvidePlugin({
      riot: 'riot'
    })
  ],
  module: {
    preLoaders: [
      { test: /\.tag$/, exclude: /node_modules/, loader: 'riotjs-loader', query: { type: 'es6' } }
    ],
    loaders: [
      { test: /\.js$|\.tag$/, exclude: /node_modules/, include: /src/, loader: 'babel-loader', query: {presets: ['es2015-riot']}, modules: 'common' },
      { test: /\.css$/, loader: 'style-loader!css-loader!postcss-loader' }
    ]
  },
  postcss: [cssimport, cssnested, customProperties, autoprefixer, csswring],
  devServer: {
    contentBase: './dist/',
    port: 8090,
    hot: true,
    inline: true
  }
};
<commit_msg>modify webpack settings.<commit_after>var webpack = require('webpack');

// postcss plugins
var cssimport = require('postcss-import');
var customProperties = require('postcss-custom-properties');
var autoprefixer = require('autoprefixer');
var csswring = require('csswring');
var cssnested = require('postcss-nested');

module.exports = {
  entry: {
    app : ['./src/index.js']
  },
  output: {
    path: __dirname + '/dist/',
    filename: 'index.js'
  },
  devtool: 'source-map',
  debug: true,
  plugins: [
    new webpack.ProvidePlugin({
      riot: 'riot'
    })
  ],
  module: {
    preLoaders: [
      { test: /\.tag$/, exclude: /node_modules/, loader: 'riotjs-loader', query: { type: 'none' } }
    ],
    loaders: [
      { test: /\.js$|\.tag$/, exclude: /node_modules/, include: /src/, loader: 'babel-loader', query: {presets: ['es2015-riot']}, modules: 'common' },
      { test: /\.css$/, loader: 'style-loader!css-loader!postcss-loader' }
    ]
  },
  postcss: [cssimport, cssnested, customProperties, autoprefixer, csswring],
  devServer: {
    contentBase: './dist/',
    port: 8090,
    hot: true,
    inline: true
  }
};
<|endoftext|>


<commit_before>function inflateModel(orig)
{
	var positions = [];
	var normals = [];

	for(var i = 0; i < orig["draw"].length; i++)
	{
		var vi = orig["draw"][i] * 3;
		positions.push.apply(positions, orig["positions"].slice(vi, vi + 3));
		if("vert_normals" in orig)
		{
			normals.push.apply(normals, orig["vert_normals"].slice(vi, vi + 3));
		}
		else if("face_normals" in orig)
		{
			var fi = i - i % 3;
			normals.push.apply(normals, orig["face_normals"].slice(fi, fi + 3));
		}
	}

	var buf_positions = gl.createBuffer();
	gl.bindBuffer(gl.ARRAY_BUFFER, buf_positions);
	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

	var buf_normals = gl.createBuffer();
	gl.bindBuffer(gl.ARRAY_BUFFER, buf_normals);
	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW);

	return {
		"positions": buf_positions,
		"normals": buf_normals,
		"numVerts": orig["draw"].length
	};
}

function loadTexture(id)
{
	var img = new Image();
	var tex = gl.createTexture();
	img.onload = function(){
		gl.bindTexture(gl.TEXTURE_2D, tex);
		gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
		gl.generateMipmap(gl.TEXTURE_2D);
	};
	img.src = "tex/" + id + ".png";
	return tex;
}

function loadModels()
{
	mdl_monkey = inflateModel(src_monkey);
	mdl_cube = inflateModel(src_cube);
	tex_white_marble = loadTexture("white_marble");
	gl.bindTexture(gl.TEXTURE_2D, tex_white_marble);
}

function drawModel(mdl)
{
	gl.uniformMatrix4fv(main_shader.uniform.model, false, mvp.getModel());

	gl.bindBuffer(gl.ARRAY_BUFFER, mdl["positions"]);
	gl.vertexAttribPointer(main_shader.attrib.pos, 3, gl.FLOAT, false, 0, 0);

	gl.bindBuffer(gl.ARRAY_BUFFER, mdl["normals"]);
	gl.vertexAttribPointer(main_shader.attrib.norm, 3, gl.FLOAT, false, 0, 0);

	gl.drawArrays(gl.TRIANGLES, 0, mdl["numVerts"]);
}
<commit_msg>Add blank texture image while loading<commit_after>function inflateModel(orig)
{
	var positions = [];
	var normals = [];

	for(var i = 0; i < orig["draw"].length; i++)
	{
		var vi = orig["draw"][i] * 3;
		positions.push.apply(positions, orig["positions"].slice(vi, vi + 3));
		if("vert_normals" in orig)
		{
			normals.push.apply(normals, orig["vert_normals"].slice(vi, vi + 3));
		}
		else if("face_normals" in orig)
		{
			var fi = i - i % 3;
			normals.push.apply(normals, orig["face_normals"].slice(fi, fi + 3));
		}
	}

	var buf_positions = gl.createBuffer();
	gl.bindBuffer(gl.ARRAY_BUFFER, buf_positions);
	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

	var buf_normals = gl.createBuffer();
	gl.bindBuffer(gl.ARRAY_BUFFER, buf_normals);
	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW);

	return {
		"positions": buf_positions,
		"normals": buf_normals,
		"numVerts": orig["draw"].length
	};
}

function loadTexture(id)
{
	var tex = gl.createTexture();
	gl.bindTexture(gl.TEXTURE_2D, tex);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
	gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([255, 255, 255, 255]));

	var img = new Image();
	img.onload = function(){
		gl.bindTexture(gl.TEXTURE_2D, tex);
		gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
		gl.generateMipmap(gl.TEXTURE_2D);
	};
	img.src = "tex/" + id + ".png";

	return tex;
}

function loadModels()
{
	mdl_monkey = inflateModel(src_monkey);
	mdl_cube = inflateModel(src_cube);
	tex_white_marble = loadTexture("white_marble");
	gl.bindTexture(gl.TEXTURE_2D, tex_white_marble);
}

function drawModel(mdl)
{
	gl.uniformMatrix4fv(main_shader.uniform.model, false, mvp.getModel());

	gl.bindBuffer(gl.ARRAY_BUFFER, mdl["positions"]);
	gl.vertexAttribPointer(main_shader.attrib.pos, 3, gl.FLOAT, false, 0, 0);

	gl.bindBuffer(gl.ARRAY_BUFFER, mdl["normals"]);
	gl.vertexAttribPointer(main_shader.attrib.norm, 3, gl.FLOAT, false, 0, 0);

	gl.drawArrays(gl.TRIANGLES, 0, mdl["numVerts"]);
}
<|endoftext|>


<commit_before>class Space {
  constructor(iterable) {
    if (!iterable) {
      throw new Error();
    }
    this.table = new Map(iterable);
  }

  toString() {
    let object = Object.create(null);
    for (let [key, value] of this.table) {
      object[key] = value;
    }
    return JSON.stringify(object);
  }

  isValid() {
    return false;
  }

  clone() {
    throw new Error("clone() is not implemented");
  }

  hex() {
    throw new Error("hex() is not implemented");
  }

  rgb() {
    throw new Error("rgb() is not implemented");
  }

  hsl() {
    throw new Error("hsl() is not implemented");
  }

  cmyk() {
    throw new Error("cmyk() is not implemented");
  }

  get(key) {
    return this.table.get(key);
  }

  set(key, value) {
    return this.table.set(key, value);
  }

  getOrSet(key, value = null) {
    if (value == null) {
      return this.get(key);
    }
    this.set(key, value);
    return this;
  }

  values() {
    return this.table.values();
  }
}

export class Rgb extends Space {
  static KEY_R = "r";
  static KEY_G = "g";
  static KEY_B = "b";

  constructor(r, g, b) {
    super([[Rgb.KEY_R, r], [Rgb.KEY_G, g], [Rgb.KEY_B, b]]);
  }

  toString() {
    return `rgb(${this.r()}, ${this.g()}, ${this.b()})`;
  }

  isValid() {
    let values = this.values();
    for (let value of values) {
      if (value < 0x00 || value > 0xFF) {
        return false;
      }
    }
    return true;
  }

  clone() {
    return new Rgb(this.r(), this.g(), this.b());
  }

  r(value = null) {
    return this.getOrSet(Rgb.KEY_R, value);
  }

  g(value = null) {
    return this.getOrSet(Rgb.KEY_G, value);
  }

  b(value = null) {
    return this.getOrSet(Rgb.KEY_B, value);
  }

  hex() {
    let parts = [];
    for (let value of this.values()) {
      let text = value.toString(16);
      if (text.length === 1) {
        text = `0${text}`;
      }
      parts.push(text.toUppderCase());
    }
    return `#${parts.join('')}`;
  }

  rgb() {
    return this;
  }

  hsl() {
    let r = this.r() / 0xFF;
    let g = this.g() / 0xFF;
    let b = this.b() / 0xFF;

    let max   = Math.max(r, g, b);
    let min   = Math.min(r, g, b);
    let delta = max - min;
    if (delta === 0) {
      return new Hsl(0, 0, max);
    }

    let h = 0;
    if (max === r) {
      h = 60 * ((g - b) / delta % 360);
    } else if (max === g) {
      h = 60 * ((b - r) / delta + 2);
    } else if (max === b) {
      h = 60 * ((r - g) / delta + 4);
    }

    let l = (max + min) / 2;

    let s = delta / (1 - Math.abs(2 * l - 1))

    return new Hsl(h, s, l);
  }

  cmyk() {
    let r = this.r() / 0xFF;
    let g = this.g() / 0xFF;
    let b = this.b() / 0xFF;

    let k = 1 - Math.max(r, g, b);
    if (k === 1) {
      return new Cmyk(0, 0, 0, 1);
    }

    let c = (1 - r - k) / (1 - k);
    let m = (1 - g - k) / (1 - k);
    let y = (1 - b - k) / (1 - k);
    return new Cmyk(c, m, y, k);
  }
}

export class Hsl extends Space {
  static KEY_H = "h";
  static KEY_S = "s";
  static KEY_L = "l";

  constructor(h, s, l) {
    super([[Hsl.KEY_H, h], [Hsl.KEY_S, s], [Hsl.KEY_L, l]]);
  }

  toString() {
    return `hsl(${this.h()}, ${this.s()}%, ${this.l()}%)`;
  }

  clone() {
    return new Hsl(this.h(), this.s(), this.l());
  }

  isValid() {
    let h = this.h();
    if (!Number.isFinite(h) || h < 0 || h > 360) {
      return false;
    }

    let s = this.s();
    if (!Number.isFinite(s) || s < 0 || s > 100) {
      return false;
    }

    let l = this.l();
    if (!Number.isFinite(l) || l < 0 || l > 100) {
      return false;
    }
    return true;
  }

  h(value = null) {
    return this.getOrSet(Hsl.KEY_H, value);
  }

  s(value = null) {
    return this.getOrSet(Hsl.KEY_S, value);
  }

  l(value = null) {
    return this.getOrSet(Hsl.KEY_L, value);
  }

  hex() {
    return this.rgb().hex();
  }

  rgb() {
    let h = this.h();
    let s = this.s();
    let l = this.l();
    if (s === 0) {
      let value = Math.round(l * 0xFF);
      return new Rgb(value, value, value);
    }

    let m2 = 0;
    if (l < 0.5) {
      m2 = l * (s + 1);
    } else {
      m2 = l + s - l * s;
    }

    let m1 = 2 * l - m2;
    let r = Math.round(255 * Hsl.hueToRgb(m1, m2, h / 360 + 1 / 3));
    let g = Math.round(255 * Hsl.hueToRgb(m1, m2, h / 360));
    let b = Math.round(255 * Hsl.hueToRgb(m1, m2, h / 360 - 1 / 3));
    return new Rgb(r, g, b)
  }

  hsl() {
    return this;
  }

  cmyk() {
    return this.rgb().cmyk();
  }

  static hueToRgb(m1, m2, h) {
    if (h < 0) {
      h += 1;
    } else if (h > 1) {
      h -= 1;
    }

    if (h * 6 < 1) {
      return m1 + (m2 - m1) * h * 6;
    } else if (h * 2 < 1) {
      return m2;
    } else if (h * 3 < 2) {
      return m1 + (m2 - m1) * (2 / 3 - h) * 6;
    }
    return m1;
  }
}

export class Cmyk extends Space {
  static KEY_C = 'c';
  static KEY_M = 'm';
  static KEY_Y = 'y';
  static KEY_K = 'k';

  constructor(c, m, y, k) {
    super([[Cmyk.KEY_C, c], [Cmyk.KEY_M, m], [Cmyk.KEY_Y, y], [Cmyk.KEY_K]]);
  }

  isValid() {
    for (let value of this.values()) {
      if (!Number.isFinite(value)) {
        return false;
      }
      if (value < 0 || value > 1) {
        return false;
      }
    }
    return true;
  }

  clone() {
    return new Cmyk(this.c(), this.m(), this.y(), this.k());
  }

  c(value = null) {
    return this.getOrSet(Cmyk.KEY_C, value);
  }

  m(value = null) {
    return this.getOrSet(Cmyk.KEY_M, value);
  }

  y(value = null) {
    return this.getOrSet(Cmyk.KEY_Y, value);
  }

  k(value = null) {
    return this.getOrSet(Cmyk.KEY_K, value);
  }

  rgb() {
    let k = this.k();
    if (k === 1) {
      return new Rgb(0, 0, 0);
    }

    let r = 0xFF * (1 - this.c()) * (1 - k);
    let g = 0xFF * (1 - this.m()) * (1 - k);
    let b = 0xFF * (1 - this.y()) * (1 - k);
    return new Rgb(r, g, b);
  }
}
<commit_msg>Added a color space conversion method that converts from cymk to hex<commit_after>class Space {
  constructor(iterable) {
    if (!iterable) {
      throw new Error();
    }
    this.table = new Map(iterable);
  }

  toString() {
    let object = Object.create(null);
    for (let [key, value] of this.table) {
      object[key] = value;
    }
    return JSON.stringify(object);
  }

  isValid() {
    return false;
  }

  clone() {
    throw new Error("clone() is not implemented");
  }

  hex() {
    throw new Error("hex() is not implemented");
  }

  rgb() {
    throw new Error("rgb() is not implemented");
  }

  hsl() {
    throw new Error("hsl() is not implemented");
  }

  cmyk() {
    throw new Error("cmyk() is not implemented");
  }

  get(key) {
    return this.table.get(key);
  }

  set(key, value) {
    return this.table.set(key, value);
  }

  getOrSet(key, value = null) {
    if (value == null) {
      return this.get(key);
    }
    this.set(key, value);
    return this;
  }

  values() {
    return this.table.values();
  }
}

export class Rgb extends Space {
  static KEY_R = "r";
  static KEY_G = "g";
  static KEY_B = "b";

  constructor(r, g, b) {
    super([[Rgb.KEY_R, r], [Rgb.KEY_G, g], [Rgb.KEY_B, b]]);
  }

  toString() {
    return `rgb(${this.r()}, ${this.g()}, ${this.b()})`;
  }

  isValid() {
    let values = this.values();
    for (let value of values) {
      if (value < 0x00 || value > 0xFF) {
        return false;
      }
    }
    return true;
  }

  clone() {
    return new Rgb(this.r(), this.g(), this.b());
  }

  r(value = null) {
    return this.getOrSet(Rgb.KEY_R, value);
  }

  g(value = null) {
    return this.getOrSet(Rgb.KEY_G, value);
  }

  b(value = null) {
    return this.getOrSet(Rgb.KEY_B, value);
  }

  hex() {
    let parts = [];
    for (let value of this.values()) {
      let text = value.toString(16);
      if (text.length === 1) {
        text = `0${text}`;
      }
      parts.push(text.toUppderCase());
    }
    return `#${parts.join('')}`;
  }

  rgb() {
    return this;
  }

  hsl() {
    let r = this.r() / 0xFF;
    let g = this.g() / 0xFF;
    let b = this.b() / 0xFF;

    let max   = Math.max(r, g, b);
    let min   = Math.min(r, g, b);
    let delta = max - min;
    if (delta === 0) {
      return new Hsl(0, 0, max);
    }

    let h = 0;
    if (max === r) {
      h = 60 * ((g - b) / delta % 360);
    } else if (max === g) {
      h = 60 * ((b - r) / delta + 2);
    } else if (max === b) {
      h = 60 * ((r - g) / delta + 4);
    }

    let l = (max + min) / 2;

    let s = delta / (1 - Math.abs(2 * l - 1))

    return new Hsl(h, s, l);
  }

  cmyk() {
    let r = this.r() / 0xFF;
    let g = this.g() / 0xFF;
    let b = this.b() / 0xFF;

    let k = 1 - Math.max(r, g, b);
    if (k === 1) {
      return new Cmyk(0, 0, 0, 1);
    }

    let c = (1 - r - k) / (1 - k);
    let m = (1 - g - k) / (1 - k);
    let y = (1 - b - k) / (1 - k);
    return new Cmyk(c, m, y, k);
  }
}

export class Hsl extends Space {
  static KEY_H = "h";
  static KEY_S = "s";
  static KEY_L = "l";

  constructor(h, s, l) {
    super([[Hsl.KEY_H, h], [Hsl.KEY_S, s], [Hsl.KEY_L, l]]);
  }

  toString() {
    return `hsl(${this.h()}, ${this.s()}%, ${this.l()}%)`;
  }

  clone() {
    return new Hsl(this.h(), this.s(), this.l());
  }

  isValid() {
    let h = this.h();
    if (!Number.isFinite(h) || h < 0 || h > 360) {
      return false;
    }

    let s = this.s();
    if (!Number.isFinite(s) || s < 0 || s > 100) {
      return false;
    }

    let l = this.l();
    if (!Number.isFinite(l) || l < 0 || l > 100) {
      return false;
    }
    return true;
  }

  h(value = null) {
    return this.getOrSet(Hsl.KEY_H, value);
  }

  s(value = null) {
    return this.getOrSet(Hsl.KEY_S, value);
  }

  l(value = null) {
    return this.getOrSet(Hsl.KEY_L, value);
  }

  hex() {
    return this.rgb().hex();
  }

  rgb() {
    let h = this.h();
    let s = this.s();
    let l = this.l();
    if (s === 0) {
      let value = Math.round(l * 0xFF);
      return new Rgb(value, value, value);
    }

    let m2 = 0;
    if (l < 0.5) {
      m2 = l * (s + 1);
    } else {
      m2 = l + s - l * s;
    }

    let m1 = 2 * l - m2;
    let r = Math.round(255 * Hsl.hueToRgb(m1, m2, h / 360 + 1 / 3));
    let g = Math.round(255 * Hsl.hueToRgb(m1, m2, h / 360));
    let b = Math.round(255 * Hsl.hueToRgb(m1, m2, h / 360 - 1 / 3));
    return new Rgb(r, g, b)
  }

  hsl() {
    return this;
  }

  cmyk() {
    return this.rgb().cmyk();
  }

  static hueToRgb(m1, m2, h) {
    if (h < 0) {
      h += 1;
    } else if (h > 1) {
      h -= 1;
    }

    if (h * 6 < 1) {
      return m1 + (m2 - m1) * h * 6;
    } else if (h * 2 < 1) {
      return m2;
    } else if (h * 3 < 2) {
      return m1 + (m2 - m1) * (2 / 3 - h) * 6;
    }
    return m1;
  }
}

export class Cmyk extends Space {
  static KEY_C = 'c';
  static KEY_M = 'm';
  static KEY_Y = 'y';
  static KEY_K = 'k';

  constructor(c, m, y, k) {
    super([[Cmyk.KEY_C, c], [Cmyk.KEY_M, m], [Cmyk.KEY_Y, y], [Cmyk.KEY_K]]);
  }

  isValid() {
    for (let value of this.values()) {
      if (!Number.isFinite(value)) {
        return false;
      }
      if (value < 0 || value > 1) {
        return false;
      }
    }
    return true;
  }

  clone() {
    return new Cmyk(this.c(), this.m(), this.y(), this.k());
  }

  c(value = null) {
    return this.getOrSet(Cmyk.KEY_C, value);
  }

  m(value = null) {
    return this.getOrSet(Cmyk.KEY_M, value);
  }

  y(value = null) {
    return this.getOrSet(Cmyk.KEY_Y, value);
  }

  k(value = null) {
    return this.getOrSet(Cmyk.KEY_K, value);
  }

  hex() {
    return this.rgb().hex();
  }

  rgb() {
    let k = this.k();
    if (k === 1) {
      return new Rgb(0, 0, 0);
    }

    let r = 0xFF * (1 - this.c()) * (1 - k);
    let g = 0xFF * (1 - this.m()) * (1 - k);
    let b = 0xFF * (1 - this.y()) * (1 - k);
    return new Rgb(r, g, b);
  }
}
<|endoftext|>


<commit_before>"use strict";

// Using "use strict" global

(function () {
    window.api = {
        getGeneInformation: function () {
        }
    };
})();
<commit_msg>first gene database helper function working<commit_after>"use strict";

// Using "use strict" global

(function ($) {
    window.api = {
        getGeneInformation: function (symbol) {
            var getUniProtInfo = function (geneSymbol) {
                return $.get("http://www.uniprot.org/uploadlists/", {
                    from: "GENENAME",
                    to: "ACC",
                    format: "tab",
                    taxon: "559292",
                    query: geneSymbol
                }).then(function (data) {
                    var regex = new RegExp(geneSymbol + "[ \t\r\n\v\f]*([A-Z0-9]+)", "gm");
                    var id = regex.exec(data)[1];
                    return $.get({
                        url: "http://www.uniprot.org/uniprot/" + id + ".xml",
                        crossDomain: true,
                    });
                }).then(function (info) {
                    console.log(info);
                });
            };
            getUniProtInfo(symbol);
        }
    };
})($);
<|endoftext|>


<commit_before>const express = require("express");
const router  = express.Router();
const usersController = require('../controllers').users;
require("dotenv").config()

const Users = require('../models').Users;

const cookieParser = require('cookie-parser');
const session = require('express-session');
const flash    = require('connect-flash');

const cors = require('cors');

const corsOptions = {
  origin: 'http://localhost:3000',
  optionSuccessStatus: 200,
  credentials: true
}
router.use(cors(corsOptions));

router.use(cookieParser());

router.use(flash()); // use connect-flash for flash messages stored in session

//passport JS configuation
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
const FacebookStrategy = require('passport-facebook').Strategy;

// Use the GoogleStrategy within Passport.
//   Strategies in Passport require a `verify` function, which accept
//   credentials (in this case, an accessToken, refreshToken, and Google
//   profile), and invoke a callback with a user object.
passport.use(new GoogleStrategy({
    clientID: process.env.CLIENTID,
    clientSecret: process.env.CLIENTSECRET,
    callbackURL: "http://localhost:3001/users/auth/google/callback"
  },
  function(accessToken, refreshToken, profile, done) {
       usersController.findOrCreate({firstName:profile._json.name.givenName, lastName:profile._json.name.familyName, image:profile._json.image.url, passportId:profile.id}).then((user) => {
        console.log('THIS LINE USER: =====> ', user)
        return done(null, user[0]);
       })

       //  , function (err, user) {
       //   return done(err, user);
       // });
  }
));

// For FACEBOOK

passport.use(new FacebookStrategy({
    clientID: process.env.APPID,
    clientSecret: process.env.APPSECRET,
    callbackURL: "http://localhost:3001/users/auth/facebook/callback",
    profileFields: ['id', 'displayName', 'picture.type(large)', "name", "email"]
  },
  function(accessToken, refreshToken, profile, done) {
    console.log(profile);
    console.log("Facebook Name: ", profile.displayName)
    console.log("Facebook ID: ", profile.id)
    console.log("image url: ", profile.photos[0].value)
    console.log("Done: ", done)

     usersController.findOrCreate({firstName:profile.name.givenName, lastName:profile.name.familyName, image:profile.photos[0].value, passportId:profile.id}, function (err, user) {
       return done(err, user);
     });
  }
));

//sequealize will be passed in here.
// Passport session setup.
//
//   For persistent logins with sessions, Passport needs to serialize users into
//   and deserialize users out of the session. Typically, this is as simple as
//   storing the user ID when serializing, and finding the user by ID when
//   deserializing.
passport.serializeUser(function(user, done) {
  console.log("USER===>", user.id);
  done(null, user.id);
});

passport.deserializeUser(function(id, done) {
  console.log("deserialize user id ==>", id);
  Users.findById(id).then( function(user) {
    console.log("Users.findby ===> ", user);
    done( user);
  })
});

module.exports = () => {
  // Attempting to show the user information in the localhost 3000
  router.get('http://localhost:3000', (req, res) => {
    console.log("Get Root Request is succeeded!!!!!")
    console.log("Session Id ===> ", connect.sid)
    // res.send(user[0])
  })

  router.use(session({
    secret: 'keyboard'
  }));
  // INITIALIZE PASSPORT got the example from https://github.com/barberboy/passport-google-oauth2-example/blob/master/app.js
  router.use(passport.initialize());
  router.use(passport.session());

  // GET /auth/google
  //   Use passport.authenticate() as route middleware to authenticate the
  //   request.  The first step in Google authentication will involve
  //   redirecting the user to google.com.  After authorization, Google
  //   will redirect the user back to this application at /auth/google/callback
  router.get('/auth/google',
    passport.authenticate('google', { scope: ['https://www.googleapis.com/auth/plus.login'] }));

  // GET /auth/google/callback
  //   Use passport.authenticate() as route middleware to authenticate the
  //   request.  If authentication fails, the user will be redirected back to the
  //   login page.  Otherwise, the primary route function function will be called,
  //   which, in this example, will redirect the user to the home page.
  router.get('/auth/google/callback',
    passport.authenticate('google', { successRedirect: "http://localhost:3000",
                                      failureRedirect: '/login' }),
    function(req, res) {
      console.log("THIS IS THE SUCCESS CODE")
      req.session.save(function() {
        res.redirect('http://localhost:3000');
      })
      // res.redirect('http://localhost:3000');
    });

  // facebook
  // Redirect the user to Facebook for authentication.  When complete,
  // Facebook will redirect the user back to the application at
  //     /auth/facebook/callback
  router.get('/auth/facebook',
  passport.authenticate('facebook', { scope : ['public_profile', 'user_photos']}));

  // Facebook will redirect the user to this URL after approval.  Finish the
  // authentication process by attempting to obtain an access token.  If
  // access was granted, the user will be logged in.  Otherwise,
  // authentication has failed.
  router.get('/auth/facebook/callback',
    passport.authenticate('facebook', { successRedirect: '/',
                                        failureRedirect: '/login' }));

  router.get("/", (req, res) => {
    // get info from redis client
    // fetch("http://localhost:3001/users", {credentials: 'include', mode: 'cors', 'Access-Control-Allow-Credentials': true }).then((req) => console.log(req))
    console.log('req.user==>', req.user)
    res.send('ok')
  });

    //Use quick/dirty estimate that 1m in y is ~0.00001 degre (of latitude) and 1m in x is 0.00001 in x
    //find friends within 100m
  router.get('/nearby/:lat/:lng/:id', (req, res) => {
    console.log(req.params)
    let latMin = Number(req.params.lat) -0.0001;
    let latMax = Number(req.params.lat) +0.0001;
    let lngMin = Number(req.params.lng) -0.0001;
    let lngMax = Number(req.params.lng) +0.0001;
    console.log('latmin', latMin)
    console.log('latmax', latMax)
    console.log('lngMin', lngMin)
    console.log('lngMax', lngMax)
    usersController.findUsersNearby({latMin, latMax, lngMin, lngMax, id:req.params.id}).then((users) => {
      console.log(users);
      res.send(users)
    })
  })

  return router;
}
<commit_msg>Finished implementing req.user<commit_after>const express = require("express");
const router  = express.Router();
const usersController = require('../controllers').users;
require("dotenv").config()

const Users = require('../models').Users;

const cookieParser = require('cookie-parser');
const session = require('express-session');
const flash    = require('connect-flash');

const cors = require('cors');

const corsOptions = {
  origin: 'http://localhost:3000',
  optionSuccessStatus: 200,
  credentials: true
}
router.use(cors(corsOptions));

router.use(cookieParser());

router.use(flash()); // use connect-flash for flash messages stored in session

//passport JS configuation
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
const FacebookStrategy = require('passport-facebook').Strategy;

// Use the GoogleStrategy within Passport.
//   Strategies in Passport require a `verify` function, which accept
//   credentials (in this case, an accessToken, refreshToken, and Google
//   profile), and invoke a callback with a user object.
passport.use(new GoogleStrategy({
    clientID: process.env.CLIENTID,
    clientSecret: process.env.CLIENTSECRET,
    callbackURL: "http://localhost:3001/users/auth/google/callback"
  },
  function(accessToken, refreshToken, profile, done) {
       usersController.findOrCreate({firstName:profile._json.name.givenName, lastName:profile._json.name.familyName, image:profile._json.image.url, passportId:profile.id}).then((user) => {
        console.log('THIS LINE USER: =====> ', user)
        return done(null, user[0]);
       })

       //  , function (err, user) {
       //   return done(err, user);
       // });
  }
));

// For FACEBOOK

passport.use(new FacebookStrategy({
    clientID: process.env.APPID,
    clientSecret: process.env.APPSECRET,
    callbackURL: "http://localhost:3001/users/auth/facebook/callback",
    profileFields: ['id', 'displayName', 'picture.type(large)', "name", "email"]
  },
  function(accessToken, refreshToken, profile, done) {
    console.log(profile);
    console.log("Facebook Name: ", profile.displayName)
    console.log("Facebook ID: ", profile.id)
    console.log("image url: ", profile.photos[0].value)
    console.log("Done: ", done)

     usersController.findOrCreate({firstName:profile.name.givenName, lastName:profile.name.familyName, image:profile.photos[0].value, passportId:profile.id}, function (err, user) {
       return done(err, user);
     });
  }
));

//sequealize will be passed in here.
// Passport session setup.
//
//   For persistent logins with sessions, Passport needs to serialize users into
//   and deserialize users out of the session. Typically, this is as simple as
//   storing the user ID when serializing, and finding the user by ID when
//   deserializing.
passport.serializeUser(function(user, done) {
  console.log("USER===>", user.id);
  done(null, user.id);
});

passport.deserializeUser(function(id, done) {
  console.log("deserialize user id ==>", id);
  Users.findById(id).then( function(user) {
    console.log("Users.findby ===> ", user);
    done(null, user);
  })
});

module.exports = () => {
  // Attempting to show the user information in the localhost 3000
  router.get('http://localhost:3000', (req, res) => {
    console.log("Get Root Request is succeeded!!!!!")
    console.log("Session Id ===> ", connect.sid)
    // res.send(user[0])
  })

  router.use(session({
    secret: 'keyboard'
  }));
  // INITIALIZE PASSPORT got the example from https://github.com/barberboy/passport-google-oauth2-example/blob/master/app.js
  router.use(passport.initialize());
  router.use(passport.session());

  // GET /auth/google
  //   Use passport.authenticate() as route middleware to authenticate the
  //   request.  The first step in Google authentication will involve
  //   redirecting the user to google.com.  After authorization, Google
  //   will redirect the user back to this application at /auth/google/callback
  router.get('/auth/google',
    passport.authenticate('google', { scope: ['https://www.googleapis.com/auth/plus.login'] }));

  // GET /auth/google/callback
  //   Use passport.authenticate() as route middleware to authenticate the
  //   request.  If authentication fails, the user will be redirected back to the
  //   login page.  Otherwise, the primary route function function will be called,
  //   which, in this example, will redirect the user to the home page.
  router.get('/auth/google/callback',
    passport.authenticate('google', { successRedirect: "http://localhost:3000",
                                      failureRedirect: '/login' }),
    function(req, res) {
      console.log("THIS IS THE SUCCESS CODE")
      req.session.save(function() {
        res.redirect('http://localhost:3000');
      })
      // res.redirect('http://localhost:3000');
    });

  // facebook
  // Redirect the user to Facebook for authentication.  When complete,
  // Facebook will redirect the user back to the application at
  //     /auth/facebook/callback
  router.get('/auth/facebook',
  passport.authenticate('facebook', { scope : ['public_profile', 'user_photos']}));

  // Facebook will redirect the user to this URL after approval.  Finish the
  // authentication process by attempting to obtain an access token.  If
  // access was granted, the user will be logged in.  Otherwise,
  // authentication has failed.
  router.get('/auth/facebook/callback',
    passport.authenticate('facebook', { successRedirect: '/',
                                        failureRedirect: '/login' }));

  router.get("/", (req, res) => {
    // get info from redis client
    // fetch("http://localhost:3001/users", {credentials: 'include', mode: 'cors', 'Access-Control-Allow-Credentials': true }).then((req) => console.log(req))
    console.log('req.user==>', req.user)
    res.send('ok')
  });

    //Use quick/dirty estimate that 1m in y is ~0.00001 degre (of latitude) and 1m in x is 0.00001 in x
    //find friends within 100m
  router.get('/nearby/:lat/:lng/:id', (req, res) => {
    console.log(req.params)
    let latMin = Number(req.params.lat) -0.0001;
    let latMax = Number(req.params.lat) +0.0001;
    let lngMin = Number(req.params.lng) -0.0001;
    let lngMax = Number(req.params.lng) +0.0001;
    console.log('latmin', latMin)
    console.log('latmax', latMax)
    console.log('lngMin', lngMin)
    console.log('lngMax', lngMax)
    usersController.findUsersNearby({latMin, latMax, lngMin, lngMax, id:req.params.id}).then((users) => {
      console.log(users);
      res.send(users)
    })
  })

  return router;
}
<|endoftext|>