<commit_before>const fs = require('fs')
const inquirer = require('inquirer')

const { fileExist, writeFile } = require('./fs.utils')
const { log } = require('./log.utils')
const { gitClone } = require('./git.utils')

const URL_REGEX = /^((?:(https?):\/\/)?((?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]|[0-9])\.(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]|[0-9])\.)(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]|[0-9])\.)(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]|[0-9]))|(?:(?:(?:\w+\.){1,2}[\w]{2,3})))(?::(\d+))?((?:\/[\w]+)*)(?:\/|(\/[\w]+\.[\w]{3,4})|(\?(?:([\w]+=[\w]+)&)*([\w]+=[\w]+))?|\?(?:(wsdl|wadl))))$/
const PATH_REGEX = /^(?:(?:~|\.{1,2})?\/)+(?:[a-zA-Z\.\-\_]+\/?)*$/

module.exports = exports = configFilename => {
  return options => {
    const userForceOverwrite = options.force || false
    const questions = [
      {
        name: 'overwrite_file',
        message: 'A configuration file already exist. Do you want to continue ?',
        type: 'confirm',
        when: () => fileExist(configFilename) && !userForceOverwrite
      },
      {
        name: 'repo_url',
        message: 'Repository url:',
        type: 'input',
        validate: url => URL_REGEX.test(url),
        when: data => !fileExist(configFilename) || data.overwrite_file || userForceOverwrite
      },
      {
        name: 'folder_path',
        message: 'Folder path:',
        type: 'input',
        validate: path => PATH_REGEX.test(path),
        when: data => !fileExist(configFilename) || data.overwrite_file || userForceOverwrite
      }
    ]

    inquirer.prompt(questions)
      .then(({ repo_url = null, folder_path, overwrite_file = true }) => {
        if (!overwrite_file) {
          throw new Error('user_stop_init')
        }

        return writeFile(configFilename, JSON.stringify(data, null, 4))
          .then(() => ({ repoUrl: repo_url, folderPath: folder_path }))
      })
      .then(data => {
        const { folderPath } = data
        if (!fileExist(folderPath)) {
          log({ type: 'info', message: 'Folder does not exist. It will be created.' })
          fs.mkdirSync(folderPath)
        }

        const isDirectory = fs.statSync(folderPath).isDirectory()
        if (!isDirectory) {
          throw new Error('folder_is_not_directory')
        }

        const folderIsEmpty = fs.readdirSync(folderPath).length < 1
        if (!folderIsEmpty) {
          throw new Error('folder_is_not_empty')
        }

        return data
      })
      .then(data => {
        if (data.repoUrl == null) {
          log({ type: 'warn', message: 'Impossible to cloned git repository. Need repository URL.' })
          return data
        }

        return gitClone(data.repoUrl, data.folderPath)
          .then(repo => {
            log({ type: 'info', message: 'Git repository cloned successuly.' })
            return data
          })
      })
      .catch(error => {
        switch (error.message) {
          case 'folder_is_not_directory':
            log({ type: 'error', message: `Path doesn't corresponding to a folder.` })
            break
          case 'folder_is_not_empty':
            log({ type: 'error', message: 'Folder is not empty.' })
            break
          case 'user_stop_init':
            log({ message: 'You stopped the command. Nothing has be made.' })
            break
          default:
            log({ type: 'error', message: 'An error occured.', prefix: ' Fail ' })
        }
      })
  }
}
<commit_msg>Fix bug on config file writting<commit_after>const fs = require('fs')
const inquirer = require('inquirer')

const { fileExist, writeFile } = require('./fs.utils')
const { log } = require('./log.utils')
const { gitClone } = require('./git.utils')

const URL_REGEX = /^((?:(https?):\/\/)?((?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]|[0-9])\.(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]|[0-9])\.)(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]|[0-9])\.)(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]|[0-9]))|(?:(?:(?:\w+\.){1,2}[\w]{2,3})))(?::(\d+))?((?:\/[\w]+)*)(?:\/|(\/[\w]+\.[\w]{3,4})|(\?(?:([\w]+=[\w]+)&)*([\w]+=[\w]+))?|\?(?:(wsdl|wadl))))$/
const PATH_REGEX = /^(?:(?:~|\.{1,2})?\/)+(?:[a-zA-Z\.\-\_]+\/?)*$/

module.exports = exports = configFilename => {
  return options => {
    const userForceOverwrite = options.force || false
    const questions = [
      {
        name: 'overwrite_file',
        message: 'A configuration file already exist. Do you want to continue ?',
        type: 'confirm',
        when: () => fileExist(configFilename) && !userForceOverwrite
      },
      {
        name: 'repo_url',
        message: 'Repository url:',
        type: 'input',
        validate: url => URL_REGEX.test(url),
        when: data => !fileExist(configFilename) || data.overwrite_file || userForceOverwrite
      },
      {
        name: 'folder_path',
        message: 'Folder path:',
        type: 'input',
        validate: path => PATH_REGEX.test(path),
        when: data => !fileExist(configFilename) || data.overwrite_file || userForceOverwrite
      }
    ]

    inquirer.prompt(questions)
      .then(({ repo_url = null, folder_path, overwrite_file = true }) => {
        if (!overwrite_file) {
          throw new Error('user_stop_init')
        }

        return writeFile(configFilename, JSON.stringify({ repo_url, folder_path }, null, 4))
          .then(() => ({ repoUrl: repo_url, folderPath: folder_path }))
      })
      .then(data => {
        const { folderPath } = data
        if (!fileExist(folderPath)) {
          log({ type: 'info', message: 'Folder does not exist. It will be created.' })
          fs.mkdirSync(folderPath)
        }

        const isDirectory = fs.statSync(folderPath).isDirectory()
        if (!isDirectory) {
          throw new Error('folder_is_not_directory')
        }

        const folderIsEmpty = fs.readdirSync(folderPath).length < 1
        if (!folderIsEmpty) {
          throw new Error('folder_is_not_empty')
        }

        return data
      })
      .then(data => {
        if (data.repoUrl == null) {
          log({ type: 'warn', message: 'Impossible to cloned git repository. Need repository URL.' })
          return data
        }

        return gitClone(data.repoUrl, data.folderPath)
          .then(repo => {
            log({ type: 'info', message: 'Git repository cloned successuly.' })
            return data
          })
      })
      .catch(error => {
        switch (error.message) {
          case 'folder_is_not_directory':
            log({ type: 'error', message: `Path doesn't corresponding to a folder.` })
            break
          case 'folder_is_not_empty':
            log({ type: 'error', message: 'Folder is not empty.' })
            break
          case 'user_stop_init':
            log({ message: 'You stopped the command. Nothing has be made.' })
            break
          default:
            log({ type: 'error', message: 'An error occured.', prefix: ' Fail ' })
        }
      })
  }
}
<|endoftext|>


<commit_before>/* jshint browser: true, node: false */

(function() {
  'use strict';

  var reEmail = /^[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,}$/i;

  var organization          = document.getElementById('organization');
  var fname                 = document.getElementById('fname');
  var lname                 = document.getElementById('lname');
  var workplace             = document.getElementById('workplace');
  var organizationFreetext  = document.getElementById('organizationFreetext');
  var username              = document.getElementById('username');
  var email                 = document.getElementById('email');
  var emailP                = document.getElementById('emailP');
  var password              = document.getElementById('password');
  var passwordV             = document.getElementById('passwordV');

  function setError(el, bool) {
    if(bool) {
      el.style.boxShadow = '#FF0000 0px 0px 1.5px 1px';
      el.parentNode.style.color = '#FF0000';
    } else {
      el.style.boxShadow = '';
      el.parentNode.style.color = '';
    }
  }

  organization.onchange = function() {
    document.getElementById('afterOrgPick').style.display = 'block';
    if(organization.dataset && organization.dataset.orgfreetext) {
      if(organization.dataset.orgfreetext.split(',').indexOf(organization.value) !== -1) {
        organizationFreetext.parentNode.style.display = 'block';
      } else {
        organizationFreetext.parentNode.style.display = 'none';
      }
    }
  };

  document.getElementsByTagName('form')[0].onsubmit = function() {
    var valid = true;
    if(!reEmail.test(email.value)) {
      setError(email, true);
      valid = false;
    } else {
      setError(email, false);
    }
    if(emailP.value && !reEmail.test(emailP.value)) {
      setError(emailP, true);
      valid = false;
    } else {
      setError(emailP, false);
    }
    if(!username.value || username.value.length < 5) {
      setError(username, true);
      valid = false;
    } else {
      setError(username, false);
    }
    var listCheck = [fname, lname, workplace, password, passwordV];
    if(organization.dataset && organization.dataset.orgfreetext) {
      if(organization.dataset.orgfreetext.split(',').indexOf(organization.value) !== -1) {
        listCheck.push(organizationFreetext);
      }
    }
    for (var i = listCheck.length - 1; i >= 0; i--) {
      if(!listCheck[i].value) {
        setError(listCheck[i], true);
        valid = false;
      } else {
        setError(listCheck[i], false);
      }
    }
    return valid;
  };
})();
<commit_msg>Fix freetextorg not hiding<commit_after>/* jshint browser: true, node: false */

(function() {
  'use strict';

  var reEmail = /^[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,}$/i;

  var organization          = document.getElementById('organization');
  var fname                 = document.getElementById('fname');
  var lname                 = document.getElementById('lname');
  var workplace             = document.getElementById('workplace');
  var organizationFreetext  = document.getElementById('organizationFreetext');
  var username              = document.getElementById('username');
  var email                 = document.getElementById('email');
  var emailP                = document.getElementById('emailP');
  var password              = document.getElementById('password');
  var passwordV             = document.getElementById('passwordV');

  function setError(el, bool) {
    if(bool) {
      el.style.boxShadow = '#FF0000 0px 0px 1.5px 1px';
      el.parentNode.style.color = '#FF0000';
    } else {
      el.style.boxShadow = '';
      el.parentNode.style.color = '';
    }
  }

  organization.onchange = function() {
    document.getElementById('afterOrgPick').style.display = 'block';
    if(organization.dataset && organization.dataset.orgfreetext) {
      if(organization.dataset.orgfreetext.split(',').indexOf(organization.value) !== -1) {
        organizationFreetext.parentNode.style.display = 'block';
      } else {
        organizationFreetext.parentNode.style.display = 'none';
      }
    } else {
      organizationFreetext.parentNode.style.display = 'none';
    }
  };

  document.getElementsByTagName('form')[0].onsubmit = function() {
    var valid = true;
    if(!reEmail.test(email.value)) {
      setError(email, true);
      valid = false;
    } else {
      setError(email, false);
    }
    if(emailP.value && !reEmail.test(emailP.value)) {
      setError(emailP, true);
      valid = false;
    } else {
      setError(emailP, false);
    }
    if(!username.value || username.value.length < 5) {
      setError(username, true);
      valid = false;
    } else {
      setError(username, false);
    }
    var listCheck = [fname, lname, workplace, password, passwordV];
    if(organization.dataset && organization.dataset.orgfreetext) {
      if(organization.dataset.orgfreetext.split(',').indexOf(organization.value) !== -1) {
        listCheck.push(organizationFreetext);
      }
    }
    for (var i = listCheck.length - 1; i >= 0; i--) {
      if(!listCheck[i].value) {
        setError(listCheck[i], true);
        valid = false;
      } else {
        setError(listCheck[i], false);
      }
    }
    return valid;
  };
})();
<|endoftext|>


