<commit_before>import Vue from 'vue'
import Router from 'vue-router'
import Hello from '@/components/Hello'
import Register from '@/components/Register'
import Login from '@/components/Login'
import Songs from '@/components/Songs'
import CreateSong from '@/components/CreateSong'
import ViewSong from '@/components/ViewSong'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'root',
      component: Hello
    },
    {
      path: '/register',
      name: 'register',
      component: Register
    },
    {
      path: '/login',
      name: 'login',
      component: Login
    },
    {
      path: '/songs',
      name: 'songs',
      component: Songs
    },
    {
      path: '/songs/create',
      name: 'create-song',
      component: CreateSong
    },
    {
      path: '/songs/:songId',
      name: 'song',
      component: ViewSong
    }
  ]
})
<commit_msg>modify ViewSong route<commit_after>import Vue from 'vue'
import Router from 'vue-router'
import Hello from '@/components/Hello'
import Register from '@/components/Register'
import Login from '@/components/Login'
import Songs from '@/components/Songs'
import CreateSong from '@/components/CreateSong'
import ViewSong from '@/components/ViewSong/ViewSong'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'root',
      component: Hello
    },
    {
      path: '/register',
      name: 'register',
      component: Register
    },
    {
      path: '/login',
      name: 'login',
      component: Login
    },
    {
      path: '/songs',
      name: 'songs',
      component: Songs
    },
    {
      path: '/songs/create',
      name: 'create-song',
      component: CreateSong
    },
    {
      path: '/songs/:songId',
      name: 'song',
      component: ViewSong
    }
  ]
})
<|endoftext|>


<commit_before>define(['jquery', 'underscore', 'queue'], function($, _, queue) {

    $.fn.canvid = function(_opts) {
        var el = $(this),
            images = {},
            firstPlay = true,
            control = {
                play: function() { console.log('cannot play before images are loaded'); }
            };

        _opts = $.extend(el.data(), _opts || {});

        if (testCanvas()) {
            // preload videos images
            var q = queue(4);

            _.each(_opts.videos, function(video, key) {
                q.defer(loadImage, key, video.src);
            });

            q.awaitAll(function(err) {
                if (err) return console.warn('error while loading video sources', err);

                var ctx = initCanvas(),
                    requestAnimationFrame = reqAnimFrame();

                control.play = function(key, reverse) {
                    if (control.pause) control.pause(); // pause current vid

                    var img = images[key],
                        opts = _opts.videos[key];

                    var curFrame = reverse ? opts.frames-1 : 0,
                        wait = 0,
                        playing = true,
                        loops = 0,
                        delay = 4;

                    requestAnimationFrame(frame);

                    control.resume = function() {
                        playing = true;
                        requestAnimationFrame(frame);
                    };

                    control.pause = function() {
                        playing = false;
                        requestAnimationFrame(frame);
                    };

                    if (firstPlay) {
                        firstPlay = false;
                        $(':not(canvas.canvid)', el).hide();
                    }

                    function frame() {
                        if (!wait) {
                            drawFrame(curFrame);
                            curFrame = (+curFrame + (reverse ? -1 : 1));
                            if (curFrame < 0) curFrame += +opts.frames;
                            if (curFrame >= opts.frames) curFrame -= opts.frames;
                            if (reverse ? curFrame == opts.frames-1 : !curFrame) loops++;
                            if (opts.loops && loops >= opts.loops) playing = false;
                        }
                        wait = (wait+1) % ((reverse ? 0.5 : 1) * delay);
                        if (playing && opts.frames > 1) requestAnimationFrame(frame);
                    }

                    function drawFrame(f) {
                        var fx = Math.floor(f % opts.cols) * _opts.width,
                            fy = Math.floor(f / opts.cols) * _opts.height;
                        ctx.clearRect(0, 0, _opts.width, _opts.height); // clear frame
                        ctx.drawImage(img, fx, fy, _opts.width, _opts.height, 0,0, _opts.width, _opts.height);
                    }

                }; // end control.play

                if ($.isFunction(_opts.loaded)) _opts.loaded(control);

            }); // end awaitAll

        } else if (opts.srcGif) {
            el.append('');
        }

        function loadImage(key, url, callback) {
            var img = images[key] = new Image();
            img.onload = function() { callback(null); };
            img.src = url;
        }

        function initCanvas() {
            var canvas = $('<canvas />')
                .attr('width', _opts.width)
                .attr('class', 'canvid')
                .attr('height', _opts.height)
                .appendTo(el);
            return canvas.get(0).getContext("2d");
        }

        function reqAnimFrame() {
            return window.requestAnimationFrame
                || window.webkitRequestAnimationFrame
                || window.mozRequestAnimationFrame
                || window.msRequestAnimationFrame
                || function(callback) { return setTimeout(callback, 1000 / 60); };
        }

        function hasCanvas() {
            // taken from Modernizr
            var elem = document.createElement('canvas');
            return !!(elem.getContext && elem.getContext('2d'));
        }

        return control;
    };

});
<commit_msg>use hasCanvas function<commit_after>define(['jquery', 'underscore', 'queue'], function($, _, queue) {

    $.fn.canvid = function(_opts) {
        var el = $(this),
            images = {},
            firstPlay = true,
            control = {
                play: function() { console.log('cannot play before images are loaded'); }
            };

        _opts = $.extend(el.data(), _opts || {});

        if (hasCanvas()) {
            // preload videos images
            var q = queue(4);

            _.each(_opts.videos, function(video, key) {
                q.defer(loadImage, key, video.src);
            });

            q.awaitAll(function(err) {
                if (err) return console.warn('error while loading video sources', err);

                var ctx = initCanvas(),
                    requestAnimationFrame = reqAnimFrame();

                control.play = function(key, reverse) {
                    if (control.pause) control.pause(); // pause current vid

                    var img = images[key],
                        opts = _opts.videos[key];

                    var curFrame = reverse ? opts.frames-1 : 0,
                        wait = 0,
                        playing = true,
                        loops = 0,
                        delay = 4;

                    requestAnimationFrame(frame);

                    control.resume = function() {
                        playing = true;
                        requestAnimationFrame(frame);
                    };

                    control.pause = function() {
                        playing = false;
                        requestAnimationFrame(frame);
                    };

                    if (firstPlay) {
                        firstPlay = false;
                        $(':not(canvas.canvid)', el).hide();
                    }

                    function frame() {
                        if (!wait) {
                            drawFrame(curFrame);
                            curFrame = (+curFrame + (reverse ? -1 : 1));
                            if (curFrame < 0) curFrame += +opts.frames;
                            if (curFrame >= opts.frames) curFrame -= opts.frames;
                            if (reverse ? curFrame == opts.frames-1 : !curFrame) loops++;
                            if (opts.loops && loops >= opts.loops) playing = false;
                        }
                        wait = (wait+1) % ((reverse ? 0.5 : 1) * delay);
                        if (playing && opts.frames > 1) requestAnimationFrame(frame);
                    }

                    function drawFrame(f) {
                        var fx = Math.floor(f % opts.cols) * _opts.width,
                            fy = Math.floor(f / opts.cols) * _opts.height;
                        ctx.clearRect(0, 0, _opts.width, _opts.height); // clear frame
                        ctx.drawImage(img, fx, fy, _opts.width, _opts.height, 0,0, _opts.width, _opts.height);
                    }

                }; // end control.play

                if ($.isFunction(_opts.loaded)) _opts.loaded(control);

            }); // end awaitAll

        } else if (opts.srcGif) {
            el.append('');
        }

        function loadImage(key, url, callback) {
            var img = images[key] = new Image();
            img.onload = function() { callback(null); };
            img.src = url;
        }

        function initCanvas() {
            var canvas = $('<canvas />')
                .attr('width', _opts.width)
                .attr('class', 'canvid')
                .attr('height', _opts.height)
                .appendTo(el);
            return canvas.get(0).getContext("2d");
        }

        function reqAnimFrame() {
            return window.requestAnimationFrame
                || window.webkitRequestAnimationFrame
                || window.mozRequestAnimationFrame
                || window.msRequestAnimationFrame
                || function(callback) { return setTimeout(callback, 1000 / 60); };
        }

        function hasCanvas() {
            // taken from Modernizr
            var elem = document.createElement('canvas');
            return !!(elem.getContext && elem.getContext('2d'));
        }

        return control;
    };

});
<|endoftext|>


<commit_before>
const RG = require('../rg');
RG.Path = require('../path');
RG.Geometry = require('../geometry');

const System = {};
System.Base = require('./system.base');

System.Animation = require('./system.animation');
System.AreaEffects = require('./system.area-effects');
System.Attack = require('./system.attack');
System.BaseAction = require('./system.base-action');
System.Battle = require('./system.battle');
System.Chat = require('./system.chat');
System.Communication = require('./system.communication');
System.Damage = require('./system.damage');
System.Disability = require('./system.disability');
System.Effects = require('./system.effects');
System.Events = require('./system.events');
System.ExpPoints = require('./system.exp-points');
System.Hunger = require('./system.hunger');
System.Missile = require('./system.missile');
System.Movement = require('./system.movement');
System.Shop = require('./system.shop');
System.Skills = require('./system.skills');
System.SpellCast = require('./system.spell-cast');
System.SpellEffect = require('./system.spell-effect');
System.SpiritBind = require('./system.spirit-bind');
System.TimeEffects = require('./system.time-effects');

module.exports = System;
<commit_msg>Added SYS.EQUIP.<commit_after>
const RG = require('../rg');
RG.Path = require('../path');
RG.Geometry = require('../geometry');

const System = {};
System.Base = require('./system.base');

