<commit_before>import morphdom from 'morphdom'
import { verifyNotMutable, verifyNotPermanent } from './callbacks'
import { assignFocus, dispatch, xpathToElement, getClassNames } from './utils'

export let activeElement

const shouldMorphCallbacks = [verifyNotMutable, verifyNotPermanent]
const didMorphCallbacks = []

// Indicates whether or not we should morph an element via onBeforeElUpdated callback
// SEE: https://github.com/patrick-steele-idem/morphdom#morphdomfromnode-tonode-options--node
//
const shouldMorph = detail => (fromEl, toEl) => {
  return !shouldMorphCallbacks
    .map(callback => {
      return typeof callback === 'function'
        ? callback(detail, fromEl, toEl)
        : true
    })
    .includes(false)
}

// Execute any pluggable functions that modify elements after morphing via onElUpdated callback
//
const didMorph = detail => el => {
  didMorphCallbacks.forEach(callback => {
    if (typeof callback === 'function') callback(detail, el)
  })
}

// Morphdom Callbacks ........................................................................................

const DOMOperations = {
  // Navigation ..............................................................................................

  pushState: config => {
    const { state, title, url } = config
    dispatch(document, 'cable-ready:before-push-state', config)
    history.pushState(state || {}, title || '', url)
    dispatch(document, 'cable-ready:after-push-state', config)
  },

  // Storage .................................................................................................

  setStorageItem: config => {
    const { key, value, type } = config
    const storage = type === 'session' ? sessionStorage : localStorage
    dispatch(document, 'cable-ready:before-set-storage-item', config)
    storage.setItem(key, value)
    dispatch(document, 'cable-ready:after-set-storage-item', config)
  },

  removeStorageItem: config => {
    const { key, type } = config
    const storage = type === 'session' ? sessionStorage : localStorage
    dispatch(document, 'cable-ready:before-remove-storage-item', config)
    storage.removeItem(key)
    dispatch(document, 'cable-ready:after-remove-storage-item', config)
  },

  clearStorage: config => {
    const { type } = config
    const storage = type === 'session' ? sessionStorage : localStorage
    dispatch(document, 'cable-ready:before-clear-storage', config)
    storage.clear()
    dispatch(document, 'cable-ready:after-clear-storage', config)
  },

  // Notifications ...........................................................................................

  consoleLog: config => {
    const { message, level } = config
    level && ['warn', 'info', 'error'].includes(level)
      ? console[level](message)
      : console.log(message)
  },

  notification: config => {
    const { title, options } = config
    dispatch(document, 'cable-ready:before-notification', config)
    let permission
    Notification.requestPermission().then(result => {
      permission = result
      if (result === 'granted') new Notification(title || '', options)
      dispatch(document, 'cable-ready:after-notification', {
        ...config,
        permission
      })
    })
  },

  // Cookies .................................................................................................

  setCookie: config => {
    const { cookie } = config
    dispatch(document, 'cable-ready:before-set-cookie', config)
    document.cookie = cookie
    dispatch(document, 'cable-ready:after-set-cookie', config)
  },

  // DOM Events ..............................................................................................

  dispatchEvent: config => {
    const { element, name, detail } = config
    dispatch(element, name, detail)
  },

  // Element Mutations .......................................................................................

  morph: detail => {
    activeElement = document.activeElement
    const { element, html, childrenOnly, focusSelector } = detail
    const template = document.createElement('template')
    template.innerHTML = String(html).trim()
    dispatch(element, 'cable-ready:before-morph', {
      ...detail,
      content: template.content
    })
    const parent = element.parentElement
    const ordinal = Array.from(parent.children).indexOf(element)
    morphdom(element, childrenOnly ? template.content : template.innerHTML, {
      childrenOnly: !!childrenOnly,
      onBeforeElUpdated: shouldMorph(detail),
      onElUpdated: didMorph(detail)
    })
    assignFocus(focusSelector)
    dispatch(parent.children[ordinal], 'cable-ready:after-morph', {
      ...detail,
      content: template.content
    })
  },

  innerHtml: detail => {
    activeElement = document.activeElement
    const { element, html, focusSelector } = detail
    dispatch(element, 'cable-ready:before-inner-html', detail)
    element.innerHTML = html
    assignFocus(focusSelector)
    dispatch(element, 'cable-ready:after-inner-html', detail)
  },

  outerHtml: detail => {
    activeElement = document.activeElement
    const { element, html, focusSelector } = detail
    dispatch(element, 'cable-ready:before-outer-html', detail)
    const parent = element.parentElement
    const ordinal = Array.from(parent.children).indexOf(element)
    element.outerHTML = html
    assignFocus(focusSelector)
    dispatch(parent.children[ordinal], 'cable-ready:after-outer-html', detail)
  },

  textContent: detail => {
    const { element, text, focusSelector } = detail
    dispatch(element, 'cable-ready:before-text-content', detail)
    element.textContent = text
    assignFocus(focusSelector)
    dispatch(element, 'cable-ready:after-text-content', detail)
  },

  insertAdjacentHtml: detail => {
    activeElement = document.activeElement
    const { element, html, position, focusSelector } = detail
    dispatch(element, 'cable-ready:before-insert-adjacent-html', detail)
    element.insertAdjacentHTML(position || 'beforeend', html)
    assignFocus(focusSelector)
    dispatch(element, 'cable-ready:after-insert-adjacent-html', detail)
  },

  insertAdjacentText: detail => {
    const { element, text, position, focusSelector } = detail
    dispatch(element, 'cable-ready:before-insert-adjacent-text', detail)
    element.insertAdjacentText(position || 'beforeend', text)
    assignFocus(focusSelector)
    dispatch(element, 'cable-ready:after-insert-adjacent-text', detail)
  },

  remove: detail => {
    activeElement = document.activeElement
    const { element, focusSelector } = detail
    dispatch(element, 'cable-ready:before-remove', detail)
    element.remove()
    assignFocus(focusSelector)
    dispatch(element, 'cable-ready:after-remove', detail)
  },

  setFocus: detail => {
    activeElement = document.activeElement
    const { element } = detail
    dispatch(element, 'cable-ready:before-set-focus', detail)
    assignFocus(element)
    dispatch(element, 'cable-ready:after-set-focus', detail)
  },

  setProperty: detail => {
    const { element, name, value } = detail
    dispatch(element, 'cable-ready:before-set-property', detail)
    if (name in element) element[name] = value
    dispatch(element, 'cable-ready:after-set-property', detail)
  },

  setValue: detail => {
    const { element, value, focusSelector } = detail
    dispatch(element, 'cable-ready:before-set-value', detail)
    element.value = value
    assignFocus(focusSelector)
    dispatch(element, 'cable-ready:after-set-value', detail)
  },

  // Attribute Mutations .....................................................................................

  setAttribute: detail => {
    const { element, name, value } = detail
    dispatch(element, 'cable-ready:before-set-attribute', detail)
    element.setAttribute(name, value)
    dispatch(element, 'cable-ready:after-set-attribute', detail)
  },

  removeAttribute: detail => {
    const { element, name } = detail
    dispatch(element, 'cable-ready:before-remove-attribute', detail)
    element.removeAttribute(name)
    dispatch(element, 'cable-ready:after-remove-attribute', detail)
  },

  // CSS Class Mutations .....................................................................................

  addCssClass: detail => {
    const { element, name } = detail
    dispatch(element, 'cable-ready:before-add-css-class', detail)
    element.classList.add(...getClassNames(name))
    dispatch(element, 'cable-ready:after-add-css-class', detail)
  },

  removeCssClass: detail => {
    const { element, name } = detail
    dispatch(element, 'cable-ready:before-remove-css-class', detail)
    element.classList.remove(...getClassNames(name))
    dispatch(element, 'cable-ready:after-remove-css-class', detail)
  },

  // Style Mutations .......................................................................................

  setStyle: detail => {
    const { element, name, value } = detail
    dispatch(element, 'cable-ready:before-set-style', detail)
    element.style[name] = value
    dispatch(element, 'cable-ready:after-set-style', detail)
  },

  setStyles: detail => {
    const { element, styles } = detail
    dispatch(element, 'cable-ready:before-set-styles', detail)
    for (let [name, value] of Object.entries(styles)) {
      element.style[name] = value
    }
    dispatch(element, 'cable-ready:after-set-styles', detail)
  },

  // Dataset Mutations .......................................................................................

  setDatasetProperty: detail => {
    const { element, name, value } = detail
    dispatch(element, 'cable-ready:before-set-dataset-property', detail)
    element.dataset[name] = value
    dispatch(element, 'cable-ready:after-set-dataset-property', detail)
  }
}

const perform = (
  operations,
  options = { emitMissingElementWarnings: true }
) => {
  for (let name in operations) {
    if (operations.hasOwnProperty(name)) {
      const entries = operations[name]
      for (let i = 0; i < entries.length; i++) {
        const detail = entries[i]
        try {
          if (detail.selector) {
            detail.element = detail.xpath
              ? xpathToElement(detail.selector)
              : document.querySelector(detail.selector)
          } else {
            detail.element = document
          }
          if (detail.element || options.emitMissingElementWarnings)
            DOMOperations[name](detail)
        } catch (e) {
          if (detail.element) {
            console.error(
              `CableReady detected an error in ${name}! ${e.message}. If you need to support older browsers make sure you've included the corresponding polyfills. https://docs.stimulusreflex.com/setup#polyfills-for-ie11.`
            )
            console.error(e)
          } else {
            console.log(
              `CableReady ${name} failed due to missing DOM element for selector: '${detail.selector}'`
            )
          }
        }
      }
    }
  }
}

const performAsync = (
  operations,
  options = { emitMissingElementWarnings: true }
) => {
  return new Promise((resolve, reject) => {
    try {
      resolve(perform(operations, options))
    } catch (err) {
      reject(err)
    }
  })
}

export default {
  perform,
  performAsync,
  DOMOperations,
  shouldMorphCallbacks,
  didMorphCallbacks
}
<commit_msg>add activeElement to setValue<commit_after>import morphdom from 'morphdom'
import { verifyNotMutable, verifyNotPermanent } from './callbacks'
import { assignFocus, dispatch, xpathToElement, getClassNames } from './utils'

export let activeElement

const shouldMorphCallbacks = [verifyNotMutable, verifyNotPermanent]
const didMorphCallbacks = []

// Indicates whether or not we should morph an element via onBeforeElUpdated callback
// SEE: https://github.com/patrick-steele-idem/morphdom#morphdomfromnode-tonode-options--node
//
const shouldMorph = detail => (fromEl, toEl) => {
  return !shouldMorphCallbacks
    .map(callback => {
      return typeof callback === 'function'
        ? callback(detail, fromEl, toEl)
        : true
    })
    .includes(false)
}

// Execute any pluggable functions that modify elements after morphing via onElUpdated callback
//
const didMorph = detail => el => {
  didMorphCallbacks.forEach(callback => {
    if (typeof callback === 'function') callback(detail, el)
  })
}

// Morphdom Callbacks ........................................................................................