<commit_before>(function($){
        var specEditor;
        var sourceEditor;

	window.tryIt = function() {
		$('.spec-runner').html($('.loading.template').html());
		$('#sandbox').remove();
		$($('.sandbox.template').html()).appendTo('body').load(function() {
			$('.spec-runner').html('');
			Sandbox().runSpecs();
		});
	};

	//Define the little iframe sandbox
	window.Sandbox = function(){
		var self = $('#sandbox').get(0).contentWindow;

		self.runSpecs = function() {
			hideErrors();
	                self.jasmine.getEnv().addReporter(new self.jasmine.TrivialReporter({
				location: window.document.location,
				body: $('.spec-runner')[0]
			}));
			self.execute(specEditor);
			self.execute(sourceEditor);
			self.jasmine.getEnv().execute();
		};
		self.execute = function(editor) {
                        var script = editor.getSession().getValue();
			localStorage[name] = script;
			try {
				self.eval(script);
			} catch(e) {
				//Well, maybe it's just coffeescript.
				try {
					self.eval(CoffeeScript.compile(script, { bare: true }));
				} catch(coffeeError) {
					showError(name);
					throw coffeeError;
				}
			}
		};

		var hideErrors = function() {
			$('.flash').html('').hide();
			$('textarea.error, .runner-wrap').removeClass('error');
		};

		var showError = function(name) {
			$('.flash').fadeIn().append("
Uh oh, it looks like your JavaScript "+(name === 'specs' ? 'specs have' : 'source has')+" a parse error!
");
			$('.runner-wrap, #'+name).addClass('error');
		};

		return self;
	};

	window.templates = {
		stillDefault: function(name, editor) {
			return this.getDefault(name) === editor.getSession().getValue();
		},
		getDefault: function(name) {
			return $.trim($('#default-'+name).text());
		},
		renderDefault: function(name, editor) {
			var script = this.getDefault(name, editor);
			if((localStorage[name] && script !== localStorage[name])) {
				$('.clear-saved').show().css('display','inline-block');
			}
                        if (!editor) {return;}
                        editor.getSession().setValue(localStorage[name] || script);
		},
		init: function() {
			this.renderDefault('specs', specEditor);
			this.renderDefault('src', sourceEditor);
		},
		goCoffee: function() {
			if((this.stillDefault('specs', specEditor) && this.stillDefault('src', sourceEditor))
					|| confirm('overwrite your code with a sampling of CoffeeScript?')) {
                                codeBoxes.switchToCoffeeScriptMode();
                                specEditor.getSession().setValue(this.getDefault('coffee-specs'));
                                sourceEditor.getSession().setValue(this.getDefault('coffee-src'));
			}
		}
	};

	//Eventy stuff
	$('.try-it.button').live('click',function(e){
		e.preventDefault();
		tryIt();
	});
  $('html, body').add(document.body).keydown(function(e){
    if(e.which == 13 && (e.ctrlKey || e.metaKey)) {
      e.preventDefault();
      tryIt();
    }
  });
	$('.source').live('keydown',function(e) {
		if(e.keyCode === 9) { //TAB
			e.preventDefault();
			if(e.shiftKey !== true) {
				$(this).insertAtCaret('  ');
			}
		}
	});
	$('.button.insert').live('click',function(e) {
		e.preventDefault();
                specEditor.insert($(this).data('snippet'));
	});
	$('.clear-saved').live('click',function(e) {
		e.preventDefault();
		delete localStorage['specs'];
		delete localStorage['src'];
		$(this).hide();
		templates.init();
	});
	$('.coffee.button').live('click',function(e){
		e.preventDefault();
		templates.goCoffee();
	});
       window.codeBoxes = {
         setupCodeBoxes: function(){ if ($('#spec-editor').length){
                specEditor = ace.edit("spec-editor");
                specEditor.setTheme("ace/theme/textmate"); var
                JavaScriptMode = require("ace/mode/javascript").Mode;
                specEditor.getSession().setMode(new JavaScriptMode());
                $('#specs').hide(); }

                if ($('#source-editor').length){
                        sourceEditor = ace.edit("source-editor");
                        sourceEditor.setTheme("ace/theme/textmate");
                        sourceEditor.getSession().setMode(new
                        JavaScriptMode()); $('#src').hide();
                }
          },
         switchToCoffeeScriptMode: function(){
         var CoffeeScriptMode = require("ace/mode/coffee").Mode;
                specEditor.getSession().setMode(new CoffeeScriptMode());
                sourceEditor.getSession().setMode(new CoffeeScriptMode());
         },

         getSpecEditor: function(){
                return specEditor;
         },

         getSourceEditor: function(){
                return sourceEditor;
         }

       }

	//Dom-ready
	$(function(){
                codeBoxes.setupCodeBoxes();
		templates.init();
	});

})(jQuery);
<commit_msg>fixing tons of whitespace. every line changed :/<commit_after>(function($){
  var specEditor;
  var sourceEditor;

  window.tryIt = function() {
    $('.spec-runner').html($('.loading.template').html());
    $('#sandbox').remove();
    $($('.sandbox.template').html()).appendTo('body').load(function() {
      $('.spec-runner').html('');
      Sandbox().runSpecs();
    });
  };

  //Define the little iframe sandbox
  window.Sandbox = function(){
    var self = $('#sandbox').get(0).contentWindow;

    self.runSpecs = function() {
      hideErrors();
      self.jasmine.getEnv().addReporter(new self.jasmine.TrivialReporter({
        location: window.document.location,
        body: $('.spec-runner')[0]
      }));
      self.execute(specEditor);
      self.execute(sourceEditor);
      self.jasmine.getEnv().execute();
    };
    self.execute = function(editor) {
      var script = editor.getSession().getValue();
      localStorage[name] = script;
      try {
        self.eval(script);
      } catch(e) {
        //Well, maybe it's just coffeescript.
        try {
          self.eval(CoffeeScript.compile(script, { bare: true }));
        } catch(coffeeError) {
          showError(name);
          throw coffeeError;
        }
      }
    };

    var hideErrors = function() {
      $('.flash').html('').hide();
      $('textarea.error, .runner-wrap').removeClass('error');
    };

    var showError = function(name) {
      $('.flash').fadeIn().append("
Uh oh, it looks like your JavaScript "+(name === 'specs' ? 'specs have' : 'source has')+" a parse error!
");
      $('.runner-wrap, #'+name).addClass('error');
    };

    return self;
  };

  window.templates = {
    stillDefault: function(name, editor) {
      return this.getDefault(name) === editor.getSession().getValue();
    },
    getDefault: function(name) {
      return $.trim($('#default-'+name).text());
    },
    renderDefault: function(name, editor) {
      var script = this.getDefault(name, editor);
      if((localStorage[name] && script !== localStorage[name])) {
        $('.clear-saved').show().css('display','inline-block');
      }
      if (!editor) {return;}
        editor.getSession().setValue(localStorage[name] || script);
      },
    init: function() {
      this.renderDefault('specs', specEditor);
      this.renderDefault('src', sourceEditor);
    },
    goCoffee: function() {
      if((this.stillDefault('specs', specEditor) && this.stillDefault('src', sourceEditor))
        || confirm('overwrite your code with a sampling of CoffeeScript?')) {
        codeBoxes.switchToCoffeeScriptMode();
        specEditor.getSession().setValue(this.getDefault('coffee-specs'));
        sourceEditor.getSession().setValue(this.getDefault('coffee-src'));
      }
    }
  };

  //Eventy stuff
  $('.try-it.button').live('click',function(e){
    e.preventDefault();
    tryIt();
  });
  $('html, body').add(document.body).keydown(function(e){
    if(e.which == 13 && (e.ctrlKey || e.metaKey)) {
      e.preventDefault();
      tryIt();
    }
  });
  $('.source').live('keydown',function(e) {
    if(e.keyCode === 9) { //TAB
      e.preventDefault();
      if(e.shiftKey !== true) {
        $(this).insertAtCaret('  ');
      }
    }
  });
  $('.button.insert').live('click',function(e) {
    e.preventDefault();
    specEditor.insert($(this).data('snippet'));
  });
  $('.clear-saved').live('click',function(e) {
    e.preventDefault();
    delete localStorage['specs'];
    delete localStorage['src'];
    $(this).hide();
    templates.init();
  });
  $('.coffee.button').live('click',function(e){
    e.preventDefault();
    templates.goCoffee();
  });

  window.codeBoxes = {
    setupCodeBoxes: function(){
      if ($('#spec-editor').length){
        specEditor = ace.edit("spec-editor");
        specEditor.setTheme("ace/theme/textmate"); var
        JavaScriptMode = require("ace/mode/javascript").Mode;
        specEditor.getSession().setMode(new JavaScriptMode());
        $('#specs').hide();
      }
      if ($('#source-editor').length){
        sourceEditor = ace.edit("source-editor");
        sourceEditor.setTheme("ace/theme/textmate");
        sourceEditor.getSession().setMode(new
        JavaScriptMode()); $('#src').hide();
      }
    },
    switchToCoffeeScriptMode: function(){
      var CoffeeScriptMode = require("ace/mode/coffee").Mode;
      specEditor.getSession().setMode(new CoffeeScriptMode());
      sourceEditor.getSession().setMode(new CoffeeScriptMode());
    },
    getSpecEditor: function(){
      return specEditor;
    },
    getSourceEditor: function(){
      return sourceEditor;
    }
  };

  //Dom-ready
  $(function(){
    codeBoxes.setupCodeBoxes();
    templates.init();
  });
})(jQuery);
<|endoftext|>


<commit_before>export default function defaultQueryConfig(id) {
  return {
    id,
    database: null,
    measurement: null,
    retentionPolicy: null,
    fields: [],
    tags: {},
    groupBy: {
      time: null,
      tags: [],
    },
    areTagsAccepted: true,
    rawText: null,
    status: null,
  }
}
<commit_msg>Add comment and import const for 'null' string value on default config<commit_after>import {NULL} from 'shared/constants/queryFillOptions'

export default function defaultQueryConfig(id) {
  return {
    id,
    database: null,
    measurement: null,
    retentionPolicy: null,
    fields: [],
    tags: {},
    groupBy: {
      time: null,
      tags: [],
    },
    fill: NULL, // handle all fill values as strings, including null
    areTagsAccepted: true,
    rawText: null,
    status: null,
  }
}
<|endoftext|>


<commit_before><commit_msg>Backbone.Model template for Teams. #54<commit_after>// TODO Describe the Team model.
//      What does it represent in real life?
//      What are its attributes?

var Team = Backbone.Model.extend({
   // This is an list of attributes and their default values
   defaults: {
      // TODO set up attributes and their defaults. Example:
      // someAttribute: 5,
      // someAttribute2: 'Hello world',
      // someAttribute3: []
   },

   // This is the constructor. It is called whenever you make a new Team.
   initialize: function() {
      this.bind('error', function(model, error) {
         // TODO Handle validation errors
      }

      // TODO Set up any other bindings (i.e. what to do when certain Events
      //      happen). Example:
      // this.bind("change:someAttribute", function() {
      //    console.log("We just changed someAttribute");
      // });

   },

   // This is used to validate any changes to the model. It is called whenever
   // team.set('someAttribute', __) is called, but before the changes are
   // actually made to someAttribute.
   validate: function(attributes) {
      // TODO Validation on the attributes. Returning a String counts as an error.
      //      Example:
      // if (attributes.someAttribute <= 0) {
      //    return "Must use positive numbers";
      // }
   }

   // TODO Add any other methods that will manipulate the Team attributes.
   //      Example:
   // ,
   // addOne: function() {
   //    this.someAttribute++;
   // }
});

<|endoftext|>


<commit_before>import BaseModel from './base-model';

/**
  * Model for product variant
  * @class ProductVariantModel
  * @constructor
*/
const ProductVariantModel = BaseModel.extend({
  constructor() {
    this.super(...arguments);
  },

  /**
    * Variant unique ID
    * @property id
    * @type {String}
  */
  get id() {
    return this.attrs.variant.id;
  },

  /**
    * ID of product variant belongs to
    * @property productId
    * @type {String}
  */
  get productId() {
    return this.attrs.product.id;
  },

  /**
    * Title of variant
    * @property title
    * @type {String}
  */
  get title() {
    return this.attrs.variant.title;
  },

  /**
    * Title of product variant belongs to
    * @property productTitle
    * @type {String}
  */
  get productTitle() {
    return this.attrs.product.title;
  },

  /**
    *
    * Compare at price for variant formatted as currency.
    * @property compareAtPrice
    * @type {String}
  */
  get compareAtPrice() {
    return this.attrs.variant.compare_at_price;
  },

  /**
    * Price of variant, formatted as currency
    * @property price
    * @type {String}
  */
  get price() {
    return this.attrs.variant.price;
  },

  /**
    * Price of variant, formatted according to shop currency format string
    * @property price
    * @type {String}
  */
  get formattedPrice() {
    return this.attrs.variant.formatted_price;
  },

  /**
    * Variant weight in grams
    * @property grams
    * @type {Number}
  */
  get grams() {
    return this.attrs.variant.grams;
  },

  /**
    * Option values associated with this variant, ex {name: "color", value: "Blue"}
    * @property optionValues
    * @type {Array|Object}
  */
  get optionValues() {
    return this.attrs.variant.option_values;
  },

  /**
    * Variant in stock (always true if inventory tracking is disabled)
    * @property available
    * @type {Boolean}
  */
  get available() {
    return this.attrs.variant.available;
  },

  /**
    * Image for variant
    * @property image
    * @type {Object}
  */
  get image() {
    const id = this.id;
    const images = this.attrs.product.images;

    const primaryImage = images[0];
    const variantImage = images.filter(image => {
      return image.variant_ids.indexOf(id) !== -1;
    })[0];

    return (variantImage || primaryImage);
  },

  /**
    * Image variants available for a variant, ex [ {"name":"pico","dimension":"16x16","src":"https://cdn.shopify.com/image-two_pico.jpg"} ]
    * See  for list of available variants.
    * @property imageVariant
    * @type {Array}
  */
  get imageVariants() {
    const image = this.image;

    if (!image) {
      return [];
    }

    const src = this.image.src;
    const extensionIndex = src.lastIndexOf('.');
    const pathAndBasename = src.slice(0, extensionIndex);
    const extension = src.slice(extensionIndex);
    const variants = [
      { name: 'pico', dimension: '16x16' },
      { name: 'icon', dimension: '32x32' },
      { name: 'thumb', dimension: '50x50' },
      { name: 'small', dimension: '100x100' },
      { name: 'compact', dimension: '160x160' },
      { name: 'medium', dimension: '240x240' },
      { name: 'large', dimension: '480x480' },
      { name: 'grande', dimension: '600x600' },
      { name: '1024x1024', dimension: '1024x1024' },
      { name: '2048x2048', dimension: '2048x2048' }
    ];

    variants.forEach(variant => {
      variant.src = `${pathAndBasename}_${variant.name}${extension}`;
    });

    return variants;
  },

  /**
    * Get a checkout url for a specific product variant. You can
    * optionally pass a quantity. If no quantity is passed then quantity
    * will default to 1. The example below will grab a checkout url for
    * 3 copies of the first variant:
    * ```
    * const checkoutURL = product.variants[ 0 ].checkoutUrl(3);
    * ```
    *
    * @method checkoutUrl
    * @param {Number} [quantity = 1] quantity of variants
    * @public
    * @return {String} Checkout URL
  */
  checkoutUrl(quantity = 1) {
    const config = this.config;
    const baseUrl = `https://${config.domain}/cart`;

    const variantPath = `${this.id}:${parseInt(quantity, 10)}`;

    const query = `api_key=${config.apiKey}`;

    return `${baseUrl}/${variantPath}?${query}`;
  }
});

export default ProductVariantModel;
<commit_msg>Added in formatted price<commit_after>import BaseModel from './base-model';

/**
  * Model for product variant
  * @class ProductVariantModel
  * @constructor
*/
const ProductVariantModel = BaseModel.extend({
  constructor() {
    this.super(...arguments);
  },

  /**
    * Variant unique ID
    * @property id
    * @type {String}
  */
  get id() {
    return this.attrs.variant.id;
  },

  /**
    * ID of product variant belongs to
    * @property productId
    * @type {String}
  */
  get productId() {
    return this.attrs.product.id;
  },

  /**
    * Title of variant
    * @property title
    * @type {String}
  */
  get title() {
    return this.attrs.variant.title;
  },

  /**
    * Title of product variant belongs to
    * @property productTitle
    * @type {String}
  */
  get productTitle() {
    return this.attrs.product.title;
  },

  /**
    * Compare at price for variant formatted as currency. The `compareAtPrice` would be
    * the price of the product previously before the product went on sale. For more info
    * go here.
    *
    * If no `compareAtPrice` is set then this value will be `null`. An example value: `"5.00"`
    * @property compareAtPrice
    * @type {String}
  */
  get compareAtPrice() {
    return this.attrs.variant.compare_at_price;
  },

  /**
    * Price of the variant. The price will be in the following form: `"10.00"`
    *
    * @property price
    * @type {String}
  */
  get price() {
    return this.attrs.variant.price;
  },

  /**
    * Price of variant, formatted according to shop currency format string
    * @property price
    * @type {String}
  */
  get formattedPrice() {
    return this.attrs.variant.formatted_price;
  },

  /**
    * Variant weight in grams. If no weight is defined grams will be `0`.
    * @property grams
    * @type {Number}
  */
  get grams() {
    return this.attrs.variant.grams;
  },

  /**
    * Option values associated with this variant. Example `optionValues`:
    * ```
    * [
    *   {
    *     "name": "Size",
    *     "option_id": 9165336518,
    *     "value": "small"
    *   },
    *   {
    *     "name": "Color",
    *     "option_id": 9640532358,
    *     "value": "blue"
    *   }
    * ]
    * ````
    *
    * @property optionValues
    * @type {Array|Object}
  */
  get optionValues() {
    return this.attrs.variant.option_values;
  },

  /**
    * Variant in stock (always true if inventory tracking is disabled)
    * @property available
    * @type {Boolean}
  */
  get available() {
    return this.attrs.variant.available;
  },

  /**
    * Image for variant. An example image `Object`:
    * ```
    * {
    *   created_at: "2016-08-29T12:35:09-04:00",
    *   id: 17690553350,
    *   position: 1,
    *   product_id: 8291029446,
    *   src: "https://cdn.shopify.com/s/files/1/1019/0495/products/i11_c3334325-2d67-4623-8cd4-0a6b08aa1b83.jpg?v=1472488509",
    *   updated_at: "2016-08-29T12:35:09-04:00",
    *   variant_ids: [ 27690103238 ]
    * }
    * ```
    *
    * @property image
    * @type {Object}
  */
  get image() {
    const id = this.id;
    const images = this.attrs.product.images;

    const primaryImage = images[0];
    const variantImage = images.filter(image => {
      return image.variant_ids.indexOf(id) !== -1;
    })[0];

    return (variantImage || primaryImage);
  },

  /**
    * Image variants available for a variant. An example value of `imageVariant`:
    * ```
    * [
    *   {
    *     "name": "pico",
    *     "dimensions": "16x16",
    *     "src": "https://cdn.shopify.com/s/files/1/1019/0495/products/alien_146ef7c1-26e9-4e96-96e6-9d37128d0005_pico.jpg?v=1469046423"
    *   },
    *   {
    *     "name": "compact",
    *     "dimensions": "160x160",
    *     "src": "https://cdn.shopify.com/s/files/1/1019/0495/products/alien_146ef7c1-26e9-4e96-96e6-9d37128d0005_compact.jpg?v=1469046423"
    *   }
    * ]
    * ```
    *
    * @property imageVariant
    * @type {Array}
  */
  get imageVariants() {
    const image = this.image;

    if (!image) {
      return [];
    }

    const src = this.image.src;
    const extensionIndex = src.lastIndexOf('.');
    const pathAndBasename = src.slice(0, extensionIndex);
    const extension = src.slice(extensionIndex);
    const variants = [
      { name: 'pico', dimension: '16x16' },
      { name: 'icon', dimension: '32x32' },
      { name: 'thumb', dimension: '50x50' },
      { name: 'small', dimension: '100x100' },
      { name: 'compact', dimension: '160x160' },
      { name: 'medium', dimension: '240x240' },
      { name: 'large', dimension: '480x480' },
      { name: 'grande', dimension: '600x600' },
      { name: '1024x1024', dimension: '1024x1024' },
      { name: '2048x2048', dimension: '2048x2048' }
    ];

    variants.forEach(variant => {
      variant.src = `${pathAndBasename}_${variant.name}${extension}`;
    });

    return variants;
  },

  /**
    * Get a checkout url for a specific product variant. You can
    * optionally pass a quantity. If no quantity is passed then quantity
    * will default to 1. The example below will grab a checkout url for
    * 3 copies of the first variant:
    * ```
    * const checkoutURL = product.variants[ 0 ].checkoutUrl(3);
    * ```
    *
    * @method checkoutUrl
    * @param {Number} [quantity = 1] quantity of variants
    * @public
    * @return {String} Checkout URL
  */
  checkoutUrl(quantity = 1) {
    const config = this.config;
    const baseUrl = `https://${config.domain}/cart`;

    const variantPath = `${this.id}:${parseInt(quantity, 10)}`;

    const query = `api_key=${config.apiKey}`;

    return `${baseUrl}/${variantPath}?${query}`;
  }
});

export default ProductVariantModel;
<|endoftext|>


<commit_before>import cytoscape from 'cytoscape';
import dagre from 'cytoscape-dagre';
import React from 'react';
import ReactDOM from 'react-dom';

cytoscape.use(dagre);

//TODO: DRY 'recent-epics' related access between graph.js & index.js
function pushRelatedEpic(epic) {
    if (typeof(Storage) === "undefined") {
        return
    }
    var epics = [];

    const rawRecentEpics = localStorage.getItem('recent-epics');
    if (rawRecentEpics) {
        try {
            var parsed = JSON.parse(rawRecentEpics);
            if (parsed && parsed.constructor === Array) {
                epics = parsed;
            }
        } catch (err) {
            console.log('failed to parse recent-epics from local storage: ' + err);
        }
    }
    for (var i = 0; i < epics.length; i++) {
        if (epics[i].key === epic.key) {
            return
        }
    }
    epics.unshift(epic);
    if (epics.length > 10) {
        epics.pop();
    }
    console.log(epics);
    localStorage.setItem('recent-epics', JSON.stringify(epics));
}

function statusToRGB(s) {
    if (s == 'Backlog' || s == 'Ready for Dev') {
        return '#ffffff';
    }
    if (s == 'In Progress' || s == 'In QA on feature branch' || s == 'In Code Review' || s == 'Resolved, on staging') {
        return '#35e82c';
    }
    if (s == 'Closed') {
        return '#959595';
    }
    return '#000000';
}

class Popup extends React.Component {
    render() {
        if (this.props.selectedEpic == null) {
            return

        }

        //TODO: a hack until offsetHeight can be figured out
        const yOffset = 45;

        const style = {
            left: this.props.selectedEpic.popupPosition.x + 'px',
            top: (this.props.selectedEpic.popupPosition.y + yOffset) + 'px',
        }

        const epic = this.props.selectedEpic.epic;

        var className = 'popup';
        if (epic.flagged) {
            className = className + ' flagged';
        }

        return (

{epic.summary}

              <PopupIcon alt={'Type: ' + epic.type} imageURL={epic.typeImageURL} />
              <PopupIcon alt={'Priority: ' + epic.priority} imageURL={epic.priorityImageURL} />
              {epic.flagged ? '⚑' : ''}
              <PopupEstimate estimate={epic.estimate} />
              <PopupKey epicKey={epic.key} />
              <PopupAssignee assignee={epic.assignee} assigneeImageURL={epic.assigneeImageURL} />

{epic.status}

              <PopupLabels labels={epic.labels} />

            <PopupStatus status={epic.status} />

        )
    }
}

class PopupIcon extends React.Component {
    render() {
        return (

        )
    }
}

class PopupAssignee extends React.Component {
    render() {
        if (this.props.assignee === '') {
            return
        }

        const alt = 'Assignee: ' + this.props.assignee;
        return (

        )
    }
}

class PopupKey extends React.Component {
    render() {
        const url = '/epics/' + this.props.epicKey + '/details';

        return (

          {this.props.epicKey}

        );
    }
}

class PopupEstimate extends React.Component {
    render() {
        return (
            {this.props.estimate === 0 ? "-" : this.props.estimate}
        );
    }
}

class PopupStatus extends React.Component {
    render() {
        const style = {
            backgroundColor: statusToRGB(this.props.status),
        }
        return

    }
}

class PopupLabels extends React.Component {
    render() {
        var labelListItems = [];
        for (var i = 0; i < this.props.labels.length; i++) {
            labelListItems.push(
{this.props.labels[i]}
);
        }
        return (

{labelListItems}

        );
    }
}

class GraphApp extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            error: null,
            isLoaded: false,
            epic: {},
        };
    }

    render() {
        if (this.state.error) {
            return
Error: failed to fetch the epic

        } else if (!this.state.isLoaded) {
            return
Loading...

        } else {
            return <Graph epic={this.state.epic} />
        }
    }

    componentDidMount() {
        const epicKey = this.props.epicKey;
        console.log('loading ' + epicKey);

        fetch("/api/epics/" + epicKey)
            .then(res => {
                if (!res.ok) {
                    throw new Error('not ok');
                }
                return res.json();
            }).then(result => {
                this.setState({
                    isLoaded: true,
                    epic: result,
                });
                console.log('loaded ' + epicKey);
            }).catch(() => {
                console.log('failed to load ' + epicKey);
                this.setState({
                    isLoaded: false,
                    error: true,
                });
            });
    }
}