System.Animation = require('./system.animation');
System.AreaEffects = require('./system.area-effects');
System.Attack = require('./system.attack');
System.BaseAction = require('./system.base-action');
System.Battle = require('./system.battle');
System.Chat = require('./system.chat');
System.Communication = require('./system.communication');
System.Damage = require('./system.damage');
System.Disability = require('./system.disability');
System.Effects = require('./system.effects');
System.Equip = require('./system.equip');
System.Events = require('./system.events');
System.ExpPoints = require('./system.exp-points');
System.Hunger = require('./system.hunger');
System.Missile = require('./system.missile');
System.Movement = require('./system.movement');
System.Shop = require('./system.shop');
System.Skills = require('./system.skills');
System.SpellCast = require('./system.spell-cast');
System.SpellEffect = require('./system.spell-effect');
System.SpiritBind = require('./system.spirit-bind');
System.TimeEffects = require('./system.time-effects');

module.exports = System;
<|endoftext|>


<commit_before>import React from 'react';
import { routerHookPropName } from './routerHooks';
import { selectProps, selectStatus } from './routerModule';

export default class RouterHookContainer extends React.Component {
  static propTypes = {
    children: React.PropTypes.node,
  }

  static contextTypes = {
    routerHookContext: React.PropTypes.object.isRequired,
  };

  constructor(props, context) {
    super(props, context);
    this.Component = props.children.type;
    this.state = {};
  }

  componentDidMount() {
    this.trySubscribe();
  }

  componentWillUnmount() {
    this.tryUnsubscribe();
    this.clearCache();
  }

  componentShouldUpdate(nextProps, nextState) {
    return nextState.componentStatus !== 'init' &&
      (this.state.routerLoading !== nextState.routerLoading ||
        this.state.componentStatus !== nextState.componentStatus);
  }

  shouldSubscribe() {
    return !!this.Component && !!this.Component[routerHookPropName];
  }

  trySubscribe() {
    if (this.shouldSubscribe() && !this.unsubscribe) {
      this.unsubscribe = this.context.routerHookContext.subscribe(this.handleChange.bind(this));
      this.handleChange();
    }
  }

  tryUnsubscribe() {
    if (this.unsubscribe) {
      this.unsubscribe();
      this.unsubscribe = null;
    }
  }

  clearCache() {
    this.hasStoreStateChanged = null;
  }

  handleChange() {
    if (!this.unsubscribe) {
      return;
    }

    const storeState = this.context.routerHookContext.getState();
    if (!storeState) {
      console.error('storeState is empty', storeState, this.context.routerHookContext);
    }
    const prevStoreState = this.state.storeState;
    if (prevStoreState === storeState) {
      return;
    }

    this.hasStoreStateChanged = true;
    this.setState({
      componentProps: selectProps(storeState, this.Component),
      componentStatus: selectStatus(storeState, this.Component),
      routerLoading: storeState.routerLoading,
    });
  }

  render() {
    this.hasStoreStateChanged = false;
    const {
      componentProps = {},
      componentStatus,
      routerLoading,
    } = this.state;
    const {
      reloadComponent,
    } = this.context.routerHookContext;

    if (componentStatus === 'init') {
      return null;
    }

    return React.cloneElement(this.props.children, {
      ...componentProps,
      componentStatus,
      reloadComponent,
      routerLoading,
    });
  }
}
<commit_msg>fix shouldComponentUpdate and add storeState<commit_after>import React from 'react';
import { routerHookPropName } from './routerHooks';
import { selectProps, selectStatus } from './routerModule';

export default class RouterHookContainer extends React.Component {
  static propTypes = {
    children: React.PropTypes.node,
    location: React.PropTypes.object.isRequired,
  }

  static contextTypes = {
    routerHookContext: React.PropTypes.object.isRequired,
  };

  constructor(props, context) {
    super(props, context);
    this.Component = props.children.type;
    this.state = {};
  }

  componentDidMount() {
    this.trySubscribe();
  }

  shouldComponentUpdate(nextProps, nextState) {
    if (this.props.location !== nextProps.location) {
      return true;
    }
    return nextState.componentStatus !== 'init' &&
      (this.state.routerLoading !== nextState.routerLoading ||
        this.state.componentStatus !== nextState.componentStatus);
  }

  componentWillUnmount() {
    this.tryUnsubscribe();
    this.clearCache();
  }

  shouldSubscribe() {
    return !!this.Component && !!this.Component[routerHookPropName];
  }

  trySubscribe() {
    if (this.shouldSubscribe() && !this.unsubscribe) {
      this.unsubscribe = this.context.routerHookContext.subscribe(this.handleChange.bind(this));
      this.handleChange();
    }
  }

  tryUnsubscribe() {
    if (this.unsubscribe) {
      this.unsubscribe();
      this.unsubscribe = null;
    }
  }

  clearCache() {
    this.hasStoreStateChanged = null;
  }

  handleChange() {
    if (!this.unsubscribe) {
      return;
    }

    const storeState = this.context.routerHookContext.getState();
    if (!storeState) {
      console.error('storeState is empty', storeState, this.context.routerHookContext);
    }
    const prevStoreState = this.state.storeState;
    if (prevStoreState === storeState) {
      return;
    }

    this.hasStoreStateChanged = true;
    this.setState({
      storeState,
      componentProps: selectProps(storeState, this.Component),
      componentStatus: selectStatus(storeState, this.Component),
      routerLoading: storeState.routerLoading,
    });
  }

  render() {
    this.hasStoreStateChanged = false;
    const {
      componentProps = {},
      componentStatus,
      routerLoading,
    } = this.state;
    const {
      reloadComponent,
    } = this.context.routerHookContext;

    if (componentStatus === 'init') {
      return null;
    }

    return React.cloneElement(this.props.children, {
      ...componentProps,
      componentStatus,
      reloadComponent,
      routerLoading,
    });
  }
}
<|endoftext|>


<commit_before>$(function () { // Same as document.addEventListener("DOMContentLoaded"...

  // Same as document.querySelector("#navbarToggle").addEventListener("blur",...
  $("#navbarToggle").blur(function (event) {
    var screenWidth = window.innerWidth;
    if (screenWidth < 768) {
      $("#collapsable-nav").collapse('hide');
    }
  });
});