const DOMOperations = {
  // Navigation ..............................................................................................

  pushState: config => {
    const { state, title, url } = config
    dispatch(document, 'cable-ready:before-push-state', config)
    history.pushState(state || {}, title || '', url)
    dispatch(document, 'cable-ready:after-push-state', config)
  },

  // Storage .................................................................................................

  setStorageItem: config => {
    const { key, value, type } = config
    const storage = type === 'session' ? sessionStorage : localStorage
    dispatch(document, 'cable-ready:before-set-storage-item', config)
    storage.setItem(key, value)
    dispatch(document, 'cable-ready:after-set-storage-item', config)
  },

  removeStorageItem: config => {
    const { key, type } = config
    const storage = type === 'session' ? sessionStorage : localStorage
    dispatch(document, 'cable-ready:before-remove-storage-item', config)
    storage.removeItem(key)
    dispatch(document, 'cable-ready:after-remove-storage-item', config)
  },

  clearStorage: config => {
    const { type } = config
    const storage = type === 'session' ? sessionStorage : localStorage
    dispatch(document, 'cable-ready:before-clear-storage', config)
    storage.clear()
    dispatch(document, 'cable-ready:after-clear-storage', config)
  },

  // Notifications ...........................................................................................

  consoleLog: config => {
    const { message, level } = config
    level && ['warn', 'info', 'error'].includes(level)
      ? console[level](message)
      : console.log(message)
  },

  notification: config => {
    const { title, options } = config
    dispatch(document, 'cable-ready:before-notification', config)
    let permission
    Notification.requestPermission().then(result => {
      permission = result
      if (result === 'granted') new Notification(title || '', options)
      dispatch(document, 'cable-ready:after-notification', {
        ...config,
        permission
      })
    })
  },

  // Cookies .................................................................................................

  setCookie: config => {
    const { cookie } = config
    dispatch(document, 'cable-ready:before-set-cookie', config)
    document.cookie = cookie
    dispatch(document, 'cable-ready:after-set-cookie', config)
  },

  // DOM Events ..............................................................................................

  dispatchEvent: config => {
    const { element, name, detail } = config
    dispatch(element, name, detail)
  },

  // Element Mutations .......................................................................................

  morph: detail => {
    activeElement = document.activeElement
    const { element, html, childrenOnly, focusSelector } = detail
    const template = document.createElement('template')
    template.innerHTML = String(html).trim()
    dispatch(element, 'cable-ready:before-morph', {
      ...detail,
      content: template.content
    })
    const parent = element.parentElement
    const ordinal = Array.from(parent.children).indexOf(element)
    morphdom(element, childrenOnly ? template.content : template.innerHTML, {
      childrenOnly: !!childrenOnly,
      onBeforeElUpdated: shouldMorph(detail),
      onElUpdated: didMorph(detail)
    })
    assignFocus(focusSelector)
    dispatch(parent.children[ordinal], 'cable-ready:after-morph', {
      ...detail,
      content: template.content
    })
  },

  innerHtml: detail => {
    activeElement = document.activeElement
    const { element, html, focusSelector } = detail
    dispatch(element, 'cable-ready:before-inner-html', detail)
    element.innerHTML = html
    assignFocus(focusSelector)
    dispatch(element, 'cable-ready:after-inner-html', detail)
  },

  outerHtml: detail => {
    activeElement = document.activeElement
    const { element, html, focusSelector } = detail
    dispatch(element, 'cable-ready:before-outer-html', detail)
    const parent = element.parentElement
    const ordinal = Array.from(parent.children).indexOf(element)
    element.outerHTML = html
    assignFocus(focusSelector)
    dispatch(parent.children[ordinal], 'cable-ready:after-outer-html', detail)
  },

  textContent: detail => {
    const { element, text, focusSelector } = detail
    dispatch(element, 'cable-ready:before-text-content', detail)
    element.textContent = text
    assignFocus(focusSelector)
    dispatch(element, 'cable-ready:after-text-content', detail)
  },

  insertAdjacentHtml: detail => {
    activeElement = document.activeElement
    const { element, html, position, focusSelector } = detail
    dispatch(element, 'cable-ready:before-insert-adjacent-html', detail)
    element.insertAdjacentHTML(position || 'beforeend', html)
    assignFocus(focusSelector)
    dispatch(element, 'cable-ready:after-insert-adjacent-html', detail)
  },

  insertAdjacentText: detail => {
    const { element, text, position, focusSelector } = detail
    dispatch(element, 'cable-ready:before-insert-adjacent-text', detail)
    element.insertAdjacentText(position || 'beforeend', text)
    assignFocus(focusSelector)
    dispatch(element, 'cable-ready:after-insert-adjacent-text', detail)
  },

  remove: detail => {
    activeElement = document.activeElement
    const { element, focusSelector } = detail
    dispatch(element, 'cable-ready:before-remove', detail)
    element.remove()
    assignFocus(focusSelector)
    dispatch(element, 'cable-ready:after-remove', detail)
  },

  setFocus: detail => {
    activeElement = document.activeElement
    const { element } = detail
    dispatch(element, 'cable-ready:before-set-focus', detail)
    assignFocus(element)
    dispatch(element, 'cable-ready:after-set-focus', detail)
  },

  setProperty: detail => {
    const { element, name, value } = detail
    dispatch(element, 'cable-ready:before-set-property', detail)
    if (name in element) element[name] = value
    dispatch(element, 'cable-ready:after-set-property', detail)
  },

  setValue: detail => {
    activeElement = document.activeElement
    const { element, value, focusSelector } = detail
    dispatch(element, 'cable-ready:before-set-value', detail)
    element.value = value
    assignFocus(focusSelector)
    dispatch(element, 'cable-ready:after-set-value', detail)
  },

  // Attribute Mutations .....................................................................................

  setAttribute: detail => {
    const { element, name, value } = detail
    dispatch(element, 'cable-ready:before-set-attribute', detail)
    element.setAttribute(name, value)
    dispatch(element, 'cable-ready:after-set-attribute', detail)
  },

  removeAttribute: detail => {
    const { element, name } = detail
    dispatch(element, 'cable-ready:before-remove-attribute', detail)
    element.removeAttribute(name)
    dispatch(element, 'cable-ready:after-remove-attribute', detail)
  },

  // CSS Class Mutations .....................................................................................

  addCssClass: detail => {
    const { element, name } = detail
    dispatch(element, 'cable-ready:before-add-css-class', detail)
    element.classList.add(...getClassNames(name))
    dispatch(element, 'cable-ready:after-add-css-class', detail)
  },

  removeCssClass: detail => {
    const { element, name } = detail
    dispatch(element, 'cable-ready:before-remove-css-class', detail)
    element.classList.remove(...getClassNames(name))
    dispatch(element, 'cable-ready:after-remove-css-class', detail)
  },

  // Style Mutations .......................................................................................

  setStyle: detail => {
    const { element, name, value } = detail
    dispatch(element, 'cable-ready:before-set-style', detail)
    element.style[name] = value
    dispatch(element, 'cable-ready:after-set-style', detail)
  },

  setStyles: detail => {
    const { element, styles } = detail
    dispatch(element, 'cable-ready:before-set-styles', detail)
    for (let [name, value] of Object.entries(styles)) {
      element.style[name] = value
    }
    dispatch(element, 'cable-ready:after-set-styles', detail)
  },

  // Dataset Mutations .......................................................................................

  setDatasetProperty: detail => {
    const { element, name, value } = detail
    dispatch(element, 'cable-ready:before-set-dataset-property', detail)
    element.dataset[name] = value
    dispatch(element, 'cable-ready:after-set-dataset-property', detail)
  }
}

const perform = (
  operations,
  options = { emitMissingElementWarnings: true }
) => {
  for (let name in operations) {
    if (operations.hasOwnProperty(name)) {
      const entries = operations[name]
      for (let i = 0; i < entries.length; i++) {
        const detail = entries[i]
        try {
          if (detail.selector) {
            detail.element = detail.xpath
              ? xpathToElement(detail.selector)
              : document.querySelector(detail.selector)
          } else {
            detail.element = document
          }
          if (detail.element || options.emitMissingElementWarnings)
            DOMOperations[name](detail)
        } catch (e) {
          if (detail.element) {
            console.error(
              `CableReady detected an error in ${name}! ${e.message}. If you need to support older browsers make sure you've included the corresponding polyfills. https://docs.stimulusreflex.com/setup#polyfills-for-ie11.`
            )
            console.error(e)
          } else {
            console.log(
              `CableReady ${name} failed due to missing DOM element for selector: '${detail.selector}'`
            )
          }
        }
      }
    }
  }
}

const performAsync = (
  operations,
  options = { emitMissingElementWarnings: true }
) => {
  return new Promise((resolve, reject) => {
    try {
      resolve(perform(operations, options))
    } catch (err) {
      reject(err)
    }
  })
}

export default {
  perform,
  performAsync,
  DOMOperations,
  shouldMorphCallbacks,
  didMorphCallbacks
}
<|endoftext|>