class Menu extends React.Component {
    render() {
        return (

      ☰
		<input type="checkbox" id="menu-toggle" />

			Related epics

            <RelatedEpics epicKey={this.props.epicKey} />

        )
    }
}

class RelatedEpics extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            error: null,
            isLoaded: false,
            epics: [],
        };
    }

    render() {
        if (this.state.error) {
            return
Error: failed to fetch related epics
;
        } else if (!this.state.isLoaded) {
            return
Loading...
;
        } else {
            const epics = this.state.epics;
            if (epics.length == 0) {
                return
none!
;
            }

            var anchors = [];
            for (var i = 0; i < epics.length; i++) {
                const url = '/epics/' + epics[i].key;
                anchors.push(

                    {epics[i].key} - {epics[i].summary}

                );
            }

            return
{anchors}
;
        }
    }

    componentDidMount() {
        const epicKey = this.props.epicKey

        console.log('loading related epics for ' + epicKey);
        fetch("/api/epics/" + epicKey + "/related")
            .then(res => {
                if (!res.ok) {
                    throw new Error('not ok');
                }
                return res.json();
            })
            .then(result => {
                this.setState({
                    isLoaded: true,
                    epics: result,
                });
                console.log('loaded related epics for ' + epicKey);
            }).catch(
                () => {
                    console.log('failed to load related epics for ' + epicKey);
                    this.setState({
                        isLoaded: false,
                        error: true,
                        epics: [],
                    });
                });
    }
}