(function (global) {

var dc = {};

var homeHtmlUrl = "snippets/home-snippet.html";
var allCategoriesUrl =
  "https://davids-restaurant.herokuapp.com/categories.json";
var categoriesTitleHtml = "snippets/categories-title-snippet.html";
var categoryHtml = "snippets/category-snippet.html";
var menuItemsUrl =
  "https://davids-restaurant.herokuapp.com/menu_items.json?category=";
var menuItemsTitleHtml = "snippets/menu-items-title.html";
var menuItemHtml = "snippets/menu-item.html";

// Convenience function for inserting innerHTML for 'select'
var insertHtml = function (selector, html) {
  var targetElem = document.querySelector(selector);
  targetElem.innerHTML = html;
};

// Show loading icon inside element identified by 'selector'.
var showLoading = function (selector) {
  var html = "
";
  html += "
";
  insertHtml(selector, html);
};

// Return substitute of '{{propName}}'
// with propValue in given 'string'
var insertProperty = function (string, propName, propValue) {
  var propToReplace = "{{" + propName + "}}";
  string = string
    .replace(new RegExp(propToReplace, "g"), propValue);
  return string;
};

// Remove the class 'active' from home and switch to Menu button
var switchMenuToActive = function () {
  // Remove 'active' from home button
  var classes = document.querySelector("#navHomeButton").className;
  classes = classes.replace(new RegExp("active", "g"), "");
  document.querySelector("#navHomeButton").className = classes;

  // Add 'active' to menu button if not already there
  classes = document.querySelector("#navMenuButton").className;
  if (classes.indexOf("active") === -1) {
    classes += " active";
    document.querySelector("#navMenuButton").className = classes;
  }
};

// On page load (before images or CSS)
document.addEventListener("DOMContentLoaded", function (event) {

// TODO: STEP 0: Look over the code from
// *** start ***
// to
// *** finish ***
// below.
// We changed this code to retrieve all categories from the server instead of
// simply requesting home HTML snippet. We now also have another function
// called buildAndShowHomeHTML that will receive all the categories from the server
// and process them: choose random category, retrieve home HTML snippet, insert that
// random category into the home HTML snippet, and then insert that snippet into our
// main page (index.html).
//
// TODO: STEP 1: Substitute [...] below with the *value* of the function buildAndShowHomeHTML,
// so it can be called when server responds with the categories data.

// *** start ***
// On first load, show home view
showLoading("#main-content");
$ajaxUtils.sendGetRequest(
  allCategoriesUrl,
  [...], // ***** <---- TODO: STEP 1: Substitute [...] ******
  true); // Explicitely setting the flag to get JSON from server processed into an object literal
});
// *** finish **

// Builds HTML for the home page based on categories array
// returned from the server.
function buildAndShowHomeHTML (categories) {

  // Load home snippet page
  $ajaxUtils.sendGetRequest(
    homeHtmlUrl,
    function (homeHtml) {

      // TODO: STEP 2: Here, call chooseRandomCategory, passing it retrieved 'categories'
      // Pay attention to what type of data that function returns vs what the chosenCategoryShortName
      // variable's name implies it expects.
      // var chosenCategoryShortName = ....

      // TODO: STEP 3: Substitute {{randomCategoryShortName}} in the home html snippet with the
      // chosen category from STEP 2. Use existing insertProperty function for that purpose.
      // Look through this code for an example of how to do use the insertProperty function.
      // WARNING! You are inserting something that will have to result in a valid Javascript
      // syntax because the substitution of {{randomCategoryShortName}} becomes an argument
      // being passed into the $dc.loadMenuItems function. Think about what that argument needs
      // to look like. For example, a valid call would look something like this:
      // $dc.loadMenuItems('L')
      // Hint: you need to surround the chosen category short name with something before inserting
      // it into the home html snippet.
      //
      // var homeHtmlToInsertIntoMainPage = ....

      // TODO: STEP 4: Insert the the produced HTML in STEP 3 into the main page
      // Use the existing insertHtml function for that purpose. Look through this code for an example
      // of how to do that.
      // ....

    },
    false); // False here because we are getting just regular HTML from the server, so no need to process JSON.
}

// Given array of category objects, returns a random category object.
function chooseRandomCategory (categories) {
  // Choose a random index into the array (from 0 inclusively until array length (exclusively))
  var randomArrayIndex = Math.floor(Math.random() * categories.length);

  // return category object with that randomArrayIndex
  return categories[randomArrayIndex];
}

// Load the menu categories view
dc.loadMenuCategories = function () {
  showLoading("#main-content");
  $ajaxUtils.sendGetRequest(
    allCategoriesUrl,
    buildAndShowCategoriesHTML);
};

// Load the menu items view
// 'categoryShort' is a short_name for a category
dc.loadMenuItems = function (categoryShort) {
  showLoading("#main-content");
  $ajaxUtils.sendGetRequest(
    menuItemsUrl + categoryShort,
    buildAndShowMenuItemsHTML);
};

// Builds HTML for the categories page based on the data
// from the server
function buildAndShowCategoriesHTML (categories) {
  // Load title snippet of categories page
  $ajaxUtils.sendGetRequest(
    categoriesTitleHtml,
    function (categoriesTitleHtml) {
      // Retrieve single category snippet
      $ajaxUtils.sendGetRequest(
        categoryHtml,
        function (categoryHtml) {
          // Switch CSS class active to menu button
          switchMenuToActive();

          var categoriesViewHtml =
            buildCategoriesViewHtml(categories,
                                    categoriesTitleHtml,
                                    categoryHtml);
          insertHtml("#main-content", categoriesViewHtml);
        },
        false);
    },
    false);
}

// Using categories data and snippets html
// build categories view HTML to be inserted into page
function buildCategoriesViewHtml(categories,
                                 categoriesTitleHtml,
                                 categoryHtml) {

  var finalHtml = categoriesTitleHtml;
  finalHtml += "
";

  // Loop over categories
  for (var i = 0; i < categories.length; i++) {
    // Insert category values
    var html = categoryHtml;
    var name = "" + categories[i].name;
    var short_name = categories[i].short_name;
    html =
      insertProperty(html, "name", name);
    html =
      insertProperty(html,
                     "short_name",
                     short_name);
    finalHtml += html;
  }

  finalHtml += "
";
  return finalHtml;
}

// Builds HTML for the single category page based on the data
// from the server
function buildAndShowMenuItemsHTML (categoryMenuItems) {
  // Load title snippet of menu items page
  $ajaxUtils.sendGetRequest(
    menuItemsTitleHtml,
    function (menuItemsTitleHtml) {
      // Retrieve single menu item snippet
      $ajaxUtils.sendGetRequest(
        menuItemHtml,
        function (menuItemHtml) {
          // Switch CSS class active to menu button
          switchMenuToActive();

          var menuItemsViewHtml =
            buildMenuItemsViewHtml(categoryMenuItems,
                                   menuItemsTitleHtml,
                                   menuItemHtml);
          insertHtml("#main-content", menuItemsViewHtml);
        },
        false);
    },
    false);
}

// Using category and menu items data and snippets html
// build menu items view HTML to be inserted into page
function buildMenuItemsViewHtml(categoryMenuItems,
                                menuItemsTitleHtml,
                                menuItemHtml) {

  menuItemsTitleHtml =
    insertProperty(menuItemsTitleHtml,
                   "name",
                   categoryMenuItems.category.name);
  menuItemsTitleHtml =
    insertProperty(menuItemsTitleHtml,
                   "special_instructions",
                   categoryMenuItems.category.special_instructions);

  var finalHtml = menuItemsTitleHtml;
  finalHtml += "
";

  // Loop over menu items
  var menuItems = categoryMenuItems.menu_items;
  var catShortName = categoryMenuItems.category.short_name;
  for (var i = 0; i < menuItems.length; i++) {
    // Insert menu item values
    var html = menuItemHtml;
    html =
      insertProperty(html, "short_name", menuItems[i].short_name);
    html =
      insertProperty(html,
                     "catShortName",
                     catShortName);
    html =
      insertItemPrice(html,
                      "price_small",
                      menuItems[i].price_small);
    html =
      insertItemPortionName(html,
                            "small_portion_name",
                            menuItems[i].small_portion_name);
    html =
      insertItemPrice(html,
                      "price_large",
                      menuItems[i].price_large);
    html =
      insertItemPortionName(html,
                            "large_portion_name",
                            menuItems[i].large_portion_name);
    html =
      insertProperty(html,
                     "name",
                     menuItems[i].name);
    html =
      insertProperty(html,
                     "description",
                     menuItems[i].description);

    // Add clearfix after every second menu item
    if (i % 2 !== 0) {
      html +=
        "

";
    }

    finalHtml += html;
  }

  finalHtml += "
";
  return finalHtml;
}

// Appends price with '$' if price exists
function insertItemPrice(html,
                         pricePropName,
                         priceValue) {
  // If not specified, replace with empty string
  if (!priceValue) {
    return insertProperty(html, pricePropName, "");
  }

  priceValue = "$" + priceValue.toFixed(2);
  html = insertProperty(html, pricePropName, priceValue);
  return html;
}

// Appends portion name in parens if it exists
function insertItemPortionName(html,
                               portionPropName,
                               portionValue) {
  // If not specified, return original string
  if (!portionValue) {
    return insertProperty(html, portionPropName, "");
  }

  portionValue = "(" + portionValue + ")";
  html = insertProperty(html, portionPropName, portionValue);
  return html;
}

global.$dc = dc;

})(window);
<commit_msg>Assignment 5 for submission<commit_after>$(function () { // Same as document.addEventListener("DOMContentLoaded"...

  // Same as document.querySelector("#navbarToggle").addEventListener("blur",...
  $("#navbarToggle").blur(function (event) {
    var screenWidth = window.innerWidth;
    if (screenWidth < 768) {
      $("#collapsable-nav").collapse('hide');
    }
  });
});