<commit_before><commit_msg>chore(gatsby-cli): Add integration tests for `gatsby develop` (#22699)<commit_after><|endoftext|>


<commit_before>window.chartColors = { // replace with colours in code?
	red: 'rgb(255, 99, 132)',
	orange: 'rgb(255, 159, 64)',
	yellow: 'rgb(255, 205, 86)',
	green: 'rgb(75, 192, 192)',
	blue: 'rgb(54, 162, 235)',
	purple: 'rgb(153, 102, 255)',
	grey: 'rgb(231,233,237)'
};

window.addEventListener("load", function(event) {
	var currentSeconds = parseInt(document.getElementsByClassName("measurementTime")[0].innerText);
	window.setInterval(function () {
		currentSeconds++;
		var timeElements = document.getElementsByClassName("measurementTime");
		for (var i = 0; i < timeElements.length; i++) {
			timeElements[i].innerText = currentSeconds;
		}
	}, 1000);

	var createGraphs = function (ajaxdata) {
		for (var i = 0; i < ajaxdata.metadata.length; i++) {
			var meta = ajaxdata.metadata[i];
			meta.unit = meta.unit.replace(/°/g, String.fromCharCode(176)); // fix degree symbol
			new Chart(document.getElementById("graph-" + meta.sensorID).getContext("2d"), {
				type: 'line',
				data: {
					labels: ["-95", "-90", "-85", "-80", "-75", "-70", "-65", "-60", "-55", "-50", "-45", "-40", "-35", "-30", "-25", "-20", "-15", "-10", "-5", "0"],
					datasets: [{
						label: meta.measurement + " (" + meta.unit + ")",
						backgroundColor: window.chartColors.red,
						borderColor: window.chartColors.red,
						data: ajaxdata.values[meta.sensorID],
						fill: false
					}]
				},
				options: {
					responsive: true,
					tooltips: {
						mode: 'index',
						intersect: false,
					},
					hover: {
						mode: 'nearest',
						intersect: true
					},
					scales: {
						xAxes: [{
							display: true,
							scaleLabel: {
								display: true,
								labelString: 'Time (Mins ago)',
								fontFamily: "sans-serif"
							}
						}],
						yAxes: [{
							display: true,
							ticks: {
								min: meta.min,
								max: meta.max
							},
							scaleLabel: {
								display: true,
								labelString: meta.measurement
							}
						}]
					}
				}
			});
		}
	};

	var oReq = new XMLHttpRequest();

	oReq.onreadystatechange = function () {
		if (oReq.readyState === XMLHttpRequest.DONE) {
			if (oReq.status === 200) {
				console.log(JSON.parse(this.responseText));
				createGraphs(JSON.parse(this.responseText));
			} else {
				console.log(oReq.status);
			}
		}
	};

	oReq.open("GET", "/data.json");
	oReq.send();
}, false);<commit_msg>Added additional time labels<commit_after>window.chartColors = { // replace with colours in code?
	red: 'rgb(255, 99, 132)',
	orange: 'rgb(255, 159, 64)',
	yellow: 'rgb(255, 205, 86)',
	green: 'rgb(75, 192, 192)',
	blue: 'rgb(54, 162, 235)',
	purple: 'rgb(153, 102, 255)',
	grey: 'rgb(231,233,237)'
};

window.addEventListener("load", function(event) {
	var currentSeconds = parseInt(document.getElementsByClassName("measurementTime")[0].innerText);
	window.setInterval(function () {
		currentSeconds++;
		var timeElements = document.getElementsByClassName("measurementTime");
		for (var i = 0; i < timeElements.length; i++) {
			timeElements[i].innerText = currentSeconds;
		}
	}, 1000);

	var createGraphs = function (ajaxdata) {
		for (var i = 0; i < ajaxdata.metadata.length; i++) {
			var meta = ajaxdata.metadata[i];
			meta.unit = meta.unit.replace(/°/g, String.fromCharCode(176)); // fix degree symbol
			new Chart(document.getElementById("graph-" + meta.sensorID).getContext("2d"), {
				type: 'line',
				data: {
					labels: ["-195", "-190", "-185", "-180", "-175", "-170", "-165", "-160", "-155", "-150", "-145", "-140", "-135", "-130", "-125", "-120", "-115", "-110", "-105", "-100", "-95", "-90", "-85", "-80", "-75", "-70", "-65", "-60", "-55", "-50", "-45", "-40", "-35", "-30", "-25", "-20", "-15", "-10", "-5", "0"],
					datasets: [{
						label: meta.measurement + " (" + meta.unit + ")",
						backgroundColor: window.chartColors.red,
						borderColor: window.chartColors.red,
						data: ajaxdata.values[meta.sensorID],
						fill: false
					}]
				},
				options: {
					responsive: true,
					tooltips: {
						mode: 'index',
						intersect: false,
					},
					hover: {
						mode: 'nearest',
						intersect: true
					},
					scales: {
						xAxes: [{
							display: true,
							scaleLabel: {
								display: true,
								labelString: 'Time (Mins ago)',
								fontFamily: "sans-serif"
							}
						}],
						yAxes: [{
							display: true,
							ticks: {
								min: meta.min,
								max: meta.max
							},
							scaleLabel: {
								display: true,
								labelString: meta.measurement
							}
						}]
					}
				}
			});
		}
	};

	var oReq = new XMLHttpRequest();

	oReq.onreadystatechange = function () {
		if (oReq.readyState === XMLHttpRequest.DONE) {
			if (oReq.status === 200) {
				console.log(JSON.parse(this.responseText));
				createGraphs(JSON.parse(this.responseText));
			} else {
				console.log(oReq.status);
			}
		}
	};

	oReq.open("GET", "/data.json");
	oReq.send();
}, false);
<|endoftext|>


<commit_before>/*
  Overview: Provided a grant name, will access the respective json file represnting that grant
    and retrieve the necessary info. There are helper variables in this class to assist in
    parsing the json file.

  The current structure of the JSON is to be as follows:
  {
    "Grants": [
      {
        "Grant_Name" : "NSF Career",
        "Grant_Columns" : [
          {
            "Column_Name" : "To Do",
            "Cards": [
              {
                "Card_Name": "Cover Sheet",
                "Modal_ID" : "Cover_Sheet",
                "Modal_Body": "
Required

Program Solicitation Number

NSF Unit of Consideration

Project Title

Co-PIs

PI eligibility information

",
                "Document_Link": "http://www.github.com"
              }
            ]
          },

          {
            "Column_Name" : "In Progress",
            "Cards": [
              {
                "Card_Name": "References Cited",
                "Modal_ID" : "References_Cited",
                "Modal_Body": "",
                "Document_Link": "http://www.github.com",
                "Assigned_People" : ["Waffles", "Waffles"]
              }
            ]
          },

          {
            "Column_Name" : "Complete",
            "Cards": [
              {
                "Card_Name": "Departmental Letter",
                "Modal_ID" : "Departmental_Letter",
                "Modal_Body": "",
                "Document_Link": "http://www.github.com",
                "Tag_List" : ["Under Review", "Complete"]
              }
            ]
          }
        ]
      }
    ]
  }

  NOTE:
    * Tag_List and Assigned_People are optional
    * Rest of the fields are required

  Current Status:
    * Dynamic column generation
    * Dynamic card generation
    * Displays body contents on In Progress or Complete column (People, Links, Tags)
    * Supported Tags for Complete column are, Under Review and Complete
    * Sick documentation @see above
  TODO:
    * Support Comments
    * Support additional tags

  @author: Morgan Nesbitt
*/

var cardTemplate;
var modalTemplate;
var grantName = "NSF Career";
var jsonInfo = {
  Grants: [
    {
      Grant_Name : "NSF Career",
      Grant_Columns : [
        {
          Column_Name : "To Do",
          Cards: [
            {
              Card_Name: "Cover Sheet",
              Modal_ID : "Cover_Sheet",
              Modal_Body: "
Required

Program Solicitation Number

NSF Unit of Consideration

Project Title

Co-PIs

PI eligibility information

",
              Document_Link: "http://www.github.com"
            },
            {
              Card_Name: "Project Description",
              Modal_ID : "Project_Description",
              Modal_Body: "
Required

Program Solicitation Number

NSF Unit of Consideration

Project Title

Co-PIs

PI eligibility information

",
              Document_Link: "http://www.github.com"
            },
            {
              Card_Name: "Budget",
              Modal_ID : "Budget",
              Modal_Body: "
Required

Program Solicitation Number

NSF Unit of Consideration

Project Title

Co-PIs

PI eligibility information

",
              Document_Link: "http://www.github.com"
            },
            {
              Card_Name: "Budget Justification",
              Modal_ID : "Budget_Justification",
              Modal_Body: "
Required

Program Solicitation Number

NSF Unit of Consideration

Project Title

Co-PIs

PI eligibility information

",
              Document_Link: "http://www.github.com"
            }
          ]
        },

        {
          Column_Name : "In Progress",
          Cards: [
            {
              Card_Name: "References Cited",
              Modal_ID : "References_Cited",
              Modal_Body: "
Required

Program Solicitation Number

NSF Unit of Consideration

Project Title

Co-PIs

PI eligibility information

",
              Document_Link: "http://www.github.com",
              Assigned_People : ["Waffles", "Waffles"]
            },
            {
              Card_Name: "Biosketch",
              Modal_ID : "Biosketch",
              Modal_Body: "
Required

Program Solicitation Number

NSF Unit of Consideration

Project Title

Co-PIs

PI eligibility information

",
              Document_Link: "http://www.github.com",
              Assigned_People : ["Waffles"]
            }
          ]
        },

        {
          Column_Name : "Complete",
          Cards: [
            {
              Card_Name: "Departmental Letter",
              Modal_ID : "Departmental_Letter",
              Modal_Body: "
Required

Program Solicitation Number

NSF Unit of Consideration

Project Title

Co-PIs

PI eligibility information

",
              Document_Link: "http://www.github.com",
              Assigned_People : ["Waffles"],
              Tag_List : ["Under Review", "Complete"]
            }
          ]
        }
      ]
    }
  ]
};
/*
$.getJSON( "json/cards.json", {}, function( data ) {
  jsonInfo = data.Grants[0];
});
*/
$.ajax({
    url: 'templates/full_card.html',
    dataType: 'html',
    method: 'GET',
    async: false,
    success: function(data) {
        cardTemplate = Handlebars.compile(data);
        $('#columnList').html(cardTemplate(jsonInfo.Grants[0]));
    }
});

$.ajax({
    url: 'templates/card_modal.html',
    dataType: 'html',
    method: 'GET',
    async: false,
    success: function(data) {
        modalTemplate = Handlebars.compile(data);
        $('#cardModals').html(modalTemplate(jsonInfo.Grants[0]));
    }
});
<commit_msg>Revert "Temporary GitHub Pages ONLY fix"<commit_after>/*
  Overview: Provided a grant name, will access the respective json file represnting that grant
    and retrieve the necessary info. There are helper variables in this class to assist in
    parsing the json file.

  The current structure of the JSON is to be as follows:
  {
    "Grants": [
      {
        "Grant_Name" : "NSF Career",
        "Grant_Columns" : [
          {
            "Column_Name" : "To Do",
            "Cards": [
              {
                "Card_Name": "Cover Sheet",
                "Modal_ID" : "Cover_Sheet",
                "Modal_Body": "
Required

Program Solicitation Number

NSF Unit of Consideration

Project Title

Co-PIs

PI eligibility information

",
                "Document_Link": "http://www.github.com"
              }
            ]
          },

          {
            "Column_Name" : "In Progress",
            "Cards": [
              {
                "Card_Name": "References Cited",
                "Modal_ID" : "References_Cited",
                "Modal_Body": "",
                "Document_Link": "http://www.github.com",
                "Assigned_People" : ["Waffles", "Waffles"]
              }
            ]
          },

          {
            "Column_Name" : "Complete",
            "Cards": [
              {
                "Card_Name": "Departmental Letter",
                "Modal_ID" : "Departmental_Letter",
                "Modal_Body": "",
                "Document_Link": "http://www.github.com",
                "Tag_List" : ["Under Review", "Complete"]
              }
            ]
          }
        ]
      }
    ]
  }

  NOTE:
    * Tag_List and Assigned_People are optional
    * Rest of the fields are required

  Current Status:
    * Dynamic column generation
    * Dynamic card generation
    * Displays body contents on In Progress or Complete column (People, Links, Tags)
    * Supported Tags for Complete column are, Under Review and Complete
    * Sick documentation @see above
  TODO:
    * Support Comments
    * Support additional tags

  @author: Morgan Nesbitt
*/

var cardTemplate;
var modalTemplate;
var grantName = "NSF Career";
var jsonInfo;

$.getJSON( "json/cards.json", {}, function( data ) {
  jsonInfo = data.Grants[0];
});

$.ajax({
    url: 'templates/full_card.html',
    dataType: 'html',
    method: 'GET',
    async: false,
    success: function(data) {
        cardTemplate = Handlebars.compile(data);
        $('#columnList').html(cardTemplate(jsonInfo));
    }
});

$.ajax({
    url: 'templates/card_modal.html',
    dataType: 'html',
    method: 'GET',
    async: false,
    success: function(data) {
        modalTemplate = Handlebars.compile(data);
        $('#cardModals').html(modalTemplate(jsonInfo));
    }
});
<|endoftext|>


<commit_before>#!/usr/bin/env node
process.on('uncaughtException', function (err) {
  console.log(new Error(err.stack + '\nRethrown:').stack)
})

var argv = require('commander')
var path = require('path')
var async = require('async')
var util = require('util')
var fs = require('fs-extra')
var childProcess = require('child_process')
var os = require('os')
var which = require('which')
var semver = require('semver')

var dir = process.cwd()

var cpFiles = function (dir, destDir, force, cb) {
  console.log('recursively copying: %s -> %s', dir, destDir)
  fs.copy(dir, destDir, { clobber: force }, cb)
}

var packageFile = path.join(__dirname, '../package.json')
var packageJson = require(packageFile)

var shared = function (appDir, force, install) {
  var processFiles = function (cb) {
    var currentPackageJson = require('./package.json')

    // Read this file first. It will throw if you are in an empty dir (which is on
    // purpose).
    var theirPackageJson = require(path.join(appDir, 'package.json'))

    var staticPath = path.join(__dirname, 'static')

    // Update dependencies
    // merge taking theirs

    ;[ 'dependencies', 'devDependencies', 'scripts', 'config' ].forEach(function (m) {
      // merge taking theirs
      theirPackageJson[ m ] = theirPackageJson[ m ] || {}
      if (!force) {
        util._extend(currentPackageJson[ m ], theirPackageJson[ m ])
      }
      util._extend(theirPackageJson[ m ], currentPackageJson[ m ])
    })

    // pwn subsection

    ;[ { sub: 'devDependencies', name: 'yaktor-lang' } ].forEach(function (d) {
      theirPackageJson[ d.sub ][ d.name ] = packageJson[ d.sub ][ d.name ]
    })

    theirPackageJson.dependencies.yaktor = packageJson.version

    fs.writeFileSync(path.join(appDir, 'package.json'), JSON.stringify(theirPackageJson, null, 2))

    async.parallel([ function (done) {
      cpFiles(path.join(staticPath, 'lib'), path.join(appDir, 'lib'), true, done)
    }, function (done) {
      cpFiles(path.join(staticPath, 'config'), path.join(appDir, 'config'), true, done)
    }, function (done) {
      cpFiles(path.join(staticPath, 'public'), path.join(appDir, 'public'), true, done)
    }, function (done) {
      cpFiles(path.join(staticPath, 'docker'), path.join(appDir, 'docker'), force, done)
    }, function (done) {
      cpFiles(path.join(staticPath, 'test'), path.join(appDir, 'test'), force, done)
    }, function (done) {
      async.series([ function (next) {
        cpFiles(path.join(staticPath, 'ROOT'), path.join(appDir), force, next)
      }, function (next) {
        fs.move(path.join(appDir, 'demo.yc.example'), path.join(appDir, 'demo.yc'), { clobber: force }, next)
      } ], done)
    } ], cb)
  }

  if (packageJson._resolved && packageJson._resolved.indexOf('file:') === 0) { // then assume you're developing yaktor itself
    console.log('NOTE: local development of yaktor detected; installing yaktor from ' + path.resolve(__dirname, '..'))
    async.series([
      async.apply(processFiles),
      function (next) {
        if (__dirname.indexOf(dir) !== 0) {
          exec('npm', [ 'install', path.resolve(__dirname, '..') ], next) // install this very yaktor
        } else {
          next() // don't install it again
        }
      },
      function (next) {
        var yaktorLangRequiredVersion = packageJson.devDependencies[ 'yaktor-lang' ]
        var yaktorLangInstalledVersion
        try {
          yaktorLangInstalledVersion = require(path.join('yaktor-lang', 'package.json')).version
        } catch (e) {
          // not installed
        }
        if (!semver.satisfies(yaktorLangInstalledVersion, yaktorLangRequiredVersion)) {
          console.log('INFO: trying to install required yaktor-lang@%s', yaktorLangRequiredVersion)
          exec('npm', [ 'install', 'yaktor-lang@' + yaktorLangRequiredVersion ], function (err) {
            if (!err) return next()
            // else try to install from location next to this very yaktor
            var yaktorLangDir = path.resolve(__dirname, '..', 'yaktor-dsl-xtext', 'target', 'npm')
            if (fs.existsSync(yaktorLangDir) &&
                semver.satisfies(require(path.resolve(path.join(yaktorLangDir, 'package.json'))).version, yaktorLangRequiredVersion)) {
              console.log('WARNING: ignore previous error; installing yaktor-lang@%s instead from directory %s', yaktorLangRequiredVersion, yaktorLangDir)
              exec('npm', [ 'install', yaktorLangDir ], next)
            } else {
              next(new Error('No yaktor-lang found that satisfies version requirement of ' + yaktorLangRequiredVersion))
            }
          })
        } else {
          next()  // don't install it again
        }
      },
      function (next) {
        if (install) {
          exec('npm', [ 'install' ], next)
        } else {
          next()
        }
      }
    ], function (err) {
      if (err) {
        console.log(err.stack)
        process.exit(1)
      } else {
        process.exit(0)
      }
    })
  } else {
    async.series([
      async.apply(processFiles),
      async.apply(exec, 'npm', [ 'install' ])
    ], function (err) {
      if (err) {
        console.log(err.stack)
        process.exit(1)
      } else {
        process.exit(0)
      }
    })
  }
}

function createRootFiles (name, appDir, options) {
  var gitignore = [
    '*.log',
    '*.def.js',
    '*.gen.js',
    '/conversations/types',
    '/conversations/ejs',
    '/conversations/security',
    '/actions',
    '/coverage',
    '/doc',
    '/public/*',
    '!/public/socketApi.js',
    '/routes',
    '/servers',
    '/simulator',
    '/src-gen',
    'node_modules',
    'bower_components'
  ].join(os.EOL)

  var dotProject = [
    '<?xml version="1.0" encoding="UTF-8"?>',
    '<projectDescription>',
    '  <name>' + name + '</name>',
    '  <comment></comment>',
    '  <projects>',
    '  </projects>',
    '  <buildSpec>',
    '    <buildCommand>',
    '      <name>org.eclipse.xtext.ui.shared.xtextBuilder</name>',
    '      <arguments>',
    '      </arguments>',
    '    </buildCommand>',
    '  </buildSpec>',
    '  <natures>',
    '    <nature>org.eclipse.xtext.ui.shared.xtextNature</nature>',
    '  </natures>',
    '</projectDescription>'
  ].join(os.EOL)

  var files = {
    '.project': dotProject,
    '.gitignore': gitignore,
    '.npmignore': ''
  }
  Object.keys(files).forEach(function (file) {
    var pathname = path.join(appDir, file)
    if (fs.existsSync(pathname) && options.safe) {
      console.error('File ' + pathname + ' exists: failing.')
      return process.exit(-1)
    }

    fs.writeFileSync(pathname, files[ file ])
  })
}

function init (appDir, options) {
  appDir = path.resolve(appDir || dir)
  console.log('yaktorizing %s', appDir)
  process.chdir(appDir)
  var theirPackageJson = path.join(appDir, 'package.json')
  var theirJson
  if (fs.existsSync(theirPackageJson)) {
    if (options.safe) {
      console.error('File ' + theirPackageJson + ' exists.  Failing.')
      process.exit(-1)
    }
    theirJson = require(theirPackageJson)
  } else {
    theirJson = {
      private: true
    }
  }
  theirJson.version = options.initialVersion
  theirJson.dependencies = theirJson.dependencies || {}
  theirJson.devDependencies = theirJson.devDependencies || {}
  theirJson.scripts = theirJson.scripts || {}

  fs.writeFileSync(theirPackageJson, JSON.stringify(theirJson, null, 2))
  if (options.npmInit) {
    childProcess.execSync('npm init -y', { stdio: 'inherit' })
  }
  createRootFiles(options.name || path.basename(appDir), appDir, options)
  shared(appDir, !options.safe, options.install)
}

function create (name, options) {
  var appDir = path.resolve(dir, name)
  if (fs.existsSync(appDir)) {
    if (options.safe) {
      console.error('Directory "%s" already exists: failing.', name)
      return process.exit(-1)
    }
  } else {
    fs.mkdirSync(appDir)
  }
  process.chdir(appDir)
  console.log('create %s %s using yaktor@%s', name, options.initialVersion, packageJson.version)
  options.name = name
  init(appDir, options)
}

argv.command('cassandra')
  .description('add cassandra support and logging')
  .action(function () {
    var staticPath = path.join(__dirname, 'cassandra')

    var theirPackageJson = require(path.join(path.resolve('package.json')))
    var currentPackageJson = require('./cassandra-package.json')
    util._extend(theirPackageJson.dependencies, currentPackageJson.dependencies)
    cpFiles(path.join(staticPath, 'config'), path.join(dir, 'config'), true)
    exec('npm', [ 'install' ])
    fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify(theirPackageJson, null, 2))
  })