class Graph extends React.Component {
    constructor(props) {
        super(props);
        this.myRef = React.createRef();
        this.state = {
            selectedEpic: null,
        };
    }

    render() {
        return (

          <Popup selectedEpic={this.state.selectedEpic} />

        );
    }

    componentDidMount() {
        this.renderGraph(this.props.epic);
    }

    renderGraph(data) {
        const root = this.myRef.current;
        var issues = data.issues.map(function(elem) {
            return {
                data: Object.assign({
                    id: elem.key
                }, elem)
            }
        });

        var issueEdges = [];
        for (var i = 0; i < issues.length; i++) {
            var blockingIssue = issues[i].data.id;
            var blockedIssues = data.graph[blockingIssue];
            for (var j = 0; j < blockedIssues.length; j++) {
                var id = blockingIssue + '_blocks_' + blockedIssues[j];
                issueEdges.push({
                    data: {
                        id: id,
                        source: blockingIssue,
                        target: blockedIssues[j]
                    }
                });
            }
        }

        var cy = cytoscape({
            container: root,

            boxSelectionEnabled: false,
            autounselectify: true,

            layout: {
                name: 'dagre',
                directed: true
            },

            style: [{
                    selector: 'node',
                    style: {
                        'content': 'data(id)',
                        'text-opacity': 0.8,
                        'color': '#000000',
                        'font-size': 18,
                        'font-weight': 'bold',
                        'background-color': function(ele) {
                            return statusToRGB(ele.data('status'))
                        },
                        'border-width': 1,
                        'border-color': '#000000'
                    }
                },

                {
                    selector: 'edge',
                    style: {
                        'curve-style': 'bezier',
                        'width': 4,
                        'target-arrow-shape': 'triangle',
                        'line-color': '#9dbaea',
                        'target-arrow-color': '#9dbaea'
                    }
                }
            ],

            elements: {
                nodes: issues,
                edges: issueEdges,
            },
        });

        cy.on('tap', (evt) => {
            if (evt.target === cy) {
                this.setState({
                    selectedEpic: null,
                });
            }
        });

        cy.on('tap', 'node', (evt) => {
            const epic = evt.target.data();
            const position = evt.renderedPosition;
            console.log(position);
            this.setState({
                selectedEpic: {
                    epic: epic,
                    popupPosition: position,
                }
            });
        });

        cy.on('mouseover', 'node', function(evt) {
            document.body.style.cursor = 'pointer';
        });

        cy.on('mouseout', 'node', function() {
            document.body.style.cursor = 'default';
        });
    }
}