(function (global) {

var dc = {};

var homeHtmlUrl = "snippets/home-snippet.html";
var allCategoriesUrl =
  "https://davids-restaurant.herokuapp.com/categories.json";
var categoriesTitleHtml = "snippets/categories-title-snippet.html";
var categoryHtml = "snippets/category-snippet.html";
var menuItemsUrl =
  "https://davids-restaurant.herokuapp.com/menu_items.json?category=";
var menuItemsTitleHtml = "snippets/menu-items-title.html";
var menuItemHtml = "snippets/menu-item.html";

// Convenience function for inserting innerHTML for 'select'
var insertHtml = function (selector, html) {
  var targetElem = document.querySelector(selector);
  targetElem.innerHTML = html;
};

// Show loading icon inside element identified by 'selector'.
var showLoading = function (selector) {
  var html = "
";
  html += "
";
  insertHtml(selector, html);
};

// Return substitute of '{{propName}}'
// with propValue in given 'string'
var insertProperty = function (string, propName, propValue) {
  var propToReplace = "{{" + propName + "}}";
  string = string
    .replace(new RegExp(propToReplace, "g"), propValue);
  return string;
};

// Remove the class 'active' from home and switch to Menu button
var switchMenuToActive = function () {
  // Remove 'active' from home button
  var classes = document.querySelector("#navHomeButton").className;
  classes = classes.replace(new RegExp("active", "g"), "");
  document.querySelector("#navHomeButton").className = classes;

  // Add 'active' to menu button if not already there
  classes = document.querySelector("#navMenuButton").className;
  if (classes.indexOf("active") === -1) {
    classes += " active";
    document.querySelector("#navMenuButton").className = classes;
  }
};

// On page load (before images or CSS)
document.addEventListener("DOMContentLoaded", function (event) {

// TODO: STEP 0: Look over the code from
// *** start ***
// to
// *** finish ***
// below.
// We changed this code to retrieve all categories from the server instead of
// simply requesting home HTML snippet. We now also have another function
// called buildAndShowHomeHTML that will receive all the categories from the server
// and process them: choose random category, retrieve home HTML snippet, insert that
// random category into the home HTML snippet, and then insert that snippet into our
// main page (index.html).
//
// TODO: STEP 1: Substitute [...] below with the *value* of the function buildAndShowHomeHTML,
// so it can be called when server responds with the categories data.

// *** start ***
// On first load, show home view
showLoading("#main-content");
$ajaxUtils.sendGetRequest(
  allCategoriesUrl,
  buildAndShowHomeHTML, // ***** <---- TODO: STEP 1: Substitute [...] ******
  true); // Explicitely setting the flag to get JSON from server processed into an object literal
});
// *** finish **

// Builds HTML for the home page based on categories array
// returned from the server.
function buildAndShowHomeHTML (categories) {

  // Load home snippet page
  $ajaxUtils.sendGetRequest(
    homeHtmlUrl,
    function (homeHtml) {

      // TODO: STEP 2: Here, call chooseRandomCategory, passing it retrieved 'categories'
      // Pay attention to what type of data that function returns vs what the chosenCategoryShortName
      // variable's name implies it expects.
      var chosenCategoryShortName = chooseRandomCategory(categories);

      // TODO: STEP 3: Substitute {{randomCategoryShortName}} in the home html snippet with the
      // chosen category from STEP 2. Use existing insertProperty function for that purpose.
      // Look through this code for an example of how to do use the insertProperty function.
      // WARNING! You are inserting something that will have to result in a valid Javascript
      // syntax because the substitution of {{randomCategoryShortName}} becomes an argument
      // being passed into the $dc.loadMenuItems function. Think about what that argument needs
      // to look like. For example, a valid call would look something like this:
      // $dc.loadMenuItems('L')
      // Hint: you need to surround the chosen category short name with something before inserting
      // it into the home html snippet.
      //
      var homeHtmlToInsertIntoMainPage = "'" + chosenCategoryShortName.short_name + "'";
      homeHtml = insertProperty(homeHtml, "randomCategoryShortName", homeHtmlToInsertIntoMainPage);

      // TODO: STEP 4: Insert the the produced HTML in STEP 3 into the main page
      // Use the existing insertHtml function for that purpose. Look through this code for an example
      // of how to do that.
      insertHtml('#main-content', homeHtml);

    },
    false); // False here because we are getting just regular HTML from the server, so no need to process JSON.
}

// Given array of category objects, returns a random category object.
function chooseRandomCategory (categories) {
  // Choose a random index into the array (from 0 inclusively until array length (exclusively))
  var randomArrayIndex = Math.floor(Math.random() * categories.length);

  // return category object with that randomArrayIndex
  return categories[randomArrayIndex];
}

// Load the menu categories view
dc.loadMenuCategories = function () {
  showLoading("#main-content");
  $ajaxUtils.sendGetRequest(
    allCategoriesUrl,
    buildAndShowCategoriesHTML);
};

// Load the menu items view
// 'categoryShort' is a short_name for a category
dc.loadMenuItems = function (categoryShort) {
  showLoading("#main-content");
  $ajaxUtils.sendGetRequest(
    menuItemsUrl + categoryShort,
    buildAndShowMenuItemsHTML);
};

// Builds HTML for the categories page based on the data
// from the server
function buildAndShowCategoriesHTML (categories) {
  // Load title snippet of categories page
  $ajaxUtils.sendGetRequest(
    categoriesTitleHtml,
    function (categoriesTitleHtml) {
      // Retrieve single category snippet
      $ajaxUtils.sendGetRequest(
        categoryHtml,
        function (categoryHtml) {
          // Switch CSS class active to menu button
          switchMenuToActive();

          var categoriesViewHtml =
            buildCategoriesViewHtml(categories,
                                    categoriesTitleHtml,
                                    categoryHtml);
          insertHtml("#main-content", categoriesViewHtml);
        },
        false);
    },
    false);
}

// Using categories data and snippets html
// build categories view HTML to be inserted into page
function buildCategoriesViewHtml(categories,
                                 categoriesTitleHtml,
                                 categoryHtml) {

  var finalHtml = categoriesTitleHtml;
  finalHtml += "
";

  // Loop over categories
  for (var i = 0; i < categories.length; i++) {
    // Insert category values
    var html = categoryHtml;
    var name = "" + categories[i].name;
    var short_name = categories[i].short_name;
    html =
      insertProperty(html, "name", name);
    html =
      insertProperty(html,
                     "short_name",
                     short_name);
    finalHtml += html;
  }

  finalHtml += "
";
  return finalHtml;
}

// Builds HTML for the single category page based on the data
// from the server
function buildAndShowMenuItemsHTML (categoryMenuItems) {
  // Load title snippet of menu items page
  $ajaxUtils.sendGetRequest(
    menuItemsTitleHtml,
    function (menuItemsTitleHtml) {
      // Retrieve single menu item snippet
      $ajaxUtils.sendGetRequest(
        menuItemHtml,
        function (menuItemHtml) {
          // Switch CSS class active to menu button
          switchMenuToActive();

          var menuItemsViewHtml =
            buildMenuItemsViewHtml(categoryMenuItems,
                                   menuItemsTitleHtml,
                                   menuItemHtml);
          insertHtml("#main-content", menuItemsViewHtml);
        },
        false);
    },
    false);
}

// Using category and menu items data and snippets html
// build menu items view HTML to be inserted into page
function buildMenuItemsViewHtml(categoryMenuItems,
                                menuItemsTitleHtml,
                                menuItemHtml) {

  menuItemsTitleHtml =
    insertProperty(menuItemsTitleHtml,
                   "name",
                   categoryMenuItems.category.name);
  menuItemsTitleHtml =
    insertProperty(menuItemsTitleHtml,
                   "special_instructions",
                   categoryMenuItems.category.special_instructions);

  var finalHtml = menuItemsTitleHtml;
  finalHtml += "
";

  // Loop over menu items
  var menuItems = categoryMenuItems.menu_items;
  var catShortName = categoryMenuItems.category.short_name;
  for (var i = 0; i < menuItems.length; i++) {
    // Insert menu item values
    var html = menuItemHtml;
    html =
      insertProperty(html, "short_name", menuItems[i].short_name);
    html =
      insertProperty(html,
                     "catShortName",
                     catShortName);
    html =
      insertItemPrice(html,
                      "price_small",
                      menuItems[i].price_small);
    html =
      insertItemPortionName(html,
                            "small_portion_name",
                            menuItems[i].small_portion_name);
    html =
      insertItemPrice(html,
                      "price_large",
                      menuItems[i].price_large);
    html =
      insertItemPortionName(html,
                            "large_portion_name",
                            menuItems[i].large_portion_name);
    html =
      insertProperty(html,
                     "name",
                     menuItems[i].name);
    html =
      insertProperty(html,
                     "description",
                     menuItems[i].description);

    // Add clearfix after every second menu item
    if (i % 2 !== 0) {
      html +=
        "

";
    }

    finalHtml += html;
  }

  finalHtml += "
";
  return finalHtml;
}

// Appends price with '$' if price exists
function insertItemPrice(html,
                         pricePropName,
                         priceValue) {
  // If not specified, replace with empty string
  if (!priceValue) {
    return insertProperty(html, pricePropName, "");
  }

  priceValue = "$" + priceValue.toFixed(2);
  html = insertProperty(html, pricePropName, priceValue);
  return html;
}

// Appends portion name in parens if it exists
function insertItemPortionName(html,
                               portionPropName,
                               portionValue) {
  // If not specified, return original string
  if (!portionValue) {
    return insertProperty(html, portionPropName, "");
  }

  portionValue = "(" + portionValue + ")";
  html = insertProperty(html, portionPropName, portionValue);
  return html;
}

global.$dc = dc;

})(window);
<|endoftext|>