argv.command('kafka')
  .description('add kafka support and logging')
  .action(function () {
    var staticPath = path.join(__dirname, 'kafka')

    var theirPackageJson = require(path.join(path.resolve('package.json')))
    var currentPackageJson = require('./kafka-package.json')
    util._extend(theirPackageJson.dependencies, currentPackageJson.dependencies)
    cpFiles(path.join(staticPath, 'config'), path.join(dir, 'config'), true)
    exec('npm', [ 'install' ])
    fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify(theirPackageJson, null, 2))
  })
argv.command('plugin <plugin>')
  .description('install a <plugin> and execute it\'s plugin command')
  .option('-n, --name <name>', 'use <name> instead of <plugin> command execution')
  .action(function (plugin, options) {
    // hack to workaround https://github.com/tj/commander.js/issues/582
    var passThrough = false
    var remainingArgs = process.argv.filter(function (arg) {
      if (passThrough) {
        return true
      } else if (arg === '--') {
        passThrough = true
      }
    })
    var pArgs = ['plugin'].concat(remainingArgs)
    var name = options.name || plugin.split('@')[0]
    async.series([
      async.apply(exec, 'npm', ['install', plugin]),
      async.apply(exec, name, pArgs)
    ])
  })
argv.command('init [path]')
  .description('initialize yaktor app at [path] to current yaktor version')
  .option('-s, --safe', 'do not force initialization if files already exist')
  .option('-n, --no-npm-init', 'do not run `npm init` even if necessary')
  .option('-i, --initial-version [version]', 'initial version for the created app', '0.0.1')
  .option('-x, --no-install', 'do not perform `npm install`')
  .action(init)

argv.command('create <appName>')
  .description('create a yaktor app in a new directory named <appName>')
  .option('-s, --safe', 'do not force initialization if files already exist')
  .option('-i, --initial-version [version]', 'initial version for the created app', '0.0.1')
  .option('-x, --no-install', 'do not perform `npm install`')
  .action(create)

argv.command('help [subCommand]')
  .description('alias to [subCommand] -h')
  .action(function (subCommand) {
    if (subCommand) {
      childProcess.fork(__filename, [ subCommand, '-h' ])
    } else {
      childProcess.fork(__filename, [ '-h' ])
    }
  })

argv.version(packageJson.version)

argv.parse(process.argv)