class App extends React.Component {
    render() {
        const issueURL = "https://" + this.props.jiraHost + "/browse/" + this.props.epicKey;
        const issueLabel = this.props.epicKey + " - " + this.props.issueSummary;
        return (

					<Menu epicKey={this.props.epicKey} />
					{issueLabel}

				<GraphApp epicKey={this.props.epicKey} />

        )
    }
}

var root = document.getElementById('root');
ReactDOM.render(<App epicKey={root.dataset.issueKey}
		issueSummary={root.dataset.issueSummary}
		jiraHost={root.dataset.jiraHost} />, root);

var epic = {
    key: root.dataset.issueKey,
    summary: root.dataset.issueSummary
};
pushRelatedEpic(epic);<commit_msg>Epics that are viewed again are shifted to the head of the array<commit_after>import cytoscape from 'cytoscape';
import dagre from 'cytoscape-dagre';
import React from 'react';
import ReactDOM from 'react-dom';

cytoscape.use(dagre);

//TODO: DRY 'recent-epics' related access between graph.js & index.js
function pushRelatedEpic(epic) {
    if (typeof(Storage) === "undefined") {
        return
    }
    var epics = [];

    const rawRecentEpics = localStorage.getItem('recent-epics');
    if (rawRecentEpics) {
        try {
            var parsed = JSON.parse(rawRecentEpics);
            if (parsed && parsed.constructor === Array) {
                epics = parsed;
            }
        } catch (err) {
            console.log('failed to parse recent-epics from local storage: ' + err);
        }
    }
    for (var i = 0; i < epics.length; i++) {
        if (epics[i].key === epic.key) {
            epics.splice(i, 1);
        }
    }
    epics.unshift(epic);
    if (epics.length > 10) {
        epics.pop();
    }
    console.log(epics);
    localStorage.setItem('recent-epics', JSON.stringify(epics));
}

function statusToRGB(s) {
    if (s == 'Backlog' || s == 'Ready for Dev') {
        return '#ffffff';
    }
    if (s == 'In Progress' || s == 'In QA on feature branch' || s == 'In Code Review' || s == 'Resolved, on staging') {
        return '#35e82c';
    }
    if (s == 'Closed') {
        return '#959595';
    }
    return '#000000';
}

class Popup extends React.Component {
    render() {
        if (this.props.selectedEpic == null) {
            return

        }

        //TODO: a hack until offsetHeight can be figured out
        const yOffset = 45;

        const style = {
            left: this.props.selectedEpic.popupPosition.x + 'px',
            top: (this.props.selectedEpic.popupPosition.y + yOffset) + 'px',
        }

        const epic = this.props.selectedEpic.epic;

        var className = 'popup';
        if (epic.flagged) {
            className = className + ' flagged';
        }

        return (

{epic.summary}

              <PopupIcon alt={'Type: ' + epic.type} imageURL={epic.typeImageURL} />
              <PopupIcon alt={'Priority: ' + epic.priority} imageURL={epic.priorityImageURL} />
              {epic.flagged ? '⚑' : ''}
              <PopupEstimate estimate={epic.estimate} />
              <PopupKey epicKey={epic.key} />
              <PopupAssignee assignee={epic.assignee} assigneeImageURL={epic.assigneeImageURL} />

{epic.status}

              <PopupLabels labels={epic.labels} />

            <PopupStatus status={epic.status} />

        )
    }
}

class PopupIcon extends React.Component {
    render() {
        return (

        )
    }
}

class PopupAssignee extends React.Component {
    render() {
        if (this.props.assignee === '') {
            return
        }

        const alt = 'Assignee: ' + this.props.assignee;
        return (

        )
    }
}

class PopupKey extends React.Component {
    render() {
        const url = '/epics/' + this.props.epicKey + '/details';

        return (

          {this.props.epicKey}

        );
    }
}

class PopupEstimate extends React.Component {
    render() {
        return (
            {this.props.estimate === 0 ? "-" : this.props.estimate}
        );
    }
}

class PopupStatus extends React.Component {
    render() {
        const style = {
            backgroundColor: statusToRGB(this.props.status),
        }
        return

    }
}

class PopupLabels extends React.Component {
    render() {
        var labelListItems = [];
        for (var i = 0; i < this.props.labels.length; i++) {
            labelListItems.push(
{this.props.labels[i]}
);
        }
        return (

{labelListItems}

        );
    }
}

class GraphApp extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            error: null,
            isLoaded: false,
            epic: {},
        };
    }

    render() {
        if (this.state.error) {
            return
Error: failed to fetch the epic

        } else if (!this.state.isLoaded) {
            return
Loading...

        } else {
            return <Graph epic={this.state.epic} />
        }
    }

    componentDidMount() {
        const epicKey = this.props.epicKey;
        console.log('loading ' + epicKey);

        fetch("/api/epics/" + epicKey)
            .then(res => {
                if (!res.ok) {
                    throw new Error('not ok');
                }
                return res.json();
            }).then(result => {
                this.setState({
                    isLoaded: true,
                    epic: result,
                });
                console.log('loaded ' + epicKey);
            }).catch(() => {
                console.log('failed to load ' + epicKey);
                this.setState({
                    isLoaded: false,
                    error: true,
                });
            });
    }
}

class Menu extends React.Component {
    render() {
        return (

      ☰
		<input type="checkbox" id="menu-toggle" />

			Related epics

            <RelatedEpics epicKey={this.props.epicKey} />

        )
    }
}

class RelatedEpics extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            error: null,
            isLoaded: false,
            epics: [],
        };
    }

    render() {
        if (this.state.error) {
            return
Error: failed to fetch related epics
;
        } else if (!this.state.isLoaded) {
            return
Loading...
;
        } else {
            const epics = this.state.epics;
            if (epics.length == 0) {
                return
none!
;
            }

            var anchors = [];
            for (var i = 0; i < epics.length; i++) {
                const url = '/epics/' + epics[i].key;
                anchors.push(

                    {epics[i].key} - {epics[i].summary}

                );
            }

            return
{anchors}
;
        }
    }

    componentDidMount() {
        const epicKey = this.props.epicKey

        console.log('loading related epics for ' + epicKey);
        fetch("/api/epics/" + epicKey + "/related")
            .then(res => {
                if (!res.ok) {
                    throw new Error('not ok');
                }
                return res.json();
            })
            .then(result => {
                this.setState({
                    isLoaded: true,
                    epics: result,
                });
                console.log('loaded related epics for ' + epicKey);
            }).catch(
                () => {
                    console.log('failed to load related epics for ' + epicKey);
                    this.setState({
                        isLoaded: false,
                        error: true,
                        epics: [],
                    });
                });
    }
}

class Graph extends React.Component {
    constructor(props) {
        super(props);
        this.myRef = React.createRef();
        this.state = {
            selectedEpic: null,
        };
    }

    render() {
        return (

          <Popup selectedEpic={this.state.selectedEpic} />

        );
    }

    componentDidMount() {
        this.renderGraph(this.props.epic);
    }

    renderGraph(data) {
        const root = this.myRef.current;
        var issues = data.issues.map(function(elem) {
            return {
                data: Object.assign({
                    id: elem.key
                }, elem)
            }
        });

        var issueEdges = [];
        for (var i = 0; i < issues.length; i++) {
            var blockingIssue = issues[i].data.id;
            var blockedIssues = data.graph[blockingIssue];
            for (var j = 0; j < blockedIssues.length; j++) {
                var id = blockingIssue + '_blocks_' + blockedIssues[j];
                issueEdges.push({
                    data: {
                        id: id,
                        source: blockingIssue,
                        target: blockedIssues[j]
                    }
                });
            }
        }

        var cy = cytoscape({
            container: root,

            boxSelectionEnabled: false,
            autounselectify: true,

            layout: {
                name: 'dagre',
                directed: true
            },

            style: [{
                    selector: 'node',
                    style: {
                        'content': 'data(id)',
                        'text-opacity': 0.8,
                        'color': '#000000',
                        'font-size': 18,
                        'font-weight': 'bold',
                        'background-color': function(ele) {
                            return statusToRGB(ele.data('status'))
                        },
                        'border-width': 1,
                        'border-color': '#000000'
                    }
                },

                {
                    selector: 'edge',
                    style: {
                        'curve-style': 'bezier',
                        'width': 4,
                        'target-arrow-shape': 'triangle',
                        'line-color': '#9dbaea',
                        'target-arrow-color': '#9dbaea'
                    }
                }
            ],

            elements: {
                nodes: issues,
                edges: issueEdges,
            },
        });

        cy.on('tap', (evt) => {
            if (evt.target === cy) {
                this.setState({
                    selectedEpic: null,
                });
            }
        });

        cy.on('tap', 'node', (evt) => {
            const epic = evt.target.data();
            const position = evt.renderedPosition;
            console.log(position);
            this.setState({
                selectedEpic: {
                    epic: epic,
                    popupPosition: position,
                }
            });
        });

        cy.on('mouseover', 'node', function(evt) {
            document.body.style.cursor = 'pointer';
        });

        cy.on('mouseout', 'node', function() {
            document.body.style.cursor = 'default';
        });
    }
}

class App extends React.Component {
    render() {
        const issueURL = "https://" + this.props.jiraHost + "/browse/" + this.props.epicKey;
        const issueLabel = this.props.epicKey + " - " + this.props.issueSummary;
        return (

					<Menu epicKey={this.props.epicKey} />
					{issueLabel}

				<GraphApp epicKey={this.props.epicKey} />

        )
    }
}

var root = document.getElementById('root');
ReactDOM.render(<App epicKey={root.dataset.issueKey}
		issueSummary={root.dataset.issueSummary}
		jiraHost={root.dataset.jiraHost} />, root);

var epic = {
    key: root.dataset.issueKey,
    summary: root.dataset.issueSummary
};
pushRelatedEpic(epic);<|endoftext|>


<commit_before>import React from 'react';
import { View } from 'react-native';
const errorLoading = <View />;

import { useDeps, composeAll, composeWithTracker } from 'mantra-core';

import Home from '../components/home';

export const composer = ({context}, onData) => {
  // const {Meteor, Collections} = context();
  onData(null, {});
};

export const depsMapper = (context) => ({
  context: () => context
});

export default composeAll(
  composeWithTracker(composer, ()=>errorLoading, ()=>errorLoading),
  useDeps(depsMapper)
)(Home);
<commit_msg>Preliminary working composeWithTracker<commit_after>import React from 'react';
import { View } from 'react-native';
const errorLoading = <View />;

import { useDeps, composeAll } from 'mantra-core';
import { composeWithTracker } from 'react-native-meteor';