<commit_before>(function(args)
{
	'use strict';
	var [obj,prop]=args,
		cherub=obj[prop]={},
		assertions=
		{
			equal:(actual,expected)=>actual===expected,
			stringify:(...args)=>assertions.equal(...args.map(JSON.stringify))
		},
		next=args=>args,
		defaults=
		{
			assert:assertions.stringify,
			cleanup:next,
			name:'',
			rtn:undefined,
			setup:next
		};
	cherub.assign=function(obj,defaults)
	{
		return Object.keys(defaults).reduce(function(obj,prop)
		{
			!obj.hasOwnProperty(prop)?obj[prop]=defaults[prop]:'';
			return obj;
		},obj);
	};
	cherub.build=function(test,inherits=defaults)
	{
		var tests=[];
		test=cherub.inherit(test,inherits);
		//don't add containers meant to pass on functions
		!test.tests.length&&test.func?tests.push(test):
		test.tests.forEach(function(subtest)//containers have tests or an empty array
		{
			tests.push(...cherub.build(subtest,test));
		});
		return tests;
	};
	cherub.config=
	{
		hidePassed:true,
		lang:'en',
		output:console.log,
		parallel:true,
		perf:
		{
			now:()=>Date.now(),
			precision:4,
			units:'ms'
		},
		shuffle:true,
		text:
		{
			en:{passed:'passed',failed:'failed'}
		}
	};
	cherub.reportTime=function(time)
	{
		var {precision,units}=cherub.config.perf;
		return time.toFixed(precision)+units;
	};
	cherub.inherit=function(test,parent)
	{
		var {assert,cleanup,func,rtn,setup}=parent,
			parentProps={assert,cleanup,func,rtn,setup},
			minProps={name:'',tests:[]};
		test=cherub.assign(test,minProps);
		test=cherub.assign(test,parentProps);
		test.name=(parent.name+'/'+test.name).replace(/^\//,'');//inherit parent's base name
		return test;
	};
	cherub.num2percent=num=>((num*100).toFixed(2)).replace(/\.00|0$/,'')+'%';
	cherub.run=function(test)///use rest parameters
	{
		var {build,config,json2msg,shuffle}=cherub,
			{output,parallel,perf}=config,
			tests=build(test),
			passed=0,
			start=perf.now();
		var run=function(test)
		{
			var {args,assert,cleanup,func,name,rtn,setup}=test,
				start=perf.now();
			return Promise.resolve()
			.then(setup)
			.then(()=>args?func(...args):func())//run tests
			.then(val=>(assert(val,rtn)?{val}:{err:val}))//eval tests
			.catch(err=>({err}))
			.then(function(obj)//report info
			{
				var time=perf.now()-start;
				json2msg(Object.assign(obj,{name,rtn,time}));
				return passed+=obj.hasOwnProperty('err')?0:1;
			})
			.then(cleanup)
			.catch(next);
		};
		tests=config.shuffle?shuffle(tests):tests;
		return (parallel?Promise.all(tests.map(run)):
		tests.reduce((promise,test)=>promise.then(()=>run(test)),Promise.resolve()))
		.then(function()//score
		{
			var {json2msg,num2percent}=cherub,
				time=perf.now()-start,
				total=tests.length,
				failed=total-passed,//failed can be infered from totals & passed
				percentPassed=total?num2percent(passed/total):0,
				name=passed+'/'+total+' ('+percentPassed+')';
			json2msg({name,time},true);
		});
	};
	cherub.json2msg=function(json,show=false)
	{
		var {err,name,rtn,time}=json,
			{hidePassed,lang,output,text}=cherub.config,
			failed=json.hasOwnProperty('err'),
			type=failed?'failed':'passed',
			msg=name+' ('+cherub.reportTime(time)+') ';
		msg=text[lang][type]+': '+msg;
		msg=failed?msg+' '+err+'!='+rtn:msg;
		(failed||!hidePassed||show)?output(msg+'\n'):'';
	};
	cherub.shuffle=function(old)
	{
		return old.reduce(function(arr,item,i)
		{
			var j=~~(Math.random()*(arr.length));
			[arr[i],arr[j]]=[arr[j],arr[i]];
			return arr;
		},old.slice(0));
	};
	return cherub;
})(typeof exports==='undefined'?[window,'cherub']:[module,'exports']);<commit_msg>simplified config<commit_after>(function(args)
{
	'use strict';
	var [obj,prop]=args,
		cherub=obj[prop]=function()
		{
		},
		assertions=
		{
			equal:(actual,expected)=>actual===expected,
			stringify:(...args)=>assertions.equal(...args.map(JSON.stringify))
		},
		next=args=>args,
		defaults=
		{
			assert:assertions.stringify,
			cleanup:next,
			name:'',
			rtn:undefined,
			setup:next
		};
	cherub.assign=function(obj,defaults)
	{
		return Object.keys(defaults).reduce(function(obj,prop)
		{
			!obj.hasOwnProperty(prop)?obj[prop]=defaults[prop]:'';
			return obj;
		},obj);
	};
	cherub.build=function(test,inherits=defaults)
	{
		var tests=[];
		test=cherub.inherit(test,inherits);
		//don't add containers meant to pass on functions
		!test.tests.length&&test.func?tests.push(test):
		test.tests.forEach(function(subtest)//containers have tests or an empty array
		{
			tests.push(...cherub.build(subtest,test));
		});
		return tests;
	};
	cherub.config=
	{
		failed:'failed',
		hidePassed:true,
		now:()=>Date.now(),
		output:console.log,
		passed:'passed',
		parallel:true,
		precision:4,
		shuffle:true,
		units:'ms'
	};
	cherub.reportTime=function(time)
	{
		var {precision,units}=cherub.config;
		return time.toFixed(precision)+units;
	};
	cherub.inherit=function(test,parent)
	{
		var {assert,cleanup,func,rtn,setup}=parent,
			parentProps={assert,cleanup,func,rtn,setup},
			minProps={name:'',tests:[]};
		test=cherub.assign(test,minProps);
		test=cherub.assign(test,parentProps);
		test.name=(parent.name+'/'+test.name).replace(/^\//,'');//inherit parent's base name
		return test;
	};
	cherub.num2percent=num=>((num*100).toFixed(2)).replace(/\.00|0$/,'')+'%';
	cherub.run=function(test)///use rest parameters
	{
		var {build,config,json2msg,shuffle}=cherub,
			{output,parallel,now}=config,
			tests=build(test),
			passed=0,
			start=now();
		var run=function(test)
		{
			var {args,assert,cleanup,func,name,rtn,setup}=test,
				start=now();
			return Promise.resolve()
			.then(setup)
			.then(()=>args?func(...args):func())//run tests
			.then(val=>(assert(val,rtn)?{val}:{err:val}))//eval tests
			.catch(err=>({err}))
			.then(function(obj)//report info
			{
				var time=now()-start;
				json2msg(Object.assign(obj,{name,rtn,time}));
				return passed+=obj.hasOwnProperty('err')?0:1;
			})
			.then(cleanup)
			.catch(next);
		};
		tests=config.shuffle?shuffle(tests):tests;
		return (parallel?Promise.all(tests.map(run)):
		tests.reduce((promise,test)=>promise.then(()=>run(test)),Promise.resolve()))
		.then(function()//score
		{
			var {json2msg,num2percent}=cherub,
				time=now()-start,
				total=tests.length,
				failed=total-passed,//failed can be infered from totals & passed
				percentPassed=total?num2percent(passed/total):0,
				name=passed+'/'+total+' ('+percentPassed+')';
			json2msg({name,time},true);
		});
	};
	cherub.json2msg=function(json,show=false)
	{
		var {err,name,rtn,time}=json,
			{hidePassed,output}=cherub.config,
			failed=json.hasOwnProperty('err'),
			type=failed?'failed':'passed',
			msg=name+' ('+cherub.reportTime(time)+') ';
		msg=cherub.config[type]+': '+msg;
		msg=failed?msg+' '+err+'!='+rtn:msg;
		(failed||!hidePassed||show)?output(msg+'\n'):'';
	};
	cherub.shuffle=function(old)
	{
		return old.reduce(function(arr,item,i)
		{
			var j=~~(Math.random()*(arr.length));
			[arr[i],arr[j]]=[arr[j],arr[i]];
			return arr;
		},old.slice(0));
	};
	return cherub;
})(typeof exports==='undefined'?[window,'cherub']:[module,'exports']);<|endoftext|>


<commit_before>import React from 'react';

import SPELLS from 'common/SPELLS';
import SpellLink from 'common/SpellLink';
import SpellIcon from 'common/SpellIcon';
import { formatNumber, formatPercentage } from 'common/format';
import Wrapper from 'common/Wrapper';

import Analyzer from 'Parser/Core/Analyzer';
import Combatants from 'Parser/Core/Modules/Combatants';

import StatisticBox, { STATISTIC_ORDER } from 'Main/StatisticBox';

const debug = false;

class EssenceFontMastery extends Analyzer {
  static dependencies = {
    combatants: Combatants,
  };

  healEF = 0;
  healing = 0;
  castEF = 0;
  gustHeal = false;
  secondGustHealing = 0;
  secondGustOverheal = 0;

  on_byPlayer_heal(event) {
    const spellId = event.ability.guid;

    const targetId = event.targetID;
    if (spellId === SPELLS.GUSTS_OF_MISTS.id) {
      if (!this.combatants.players[targetId]) {
        return;
      }
      if (this.combatants.players[targetId].hasBuff(SPELLS.ESSENCE_FONT_BUFF.id, event.timestamp, 0, 0) === true && !this.gustHeal) {
        debug && console.log(`First Gust Heal: Player ID: ${event.targetID}  Timestamp: ${event.timestamp}`);
        this.healEF += 1;
        this.healing += (event.amount || 0) + (event.absorbed || 0);
        this.gustHeal = true;
      } else if (this.combatants.players[targetId].hasBuff(SPELLS.ESSENCE_FONT_BUFF.id, event.timestamp, 0, 0) === true && this.gustHeal) {
        this.healEF += 1;
        this.healing += (event.amount || 0) + (event.absorbed || 0);
        this.secondGustHealing += (event.amount || 0) + (event.absorbed || 0) + (event.overheal || 0);
        this.secondGustOverheal += (event.overheal || 0);
        this.gustHeal = false;
      }
    }
  }

  on_byPlayer_cast(event) {
    const spellId = event.ability.guid;

    if (spellId === SPELLS.ESSENCE_FONT.id) {
      this.castEF += 1;
    }
  }

  on_finished() {
    if (debug) {
      console.log(`EF Mastery Hots Casted into: ${this.healEF / 2}`);
      console.log(`EF Mastery Healing Amount: ${this.healing}`);
      console.log(`EF Casts: ${this.castEF}`);
      console.log(`EF Targets Hit: ${this.targetsEF}`);
      console.log(`EF Avg Targets Hit per Cast: ${this.targetsEF / this.castEF}`);
    }
  }

  get avgMasteryCastsPerEF() {
    const efMasteryCasts = (this.healEF / 2) || 0;

    return (efMasteryCasts / this.castEF) || 0;
  }

  get suggestionThresholds() {
    return {
      actual: this.avgMasteryCastsPerEF,
      isLessThan: {
        minor: 2,
        average: 1.5,
        major: 1,
      },
      style: 'number',
    };
  }

  suggestions(when) {
    when(this.suggestionThresholds).addSuggestion((suggest, actual, recommended) => {
        return suggest(
          <Wrapper>
            You are currently not utilizing your <SpellLink id={SPELLS.ESSENCE_FONT.id} /> HOT buffs effectively. Casting into injured targets with the <SpellLink id={SPELLS.ESSENCE_FONT.id} /> allows you to take advantage of the double <SpellLink id={SPELLS.GUSTS_OF_MISTS.id} /> procs.
          </Wrapper>
        )
          .icon(SPELLS.ESSENCE_FONT.icon)
          .actual(`${this.avgMasteryCastsPerEF.toFixed(2)} average EF HoTs`)
          .recommended(`${recommended} or more EF HoTs utilized is recommended`);
      });
  }

  statistic() {
    const efMasteryCasts = (this.healEF / 2) || 0;
    const efMasteryEffectiveHealing = ((this.healing) / 2) || 0;
    const avgEFMasteryHealing = efMasteryEffectiveHealing / efMasteryCasts || 0;

    return (
      <StatisticBox
        icon={<SpellIcon id={SPELLS.GUSTS_OF_MISTS.id} />}
        value={`${efMasteryCasts}`}
        label={(
          <dfn data-tip={`You healed an average of ${this.avgMasteryCastsPerEF.toFixed(2)} targets per Essence Font cast.

${formatNumber(avgEFMasteryHealing)} average healing per cast

${formatNumber(this.secondGustOverheal)} Second Gust of Mists overhealing (${formatPercentage(this.secondGustOverheal / this.secondGustHealing)}%)

`}>
            Mastery Buffs utilized
          </dfn>
        )}
      />
    );
  }
  statisticOrder = STATISTIC_ORDER.OPTIONAL(0);
}

export default EssenceFontMastery;
<commit_msg>EF HoT Suggestion Update<commit_after>import React from 'react';

import SPELLS from 'common/SPELLS';
import SpellLink from 'common/SpellLink';
import SpellIcon from 'common/SpellIcon';
import { formatNumber, formatPercentage } from 'common/format';
import Wrapper from 'common/Wrapper';

import Analyzer from 'Parser/Core/Analyzer';
import Combatants from 'Parser/Core/Modules/Combatants';

import StatisticBox, { STATISTIC_ORDER } from 'Main/StatisticBox';

const debug = false;

class EssenceFontMastery extends Analyzer {
  static dependencies = {
    combatants: Combatants,
  };

  healEF = 0;
  healing = 0;
  castEF = 0;
  gustHeal = false;
  secondGustHealing = 0;
  secondGustOverheal = 0;

  on_byPlayer_heal(event) {
    const spellId = event.ability.guid;

    const targetId = event.targetID;
    if (spellId === SPELLS.GUSTS_OF_MISTS.id) {
      if (!this.combatants.players[targetId]) {
        return;
      }
      if (this.combatants.players[targetId].hasBuff(SPELLS.ESSENCE_FONT_BUFF.id, event.timestamp, 0, 0) === true && !this.gustHeal) {
        debug && console.log(`First Gust Heal: Player ID: ${event.targetID}  Timestamp: ${event.timestamp}`);
        this.healEF += 1;
        this.healing += (event.amount || 0) + (event.absorbed || 0);
        this.gustHeal = true;
      } else if (this.combatants.players[targetId].hasBuff(SPELLS.ESSENCE_FONT_BUFF.id, event.timestamp, 0, 0) === true && this.gustHeal) {
        this.healEF += 1;
        this.healing += (event.amount || 0) + (event.absorbed || 0);
        this.secondGustHealing += (event.amount || 0) + (event.absorbed || 0) + (event.overheal || 0);
        this.secondGustOverheal += (event.overheal || 0);
        this.gustHeal = false;
      }
    }
  }

  on_byPlayer_cast(event) {
    const spellId = event.ability.guid;

    if (spellId === SPELLS.ESSENCE_FONT.id) {
      this.castEF += 1;
    }
  }

  on_finished() {
    if (debug) {
      console.log(`EF Mastery Hots Casted into: ${this.healEF / 2}`);
      console.log(`EF Mastery Healing Amount: ${this.healing}`);
      console.log(`EF Casts: ${this.castEF}`);
      console.log(`EF Targets Hit: ${this.targetsEF}`);
      console.log(`EF Avg Targets Hit per Cast: ${this.targetsEF / this.castEF}`);
    }
  }

  get avgMasteryCastsPerEF() {
    const efMasteryCasts = (this.healEF / 2) || 0;

    return (efMasteryCasts / this.castEF) || 0;
  }

  get suggestionThresholds() {
    return {
      actual: this.avgMasteryCastsPerEF,
      isLessThan: {
        minor: 1.5,
        average: 1,
        major: .5,
      },
      style: 'number',
    };
  }

  suggestions(when) {
    when(this.suggestionThresholds).addSuggestion((suggest, actual, recommended) => {
        return suggest(
          <Wrapper>
            You are currently not utilizing your <SpellLink id={SPELLS.ESSENCE_FONT.id} /> HOT buffs effectively. Casting into injured targets with the <SpellLink id={SPELLS.ESSENCE_FONT.id} /> allows you to take advantage of the double <SpellLink id={SPELLS.GUSTS_OF_MISTS.id} /> procs.
          </Wrapper>
        )
          .icon(SPELLS.ESSENCE_FONT.icon)
          .actual(`${this.avgMasteryCastsPerEF.toFixed(2)} average EF HoTs`)
          .recommended(`${recommended} or more EF HoTs utilized is recommended`);
      });
  }

  statistic() {
    const efMasteryCasts = (this.healEF / 2) || 0;
    const efMasteryEffectiveHealing = ((this.healing) / 2) || 0;
    const avgEFMasteryHealing = efMasteryEffectiveHealing / efMasteryCasts || 0;

    return (
      <StatisticBox
        icon={<SpellIcon id={SPELLS.GUSTS_OF_MISTS.id} />}
        value={`${efMasteryCasts}`}
        label={(
          <dfn data-tip={`You healed an average of ${this.avgMasteryCastsPerEF.toFixed(2)} targets per Essence Font cast.

${formatNumber(avgEFMasteryHealing)} average healing per cast

${formatNumber(this.secondGustOverheal)} Second Gust of Mists overhealing (${formatPercentage(this.secondGustOverheal / this.secondGustHealing)}%)

`}>
            Mastery Buffs utilized
          </dfn>
        )}
      />
    );
  }
  statisticOrder = STATISTIC_ORDER.OPTIONAL(0);
}

export default EssenceFontMastery;
<|endoftext|>


<commit_before>window.onload = function(){

function appendHtml(el) {

  var div = document.createElement('div');
  div.innerHTML = '

Website

Documentation

Cookbook

';//<gcse:search></gcse:search>
  el.insertBefore(div,el.childNodes[0]);
}

(function() {
  var cx = '002866056653122356950:ju52xx-w-w8';
  var gcse = document.createElement('script');
  gcse.type = 'text/javascript';
  gcse.async = true;
  gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
    '//cse.google.com/cse.js?cx=' + cx;
  var s = document.getElementsByTagName('script')[0];
  s.parentNode.insertBefore(gcse, s);
})();

appendHtml(document.body);

var header = document.querySelector("#header");

};
<commit_msg>Changed path of images in the documentation header<commit_after>window.onload = function(){

function appendHtml(el) {

  var div = document.createElement('div');
  div.innerHTML = '

Website

Documentation

Cookbook

';//<gcse:search></gcse:search>
  el.insertBefore(div,el.childNodes[0]);
}

(function() {
  var cx = '002866056653122356950:ju52xx-w-w8';
  var gcse = document.createElement('script');
  gcse.type = 'text/javascript';
  gcse.async = true;
  gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
    '//cse.google.com/cse.js?cx=' + cx;
  var s = document.getElementsByTagName('script')[0];
  s.parentNode.insertBefore(gcse, s);
})();

appendHtml(document.body);

var header = document.querySelector("#header");

};
<|endoftext|>


<commit_before>/*************************************************
 * Copyright (c) 2015 Ansible, Inc.
 *
 * All Rights Reserved
 *************************************************/

export default ['i18n', function(i18n) {
    return {
        // These tooltip fields are consumed to build disabled related tabs tooltips in the form > add view
        awToolTip: i18n._('Please save and run a job to view'),
        dataPlacement: 'top',
        name: 'completed_jobs',
        basePath: 'unified_jobs',
        iterator: 'completed_job',
        search: {
            "or__job__inventory": ''
        },
        editTitle: i18n._('COMPLETED JOBS'),
        index: false,
        hover: true,
        well: false,
        emptyListText: i18n._('No completed jobs'),

        fields: {
            status: {
                label: '',
                columnClass: 'List-staticColumn--smallStatus',
                awToolTip: "{{ completed_job.status_tip }}",
                awTipPlacement: "right",
                dataTitle: "{{ completed_job.status_popover_title }}",
                icon: 'icon-job-{{ completed_job.status }}',
                iconOnly: true,
                ngClick:"viewjobResults(completed_job)",
            },
            id: {
                label: 'ID',
                ngClick:"viewjobResults(completed_job)",
                columnClass: 'col-lg-1 col-md-1 col-sm-2 col-xs-2 List-staticColumnAdjacent',
                awToolTip: "{{ completed_job.status_tip }}",
                dataPlacement: 'top'
            },
            name: {
                label: i18n._('Name'),
                columnClass: 'col-lg-4 col-md-4 col-sm-4 col-xs-6',
                ngClick: "viewjobResults(completed_job)",
                awToolTip: "{{ completed_job.name | sanitize }}",
                dataPlacement: 'top'
            },
            type: {
                label: i18n._('Type'),
                ngBind: 'completed_job.type_label',
                link: false,
                columnClass: "col-lg-2 col-md-2 hidden-sm hidden-xs",
            },
            finished: {
                label: i18n._('Finished'),
                noLink: true,
                filter: "longDate",
                columnClass: "col-lg-3 col-md-3 col-sm-3 hidden-xs",
                key: true,
                desc: true
            }
        },

        actions: { },

        fieldActions: {

            columnClass: 'col-lg-2 col-md-2 col-sm-3 col-xs-4',

            submit: {
                icon: 'icon-rocket',
                mode: 'all',
                ngClick: 'relaunchJob($event, completed_job.id)',
                awToolTip: i18n._('Relaunch using the same parameters'),
                dataPlacement: 'top',
                ngShow: "!completed_job.type == 'system_job' || completed_job.summary_fields.user_capabilities.start"
            },
            "delete": {
                mode: 'all',
                ngClick: 'deleteJob(completed_job.id)',
                awToolTip: i18n._('Delete the job'),
                dataPlacement: 'top',
                ngShow: 'completed_job.summary_fields.user_capabilities.delete'
            }
        }
    };}];
<commit_msg>Remove sorting on completed jobs status<commit_after>/*************************************************
 * Copyright (c) 2015 Ansible, Inc.
 *
 * All Rights Reserved
 *************************************************/

export default ['i18n', function(i18n) {
    return {
        // These tooltip fields are consumed to build disabled related tabs tooltips in the form > add view
        awToolTip: i18n._('Please save and run a job to view'),
        dataPlacement: 'top',
        name: 'completed_jobs',
        basePath: 'unified_jobs',
        iterator: 'completed_job',
        search: {
            "or__job__inventory": ''
        },
        editTitle: i18n._('COMPLETED JOBS'),
        index: false,
        hover: true,
        well: false,
        emptyListText: i18n._('No completed jobs'),

        fields: {
            status: {
                label: '',
                columnClass: 'List-staticColumn--smallStatus',
                awToolTip: "{{ completed_job.status_tip }}",
                awTipPlacement: "right",
                dataTitle: "{{ completed_job.status_popover_title }}",
                icon: 'icon-job-{{ completed_job.status }}',
                iconOnly: true,
                ngClick:"viewjobResults(completed_job)",
                nosort: true
            },
            id: {
                label: 'ID',
                ngClick:"viewjobResults(completed_job)",
                columnClass: 'col-lg-1 col-md-1 col-sm-2 col-xs-2 List-staticColumnAdjacent',
                awToolTip: "{{ completed_job.status_tip }}",
                dataPlacement: 'top'
            },
            name: {
                label: i18n._('Name'),
                columnClass: 'col-lg-4 col-md-4 col-sm-4 col-xs-6',
                ngClick: "viewjobResults(completed_job)",
                awToolTip: "{{ completed_job.name | sanitize }}",
                dataPlacement: 'top'
            },
            type: {
                label: i18n._('Type'),
                ngBind: 'completed_job.type_label',
                link: false,
                columnClass: "col-lg-2 col-md-2 hidden-sm hidden-xs",
            },
            finished: {
                label: i18n._('Finished'),
                noLink: true,
                filter: "longDate",
                columnClass: "col-lg-3 col-md-3 col-sm-3 hidden-xs",
                key: true,
                desc: true
            }
        },

        actions: { },

        fieldActions: {

            columnClass: 'col-lg-2 col-md-2 col-sm-3 col-xs-4',

            submit: {
                icon: 'icon-rocket',
                mode: 'all',
                ngClick: 'relaunchJob($event, completed_job.id)',
                awToolTip: i18n._('Relaunch using the same parameters'),
                dataPlacement: 'top',
                ngShow: "!completed_job.type == 'system_job' || completed_job.summary_fields.user_capabilities.start"
            },
            "delete": {
                mode: 'all',
                ngClick: 'deleteJob(completed_job.id)',
                awToolTip: i18n._('Delete the job'),
                dataPlacement: 'top',
                ngShow: 'completed_job.summary_fields.user_capabilities.delete'
            }
        }
    };}];
<|endoftext|>


<commit_before>/*************************************************
 * Copyright (c) 2017 Ansible, Inc.
 *
 * All Rights Reserved
 *************************************************/

export default ['$state', '$stateParams', '$scope', 'SourcesFormDefinition',
    'ParseTypeChange', 'GenerateForm', 'inventoryData', 'GroupManageService',
    'GetChoices', 'GetBasePath', 'CreateSelect2', 'GetSourceTypeOptions', 'Empty',
    'rbacUiControlService', 'ToJSON', 'SourcesService', 'Wait', 'Rest',
    function($state, $stateParams, $scope, SourcesFormDefinition,  ParseTypeChange,
        GenerateForm, inventoryData, GroupManageService, GetChoices,
        GetBasePath, CreateSelect2, GetSourceTypeOptions, Empty, rbacUiControlService,
        ToJSON, SourcesService, Wait, Rest) {

        let form = SourcesFormDefinition;
        init();

        function init() {
            // apply form definition's default field values
            GenerateForm.applyDefaults(form, $scope);

            rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/inventory_sources")
                .then(function(canAdd) {
                    $scope.canAdd = canAdd;
                });

            initSources();
        }

        var getInventoryFiles = function (project) {
            var url;

            if (!Empty(project)) {
                url = GetBasePath('projects') + project + '/inventories/';
                Wait('start');
                Rest.setUrl(url);
                Rest.get()
                    .success(function (data) {
                        $scope.inventory_files = data;
                        $scope.inventory_files.push("/ (project root)");
                        sync_inventory_file_select2();
                        Wait('stop');
                    })
                    .error(function (ret,status_code) {
                        Alert('Cannot get inventory files', 'Unable to retrieve the list of inventory files for this project.', 'alert-info');
                        Wait('stop');
                    });
            }
        };

        // Detect and alert user to potential SCM status issues
        var checkSCMStatus = function () {
            if (!Empty($scope.project)) {
                Rest.setUrl(GetBasePath('projects') + $scope.project + '/');
                Rest.get()
                    .success(function (data) {
                        var msg;
                        switch (data.status) {
                        case 'failed':
                            msg = "
The Project selected has a status of \"failed\". You must run a successful update before you can select an inventory file.";
                            break;
                        case 'never updated':
                            msg = "
The Project selected has a status of \"never updated\". You must run a successful update before you can select an inventory file.";
                            break;
                        case 'missing':
                            msg = '
The selected project has a status of \"missing\". Please check the server and make sure ' +
                                ' the directory exists and file permissions are set correctly.
';
                            break;
                        }
                        if (msg) {
                            Alert('Warning', msg, 'alert-info alert-info--noTextTransform', null, null, null, null, true);
                        }
                    })
                    .error(function (data, status) {
                        ProcessErrors($scope, data, status, form, { hdr: 'Error!',
                            msg: 'Failed to get project ' + $scope.project + '. GET returned status: ' + status });
                    });
            }
        };

        // Register a watcher on project_name
        if ($scope.getInventoryFilesUnregister) {
            $scope.getInventoryFilesUnregister();
        }
        $scope.getInventoryFilesUnregister = $scope.$watch('project', function (newValue, oldValue) {
            if (newValue !== oldValue) {
                getInventoryFiles(newValue);
                checkSCMStatus();
            }
        });

        function sync_inventory_file_select2() {
            CreateSelect2({
                element:'#inventory-file-select',
                addNew: true,
                multiple: false,
                scope: $scope,
                options: 'inventory_files',
                model: 'inventory_file'
            });

            // TODO: figure out why the inventory file model is being set to
            // dirty
        }

        $scope.lookupCredential = function(){
            $state.go('.credential', {
                credential_search: {
                    // TODO: get kind sorting for credential properly implemented
                    // kind: kind,
                    page_size: '5',
                    page: '1'
                }
            });
        };

        $scope.lookupProject = function(){
            $state.go('.project', {
                project_search: {
                    page_size: '5',
                    page: '1'
                }
            });
        };

        $scope.projectBasePath = GetBasePath('projects');
        $scope.credentialBasePath = GetBasePath('credentials') + '?credential_type__kind__in=cloud,network';

        $scope.sourceChange = function(source) {
            if (source) {
              source = source.value;
            } else {
              source = "";
            }

            http://localhost:8013/api/v2/credentials/?credential_type__kind__in=cloud,network

            $scope.credentialBasePath = GetBasePath('credentials') + '?credential_type__kind__in=cloud,network';

            if (source === 'custom'){
                $scope.credentialBasePath = GetBasePath('inventory_script');
            }

            if (source === 'ec2' || source === 'custom' || source === 'vmware' || source === 'openstack' || source === 'scm') {
                $scope.envParseType = 'yaml';

                var varName;
                if (source === 'scm') {
                    varName = 'custom_variables';
                } else {
                    varName = source + '_variables';
                }

                ParseTypeChange({
                    scope: $scope,
                    field_id: varName,
                    variable: varName,
                    parse_variable: 'envParseType'
                });
            }

            if (source === 'scm') {
              $scope.overwrite_vars = true;
            } else {
              $scope.overwrite_vars = false;
            }

            // reset fields
            $scope.group_by_choices = source === 'ec2' ? $scope.ec2_group_by : null;
            // azure_rm regions choices are keyed as "azure" in an OPTIONS request to the inventory_sources endpoint
            $scope.source_region_choices = source === 'azure_rm' ? $scope.azure_regions : $scope[source + '_regions'];
            $scope.cloudCredentialRequired = source !== '' && source !== 'scm' && source !== 'custom' && source !== 'ec2' ? true : false;
            $scope.group_by = null;
            $scope.source_regions = null;
            $scope.credential = null;
            $scope.credential_name = null;
            initRegionSelect();
        };
        // region / source options callback
        $scope.$on('choicesReadyGroup', function() {
            initRegionSelect();
        });

        $scope.$on('choicesReadyVerbosity', function() {
            initVerbositySelect();
        });

        $scope.$on('sourceTypeOptionsReady', function() {
            initSourceSelect();
        });

        function initRegionSelect(){
            CreateSelect2({
                element: '#inventory_source_source_regions',
                multiple: true
            });
            CreateSelect2({
                element: '#inventory_source_group_by',
                multiple: true
            });
        }

        function initSourceSelect(){
            CreateSelect2({
                element: '#inventory_source_source',
                multiple: false
            });
        }

        function initVerbositySelect(){
            CreateSelect2({
                element: '#inventory_source_verbosity',
                multiple: false
            });

            $scope.verbosity = $scope.verbosity_options[0];
        }

        function initSources(){
            GetChoices({
                scope: $scope,
                url: GetBasePath('inventory_sources'),
                field: 'source_regions',
                variable: 'rax_regions',
                choice_name: 'rax_region_choices',
                callback: 'choicesReadyGroup'
            });

            GetChoices({
                scope: $scope,
                url: GetBasePath('inventory_sources'),
                field: 'source_regions',
                variable: 'ec2_regions',
                choice_name: 'ec2_region_choices',
                callback: 'choicesReadyGroup'
            });

            GetChoices({
                scope: $scope,
                url: GetBasePath('inventory_sources'),
                field: 'source_regions',
                variable: 'gce_regions',
                choice_name: 'gce_region_choices',
                callback: 'choicesReadyGroup'
            });

            GetChoices({
                scope: $scope,
                url: GetBasePath('inventory_sources'),
                field: 'source_regions',
                variable: 'azure_regions',
                choice_name: 'azure_region_choices',
                callback: 'choicesReadyGroup'
            });

            // Load options for group_by
            GetChoices({
                scope: $scope,
                url: GetBasePath('inventory_sources'),
                field: 'group_by',
                variable: 'ec2_group_by',
                choice_name: 'ec2_group_by_choices',
                callback: 'choicesReadyGroup'
            });

            GetChoices({
                scope: $scope,
                url: GetBasePath('inventory_sources'),
                field: 'verbosity',
                variable: 'verbosity_options',
                callback: 'choicesReadyVerbosity'
            });

            GetSourceTypeOptions({
                scope: $scope,
                variable: 'source_type_options',
                //callback: 'sourceTypeOptionsReady' this callback is hard-coded into GetSourceTypeOptions(), included for ref
            });
        }

        $scope.formCancel = function() {
            $state.go('^');
        };

        $scope.formSave = function() {
            var params;

            params = {
                name: $scope.name,
                description: $scope.description,
                inventory: inventoryData.id,
                instance_filters: $scope.instance_filters,
                source_script: $scope.inventory_script,
                credential: $scope.credential,
                overwrite: $scope.overwrite,
                overwrite_vars: $scope.overwrite_vars,
                update_on_launch: $scope.update_on_launch,
                verbosity: $scope.verbosity.value,
                update_cache_timeout: $scope.update_cache_timeout || 0,
                // comma-delimited strings
                group_by: _.map($scope.group_by, 'value').join(','),
                source_regions: _.map($scope.source_regions, 'value').join(',')
            };

            if ($scope.source) {
                params.source_vars = $scope[$scope.source.value + '_variables'] === '---' || $scope[$scope.source.value + '_variables'] === '{}' ? null : $scope[$scope.source.value + '_variables'];
                params.source = $scope.source.value;
                if ($scope.source.value === 'scm') {
                  params.update_on_project_update = $scope.update_on_project_update;
                  params.source_project = $scope.project;

                  if ($scope.inventory_file === '/ (project root)') {
                      params.source_path = "";
                  } else {
                      params.source_path = $scope.inventory_file;
                  }
                }
            } else {
                params.source = null;
            }
            SourcesService.post(params).then(function(res){
                let inventory_source_id = res.data.id;
                $state.go('^.edit', {inventory_source_id: inventory_source_id}, {reload: true});
            });
        };
    }
];
<commit_msg>remove unwanted line<commit_after>/*************************************************
 * Copyright (c) 2017 Ansible, Inc.
 *
 * All Rights Reserved
 *************************************************/

export default ['$state', '$stateParams', '$scope', 'SourcesFormDefinition',
    'ParseTypeChange', 'GenerateForm', 'inventoryData', 'GroupManageService',
    'GetChoices', 'GetBasePath', 'CreateSelect2', 'GetSourceTypeOptions', 'Empty',
    'rbacUiControlService', 'ToJSON', 'SourcesService', 'Wait', 'Rest',
    function($state, $stateParams, $scope, SourcesFormDefinition,  ParseTypeChange,
        GenerateForm, inventoryData, GroupManageService, GetChoices,
        GetBasePath, CreateSelect2, GetSourceTypeOptions, Empty, rbacUiControlService,
        ToJSON, SourcesService, Wait, Rest) {

        let form = SourcesFormDefinition;
        init();

        function init() {
            // apply form definition's default field values
            GenerateForm.applyDefaults(form, $scope);

            rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/inventory_sources")
                .then(function(canAdd) {
                    $scope.canAdd = canAdd;
                });

            initSources();
        }

        var getInventoryFiles = function (project) {
            var url;

            if (!Empty(project)) {
                url = GetBasePath('projects') + project + '/inventories/';
                Wait('start');
                Rest.setUrl(url);
                Rest.get()
                    .success(function (data) {
                        $scope.inventory_files = data;
                        $scope.inventory_files.push("/ (project root)");
                        sync_inventory_file_select2();
                        Wait('stop');
                    })
                    .error(function (ret,status_code) {
                        Alert('Cannot get inventory files', 'Unable to retrieve the list of inventory files for this project.', 'alert-info');
                        Wait('stop');
                    });
            }
        };

        // Detect and alert user to potential SCM status issues
        var checkSCMStatus = function () {
            if (!Empty($scope.project)) {
                Rest.setUrl(GetBasePath('projects') + $scope.project + '/');
                Rest.get()
                    .success(function (data) {
                        var msg;
                        switch (data.status) {
                        case 'failed':
                            msg = "
The Project selected has a status of \"failed\". You must run a successful update before you can select an inventory file.";
                            break;
                        case 'never updated':
                            msg = "
The Project selected has a status of \"never updated\". You must run a successful update before you can select an inventory file.";
                            break;
                        case 'missing':
                            msg = '
The selected project has a status of \"missing\". Please check the server and make sure ' +
                                ' the directory exists and file permissions are set correctly.
';
                            break;
                        }
                        if (msg) {
                            Alert('Warning', msg, 'alert-info alert-info--noTextTransform', null, null, null, null, true);
                        }
                    })
                    .error(function (data, status) {
                        ProcessErrors($scope, data, status, form, { hdr: 'Error!',
                            msg: 'Failed to get project ' + $scope.project + '. GET returned status: ' + status });
                    });
            }
        };

        // Register a watcher on project_name
        if ($scope.getInventoryFilesUnregister) {
            $scope.getInventoryFilesUnregister();
        }
        $scope.getInventoryFilesUnregister = $scope.$watch('project', function (newValue, oldValue) {
            if (newValue !== oldValue) {
                getInventoryFiles(newValue);
                checkSCMStatus();
            }
        });

        function sync_inventory_file_select2() {
            CreateSelect2({
                element:'#inventory-file-select',
                addNew: true,
                multiple: false,
                scope: $scope,
                options: 'inventory_files',
                model: 'inventory_file'
            });

            // TODO: figure out why the inventory file model is being set to
            // dirty
        }

        $scope.lookupCredential = function(){
            $state.go('.credential', {
                credential_search: {
                    // TODO: get kind sorting for credential properly implemented
                    // kind: kind,
                    page_size: '5',
                    page: '1'
                }
            });
        };

        $scope.lookupProject = function(){
            $state.go('.project', {
                project_search: {
                    page_size: '5',
                    page: '1'
                }
            });
        };

        $scope.projectBasePath = GetBasePath('projects');
        $scope.credentialBasePath = GetBasePath('credentials') + '?credential_type__kind__in=cloud,network';

        $scope.sourceChange = function(source) {
            if (source) {
              source = source.value;
            } else {
              source = "";
            }

            $scope.credentialBasePath = GetBasePath('credentials') + '?credential_type__kind__in=cloud,network';

            if (source === 'custom'){
                $scope.credentialBasePath = GetBasePath('inventory_script');
            }

            if (source === 'ec2' || source === 'custom' || source === 'vmware' || source === 'openstack' || source === 'scm') {
                $scope.envParseType = 'yaml';

                var varName;
                if (source === 'scm') {
                    varName = 'custom_variables';
                } else {
                    varName = source + '_variables';
                }

                ParseTypeChange({
                    scope: $scope,
                    field_id: varName,
                    variable: varName,
                    parse_variable: 'envParseType'
                });
            }

            if (source === 'scm') {
              $scope.overwrite_vars = true;
            } else {
              $scope.overwrite_vars = false;
            }

            // reset fields
            $scope.group_by_choices = source === 'ec2' ? $scope.ec2_group_by : null;
            // azure_rm regions choices are keyed as "azure" in an OPTIONS request to the inventory_sources endpoint
            $scope.source_region_choices = source === 'azure_rm' ? $scope.azure_regions : $scope[source + '_regions'];
            $scope.cloudCredentialRequired = source !== '' && source !== 'scm' && source !== 'custom' && source !== 'ec2' ? true : false;
            $scope.group_by = null;
            $scope.source_regions = null;
            $scope.credential = null;
            $scope.credential_name = null;
            initRegionSelect();
        };
        // region / source options callback
        $scope.$on('choicesReadyGroup', function() {
            initRegionSelect();
        });

        $scope.$on('choicesReadyVerbosity', function() {
            initVerbositySelect();
        });

        $scope.$on('sourceTypeOptionsReady', function() {
            initSourceSelect();
        });

        function initRegionSelect(){
            CreateSelect2({
                element: '#inventory_source_source_regions',
                multiple: true
            });
            CreateSelect2({
                element: '#inventory_source_group_by',
                multiple: true
            });
        }

        function initSourceSelect(){
            CreateSelect2({
                element: '#inventory_source_source',
                multiple: false
            });
        }

        function initVerbositySelect(){
            CreateSelect2({
                element: '#inventory_source_verbosity',
                multiple: false
            });

            $scope.verbosity = $scope.verbosity_options[0];
        }

        function initSources(){
            GetChoices({
                scope: $scope,
                url: GetBasePath('inventory_sources'),
                field: 'source_regions',
                variable: 'rax_regions',
                choice_name: 'rax_region_choices',
                callback: 'choicesReadyGroup'
            });

            GetChoices({
                scope: $scope,
                url: GetBasePath('inventory_sources'),
                field: 'source_regions',
                variable: 'ec2_regions',
                choice_name: 'ec2_region_choices',
                callback: 'choicesReadyGroup'
            });

            GetChoices({
                scope: $scope,
                url: GetBasePath('inventory_sources'),
                field: 'source_regions',
                variable: 'gce_regions',
                choice_name: 'gce_region_choices',
                callback: 'choicesReadyGroup'
            });

            GetChoices({
                scope: $scope,
                url: GetBasePath('inventory_sources'),
                field: 'source_regions',
                variable: 'azure_regions',
                choice_name: 'azure_region_choices',
                callback: 'choicesReadyGroup'
            });

            // Load options for group_by
            GetChoices({
                scope: $scope,
                url: GetBasePath('inventory_sources'),
                field: 'group_by',
                variable: 'ec2_group_by',
                choice_name: 'ec2_group_by_choices',
                callback: 'choicesReadyGroup'
            });

            GetChoices({
                scope: $scope,
                url: GetBasePath('inventory_sources'),
                field: 'verbosity',
                variable: 'verbosity_options',
                callback: 'choicesReadyVerbosity'
            });

            GetSourceTypeOptions({
                scope: $scope,
                variable: 'source_type_options',
                //callback: 'sourceTypeOptionsReady' this callback is hard-coded into GetSourceTypeOptions(), included for ref
            });
        }

        $scope.formCancel = function() {
            $state.go('^');
        };

        $scope.formSave = function() {
            var params;

            params = {
                name: $scope.name,
                description: $scope.description,
                inventory: inventoryData.id,
                instance_filters: $scope.instance_filters,
                source_script: $scope.inventory_script,
                credential: $scope.credential,
                overwrite: $scope.overwrite,
                overwrite_vars: $scope.overwrite_vars,
                update_on_launch: $scope.update_on_launch,
                verbosity: $scope.verbosity.value,
                update_cache_timeout: $scope.update_cache_timeout || 0,
                // comma-delimited strings
                group_by: _.map($scope.group_by, 'value').join(','),
                source_regions: _.map($scope.source_regions, 'value').join(',')
            };

            if ($scope.source) {
                params.source_vars = $scope[$scope.source.value + '_variables'] === '---' || $scope[$scope.source.value + '_variables'] === '{}' ? null : $scope[$scope.source.value + '_variables'];
                params.source = $scope.source.value;
                if ($scope.source.value === 'scm') {
                  params.update_on_project_update = $scope.update_on_project_update;
                  params.source_project = $scope.project;

                  if ($scope.inventory_file === '/ (project root)') {
                      params.source_path = "";
                  } else {
                      params.source_path = $scope.inventory_file;
                  }
                }
            } else {
                params.source = null;
            }
            SourcesService.post(params).then(function(res){
                let inventory_source_id = res.data.id;
                $state.go('^.edit', {inventory_source_id: inventory_source_id}, {reload: true});
            });
        };
    }
];
<|endoftext|>