function exec (cmd, args, cb) {
  console.log([ cmd ].concat(args).join(' '))
  var p = childProcess.spawn(which.sync(cmd), args || [], { stdio: 'inherit' })
  if (cb) {
    p.on('close', cb)
  }
  return p
}
<commit_msg>closes #29<commit_after>#!/usr/bin/env node
process.on('uncaughtException', function (err) {
  console.log(new Error(err.stack + '\nRethrown:').stack)
})

var argv = require('commander')
var path = require('path')
var async = require('async')
var util = require('util')
var fs = require('fs-extra')
var childProcess = require('child_process')
var os = require('os')
var which = require('which')
var semver = require('semver')

var dir = process.cwd()

var cpFiles = function (dir, destDir, force, cb) {
  console.log('recursively copying: %s -> %s', dir, destDir)
  fs.copy(dir, destDir, { clobber: force }, cb)
}

var packageFile = path.join(__dirname, '../package.json')
var packageJson = require(packageFile)

var shared = function (appDir, force, install) {
  var processFiles = function (cb) {
    var currentPackageJson = require('./package.json')

    // Read this file first. It will throw if you are in an empty dir (which is on
    // purpose).
    var theirPackageJson = require(path.join(appDir, 'package.json'))

    var staticPath = path.join(__dirname, 'static')

    // Update dependencies
    // merge taking theirs

    ;[ 'dependencies', 'devDependencies', 'scripts', 'config' ].forEach(function (m) {
      // merge taking theirs
      theirPackageJson[ m ] = theirPackageJson[ m ] || {}
      if (!force) {
        util._extend(currentPackageJson[ m ], theirPackageJson[ m ])
      }
      util._extend(theirPackageJson[ m ], currentPackageJson[ m ])
    })

    // pwn subsection

    ;[ { sub: 'devDependencies', name: 'yaktor-lang' } ].forEach(function (d) {
      theirPackageJson[ d.sub ][ d.name ] = packageJson[ d.sub ][ d.name ]
    })

    theirPackageJson.dependencies.yaktor = packageJson.version

    fs.writeFileSync(path.join(appDir, 'package.json'), JSON.stringify(theirPackageJson, null, 2))

    async.parallel([ function (done) {
      cpFiles(path.join(staticPath, 'lib'), path.join(appDir, 'lib'), true, done)
    }, function (done) {
      cpFiles(path.join(staticPath, 'config'), path.join(appDir, 'config'), true, done)
    }, function (done) {
      cpFiles(path.join(staticPath, 'public'), path.join(appDir, 'public'), true, done)
    }, function (done) {
      cpFiles(path.join(staticPath, 'docker'), path.join(appDir, 'docker'), force, done)
    }, function (done) {
      cpFiles(path.join(staticPath, 'test'), path.join(appDir, 'test'), force, done)
    }, function (done) {
      async.series([ function (next) {
        cpFiles(path.join(staticPath, 'ROOT'), path.join(appDir), force, next)
      }, function (next) {
        fs.move(path.join(appDir, 'demo.yc.example'), path.join(appDir, 'demo.yc'), { clobber: force }, next)
      } ], done)
    } ], cb)
  }

  if (packageJson._resolved && packageJson._resolved.indexOf('file:') === 0) { // then assume you're developing yaktor itself
    console.log('NOTE: local development of yaktor detected; installing yaktor from ' + path.resolve(__dirname, '..'))
    async.series([
      async.apply(processFiles),
      function (next) {
        if (__dirname.indexOf(dir) !== 0) {
          exec('npm', [ 'install', path.resolve(__dirname, '..') ], next) // install this very yaktor
        } else {
          next() // don't install it again
        }
      },
      function (next) {
        var yaktorLangRequiredVersion = packageJson.devDependencies[ 'yaktor-lang' ]
        var yaktorLangInstalledVersion
        try {
          yaktorLangInstalledVersion = require(path.join('yaktor-lang', 'package.json')).version
        } catch (e) {
          // not installed
        }
        if (!semver.satisfies(yaktorLangInstalledVersion, yaktorLangRequiredVersion)) {
          console.log('INFO: trying to install required yaktor-lang@%s', yaktorLangRequiredVersion)
          exec('npm', [ 'install', 'yaktor-lang@' + yaktorLangRequiredVersion ], function (err) {
            if (!err) return next()
            // else try to install from location next to this very yaktor
            var yaktorLangDir = path.resolve(__dirname, '..', 'yaktor-dsl-xtext', 'target', 'npm')
            if (fs.existsSync(yaktorLangDir) &&
                semver.satisfies(require(path.resolve(path.join(yaktorLangDir, 'package.json'))).version, yaktorLangRequiredVersion)) {
              console.log('WARNING: ignore previous error; installing yaktor-lang@%s instead from directory %s', yaktorLangRequiredVersion, yaktorLangDir)
              exec('npm', [ 'install', yaktorLangDir ], next)
            } else {
              next(new Error('No yaktor-lang found that satisfies version requirement of ' + yaktorLangRequiredVersion))
            }
          })
        } else {
          next()  // don't install it again
        }
      },
      function (next) {
        if (install) {
          exec('npm', [ 'install' ], next)
        } else {
          next()
        }
      }
    ], function (err) {
      if (err) {
        console.log(err.stack)
        process.exit(1)
      } else {
        process.exit(0)
      }
    })
  } else {
    async.series([
      async.apply(processFiles),
      async.apply(exec, 'npm', [ 'install' ])
    ], function (err) {
      if (err) {
        console.log(err.stack)
        process.exit(1)
      } else {
        process.exit(0)
      }
    })
  }
}

function createRootFiles (name, appDir, options) {
  var gitignore = [
    '*.log',
    '*.def.js',
    '*.gen.js',
    'views',
    '/conversations/types',
    '/conversations/ejs',
    '/conversations/security',
    '/actions',
    '/coverage',
    '/doc',
    '/public/*',
    '!/public/socketApi.js',
    '/routes',
    '/servers',
    '/simulator',
    '/src-gen',
    'node_modules',
    'bower_components',
    '.idea/'
  ].join(os.EOL)

  var dotProject = [
    '<?xml version="1.0" encoding="UTF-8"?>',
    '<projectDescription>',
    '  <name>' + name + '</name>',
    '  <comment></comment>',
    '  <projects>',
    '  </projects>',
    '  <buildSpec>',
    '    <buildCommand>',
    '      <name>org.eclipse.xtext.ui.shared.xtextBuilder</name>',
    '      <arguments>',
    '      </arguments>',
    '    </buildCommand>',
    '  </buildSpec>',
    '  <natures>',
    '    <nature>org.eclipse.xtext.ui.shared.xtextNature</nature>',
    '  </natures>',
    '</projectDescription>'
  ].join(os.EOL)

  var files = {
    '.project': dotProject,
    '.gitignore': gitignore,
    '.npmignore': ''
  }
  Object.keys(files).forEach(function (file) {
    var pathname = path.join(appDir, file)
    if (fs.existsSync(pathname) && options.safe) {
      console.error('File ' + pathname + ' exists: failing.')
      return process.exit(-1)
    }

    fs.writeFileSync(pathname, files[ file ])
  })
}

function init (appDir, options) {
  appDir = path.resolve(appDir || dir)
  console.log('yaktorizing %s', appDir)
  process.chdir(appDir)
  var theirPackageJson = path.join(appDir, 'package.json')
  var theirJson
  if (fs.existsSync(theirPackageJson)) {
    if (options.safe) {
      console.error('File ' + theirPackageJson + ' exists.  Failing.')
      process.exit(-1)
    }
    theirJson = require(theirPackageJson)
  } else {
    theirJson = {
      private: true
    }
  }
  theirJson.version = options.initialVersion
  theirJson.dependencies = theirJson.dependencies || {}
  theirJson.devDependencies = theirJson.devDependencies || {}
  theirJson.scripts = theirJson.scripts || {}

  fs.writeFileSync(theirPackageJson, JSON.stringify(theirJson, null, 2))
  if (options.npmInit) {
    childProcess.execSync('npm init -y', { stdio: 'inherit' })
  }
  createRootFiles(options.name || path.basename(appDir), appDir, options)
  shared(appDir, !options.safe, options.install)
}

function create (name, options) {
  var appDir = path.resolve(dir, name)
  if (fs.existsSync(appDir)) {
    if (options.safe) {
      console.error('Directory "%s" already exists: failing.', name)
      return process.exit(-1)
    }
  } else {
    fs.mkdirSync(appDir)
  }
  process.chdir(appDir)
  console.log('create %s %s using yaktor@%s', name, options.initialVersion, packageJson.version)
  options.name = name
  init(appDir, options)
}

argv.command('cassandra')
  .description('add cassandra support and logging')
  .action(function () {
    var staticPath = path.join(__dirname, 'cassandra')

    var theirPackageJson = require(path.join(path.resolve('package.json')))
    var currentPackageJson = require('./cassandra-package.json')
    util._extend(theirPackageJson.dependencies, currentPackageJson.dependencies)
    cpFiles(path.join(staticPath, 'config'), path.join(dir, 'config'), true)
    exec('npm', [ 'install' ])
    fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify(theirPackageJson, null, 2))
  })
argv.command('kafka')
  .description('add kafka support and logging')
  .action(function () {
    var staticPath = path.join(__dirname, 'kafka')

    var theirPackageJson = require(path.join(path.resolve('package.json')))
    var currentPackageJson = require('./kafka-package.json')
    util._extend(theirPackageJson.dependencies, currentPackageJson.dependencies)
    cpFiles(path.join(staticPath, 'config'), path.join(dir, 'config'), true)
    exec('npm', [ 'install' ])
    fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify(theirPackageJson, null, 2))
  })
argv.command('plugin <plugin>')
  .description('install a <plugin> and execute it\'s plugin command')
  .option('-n, --name <name>', 'use <name> instead of <plugin> command execution')
  .action(function (plugin, options) {
    // hack to workaround https://github.com/tj/commander.js/issues/582
    var passThrough = false
    var remainingArgs = process.argv.filter(function (arg) {
      if (passThrough) {
        return true
      } else if (arg === '--') {
        passThrough = true
      }
    })
    var pArgs = ['plugin'].concat(remainingArgs)
    var name = options.name || plugin.split('@')[0]
    async.series([
      async.apply(exec, 'npm', ['install', plugin]),
      async.apply(exec, name, pArgs)
    ])
  })
argv.command('init [path]')
  .description('initialize yaktor app at [path] to current yaktor version')
  .option('-s, --safe', 'do not force initialization if files already exist')
  .option('-n, --no-npm-init', 'do not run `npm init` even if necessary')
  .option('-i, --initial-version [version]', 'initial version for the created app', '0.0.1')
  .option('-x, --no-install', 'do not perform `npm install`')
  .action(init)

argv.command('create <appName>')
  .description('create a yaktor app in a new directory named <appName>')
  .option('-s, --safe', 'do not force initialization if files already exist')
  .option('-i, --initial-version [version]', 'initial version for the created app', '0.0.1')
  .option('-x, --no-install', 'do not perform `npm install`')
  .action(create)

argv.command('help [subCommand]')
  .description('alias to [subCommand] -h')
  .action(function (subCommand) {
    if (subCommand) {
      childProcess.fork(__filename, [ subCommand, '-h' ])
    } else {
      childProcess.fork(__filename, [ '-h' ])
    }
  })