import Home from '../components/home';

export const composer = ({context}, onData) => {
  const { Meteor } = context();
  console.log(Meteor.status());
  onData(null, {});
};

export const depsMapper = (context) => ({
  context: () => context
});

export default composeAll(
  composeWithTracker(composer, ()=>errorLoading, ()=>errorLoading),
  useDeps(depsMapper)
)(Home);
<|endoftext|>


<commit_before>import FilterModule from "../FilterModule";
import Configuration from "../../util/Configuration";
import { dependencies as Inject, singleton as Singleton } from "needlepoint";
import Promise from "bluebird";

@Singleton
@Inject(Configuration)
export default class ThreadFilter extends FilterModule {
    /**
     * @param {Configuration} config
     */
    constructor(config) {
        super();

        this.config = config;

        this.threadsToListen = this.config.get("threads");
    }

    filter(msg) {
        if (this.threadsToListen.indexOf(parseInt(msg.threadID)) != -1) {
            return Promise.resolve(msg);
        } else {
            return Promise.reject("Received message from thread (" + msg.threadID + ") we're not listening to");
        }
    }
}<commit_msg>ThreadFilter: Fix broken parsing of new configuration format<commit_after>import FilterModule from "../FilterModule";
import Configuration from "../../util/Configuration";
import { dependencies as Inject, singleton as Singleton } from "needlepoint";
import Promise from "bluebird";
import Bro from "brototype";

@Singleton
@Inject(Configuration)
export default class ThreadFilter extends FilterModule {
    /**
     * @param {Configuration} config
     */
    constructor(config) {
        super();

        this.config = config;

        this.threadsToListen = this.config.get("threads");
    }

    filter(msg) {
        const threadId = parseInt(msg.threadID);

        const shouldListen = this.threadsToListen.some(t => {
            // simple threadId without aliases or other properties
            if (t == threadId)
                return true;

            // threadId object with properties
            const id = parseInt(new Bro(t).giveMeProps()[0]);

            return threadId == id;
        });

        if (shouldListen) {
            return Promise.resolve(msg);
        } else {
            return Promise.reject("Received message from thread (" + threadId + ") we're not listening to");
        }
    }
}<|endoftext|>


<commit_before>(function() {
  'use strict'

  function byTriggerPoint(a, b) {
    return a.triggerPoint - b.triggerPoint
  }

  function byReverseTriggerPoint(a, b) {
    return b.triggerPoint - a.triggerPoint
  }

  var groups = {
    vertical: {},
    horizontal: {}
  }
  var Waypoint = window.Waypoint

  function Group(options) {
    this.name = options.name
    this.axis = options.axis
    this.id = this.name + '-' + this.axis
    this.waypoints = []
    this.clearTriggerQueues()
    groups[this.axis][this.name] = this
  }

  /* Private */
  Group.prototype.add = function(waypoint) {
    this.waypoints.push(waypoint)
  }

  /* Private */
  Group.prototype.clearTriggerQueues = function() {
    this.triggerQueues = {
      up: [],
      down: [],
      left: [],
      right: []
    }
  }

  /* Private */
  Group.prototype.flushTriggers = function() {
    for (var direction in this.triggerQueues) {
      var waypoints = this.triggerQueues[direction]
      var reverse = direction === 'up' || direction === 'left'
      waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint)
      for (var i = 0, end = waypoints.length; i < end; i += 1) {
        var waypoint = waypoints[i]
        if (waypoint.options.continuous || i === waypoints.length - 1) {
          waypoint.trigger([direction])
        }
      }
    }
    this.clearTriggerQueues()
  }

  /* Private */
  Group.prototype.next = function(waypoint) {
    this.sort()
    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
    var isLast = index === this.waypoints.length - 1
    return isLast ? null : this.waypoints[index + 1]
  }

  /* Private */
  Group.prototype.previous = function(waypoint) {
    this.sort()
    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
    return index ? this.waypoints[index - 1] : null
  }

  /* Private */
  Group.prototype.queueTrigger = function(waypoint, direction) {
    this.triggerQueues[direction].push(waypoint)
  }

  /* Private */
  Group.prototype.remove = function(waypoint) {
    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
    if (index > -1) {
      this.waypoints.splice(index, 1)
    }
  }

  /* Private */
  Group.prototype.sort = function() {
    this.waypoints.sort(function(a, b) {
      return a.triggerPoint - b.triggerPoint
    })
  }

  /* Public */
  Group.prototype.first = function() {
    return this.waypoints[0]
  }

  /* Public */
  Group.prototype.last = function() {
    return this.waypoints[this.waypoints.length - 1]
  }

  /* Private */
  Group.findOrCreate = function(options) {
    return groups[options.axis][options.name] || new Group(options)
  }

  Waypoint.Group = Group
}())
<commit_msg>Remove unneccesary sort method<commit_after>(function() {
  'use strict'

  function byTriggerPoint(a, b) {
    return a.triggerPoint - b.triggerPoint
  }

  function byReverseTriggerPoint(a, b) {
    return b.triggerPoint - a.triggerPoint
  }

  var groups = {
    vertical: {},
    horizontal: {}
  }
  var Waypoint = window.Waypoint

  function Group(options) {
    this.name = options.name
    this.axis = options.axis
    this.id = this.name + '-' + this.axis
    this.waypoints = []
    this.clearTriggerQueues()
    groups[this.axis][this.name] = this
  }

  /* Private */
  Group.prototype.add = function(waypoint) {
    this.waypoints.push(waypoint)
  }

  /* Private */
  Group.prototype.clearTriggerQueues = function() {
    this.triggerQueues = {
      up: [],
      down: [],
      left: [],
      right: []
    }
  }

  /* Private */
  Group.prototype.flushTriggers = function() {
    for (var direction in this.triggerQueues) {
      var waypoints = this.triggerQueues[direction]
      var reverse = direction === 'up' || direction === 'left'
      waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint)
      for (var i = 0, end = waypoints.length; i < end; i += 1) {
        var waypoint = waypoints[i]
        if (waypoint.options.continuous || i === waypoints.length - 1) {
          waypoint.trigger([direction])
        }
      }
    }
    this.clearTriggerQueues()
  }

  /* Private */
  Group.prototype.next = function(waypoint) {
    this.waypoints.sort(byTriggerPoint)
    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
    var isLast = index === this.waypoints.length - 1
    return isLast ? null : this.waypoints[index + 1]
  }

  /* Private */
  Group.prototype.previous = function(waypoint) {
    this.waypoints.sort(byTriggerPoint)
    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
    return index ? this.waypoints[index - 1] : null
  }

  /* Private */
  Group.prototype.queueTrigger = function(waypoint, direction) {
    this.triggerQueues[direction].push(waypoint)
  }

  /* Private */
  Group.prototype.remove = function(waypoint) {
    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
    if (index > -1) {
      this.waypoints.splice(index, 1)
    }
  }

  /* Public */
  Group.prototype.first = function() {
    return this.waypoints[0]
  }

  /* Public */
  Group.prototype.last = function() {
    return this.waypoints[this.waypoints.length - 1]
  }

  /* Private */
  Group.findOrCreate = function(options) {
    return groups[options.axis][options.name] || new Group(options)
  }

  Waypoint.Group = Group
}())
<|endoftext|>


<commit_before>var lookup = [
  {
    condition: function(data) {return data.indexOf('(Potion)') !== -1;},
    id: 1
  },
  {
    condition: function(data) {
      return data.indexOf('recalled the item') !== -1;
    },
    id: 2
  },
  {
    condition: function(data) {
      return data.indexOf('took the item') !== -1;
    },
    id: 2
  },
  {
    condition: function(data) {
      return data.indexOf('auto-returned the') !== -1;
    },
    id: 2
  },
  {
    condition: function(data) {
      return data.indexOf('stored the item') !== -1;
    },
    id: 2
  },
  {
    condition: function(data) {
      return data.indexOf('has added flags to') !== -1;
    },
    id: 3
  },
  {
    condition: function(data) {
      return data.indexOf('has removed flags to') !== -1;
    },
    id: 3
  },
  {
    condition: function(data) {
      return data.indexOf(
        'relic. This relic now has an empower level of') !== -1;
    },
    id: 4
  },
  {
    condition: function(data) {
      return data.indexOf(
        'relic. The relic empower level has been reset to zero.') !== -1;
    },
    id: 4
  },
  {
    condition: function(data) {
      return data.indexOf('failed to capture the relic') !== -1;
    },
    id: 4
  },
  {
    condition: function(data) {
      return data.indexOf('captured the relic') !== -1;
    },
    id: 4
  },
  {
    condition: function(data) {
      return data.indexOf('captured your relic') !== -1;
    },
    id: 4
  },
  {
    condition: function(data) {
      return data.indexOf('has captured the undefended relic') !== -1;
    },
    id: 4
  },
  {
    condition: function(data) {
      return data.indexOf('attempted to capture your relic') !== -1;
    },
    id: 4
  },
  {
    condition: function(data) {
      return / empowered the .+ relic/.test(data);
    },
    id: 4
  },
  {
    condition: function(data) {
      return / removed the empowerment from the .+ relic/.test(data);
    },
    id: 4
  },
  {
    condition: function(data) {
      return data.indexOf('disbanded a mercenary.') !== -1;
    },
    id: 5
  },
  {
    condition: function(data) {
      return data.indexOf('hired the mercenary') !== -1;
    },
    id: 5
  },
  {
    condition: function(data) {
      return data.indexOf('has disbanded one of their groups') !== -1;
    },
    id: 6
  },
  {
    condition: function(data) {
      return /A group from your guild was (.*) in combat./.test(data);
    },
    id: 6
  },
  {
    condition: function(data) {
      return /deposited ([,0-9]+) gold into the guild bank/.test(data);
    },
    id: 7
  },
  {
    condition: function(data) {
      return (
        /deposited ([,0-9]+) FallenSword Points into the guild./.test(data));
    },
    id: 7
  },
  {
    condition: function(data) {
      return data.indexOf('has added a new rank entitled') !== -1;
    },
    id: 8
  },
  {
    condition: function(data) {
      return data.indexOf('has deleted the rank') !== -1;
    },
    id: 8
  },
  {
    condition: function(data) {
      return data.indexOf('has requested to join the guild') !== -1;
    },
    id: 8
  },
  {
    condition: function(data) {
      return data.indexOf('has invited the player') !== -1;
    },
    id: 8
  },
  {
    condition: function(data) {
      return data.indexOf('has officially joined the guild') !== -1;
    },
    id: 8
  },
  {
    condition: function(data) {
      return data.indexOf('has been kicked from the guild by') !== -1;
    },
    id: 8
  },
  {
    condition: function(data) {
      return data.indexOf('has left the guild') !== -1;
    },
    id: 8
  },
  {
    condition: function(data) {
      return data.indexOf('has been assigned the rank') !== -1;
    },
    id: 8
  },
  {
    condition: function(data) {
      return /resulted in (.*) with a final score of/.test(data);
    },
    id: 9
  },
  {
    condition: function(data) {
      return data.indexOf('resulted in a draw. Your GvG rating ' +
        'and Guild RP was unaffected.') !== -1;
    },
    id: 9
  },
  {
    condition: function(data) {
      return data.indexOf(
        'has just initiated a conflict with the guild') !== -1;
    },
    id: 9
  },
  {
    condition: function(data) {
      return data.indexOf('has initiated a conflict with your guild') !== -1;
    },
    id: 9
  },
  {
    condition: function(data) {
      return data.indexOf('is participating in the conflict ' +
        'against the guild') !== -1;
    },
    id: 9
  },
  {
    condition: function(data) {
      return data.indexOf('bought the Titan Reward item') !== -1;
    },
    id: 10
  },
  {
    condition: function(data) {
      return data.indexOf('from your guild\'s contribution to the ' +
        'defeat of the titan') !== -1;
    },
    id: 10
  },
  {
    condition: function(data) {
      return data.indexOf('a 7 day cooldown has been activated ' +
        'on your guild for this titan') !== -1;
    },
    id: 10
  }
];