argv.version(packageJson.version)

argv.parse(process.argv)

function exec (cmd, args, cb) {
  console.log([ cmd ].concat(args).join(' '))
  var p = childProcess.spawn(which.sync(cmd), args || [], { stdio: 'inherit' })
  if (cb) {
    p.on('close', cb)
  }
  return p
}
<|endoftext|>


<commit_before>(function ($) {

    if (!$) { throw new Error('OpenSeadragon Annotations requires OpenSeadragon'); }

    $.Viewer.prototype.initializeAnnotations = function (options) {
        var options = $.extend({ viewer: this }, options);
        this.addHandler('open', annotations.onOpen.bind(annotations));
        return this.annotations = this.annotations || annotations.initialize(options);
    };

    var annotations = {

        initialize: function (options) {
            $.extend(this, {
                state: move.initialize(),
                controls: controls.initialize()
            }, options);
            this.controls.addHandler('add', function (button) {
                this.viewer.addControl(button.element, {
                    anchor: $.ControlAnchor.BOTTOM_LEFT
                });
            }.bind(this));
            return this;
        },

        onOpen: function () {
            this.overlay = overlay.initialize({
                viewer: this.viewer
            });

            this.viewer.addHandler('animation', function () {
                var width = this.overlay.el.clientWidth;
                var height = this.overlay.el.clientHeight;
                var viewPort = '0 0 ' + width + ' ' + height;
                var svg = this.overlay.el.querySelector('svg');
                svg.setAttribute('viewPort', viewPort);
            }.bind(this));

            this.controls.add('move', true).addHandler('click', function () {
                this.viewer.setMouseNavEnabled(true);
                this.state = move.initialize();
            }.bind(this));

            this.controls.add('draw').addHandler('click', function () {
                this.viewer.setMouseNavEnabled(false);
                this.state = draw.initialize();
            }.bind(this));

            this.overlay.el.addEventListener('mousedown', function (e) {
                this.state.handleMouseDown(e, this.overlay);
            }.bind(this), false);

            this.overlay.el.addEventListener('mouseup', function (e) {
                this.state.handleMouseUp(e, this.overlay);
            }.bind(this), false);

            return this;
        }

    };

    var state = {

        initialize: function (options) {
            $.extend(this, options);
            return this;
        },

        handleMouseDown: function () {
            return this;
        },

        handleMouseUp: function () {
            return this;
        }

    }

    var move = Object.create(state);

    var draw = $.extend(Object.create(state), {

        handleMouseDown: function (e, overlay) {
            var x = e.offsetX;
            var y = e.offsetY;

            this._mouseTracker = function (e) {
                x = e.offsetX;
                y = e.offsetY;
            };

            overlay.el.addEventListener('mousemove', this._mouseTracker, false);

            this._interval = window.setInterval(function () {
                var svg = overlay.el.querySelector('svg');
                var circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
                circle.setAttribute('class', 'circle');
                circle.setAttribute('cx', (x / overlay.el.clientWidth * 100) + '%');
                circle.setAttribute('cy', (y / overlay.el.clientHeight * 100) + '%');
                circle.setAttribute('r', '1%');
                circle.setAttribute('fill', 'none');
                circle.setAttribute('stroke', 'red');
                circle.setAttribute('stroke-width', '2');
                svg.appendChild(circle);
            }.bind(this), 100);

            e.stopPropagation();
            return this;
        },

        handleMouseUp: function (e, overlay) {
            overlay.el.removeEventListener('mousemove', this._mouseTracker);
            clearInterval(this._interval);
            return this;
        }

    });

    var controls = $.extend(new $.EventSource(), {

        imagePath: 'bower_components/OpenSeadragonAnnotations/img/',

        list: {},

        initialize: function (options) {
            $.extend(this, options);
            this.addHandler('click', this.onClick.bind(this));
            return this;
        },

        onClick: function (name) {
            for (var button in this.list) {
                if (this.list.hasOwnProperty(button)) {
                    if (button === name) {
                        this.list[button].imgDown.style.visibility = 'visible';
                    } else {
                        this.list[button].imgDown.style.visibility = 'hidden';
                    }
                }
            }
            return this;
        },

        add: function (name, active) {
            this.list[name] = new $.Button({
                tooltip: name[0].toUpperCase() + name.substr(1),
                srcRest: this.imagePath + name + '_rest.png',
                srcGroup: this.imagePath + name + '_grouphover.png',
                srcHover: this.imagePath + name + '_hover.png',
                srcDown: this.imagePath + name + '_pressed.png',
                onClick: this.raiseEvent.bind(this, 'click', name)
            });
            if (active) {
                this.list[name].imgDown.style.visibility = 'visible';
            }
            this.raiseEvent('add', this.list[name]);
            return this.list[name];
        },

        get: function (name) {
            return this.list[name];
        }

    });

    var overlay = {

        initialize: function (options) {
            $.extend(this, options);
            this.el = document.createElement('div');
            this.el.className = 'overlay';
            var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            svg.setAttribute('version', '1.1');
            svg.setAttribute('width', '100%');
            svg.setAttribute('height', '100%');
            svg.setAttribute('preserveAspectRatio', 'none');
            svg.style.cursor = 'default';
            this.el.appendChild(svg);
            var width = this.viewer.viewport.homeBounds.width;
            var height = this.viewer.viewport.homeBounds.height;
            this.viewer.addOverlay(this.el, new $.Rect(0, 0, width, height));
            return this;
        }

    };

})(OpenSeadragon);
<commit_msg>Draw a path instead of circles<commit_after>(function ($) {

    if (!$) { throw new Error('OpenSeadragon Annotations requires OpenSeadragon'); }

    $.Viewer.prototype.initializeAnnotations = function (options) {
        var options = $.extend({ viewer: this }, options);
        this.addHandler('open', annotations.onOpen.bind(annotations));
        return this.annotations = this.annotations || annotations.initialize(options);
    };

    var annotations = {

        initialize: function (options) {
            $.extend(this, {
                state: move.initialize(),
                controls: controls.initialize()
            }, options);
            this.controls.addHandler('add', function (button) {
                this.viewer.addControl(button.element, {
                    anchor: $.ControlAnchor.BOTTOM_LEFT
                });
            }.bind(this));
            return this;
        },

        onOpen: function () {
            this.overlay = overlay.initialize({
                viewer: this.viewer
            });

            this.viewer.addHandler('animation', function () {
                var width = this.overlay.el.clientWidth;
                var height = this.overlay.el.clientHeight;
                var viewPort = '0 0 ' + width + ' ' + height;
                var svg = this.overlay.el.querySelector('svg');
                svg.setAttribute('viewPort', viewPort);
            }.bind(this));

            this.controls.add('move', true).addHandler('click', function () {
                this.viewer.setMouseNavEnabled(true);
                this.state = move.initialize();
            }.bind(this));

            this.controls.add('draw').addHandler('click', function () {
                this.viewer.setMouseNavEnabled(false);
                this.state = draw.initialize();
            }.bind(this));

            this.overlay.el.addEventListener('mousedown', function (e) {
                this.state.handleMouseDown(e, this.overlay);
            }.bind(this), false);

            this.overlay.el.addEventListener('mouseup', function (e) {
                this.state.handleMouseUp(e, this.overlay);
            }.bind(this), false);

            return this;
        }

    };

    var state = {

        initialize: function (options) {
            $.extend(this, options);
            return this;
        },

        handleMouseDown: function () {
            return this;
        },

        handleMouseUp: function () {
            return this;
        }

    }

    var move = Object.create(state);

    var draw = $.extend(Object.create(state), {

        handleMouseDown: function (e, overlay) {
            var x = e.offsetX;
            var y = e.offsetY;
            var svg = overlay.el.querySelector('svg');
            var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
            path.setAttribute('fill', 'none');
            path.setAttribute('stroke', 'red');
            path.setAttribute('stroke-width', '0.5');
            path.setAttribute('d', 'M' + x / overlay.el.clientWidth * 100 +
                ' ' + y / overlay.el.clientHeight * 100);
            svg.appendChild(path);

            this._mouseTracker = function (e) {
                x = e.offsetX;
                y = e.offsetY;
            };

            overlay.el.addEventListener('mousemove', this._mouseTracker, false);

            this._interval = window.setInterval(function () {
                path.setAttribute('d', path.getAttribute('d') +
                    ' L' + x / overlay.el.clientWidth * 100 +
                    ' ' + y / overlay.el.clientHeight * 100);
            }.bind(this), 25);

            e.stopPropagation();
            return this;
        },

        handleMouseUp: function (e, overlay) {
            overlay.el.removeEventListener('mousemove', this._mouseTracker);
            clearInterval(this._interval);
            return this;
        }

    });

    var controls = $.extend(new $.EventSource(), {

        imagePath: 'bower_components/OpenSeadragonAnnotations/img/',

        list: {},

        initialize: function (options) {
            $.extend(this, options);
            this.addHandler('click', this.onClick.bind(this));
            return this;
        },

        onClick: function (name) {
            for (var button in this.list) {
                if (this.list.hasOwnProperty(button)) {
                    if (button === name) {
                        this.list[button].imgDown.style.visibility = 'visible';
                    } else {
                        this.list[button].imgDown.style.visibility = 'hidden';
                    }
                }
            }
            return this;
        },

        add: function (name, active) {
            this.list[name] = new $.Button({
                tooltip: name[0].toUpperCase() + name.substr(1),
                srcRest: this.imagePath + name + '_rest.png',
                srcGroup: this.imagePath + name + '_grouphover.png',
                srcHover: this.imagePath + name + '_hover.png',
                srcDown: this.imagePath + name + '_pressed.png',
                onClick: this.raiseEvent.bind(this, 'click', name)
            });
            if (active) {
                this.list[name].imgDown.style.visibility = 'visible';
            }
            this.raiseEvent('add', this.list[name]);
            return this.list[name];
        },

        get: function (name) {
            return this.list[name];
        }

    });

    var overlay = {

        initialize: function (options) {
            $.extend(this, options);
            this.el = document.createElement('div');
            this.el.className = 'overlay';
            var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            svg.setAttribute('version', '1.1');
            svg.setAttribute('width', '100%');
            svg.setAttribute('height', '100%');
            svg.setAttribute('preserveAspectRatio', 'none');
            svg.setAttribute('viewBox', '0 0 100 100')
            svg.style.cursor = 'default';
            this.el.appendChild(svg);
            var width = this.viewer.viewport.homeBounds.width;
            var height = this.viewer.viewport.homeBounds.height;
            this.viewer.addOverlay(this.el, new $.Rect(0, 0, width, height));
            return this;
        }

    };

})(OpenSeadragon);
<|endoftext|>


<commit_before>import React from 'react';
import { Message } from 'retranslate';
import { shallow } from 'enzyme';

import TargetFundSelector from './TargetFundSelector';