export function rowProfile(data) {
  var rowId = 0;
  var index = 0;
  while (!rowId && index < lookup.length) {
    var test = lookup[index];
    if (test.condition(data)) {rowId = test.id;}
    index += 1;
  }
  return rowId;
}
<commit_msg>reformat<commit_after>var lookup = [
  {
    condition: function(data) {return data.indexOf('(Potion)') !== -1;},
    id: 1
  },
  {
    condition: function(data) {
      return data.indexOf('recalled the item') !== -1;
    },
    id: 2
  },
  {
    condition: function(data) {
      return data.indexOf('took the item') !== -1;
    },
    id: 2
  },
  {
    condition: function(data) {
      return data.indexOf('auto-returned the') !== -1;
    },
    id: 2
  },
  {
    condition: function(data) {
      return data.indexOf('stored the item') !== -1;
    },
    id: 2
  },
  {
    condition: function(data) {
      return data.indexOf('has added flags to') !== -1;
    },
    id: 3
  },
  {
    condition: function(data) {
      return data.indexOf('has removed flags to') !== -1;
    },
    id: 3
  },
  {
    condition: function(data) {
      return data.indexOf(
        'relic. This relic now has an empower level of') !== -1;
    },
    id: 4
  },
  {
    condition: function(data) {
      return data.indexOf(
        'relic. The relic empower level has been reset to zero.') !== -1;
    },
    id: 4
  },
  {
    condition: function(data) {
      return data.indexOf('failed to capture the relic') !== -1;
    },
    id: 4
  },
  {
    condition: function(data) {
      return data.indexOf('captured the relic') !== -1;
    },
    id: 4
  },
  {
    condition: function(data) {
      return data.indexOf('captured your relic') !== -1;
    },
    id: 4
  },
  {
    condition: function(data) {
      return data.indexOf('has captured the undefended relic') !== -1;
    },
    id: 4
  },
  {
    condition: function(data) {
      return data.indexOf('attempted to capture your relic') !== -1;
    },
    id: 4
  },
  {
    condition: function(data) {
      return / empowered the .+ relic/.test(data);
    },
    id: 4
  },
  {
    condition: function(data) {
      return / removed the empowerment from the .+ relic/.test(data);
    },
    id: 4
  },
  {
    condition: function(data) {
      return data.indexOf('disbanded a mercenary.') !== -1;
    },
    id: 5
  },
  {
    condition: function(data) {
      return data.indexOf('hired the mercenary') !== -1;
    },
    id: 5
  },
  {
    condition: function(data) {
      return data.indexOf('has disbanded one of their groups') !== -1;
    },
    id: 6
  },
  {
    condition: function(data) {
      return /A group from your guild was (.*) in combat./.test(data);
    },
    id: 6
  },
  {
    condition: function(data) {
      return /deposited ([,0-9]+) gold into the guild bank/.test(data);
    },
    id: 7
  },
  {
    condition: function(data) {
      var re = /deposited ([,0-9]+) FallenSword Points into the guild./;
      return re.test(data);
    },
    id: 7
  },
  {
    condition: function(data) {
      return data.indexOf('has added a new rank entitled') !== -1;
    },
    id: 8
  },
  {
    condition: function(data) {
      return data.indexOf('has deleted the rank') !== -1;
    },
    id: 8
  },
  {
    condition: function(data) {
      return data.indexOf('has requested to join the guild') !== -1;
    },
    id: 8
  },
  {
    condition: function(data) {
      return data.indexOf('has invited the player') !== -1;
    },
    id: 8
  },
  {
    condition: function(data) {
      return data.indexOf('has officially joined the guild') !== -1;
    },
    id: 8
  },
  {
    condition: function(data) {
      return data.indexOf('has been kicked from the guild by') !== -1;
    },
    id: 8
  },
  {
    condition: function(data) {
      return data.indexOf('has left the guild') !== -1;
    },
    id: 8
  },
  {
    condition: function(data) {
      return data.indexOf('has been assigned the rank') !== -1;
    },
    id: 8
  },
  {
    condition: function(data) {
      return /resulted in (.*) with a final score of/.test(data);
    },
    id: 9
  },
  {
    condition: function(data) {
      return data.indexOf('resulted in a draw. Your GvG rating ' +
        'and Guild RP was unaffected.') !== -1;
    },
    id: 9
  },
  {
    condition: function(data) {
      return data.indexOf(
        'has just initiated a conflict with the guild') !== -1;
    },
    id: 9
  },
  {
    condition: function(data) {
      return data.indexOf('has initiated a conflict with your guild') !== -1;
    },
    id: 9
  },
  {
    condition: function(data) {
      return data.indexOf('is participating in the conflict ' +
        'against the guild') !== -1;
    },
    id: 9
  },
  {
    condition: function(data) {
      return data.indexOf('bought the Titan Reward item') !== -1;
    },
    id: 10
  },
  {
    condition: function(data) {
      return data.indexOf('from your guild\'s contribution to the ' +
        'defeat of the titan') !== -1;
    },
    id: 10
  },
  {
    condition: function(data) {
      return data.indexOf('a 7 day cooldown has been activated ' +
        'on your guild for this titan') !== -1;
    },
    id: 10
  }
];

export function rowProfile(data) {
  var rowId = 0;
  var index = 0;
  while (!rowId && index < lookup.length) {
    var test = lookup[index];
    if (test.condition(data)) {rowId = test.id;}
    index += 1;
  }
  return rowId;
}
<|endoftext|>


<commit_before>alert("Hello World, from Git");
alert("A second Hello...");
alert("A third Hello...);

<commit_msg>Missing quotes error repaired<commit_after>alert("Hello World, from Git");
alert("A second Hello...");
alert("A third Hello...");

<|endoftext|>


<commit_before>const express = require('express');
const helmet = require('helmet');
require('express-async-errors');
const path = require('path');
const logger = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');

const apiBasePathRouter = require('./routes');
const versionRouter = require('./routes/version/version');
const userRouter = require('./routes/users/user.router');
const webPageInfoRouter = require('./routes/webpage-info/webpage-info.router');
const adminRouter = require('./routes/admin/admin.router');
const publicBookmarksRouter = require('./routes/public/public-bookmarks.router');
const publicUsersRouter = require('./routes/public/public-users.router');
const {MongoError} = require('mongodb');
const ValidationError = require('./error/validation.error');
const NotFoundError = require('./error/not-found.error');
const PublicBookmarkExistingError = require('./error/public-bookmark-existent.error');
const UseridValidationError = require('./routes/users/userid-validation.error');

const fs = require('fs-extra');
const rfs = require('rotating-file-stream/index');

const HttpStatus = require('http-status-codes/index');

const swaggerUi = require('swagger-ui-express');
const YAML = require('yamljs');
const swaggerDocument = YAML.load('./docs/openapi/openapi.yaml');

const app = express();

// Sets "Strict-Transport-Security: max-age=5184000; includeSubDomains".
const sixtyDaysInSeconds = 5184000;
app.use(helmet.hsts({
  maxAge: sixtyDaysInSeconds
}));
app.disable('x-powered-by');

const mongoUserName = process.env.MONGODB_BOOKMARKS_USERNAME || 'bookmarks';
const mongoUserPwd = process.env.MONGODB_BOOKMARKS_PASSWORD || 'secret';
const mongoBookmarksCollectionName = process.env.MONGODB_BOOKMARKS_COLLECTION || 'dev-bookmarks';
const mongoHost = process.env.MONGODB_HOST || 'localhost';
const mongoPort = process.env.MONGODB_PORT || '27017';

const mongooseConnectOptions = {
  useNewUrlParser: true,
  useUnifiedTopology: true,
  useFindAndModify: false
};

const mongoUrl = `mongodb://${mongoUserName}:${mongoUserPwd}@${mongoHost}:${mongoPort}/${mongoBookmarksCollectionName}`;
mongoose.connect(mongoUrl, mongooseConnectOptions);

// sets port 3000 to default or unless otherwise specified in the environment
app.set('port', process.env.PORT || 3000);

let setUpLogging = function () {
  const logDirectory = (process.env.CONTAINER_HOME || '.') + '/log';
  // ensure log directory exists
  fs.existsSync(logDirectory) || fs.mkdirSync(logDirectory);
  // create a rotating write stream
  let accessLogStream = rfs('access.log', {
    interval: '1d', // rotate daily
    path: logDirectory
  })
  app.use(logger('combined', {stream: accessLogStream}));// logs in file in Apache style format
  app.use(logger('dev'));// logs at the console in 'dev' format
};

setUpLogging();

app.use('/api/docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));//swagger docs are not protected

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

//add CORS support
app.use(function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Access-Control-Allow-Methods', 'POST, GET, PUT, PATCH, DELETE, OPTIONS');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, Location');
  res.setHeader('Access-Control-Expose-Headers', 'Content-Type, Authorization, Location');
  next();
});