describe('Target fund selector', () => {
  let component;

  beforeEach(() => {
    component = shallow(<TargetFundSelector />);
  });

  it('renders a target fund selector button for every target fund', () => {
    const targetFunds = [
      { isin: '123' },
      { isin: '456' },
      { isin: '789' },
    ];
    component.setProps({ targetFunds });
    expect(component.find('button').length).toBe(3);
    targetFunds.forEach(({ isin }) => {
      expect(component.contains(<Message>{`target.funds.${isin}.title`}</Message>)).toBe(true);
      expect(component.contains(<Message>{`target.funds.${isin}.description`}</Message>)).toBe(true);
      // TODO: add test for terms link once we have the links.
    });
  });

  it('sets the active target fund as active', () => {
    const selectedTargetFundIsin = '456';
    const targetFunds = [
      { isin: '123' },
      { isin: '456' },
      { isin: '789' },
    ];
    component.setProps({ targetFunds, selectedTargetFundIsin });
    expect(component.find('button').first().hasClass('tv-target-fund--active')).toBe(false);
    expect(component.find('button').at(1).hasClass('tv-target-fund--active')).toBe(true);
    expect(component.find('button').last().hasClass('tv-target-fund--active')).toBe(false);
  });

  it('can select a target fund', () => {
    const onSelectFund = jest.fn();
    const targetFunds = [
      { isin: '123' },
      { isin: '456' },
      { isin: '789' },
    ];
    component.setProps({ targetFunds, onSelectFund });
    expect(onSelectFund).not.toHaveBeenCalled();
    component.find('button').last().simulate('click');
    expect(onSelectFund).toHaveBeenCalledTimes(1);
    expect(onSelectFund).toHaveBeenCalledWith(targetFunds[2]);
  });
});
<commit_msg>Test for terms link in target fund selector<commit_after>import React from 'react';
import { Message } from 'retranslate';
import { shallow } from 'enzyme';

import TargetFundSelector from './TargetFundSelector';

describe('Target fund selector', () => {
  let component;

  beforeEach(() => {
    component = shallow(<TargetFundSelector />);
  });

  it('renders a target fund selector button for every target fund', () => {
    const targetFunds = [
      { isin: '123' },
      { isin: '456' },
      { isin: '789' },
    ];
    component.setProps({ targetFunds });
    expect(component.find('button').length).toBe(3);
    targetFunds.forEach(({ isin }) => {
      expect(component.contains(<Message>{`target.funds.${isin}.title`}</Message>)).toBe(true);
      expect(component.contains(<Message>{`target.funds.${isin}.description`}</Message>)).toBe(true);
      // TODO: add test for terms link once we have the links.
    });
  });

  it('sets the active target fund as active', () => {
    const selectedTargetFundIsin = '456';
    const targetFunds = [
      { isin: '123' },
      { isin: '456' },
      { isin: '789' },
    ];
    component.setProps({ targetFunds, selectedTargetFundIsin });
    expect(component.find('button').first().hasClass('tv-target-fund--active')).toBe(false);
    expect(component.find('button').at(1).hasClass('tv-target-fund--active')).toBe(true);
    expect(component.find('button').last().hasClass('tv-target-fund--active')).toBe(false);
  });

  it('can select a target fund', () => {
    const onSelectFund = jest.fn();
    const targetFunds = [
      { isin: '123' },
      { isin: '456' },
      { isin: '789' },
    ];
    component.setProps({ targetFunds, onSelectFund });
    expect(onSelectFund).not.toHaveBeenCalled();
    component.find('button').last().simulate('click');
    expect(onSelectFund).toHaveBeenCalledTimes(1);
    expect(onSelectFund).toHaveBeenCalledWith(targetFunds[2]);
  });

  it('has terms links for every fund', () => {
    const onSelectFund = jest.fn();
    const targetFunds = [
      { isin: '123' },
      { isin: '456' },
    ];
    component.setProps({ targetFunds, onSelectFund });

    expect(component.find('a').first().prop('href')).toEqual('https://tuleva.ee/fondid/');
    expect(component.find('a').last().prop('href')).toEqual('https://tuleva.ee/fondid/');

  });
});
<|endoftext|>


<commit_before><commit_msg>Allow removing the image.<commit_after><|endoftext|>


<commit_before>var testResourceRe = /^dijit\/tests\//,
	copyOnly = function(mid){
		var list = {
			"dijit/dijit.profile":1,
			"dijit/package.json":1,
			"dijit/themes/claro/compile":1
		};
		return (mid in list) || /^dijit\/resources\//.test(mid);
	};

var profile = {
	resourceTags:{
		test: function(filename, mid){
			return testResourceRe.test(mid) || mid=="dijit/robot" || mid=="dijit/robotx";
		},

		copyOnly: function(filename, mid){
			return copyOnly(mid);
		},

		amd: function(filename, mid){
			return !testResourceRe.test(mid) && !copyOnly(mid) && /\.js$/.test(filename);
		},

		miniExclude: function(filename, mid){
			return /^dijit\/bench\//.test(mid) || /^dijit\/themes\/themeTest/.test(mid);
		}
	},

	trees:[
		[".", ".", /(\/\.)|(~$)/]
	]
};

<commit_msg>ensure css files are not marked as copyOnly during build, thereby allowing them to be subject to css transforms; refs #14108<commit_after>var testResourceRe = /^dijit\/tests\//,
	copyOnly = function(mid){
		var list = {
			"dijit/dijit.profile":1,
			"dijit/package.json":1,
			"dijit/themes/claro/compile":1
		};
		return (mid in list) || (/^dijit\/resources\//.test(mid) && !/\.css$/.test(mid));
	};

var profile = {
	resourceTags:{
		test: function(filename, mid){
			return testResourceRe.test(mid) || mid=="dijit/robot" || mid=="dijit/robotx";
		},

		copyOnly: function(filename, mid){
			return copyOnly(mid);
		},

		amd: function(filename, mid){
			return !testResourceRe.test(mid) && !copyOnly(mid) && /\.js$/.test(filename);
		},

		miniExclude: function(filename, mid){
			return /^dijit\/bench\//.test(mid) || /^dijit\/themes\/themeTest/.test(mid);
		}
	},

	trees:[
		[".", ".", /(\/\.)|(~$)/]
	]
};

<|endoftext|>


<commit_before>var config           = require('mbc-common').config.Mosto.HeartBeats,
    util             = require('util'),
    events           = require('events'),
    Mosto            = require('./models/Mosto'),
    moment           = require('moment'),
    mvcp_server      = require('./drivers/mvcp/mvcp-driver'),
    utils            = require('./utils');

/* Events emited
 *  forceCheckout: When medias loaded are less than config time
 *  clipStatus: When clip changes
 *  frameStatus: Every 50 millis
 *  startPlaying: When melted wasnt playing
 *  outOfSync: When melted was more than 1 second defased
 *  hbError: Other errors
 *  noClips: No clips loaded
 */
function heartbeats(customConfig) {
    //THIS MODULE ASSUMES MELTED ALWAYS HAS THE SAME CLIPS AS MELTED_MEDIAS
    //AND THAT THEY ARE IN THE SAME ORDER
    var defaults = {
        gc_interval: 1000 * 60 * 60,
        sync_interval: 50,
        min_scheduled: 1000 * 60 * 60 * 4,
        checkout_interval: undefined,
        mvcp_server: "melted"
    };
    this.config = customConfig || config || defaults;

    if (this.config.checkout_interval === undefined)
        this.config.checkout_interval = this.config.min_scheduled / 4;

    this.melted_medias = Mosto.Playlists().get('melted_medias');

    this.current_media = false;

    this.stop_timers = false;

    this.server = new mvcp_server(this.config.mvcp_server);
    console.log("[HEARTBEAT-MVCP] MVCP server instantiated: " + this.server.uuid);

    events.EventEmitter.call(this);
}

util.inherits(heartbeats, events.EventEmitter);

heartbeats.prototype.startMvcpServer = function(callback) {
    var self = this;
    var result = self.server.initServer();
    result.then(function() {
        console.log("[HEARTBEAT-MVCP] MVCP server started");
        if (callback !== undefined) {
            callback();
        }
    }, function(err) {
        var e = new Error("[HEARTBEAT-MVCP] Error starting MVCP server: " + err + ".\nRetrying in 2 seconds...");
        console.error(e);
        setTimeout(function() {
            self.startMvcpServer(callback);
        }, 2000);
    });
};

heartbeats.prototype.init = function() {
    this.startMvcpServer(this.initTimers.bind(this));
};

heartbeats.prototype.initTimers = function() {
    var self = this;
    self.scheduleGc();
    self.scheduleSync();
    self.scheduleCheckout();
};

heartbeats.prototype.scheduleGc = function() {
    var self = this;
    if (!self.stop_timers) {
        setTimeout(function() {
            self.executeGc();
        }, self.config.gc_interval);
    }
};

heartbeats.prototype.scheduleSync = function() {
    var self = this;
    if (!self.stop_timers) {
        setTimeout(function() {
            self.melted_medias.take(self.syncMelted.bind(self));
        }, self.config.sync_interval);
    }
};

heartbeats.prototype.scheduleCheckout = function() {
    var self = this;
    if (!self.stop_timers) {
        setTimeout(function() {
            self.checkSchedules();
        }, self.config.checkout_interval);
    }
};

heartbeats.prototype.stop = function() {
    this.stop_timers = true;
};

heartbeats.prototype.checkSchedules =  function() {
    var self = this;
    console.log("[HEARTBEAT-CS] Started Check Schedules");
    var last = self.melted_medias.at(self.melted_medias.length - 1);
    if (last) {
        var scheduled =  last.get('end') - moment();
        if (scheduled < self.config.min_scheduled) {
            //TODO: Esto esta bien?????????????
            self.emit("forceCheckout", {from: last.get('end'), to: last.get('end') + scheduled});
            console.warn("[HEARTBEAT-CS] Sent forceCheckout event!");
        }
    } else {
        self.handleNoMedias();
    }
    self.scheduleCheckout();
    console.log("[HEARTBEAT-CS] Finished Check Schedules");
};

heartbeats.prototype.executeGc = function() {
    //TODO: Eliminar los xml viejos
    //TODO: Eliminar las playlist caspa en vez de las de melted
    var self = this;
    console.log("[HEARTBEAT-GC] Started Garbage Collector");
    var timeLimit = moment().subtract('hours', 1);
    var oldMedias = self.melted_medias.filter(function(media) {
        return moment(media.get('end')) < timeLimit;
    });
    if (oldMedias) {
        oldMedias.forEach(function(media) {
            self.melted_medias.remove(media);
        });
        Mosto.Playlists().save();
    }
    self.scheduleGc();
    console.log("[HEARTBEAT-GC] Finished Garbage Collector: " + oldMedias.length + " removed.");
};

heartbeats.prototype.sendStatus = function() {
    var self = this;
    console.log("[HEARTBEAT-FS] Started Status");
    var expected = self.melted_medias.getExpectedMedia();
    if ((!self.current_media) || (expected.media.get("id").toString() !== self.current_media.get("id").toString())) {
        self.emit("clipStatus", expected.media);
        console.log("[HEARTBEAT-FS] Sent clipStatus");
        self.current_media = expected.media;
    } else {
        self.emit("frameStatus", {media: expected.media, frame: expected.frame});
        console.log("[HEARTBEAT-FS] Sent frameStatus");
    }
    console.log("[HEARTBEAT-FS] Finished Status");
};

heartbeats.prototype.syncMelted = function() {
    console.log("[HEARTBEAT-SY] Start Sync");
    var self = this;
    self.server.getServerStatus().then(function(meltedStatus) {
        var expected = self.melted_medias.getExpectedMedia();
        if (expected.media) {
            var result = undefined;
            var meltedClip = meltedStatus.currentClip;
            if (expected.media.get("id").toString() !== meltedClip.id.toString()) {
                var index = expected.media.get('actual_order');
                var frames = 9999;
                var currentMedia = self.melted_medias.get(meltedClip.id);
                if (currentMedia) {
                    var indexDiff = self.melted_medias.indexOf(currentMedia) - index;
                    if (indexDiff === -1) {
                        // melted's right before the expected media
                        frames = currentMedia.get('out') - meltedClip.currentFrame + expected.frame;
                    } else if (indexDiff === 1) {
                        // melted's right after the expected media
                        frames = meltedClip.currentFrame + (expected.media.get('out') - expected.frame);
                    }
                }

                if (frames > expected.media.get('fps'))
                    result = self.fixMelted(expected);
            } else if (Math.abs(meltedClip.currentFrame - expected.frame) > expected.media.get('fps'))
                result = self.fixMelted(expected);
            if (meltedStatus.status !== "playing") {
                if (result)
                    result = result.then(self.startPlaying()).then(self.sendStatus());
            } else {
                if (result)
                    result = result.then(self.sendStatus());
                else
                    self.sendStatus();
            }
            if (result)
                return result;
        } else {
            self.handleNoMedias();
        }
    }).fail(self.handleError.bind(self)).fin(function() {
        self.scheduleSync();
        self.melted_medias.leave();
        console.log("[HEARTBEAT-SY] Finish Sync");
    });
};

heartbeats.prototype.startPlaying = function() {
    var self = this;
    self.emit("startPlaying", "Melted was not playing");
    console.warn("[HEARTBEATS-SY] Melted was not playing");
    return self.server.play();
};

heartbeats.prototype.handleNoMedias = function() {
    var self = this;
    self.emit("noClips", "No medias loaded!");
};

heartbeats.prototype.fixMelted = function(expected) {
    var self = this;
    console.error("[HEARTBEAT-SY] Melted is out of sync!");
    self.emit("outOfSync", expected);
    return self.server.goto(expected.media.get('actual_order'), expected.frame);
};

heartbeats.prototype.handleError = function(error) {
    var self = this;
    console.error(error);
    //NEVER emit 'error' event, see https://github.com/LearnBoost/socket.io/issues/476
    self.emit("hbError", error);
};

exports = module.exports = function(customConfig) {
    var hb = new heartbeats(customConfig);
    return hb;
};
<commit_msg>Improved garbage collector to remove playlists instead of melted medias and delete old xmls<commit_after>var config           = require('mbc-common').config.Mosto.HeartBeats,
    mvcpConfig       = require('mbc-common').config.Mosto.Melted,
    util             = require('util'),
    events           = require('events'),
    Mosto            = require('./models/Mosto'),
    moment           = require('moment'),
    fs               = require('fs'),
    mvcp_server      = require('./drivers/mvcp/mvcp-driver'),
    utils            = require('./utils');

/* Events emited
 *  forceCheckout: When medias loaded are less than config time
 *  clipStatus: When clip changes
 *  frameStatus: Every 50 millis
 *  startPlaying: When melted wasnt playing
 *  outOfSync: When melted was more than 1 second defased
 *  hbError: Other errors
 *  noClips: No clips loaded
 */
function heartbeats(customConfig) {
    //THIS MODULE ASSUMES MELTED ALWAYS HAS THE SAME CLIPS AS MELTED_MEDIAS
    //AND THAT THEY ARE IN THE SAME ORDER
    var defaults = {
        gc_interval: 1000 * 60 * 60,
        sync_interval: 50,
        min_scheduled: 1000 * 60 * 60 * 4,
        checkout_interval: undefined,
        mvcp_server: "melted"
    };
    this.config = customConfig || config || defaults;

    if (this.config.checkout_interval === undefined)
        this.config.checkout_interval = this.config.min_scheduled / 4;

    this.melted_medias = Mosto.Playlists().get('melted_medias');

    this.current_media = false;

    this.stop_timers = false;

    this.server = new mvcp_server(this.config.mvcp_server);
    console.log("[HEARTBEAT-MVCP] MVCP server instantiated: " + this.server.uuid);

    events.EventEmitter.call(this);
}

util.inherits(heartbeats, events.EventEmitter);

heartbeats.prototype.startMvcpServer = function(callback) {
    var self = this;
    var result = self.server.initServer();
    result.then(function() {
        console.log("[HEARTBEAT-MVCP] MVCP server started");
        if (callback !== undefined) {
            callback();
        }
    }, function(err) {
        var e = new Error("[HEARTBEAT-MVCP] Error starting MVCP server: " + err + ".\nRetrying in 2 seconds...");
        console.error(e);
        setTimeout(function() {
            self.startMvcpServer(callback);
        }, 2000);
    });
};

heartbeats.prototype.init = function() {
    this.startMvcpServer(this.initTimers.bind(this));
};

heartbeats.prototype.initTimers = function() {
    var self = this;
    self.scheduleGc();
    self.scheduleSync();
    self.scheduleCheckout();
};

heartbeats.prototype.scheduleGc = function() {
    var self = this;
    if (!self.stop_timers) {
        setTimeout(function() {
            self.executeGc();
        }, self.config.gc_interval);
    }
};

heartbeats.prototype.scheduleSync = function() {
    var self = this;
    if (!self.stop_timers) {
        setTimeout(function() {
            self.melted_medias.take(self.syncMelted.bind(self));
        }, self.config.sync_interval);
    }
};

heartbeats.prototype.scheduleCheckout = function() {
    var self = this;
    if (!self.stop_timers) {
        setTimeout(function() {
            self.checkSchedules();
        }, self.config.checkout_interval);
    }
};

heartbeats.prototype.stop = function() {
    this.stop_timers = true;
};

heartbeats.prototype.checkSchedules =  function() {
    var self = this;
    console.log("[HEARTBEAT-CS] Started Check Schedules");
    var last = self.melted_medias.at(self.melted_medias.length - 1);
    if (last) {
        var scheduled =  last.get('end') - moment();
        if (scheduled < self.config.min_scheduled) {
            //TODO: Esto esta bien?????????????
            self.emit("forceCheckout", {from: last.get('end'), to: last.get('end') + scheduled});
            console.warn("[HEARTBEAT-CS] Sent forceCheckout event!");
        }
    } else {
        self.handleNoMedias();
    }
    self.scheduleCheckout();
    console.log("[HEARTBEAT-CS] Finished Check Schedules");
};

heartbeats.prototype.executeGc = function() {
    //TODO: Eliminar los xml viejos
    var self = this;
    console.log("[HEARTBEAT-GC] Started Garbage Collector");
    var timeLimit = moment().subtract('hours', 1);
    var playlists = Mosto.Playlists().get("playlists");
    var oldPlaylists = playlists.filter(function(media) {
        return moment(media.get('end')) < timeLimit;
    });
    if (oldPlaylists) {
        oldPlaylists.forEach(function(pl) {
            self.removeXml(pl);
            //TODO: Check if it is ok to make this silent
            playlists.remove(pl, {silent: true});
        });
    }
    self.scheduleGc();
    console.log("[HEARTBEAT-GC] Finished Garbage Collector: " + oldPlaylists.length + " playlists removed.");
};

heartbeats.prototype.removeXml = function(playlist) {
    var self = this;
    var baseDir = config.playlists_xml_dir;
    playlist.forEach(function(media) {
        var filename = utils.getXmlFileNameFromClip(media.toJSON());
        var xmlFile = baseDir + "/" + filename;
        fs.unlinkSync(xmlFile, function(err) {
            if (err)
                self.handleError(err);
        });
    });
};

heartbeats.prototype.sendStatus = function() {
    var self = this;
    console.log("[HEARTBEAT-FS] Started Status");
    var expected = self.melted_medias.getExpectedMedia();
    if ((!self.current_media) || (expected.media.get("id").toString() !== self.current_media.get("id").toString())) {
        self.emit("clipStatus", expected.media);
        console.log("[HEARTBEAT-FS] Sent clipStatus");
        self.current_media = expected.media;
    } else {
        self.emit("frameStatus", {media: expected.media, frame: expected.frame});
        console.log("[HEARTBEAT-FS] Sent frameStatus");
    }
    console.log("[HEARTBEAT-FS] Finished Status");
};

heartbeats.prototype.syncMelted = function() {
    console.log("[HEARTBEAT-SY] Start Sync");
    var self = this;
    self.server.getServerStatus().then(function(meltedStatus) {
        var expected = self.melted_medias.getExpectedMedia();
        if (expected.media) {
            var result = undefined;
            var meltedClip = meltedStatus.currentClip;
            if (expected.media.get("id").toString() !== meltedClip.id.toString()) {
                var index = expected.media.get('actual_order');
                var frames = 9999;
                var currentMedia = self.melted_medias.get(meltedClip.id);
                if (currentMedia) {
                    var indexDiff = self.melted_medias.indexOf(currentMedia) - index;
                    if (indexDiff === -1) {
                        // melted's right before the expected media
                        frames = currentMedia.get('out') - meltedClip.currentFrame + expected.frame;
                    } else if (indexDiff === 1) {
                        // melted's right after the expected media
                        frames = meltedClip.currentFrame + (expected.media.get('out') - expected.frame);
                    }
                }

                if (frames > expected.media.get('fps'))
                    result = self.fixMelted(expected);
            } else if (Math.abs(meltedClip.currentFrame - expected.frame) > expected.media.get('fps'))
                result = self.fixMelted(expected);
            if (meltedStatus.status !== "playing") {
                if (result)
                    result = result.then(self.startPlaying()).then(self.sendStatus());
            } else {
                if (result)
                    result = result.then(self.sendStatus());
                else
                    self.sendStatus();
            }
            if (result)
                return result;
        } else {
            self.handleNoMedias();
        }
    }).fail(self.handleError.bind(self)).fin(function() {
        self.scheduleSync();
        self.melted_medias.leave();
        console.log("[HEARTBEAT-SY] Finish Sync");
    });
};

heartbeats.prototype.startPlaying = function() {
    var self = this;
    self.emit("startPlaying", "Melted was not playing");
    console.warn("[HEARTBEATS-SY] Melted was not playing");
    return self.server.play();
};

heartbeats.prototype.handleNoMedias = function() {
    var self = this;
    self.emit("noClips", "No medias loaded!");
};

heartbeats.prototype.fixMelted = function(expected) {
    var self = this;
    console.error("[HEARTBEAT-SY] Melted is out of sync!");
    self.emit("outOfSync", expected);
    return self.server.goto(expected.media.get('actual_order'), expected.frame);
};

heartbeats.prototype.handleError = function(error) {
    var self = this;
    console.error(error);
    //NEVER emit 'error' event, see https://github.com/LearnBoost/socket.io/issues/476
    self.emit("hbError", error);
};

exports = module.exports = function(customConfig) {
    var hb = new heartbeats(customConfig);
    return hb;
};
<|endoftext|>