app.use('/api', apiBasePathRouter);
app.use('/api/version', versionRouter);
app.use('/api/public/users', publicUsersRouter);
app.use('/api/public/bookmarks', publicBookmarksRouter);
app.use('/api/personal/users', userRouter);
app.use('/api/webpage-info', webPageInfoRouter);
app.use('/api/admin', adminRouter);

// catch 404 and forward to error handler
app.use(function (req, res, next) {
  const err = new Error('Not Found');
  err.status = HttpStatus.NOT_FOUND;
  next(err);
});

// error handlers
app.use(function handleNotFoundError(error, req, res, next) {
  if ( error instanceof NotFoundError ) {
    return res.status(HttpStatus.NOT_FOUND).send({
      httpStatus: HttpStatus.NOT_FOUND,
      message: error.message,
      stack: app.get('env') === 'development' ? error.stack : {}
    });
  }
  next(error);
});

app.use(function handlePublicBookmarkExistingError(error, req, res, next) {
  if ( error instanceof PublicBookmarkExistingError ) {
    return res.status(HttpStatus.CONFLICT).send({
      httpStatus: HttpStatus.CONFLICT,
      message: error.message,
      stack: app.get('env') === 'development' ? error.stack : {}
    });
  }
  next(error);
});

app.use(function handleUserIdValidationError(error, req, res, next) {
  if ( error instanceof UseridValidationError ) {
    res.status(HttpStatus.UNAUTHORIZED);
    return res.send({
      httpStatus: HttpStatus.UNAUTHORIZED,
      message: error.message,
      stack: app.get('env') === 'development' ? error.stack : {}
    });
  }
  next(error);
});

app.use(function handleValidationError(error, request, response, next) {
  if ( error instanceof ValidationError ) {
    return response
      .status(HttpStatus.BAD_REQUEST)
      .json({
        httpStatus: HttpStatus.BAD_REQUEST,
        message: error.message,
        validationErrors: error.validationErrors,
        stack: app.get('env') === 'development' ? error.stack : {}
      });
  }
  next(error);
});

app.use(function handleDatabaseError(error, request, response, next) {
  if ( error instanceof MongoError ) {
    if ( error.code === 11000 ) {
      return response
        .status(HttpStatus.CONFLICT)
        .json({
          httpStatus: HttpStatus.CONFLICT,
          type: 'MongoError',
          message: error.message,
          stack: app.get('env') === 'development' ? error.stack : {}
        });
    } else {
      return response.status(503).json({
        httpStatus: HttpStatus.SERVICE_UNAVAILABLE,
        type: 'MongoError',
        message: error.message,
        stack: app.get('env') === 'development' ? error.stack : {}
      });
    }
  }
  next(error);
});

// production error handler
// no stacktraces leaked to user
app.use(function (error, req, res, next) {
  if ( res.headersSent ) {
    return next(error)
  } else if ( error.code === 'LIMIT_FILE_SIZE') { // Multer error - see https://github.com/expressjs/multer/blob/master/lib/multer-error.js && https://github.com/expressjs/multer#error-handling
    return res
      .status(HttpStatus.BAD_REQUEST)
      .json({
        httpStatus: HttpStatus.BAD_REQUEST,
        message: error.code + ' ' + error.message,
        stack: app.get('env') === 'development' ? error.stack : {}
      });
  } else {
    res.status(error.status || HttpStatus.INTERNAL_SERVER_ERROR);
    res.send({
      message: error.message,
      stack: app.get('env') === 'development' ? error.stack : {}
    });
  }

});

module.exports = app;
<commit_msg>fix(be-trust-proxy): set trust proxy in app.js<commit_after>const express = require('express');
const helmet = require('helmet');
require('express-async-errors');
const path = require('path');
const logger = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');

const apiBasePathRouter = require('./routes');
const versionRouter = require('./routes/version/version');
const userRouter = require('./routes/users/user.router');
const webPageInfoRouter = require('./routes/webpage-info/webpage-info.router');
const adminRouter = require('./routes/admin/admin.router');
const publicBookmarksRouter = require('./routes/public/public-bookmarks.router');
const publicUsersRouter = require('./routes/public/public-users.router');
const {MongoError} = require('mongodb');
const ValidationError = require('./error/validation.error');
const NotFoundError = require('./error/not-found.error');
const PublicBookmarkExistingError = require('./error/public-bookmark-existent.error');
const UseridValidationError = require('./routes/users/userid-validation.error');

const fs = require('fs-extra');
const rfs = require('rotating-file-stream/index');

const HttpStatus = require('http-status-codes/index');

const swaggerUi = require('swagger-ui-express');
const YAML = require('yamljs');
const swaggerDocument = YAML.load('./docs/openapi/openapi.yaml');

const app = express();

// Sets "Strict-Transport-Security: max-age=5184000; includeSubDomains".
const sixtyDaysInSeconds = 5184000;
app.use(helmet.hsts({
  maxAge: sixtyDaysInSeconds
}));
app.disable('x-powered-by');

const mongoUserName = process.env.MONGODB_BOOKMARKS_USERNAME || 'bookmarks';
const mongoUserPwd = process.env.MONGODB_BOOKMARKS_PASSWORD || 'secret';
const mongoBookmarksCollectionName = process.env.MONGODB_BOOKMARKS_COLLECTION || 'dev-bookmarks';
const mongoHost = process.env.MONGODB_HOST || 'localhost';
const mongoPort = process.env.MONGODB_PORT || '27017';

const mongooseConnectOptions = {
  useNewUrlParser: true,
  useUnifiedTopology: true,
  useFindAndModify: false
};

const mongoUrl = `mongodb://${mongoUserName}:${mongoUserPwd}@${mongoHost}:${mongoPort}/${mongoBookmarksCollectionName}`;
mongoose.connect(mongoUrl, mongooseConnectOptions);

// sets port 3000 to default or unless otherwise specified in the environment
app.set('port', process.env.PORT || 3000);

let setUpLogging = function () {
  const logDirectory = (process.env.CONTAINER_HOME || '.') + '/log';
  // ensure log directory exists
  fs.existsSync(logDirectory) || fs.mkdirSync(logDirectory);
  // create a rotating write stream
  let accessLogStream = rfs('access.log', {
    interval: '1d', // rotate daily
    path: logDirectory
  })
  app.use(logger('combined', {stream: accessLogStream}));// logs in file in Apache style format
  app.use(logger('dev'));// logs at the console in 'dev' format
};

setUpLogging();

app.use('/api/docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));//swagger docs are not protected

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));

app.set("trust proxy", "loopback");

//add CORS support
app.use(function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Access-Control-Allow-Methods', 'POST, GET, PUT, PATCH, DELETE, OPTIONS');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, Location');
  res.setHeader('Access-Control-Expose-Headers', 'Content-Type, Authorization, Location');
  next();
});

app.use('/api', apiBasePathRouter);
app.use('/api/version', versionRouter);
app.use('/api/public/users', publicUsersRouter);
app.use('/api/public/bookmarks', publicBookmarksRouter);
app.use('/api/personal/users', userRouter);
app.use('/api/webpage-info', webPageInfoRouter);
app.use('/api/admin', adminRouter);

// catch 404 and forward to error handler
app.use(function (req, res, next) {
  const err = new Error('Not Found');
  err.status = HttpStatus.NOT_FOUND;
  next(err);
});

// error handlers
app.use(function handleNotFoundError(error, req, res, next) {
  if ( error instanceof NotFoundError ) {
    return res.status(HttpStatus.NOT_FOUND).send({
      httpStatus: HttpStatus.NOT_FOUND,
      message: error.message,
      stack: app.get('env') === 'development' ? error.stack : {}
    });
  }
  next(error);
});

app.use(function handlePublicBookmarkExistingError(error, req, res, next) {
  if ( error instanceof PublicBookmarkExistingError ) {
    return res.status(HttpStatus.CONFLICT).send({
      httpStatus: HttpStatus.CONFLICT,
      message: error.message,
      stack: app.get('env') === 'development' ? error.stack : {}
    });
  }
  next(error);
});

app.use(function handleUserIdValidationError(error, req, res, next) {
  if ( error instanceof UseridValidationError ) {
    res.status(HttpStatus.UNAUTHORIZED);
    return res.send({
      httpStatus: HttpStatus.UNAUTHORIZED,
      message: error.message,
      stack: app.get('env') === 'development' ? error.stack : {}
    });
  }
  next(error);
});

app.use(function handleValidationError(error, request, response, next) {
  if ( error instanceof ValidationError ) {
    return response
      .status(HttpStatus.BAD_REQUEST)
      .json({
        httpStatus: HttpStatus.BAD_REQUEST,
        message: error.message,
        validationErrors: error.validationErrors,
        stack: app.get('env') === 'development' ? error.stack : {}
      });
  }
  next(error);
});

app.use(function handleDatabaseError(error, request, response, next) {
  if ( error instanceof MongoError ) {
    if ( error.code === 11000 ) {
      return response
        .status(HttpStatus.CONFLICT)
        .json({
          httpStatus: HttpStatus.CONFLICT,
          type: 'MongoError',
          message: error.message,
          stack: app.get('env') === 'development' ? error.stack : {}
        });
    } else {
      return response.status(503).json({
        httpStatus: HttpStatus.SERVICE_UNAVAILABLE,
        type: 'MongoError',
        message: error.message,
        stack: app.get('env') === 'development' ? error.stack : {}
      });
    }
  }
  next(error);
});

// production error handler
// no stacktraces leaked to user
app.use(function (error, req, res, next) {
  if ( res.headersSent ) {
    return next(error)
  } else if ( error.code === 'LIMIT_FILE_SIZE') { // Multer error - see https://github.com/expressjs/multer/blob/master/lib/multer-error.js && https://github.com/expressjs/multer#error-handling
    return res
      .status(HttpStatus.BAD_REQUEST)
      .json({
        httpStatus: HttpStatus.BAD_REQUEST,
        message: error.code + ' ' + error.message,
        stack: app.get('env') === 'development' ? error.stack : {}
      });
  } else {
    res.status(error.status || HttpStatus.INTERNAL_SERVER_ERROR);
    res.send({
      message: error.message,
      stack: app.get('env') === 'development' ? error.stack : {}
    });
  }

});

module.exports = app;
<|endoftext|>