<commit_before>class DCFSlideshow {
  constructor(slideshows, uls, openCaption, closeCaption) {
    this.slideshows = slideshows;
    this.uls = uls;
    this.openCaptionEvent = openCaption;
    this.closeCaptionEvent = closeCaption;
  }

  // Caption visibility transition
  captionTransition(event) {
    // Remove event listener and toggle visibility after caption has closed
    event.removeEventListener('transitionend', this.captionTransition, true);
    // Check if caption is already visible
    if (!event.classList.contains('dcf-invisible')) {
      // Add class to hide caption
      event.classList.add('dcf-invisible');
    }
  }

  // Add classes to the caption & button
  captionClasses(button, caption) {
    // Check if caption is already visible
    if (!caption.classList.contains('dcf-invisible')) {
      // Hide content
      caption.addEventListener('transitionend', this.captionTransition(caption), true);
      // Update ARIA attributes
      button.setAttribute('aria-expanded', 'false');
      button.setAttribute('aria-label', 'Show caption');
      caption.setAttribute('aria-hidden', 'true');
      caption.classList.remove('dcf-opacity-1', 'dcf-pointer-events-auto');
      caption.classList.add('dcf-opacity-0', 'dcf-pointer-events-none', 'dcf-invisible');

      caption.dispatchEvent(this.openCaptionEvent);
    } else {
      // Remove class to show content
      caption.classList.remove('dcf-invisible');
      // Update ARIA attributes
      button.setAttribute('aria-expanded', 'true');
      button.setAttribute('aria-label', 'Hide caption');
      caption.setAttribute('aria-hidden', 'false');
      caption.classList.remove('dcf-invisible', 'dcf-opacity-0', 'dcf-pointer-events-none');
      caption.classList.add('dcf-opacity-1', 'dcf-pointer-events-auto');
      caption.dispatchEvent(this.closeCaptionEvent);
    }
  }

  // Functions for intersection observer.

  scrollIt(slideToShow, slides, slidedeck) {
    let scrollPos = Array.prototype.indexOf.call(slides, slideToShow) * (slidedeck.scrollWidth / slides.length);
    slidedeck.scrollLeft = scrollPos;
  }

  showSlide(dir, slideshow, slides, slidedeck) {
    let visible = slideshow.querySelectorAll('.dcf-slideshow .visible');
    let index = dir === 'previous' ? DCFUtility.magicNumbers('int0') : DCFUtility.magicNumbers('int1');

    if (visible.length > DCFUtility.magicNumbers('int1')) {
      this.scrollIt(visible[index], slides, slidedeck);
    } else {
      let newSlide = index === DCFUtility.magicNumbers('int0') ?
        visible[DCFUtility.magicNumbers('int0')].previousElementSibling :
        visible[DCFUtility.magicNumbers('int0')].nextElementSibling;
      if (newSlide) {
        this.scrollIt(newSlide, slides, slidedeck);
      }
    }
  }

  callback(slides) {
    Array.prototype.forEach.call(slides, (entry) => {
      entry.target.classList.remove('visible');
      let slide = entry.target.querySelector('div');
      slide.setAttribute('tabindex', '-1');
      if (!entry.intersectionRatio > DCFUtility.magicNumbers('int0')) {
        return;
      }
      let img = entry.target.querySelector('img');
      if (img.dataset.src) {
        img.setAttribute('src', img.dataset.src);
        img.removeAttribute('data-src');
      }
      entry.target.classList.add('visible');
      slide.removeAttribute('tabindex', '-1');
    });
  }

  initialize() {
    Array.prototype.forEach.call(this.slideshows, (slideshow, slideshowIndex) => {
      let slidedeck = this.uls[slideshowIndex];
      let slides = slideshow.querySelectorAll('.dcf-slideshow li');
      let figures = slideshow.querySelectorAll('.dcf-slideshow figure');
      let captions = slideshow.querySelectorAll('.dcf-slideshow figcaption');
      let uuid = DCFUtility.uuidv4();
      let slideshowName = `Slideshow ${slideshowIndex}`;
      let slideAriaLabel = slideshow.getAttribute('aria-label');
      if (slideAriaLabel) {
        slideshowName = slideAriaLabel;
      }

      // Set a unique ID for each slideshow
      slideshow.setAttribute('id', uuid.concat('-slideshow'));

      // Add classes to slideshow unordered lists
      slidedeck.classList.add('dcf-slide-deck');

      // Create slideshow controls (previous/next slide buttons)
      let ctrls = document.createElement('ul');
      let ctrlPrevious = document.createElement('li');
      let ctrlNext = document.createElement('li');
      let ctrlPreviousButton = document.createElement('button');
      let ctrlNextButton = document.createElement('button');

      // Add classes to slideshow controls group (Keep in DCF)
      ctrls.classList.add('dcf-slideshow-controls',
        'dcf-list-bare',
        'dcf-btn-group',
        'dcf-absolute',
        'dcf-pin-right',
        'dcf-pin-bottom',
        'dcf-z-1');

      // Add role and aria-label to controls group
      ctrls.setAttribute('aria-label', `${slideshowName} controls`);
      ctrls.setAttribute('role', 'list');

      ctrlPreviousButton.classList.add('dcf-btn', 'dcf-btn-primary', 'dcf-button-slide', 'dcf-btn-slide-prev');
      ctrlPreviousButton.setAttribute('aria-label', `${slideshowName} previous`);

      ctrlNextButton.classList.add('dcf-btn', 'dcf-btn-primary', 'dcf-btn-slide', 'dcf-btn-slide-next');
      ctrlNextButton.setAttribute('aria-label', `${slideshowName} next`);

      ctrlPrevious.setAttribute('id', uuid.concat('-previous'));
      ctrlPrevious.classList.add('dcf-li-slide-prev');
      ctrlNext.setAttribute('id', uuid.concat('-next'));
      ctrlNext.classList.add('dcf-li-slide-next');
      // Add relative class for absolute positioning of slideshow controls
      slideshow.classList.add('dcf-relative');
      // Append controls (previous/next slide) to slideshow
      ctrlPrevious.appendChild(ctrlPreviousButton);
      ctrlNext.appendChild(ctrlNextButton);
      ctrls.appendChild(ctrlPrevious);
      ctrls.appendChild(ctrlNext);
      slideshow.appendChild(ctrls);

      // Slides
      Array.prototype.forEach.call(slides, (slide, slideIndex) => {
        // Set unique ID for each slide
        slide.setAttribute('id', uuid.concat('-slide-', slideIndex));
        // Add classes to each slide
        slide.classList.add('dcf-slide', 'dcf-relative');
        slide.querySelector('div').setAttribute('tabindex', '-1');
      });

      Array.prototype.forEach.call(figures, (figure, figureIndex) => {
        let caption = captions[figureIndex];

        if (!(typeof caption == 'undefined')) {
          // Create button to show/hide caption
          let captionBtn = document.createElement('button');
          // Add classes to each caption toggle button
          captionBtn.classList.add('dcf-btn', 'dcf-btn-slide', 'dcf-btn-slide-caption');
          // Create a unique ID for each caption toggle button
          captionBtn.setAttribute('id', uuid.concat('-button-', figureIndex));
          // Add ARIA attributes to each caption toggle button
          captionBtn.setAttribute('aria-controls', uuid.concat('-caption-', figureIndex));
          captionBtn.setAttribute('aria-label', `${slideshowName} Show caption`);
          captionBtn.setAttribute('aria-expanded', 'false');
          // Add class to each figure
          figure.classList.add('dcf-slide-figure');
          // Append caption toggle button to each figure
          figure.appendChild(captionBtn);
          // Style each caption
          // Might be something here!!!!!
          caption.classList.add('dcf-opacity-0', 'dcf-pointer-events-none', 'dcf-invisible', 'dcf-slide-caption', 'dcf-figcaption');
          // Create a unique ID for each caption
          caption.setAttribute('id', uuid.concat('-caption-', figureIndex));
          // Add ARIA attributes to each caption
          caption.setAttribute('aria-labelledby', uuid.concat('-button-', figureIndex));
          caption.setAttribute('aria-hidden', 'true');
        }
      });

      // WIP for Content slider:  https://codepen.io/heydon/pen/xPWOLp?editors=0010

      let observerSettings = {
        root: slideshow,
        rootMargin: '-10px'
      };
      if ('IntersectionObserver' in window) {
        let observer = new IntersectionObserver(this.callback, observerSettings);
        Array.prototype.forEach.call(slides, (elem) => {
          observer.observe(elem);
        });
        ctrlPrevious.addEventListener('click', () => {
          this.showSlide('previous', slideshow, slides, slidedeck);
        });

        ctrlNext.addEventListener('click', () => {
          this.showSlide('next', slideshow, slides, slidedeck);
        });
      } else {
        Array.prototype.forEach.call(slides, (slide) => {
          let img = slide.querySelector('img');
          img.setAttribute('src', img.getAttribute('data-src'));
        });
      }
    });

    // Caption toggle buttons
    let buttons = document.querySelectorAll('.dcf-btn-slide-caption');
    [].forEach.call(buttons, (button) => {
      let caption = button.previousElementSibling;
      // Handle Click
      button.addEventListener('click', (onClick) => {
        this.captionClasses(onClick.currentTarget, caption);
        return false;
      }, false);

      // Show caption when the 'space' key is pressed
      button.addEventListener('keydown', (onSpace) => {
        // Handle 'space' key
        if (onSpace.which === DCFUtility.magicNumbers('spaceKeyCode')) {
          onSpace.preventDefault();
          this.captionClasses(onSpace.currentTarget, caption);
        }
      }, false);
    });
  }
}
<commit_msg>Add line breaks for easier reading<commit_after>class DCFSlideshow {
  constructor(slideshows, uls, openCaption, closeCaption) {
    this.slideshows = slideshows;
    this.uls = uls;
    this.openCaptionEvent = openCaption;
    this.closeCaptionEvent = closeCaption;
  }

  // Caption visibility transition
  captionTransition(event) {

    // Remove event listener and toggle visibility after caption has closed
    event.removeEventListener('transitionend', this.captionTransition, true);

    // Check if caption is already visible
    if (!event.classList.contains('dcf-invisible')) {

      // Add class to hide caption
      event.classList.add('dcf-invisible');
    }
  }

  // Add classes to the caption & button
  captionClasses(button, caption) {

    // Check if caption is already visible
    if (!caption.classList.contains('dcf-invisible')) {

      // Hide content
      caption.addEventListener('transitionend', this.captionTransition(caption), true);

      // Update ARIA attributes
      button.setAttribute('aria-expanded', 'false');
      button.setAttribute('aria-label', 'Show caption');
      caption.setAttribute('aria-hidden', 'true');
      caption.classList.remove('dcf-opacity-1', 'dcf-pointer-events-auto');
      caption.classList.add('dcf-opacity-0', 'dcf-pointer-events-none', 'dcf-invisible');

      caption.dispatchEvent(this.openCaptionEvent);
    } else {

      // Remove class to show content
      caption.classList.remove('dcf-invisible');

      // Update ARIA attributes
      button.setAttribute('aria-expanded', 'true');
      button.setAttribute('aria-label', 'Hide caption');
      caption.setAttribute('aria-hidden', 'false');
      caption.classList.remove('dcf-invisible', 'dcf-opacity-0', 'dcf-pointer-events-none');
      caption.classList.add('dcf-opacity-1', 'dcf-pointer-events-auto');
      caption.dispatchEvent(this.closeCaptionEvent);
    }
  }

  // Functions for intersection observer.

  scrollIt(slideToShow, slides, slidedeck) {
    let scrollPos = Array.prototype.indexOf.call(slides, slideToShow) * (slidedeck.scrollWidth / slides.length);
    slidedeck.scrollLeft = scrollPos;
  }

  showSlide(dir, slideshow, slides, slidedeck) {
    let visible = slideshow.querySelectorAll('.dcf-slideshow .visible');
    let index = dir === 'previous' ? DCFUtility.magicNumbers('int0') : DCFUtility.magicNumbers('int1');

    if (visible.length > DCFUtility.magicNumbers('int1')) {
      this.scrollIt(visible[index], slides, slidedeck);
    } else {
      let newSlide = index === DCFUtility.magicNumbers('int0') ?
        visible[DCFUtility.magicNumbers('int0')].previousElementSibling :
        visible[DCFUtility.magicNumbers('int0')].nextElementSibling;
      if (newSlide) {
        this.scrollIt(newSlide, slides, slidedeck);
      }
    }
  }

  callback(slides) {
    Array.prototype.forEach.call(slides, (entry) => {
      entry.target.classList.remove('visible');
      let slide = entry.target.querySelector('div');
      slide.setAttribute('tabindex', '-1');
      if (!entry.intersectionRatio > DCFUtility.magicNumbers('int0')) {
        return;
      }
      let img = entry.target.querySelector('img');
      if (img.dataset.src) {
        img.setAttribute('src', img.dataset.src);
        img.removeAttribute('data-src');
      }
      entry.target.classList.add('visible');
      slide.removeAttribute('tabindex', '-1');
    });
  }

  initialize() {
    Array.prototype.forEach.call(this.slideshows, (slideshow, slideshowIndex) => {
      let slidedeck = this.uls[slideshowIndex];
      let slides = slideshow.querySelectorAll('.dcf-slideshow li');
      let figures = slideshow.querySelectorAll('.dcf-slideshow figure');
      let captions = slideshow.querySelectorAll('.dcf-slideshow figcaption');
      let uuid = DCFUtility.uuidv4();
      let slideshowName = `Slideshow ${slideshowIndex}`;
      let slideAriaLabel = slideshow.getAttribute('aria-label');
      if (slideAriaLabel) {
        slideshowName = slideAriaLabel;
      }

      // Set a unique ID for each slideshow
      slideshow.setAttribute('id', uuid.concat('-slideshow'));

      // Add classes to slideshow unordered lists
      slidedeck.classList.add('dcf-slide-deck');

      // Create slideshow controls (previous/next slide buttons)
      let ctrls = document.createElement('ul');
      let ctrlPrevious = document.createElement('li');
      let ctrlNext = document.createElement('li');
      let ctrlPreviousButton = document.createElement('button');
      let ctrlNextButton = document.createElement('button');

      // Add classes to slideshow controls group (Keep in DCF)
      ctrls.classList.add('dcf-slideshow-controls',
        'dcf-list-bare',
        'dcf-btn-group',
        'dcf-absolute',
        'dcf-pin-right',
        'dcf-pin-bottom',
        'dcf-z-1');

      // Add role and aria-label to controls group
      ctrls.setAttribute('aria-label', `${slideshowName} controls`);
      ctrls.setAttribute('role', 'list');

      ctrlPreviousButton.classList.add('dcf-btn', 'dcf-btn-primary', 'dcf-button-slide', 'dcf-btn-slide-prev');
      ctrlPreviousButton.setAttribute('aria-label', `${slideshowName} previous`);

      ctrlNextButton.classList.add('dcf-btn', 'dcf-btn-primary', 'dcf-btn-slide', 'dcf-btn-slide-next');
      ctrlNextButton.setAttribute('aria-label', `${slideshowName} next`);

      ctrlPrevious.setAttribute('id', uuid.concat('-previous'));
      ctrlPrevious.classList.add('dcf-li-slide-prev');
      ctrlNext.setAttribute('id', uuid.concat('-next'));
      ctrlNext.classList.add('dcf-li-slide-next');

      // Add relative class for absolute positioning of slideshow controls
      slideshow.classList.add('dcf-relative');

      // Append controls (previous/next slide) to slideshow
      ctrlPrevious.appendChild(ctrlPreviousButton);
      ctrlNext.appendChild(ctrlNextButton);
      ctrls.appendChild(ctrlPrevious);
      ctrls.appendChild(ctrlNext);
      slideshow.appendChild(ctrls);

      // Slides
      Array.prototype.forEach.call(slides, (slide, slideIndex) => {

        // Set unique ID for each slide
        slide.setAttribute('id', uuid.concat('-slide-', slideIndex));

        // Add classes to each slide
        slide.classList.add('dcf-slide', 'dcf-relative');

        slide.querySelector('div').setAttribute('tabindex', '-1');
      });

      Array.prototype.forEach.call(figures, (figure, figureIndex) => {
        let caption = captions[figureIndex];

        if (!(typeof caption == 'undefined')) {

          // Create button to show/hide caption
          let captionBtn = document.createElement('button');

          // Add classes to each caption toggle button
          captionBtn.classList.add('dcf-btn', 'dcf-btn-slide', 'dcf-btn-slide-caption');

          // Create a unique ID for each caption toggle button
          captionBtn.setAttribute('id', uuid.concat('-button-', figureIndex));

          // Add ARIA attributes to each caption toggle button
          captionBtn.setAttribute('aria-controls', uuid.concat('-caption-', figureIndex));
          captionBtn.setAttribute('aria-label', `${slideshowName} Show caption`);
          captionBtn.setAttribute('aria-expanded', 'false');

          // Add class to each figure
          figure.classList.add('dcf-slide-figure');

          // Append caption toggle button to each figure
          figure.appendChild(captionBtn);

          // Style each caption
          // Might be something here!!!!!
          caption.classList.add('dcf-opacity-0', 'dcf-pointer-events-none', 'dcf-invisible', 'dcf-slide-caption', 'dcf-figcaption');

          // Create a unique ID for each caption
          caption.setAttribute('id', uuid.concat('-caption-', figureIndex));

          // Add ARIA attributes to each caption
          caption.setAttribute('aria-labelledby', uuid.concat('-button-', figureIndex));
          caption.setAttribute('aria-hidden', 'true');
        }
      });

      // WIP for Content slider:  https://codepen.io/heydon/pen/xPWOLp?editors=0010

      let observerSettings = {
        root: slideshow,
        rootMargin: '-10px'
      };
      if ('IntersectionObserver' in window) {
        let observer = new IntersectionObserver(this.callback, observerSettings);
        Array.prototype.forEach.call(slides, (elem) => {
          observer.observe(elem);
        });
        ctrlPrevious.addEventListener('click', () => {
          this.showSlide('previous', slideshow, slides, slidedeck);
        });

        ctrlNext.addEventListener('click', () => {
          this.showSlide('next', slideshow, slides, slidedeck);
        });
      } else {
        Array.prototype.forEach.call(slides, (slide) => {
          let img = slide.querySelector('img');
          img.setAttribute('src', img.getAttribute('data-src'));
        });
      }
    });

    // Caption toggle buttons
    let buttons = document.querySelectorAll('.dcf-btn-slide-caption');
    [].forEach.call(buttons, (button) => {
      let caption = button.previousElementSibling;

      // Handle click
      button.addEventListener('click', (onClick) => {
        this.captionClasses(onClick.currentTarget, caption);
        return false;
      }, false);

      // Show caption when the 'space' key is pressed
      button.addEventListener('keydown', (onSpace) => {

        // Handle 'space' key
        if (onSpace.which === DCFUtility.magicNumbers('spaceKeyCode')) {
          onSpace.preventDefault();
          this.captionClasses(onSpace.currentTarget, caption);
        }
      }, false);
    });
  }
}
<|endoftext|>


<commit_before><commit_msg>Made scheduling a little better, but using compare operators instead of scores so I can do more nuanced comparisons. Now also prioritize "on the way" cars to pick up passengers more than idle ones, and for idle ones will calculate the one with the closest distance.<commit_after><|endoftext|>


<commit_before>// David Inglis
// Progress Software
// August 2014
// app.js

var express = require('express');
var http = require('http');
var cors = require('cors');

var app = express();
app.use(cors());
app.set('port', process.env.PORT || 3000);

XMLHttpRequest = require("./XMLHttpRequest.js").XMLHttpRequest;
require("./progress.js");
require("./progress.session.js");
var serviceURI = "nodejsdo-21944.onmodulus.net";
var catalogURI = "nodejsdo-21944.onmodulus.net/catalogURI";

// serviceURI = 'http://oemobiledemo.progress.com/MobilityDemoService';
// catalogURI = 'http://oemobiledemo.progress.com/MobilityDemoService/static/mobile/MobilityDemoService.json';

var server = http.createServer(app);

server.listen(app.get('port'), function()
{
	console.log('express server listening on port ' + app.get('port'));
});

/*
app.get('/test', function(req, res)
{
*/
	console.log('1');
	session = new progress.data.Session();
	console.log('1.1');
	session.login(serviceURI, "", "");
	console.log('1.2');
	session.addCatalog(catalogURI);
	console.log('2');
	jsdo = new progress.data.JSDO({ name: 'dsCustomer' });
	jsdo.subscribe('AfterFill', onAfterFillCustomers, this);
	jsdo.fill(); // fills the locally initialized jsdo from the catalog
	var arr = [];
	console.log('3');
	function onAfterFillCustomers(jsdo, success, request)
	{
		console.log('4');
		jsdo.eCustomer.foreach(function(customer)
		{
			arr.push({name: jsdo.eCustomer.Name, address: jsdo.eCustomer.Address,
						city: jsdo.eCustomer.City, state: jsdo.eCustomer.State});
		});
		console.log(arr);
		// res.write(JSON.stringify(arr));
		console.log('5');
	}
	// res.write('end');
	// res.end();
// });

<commit_msg>Delete app.js<commit_after><|endoftext|>


<commit_before>var e = module.exports = {};

const fs = require('fs');
const path = require('path');

e.init = () => {
    e.category = bu.CommandType.CAT;
};

e.requireCtx = require;

e.isCommand = true;
e.hidden = false;
e.usage = '';
e.info = '';

e.execute = async function(msg, words) {
    if (msg.author.id == bu.CAT_ID) {
        await bot.sendChannelTyping(msg.channel.id);
        if (words[1]) {
            switch (words[1].toLowerCase()) {
                case 'chis':
                    genlogs(msg, '100463282099326976', 'chis');
                    break;
                case 'mindy':
                    genlogs(msg, '217122202934444033', 'mindy');
                    break;
                case 'zeta':
                    genlogs(msg, '94129005791281152', 'zeta');
                    break;
                case 'fuyu':
                    genlogs(msg, ['141545699442425856', '214796473689178133'], 'fuyu');
                    break;
                case 'triping':
                    genlogs(msg, '128694295170514944', 'triping');
                    break;
                case 'hk':
                    genlogs(msg, '104360151208706048', 'hk');
                    break;
                case 'tttie':
                    genlogs(msg, '150628341316059136', 'tttie');
                    break;
                case 'blarg':
                    genlogs(msg, '134133271750639616', 'blarg');
                    break;
                case 'xeta':
                    genlogs(msg, '155490847494897664', 'xeta');
                    break;
                case 'axonium':
                    genlogs(msg, '133332642685779968', 'axonium');
                    break;
                case 'notso':
                    genlogs(msg, '130070621034905600', 'notso');
                    break;
                case 'mine':
                    genlogs(msg, '155112606661607425', 'mine');
                    break;
                case 'abal':
                    genlogs(msg, ['150061853001777154', '98295630480314368'], 'abal');
                    break;
                case 'pollr':
                    genlogs(msg, '168169809303961600', 'pollr');
                    break;
                case 'alex':
                    genlogs(msg, '86477779717066752', 'alex');
                    break;
                case 'randon':
                    genlogs(msg, '145162973910925312', 'randon');
                    break;
            }
        } else {
            let catMsgs = await r.table('catchat').orderBy('msgid');
            let content = [];
            for (let message of catMsgs) {
                if (message.guildid != '197529405659021322' && message.nsfw == 0)
                    content.push(message.content);
            }
            fs.writeFile(path.join(__dirname, '..', '..', 'catbot', 'cat.json'),
                JSON.stringify(content, null, 2), (err) => {
                    if (err) bu.send(msg, err);
                    bu.send(msg, 'Done!');
                });
        }
    }
};

async function genlogs(msg, id, name) {
    let msg2 = await bu.send(msg, 'Performing query...');
    let msgs;
    if (Array.isArray(id)) {
        id.push({
            index: 'userid'
        });
        msgs = await r.db('blargdb').table('chatlogs').getAll(id[0], id[1], id[2]);
    } else
        msgs = await r.db('blargdb').table('chatlogs').getAll(id, {
            index: 'userid'
        });
    await msg2.edit('Generating array...');
    let content = [];
    for (let message of msgs) {
        content.push(message.content);
    }
    let userId;
    if (Array.isArray(id)) userId = id[0];
    else userId = id;
    msg2.edit('Writing file...');
    fs.writeFile(path.join(__dirname, '..', '..', 'catbot', 'jsons', userId + '.json'),
        JSON.stringify({
            name: name,
            lines: content
        }, null, 2), (err) => {
            if (err) bu.send(msg, err);
            msg2.edit('Done.');
        });
}<commit_msg>more dynamic<commit_after>var e = module.exports = {};

const fs = require('fs');
const path = require('path');

e.init = () => {
    e.category = bu.CommandType.CAT;
};

e.requireCtx = require;

e.isCommand = true;
e.hidden = false;
e.usage = '';
e.info = '';

e.execute = async function(msg, words) {
    if (msg.author.id == bu.CAT_ID) {
        await bot.sendChannelTyping(msg.channel.id);
        if (words[1]) {
            switch (words[1].toLowerCase()) {
                case 'add':
                    if (msg.mentions.length > 0 && words[2]) {
                        await r.db('blargdb').table('markovs').insert({
                            userid: msg.mentions.map(u => u.id),
                            id: words[2].toLowerCase()
                        });
                        bu.send(msg, 'Added.');
                    } else {
                        bu.send(msg, 'Nope.');
                    }
                    break;
                case 'remove':
                    if (words[2]) {
                        await r.db('blargdb').table('markovs').get(words[2].toLowerCase()).delete();
                        bu.send(msg, 'Removed.');
                    } else {
                        bu.send(msg, 'Nope.');
                    }
                    break;
                default:
                    let markov = await r.db('blargdb').table('markovs').get(words[1]);
                    if (markov) {
                        genlogs(msg, markov.userid, markov.id);
                    }
                    break;
            }

        } else {
            let catMsgs = await r.table('catchat').orderBy('msgid');
            let content = [];
            for (let message of catMsgs) {
                if (message.guildid != '197529405659021322' && message.nsfw == 0)
                    content.push(message.content);
            }
            fs.writeFile(path.join(__dirname, '..', '..', 'catbot', 'cat.json'),
                JSON.stringify(content, null, 2), (err) => {
                    if (err) bu.send(msg, err);
                    bu.send(msg, 'Done!');
                });
        }
    }
};

async function genlogs(msg, id, name) {
    let msg2 = await bu.send(msg, 'Performing query...');
    let msgs;
    if (Array.isArray(id)) {
        id.push({
            index: 'userid'
        });
        msgs = await r.db('blargdb').table('chatlogs').getAll(id[0], id[1], id[2]);
    } else
        msgs = await r.db('blargdb').table('chatlogs').getAll(id, {
            index: 'userid'
        });
    await msg2.edit('Generating array...');
    let content = [];
    for (let message of msgs) {
        content.push(message.content);
    }
    let userId;
    if (Array.isArray(id)) userId = id[0];
    else userId = id;
    msg2.edit('Writing file...');
    fs.writeFile(path.join(__dirname, '..', '..', 'catbot', 'jsons', userId + '.json'),
        JSON.stringify({
            name: name,
            lines: content
        }, null, 2), (err) => {
            if (err) bu.send(msg, err);
            msg2.edit('Done.');
        });
}<|endoftext|>


<commit_before><commit_msg>Update test to use jsonFileContent<commit_after><|endoftext|>


<commit_before>const {remote} = require('electron')
const {Menu, MenuItem} = remote
const electron = require('electron')
const pack = require('../js/pack')
const frame = require('../js/frame')
const matrix = require('../js/mainmatrix')
const frameText = require('../js/frametext')
const player = require('../js/player')
const hardware = require('../js/hardware')
const windowMaker = require('../js/windowmaker')

//const platform = process.platform
const platform = 'win32' // darwin, freebsd, linux, win32

var template = []
const name = 'pixelFlow'

/*
* The App Menu (macOS)
*/
if (platform == 'darwin') {
  var appMenu = {
    label: name,
    submenu: [
      {
        lable: 'About ' + name,
        click() { windowMaker.openAbout() }
      },
      {
        type: 'separator'
      },
      {
        role: 'services',
        submenu: []
      },
      {
        type: 'separator'
      },
      {
        role: 'hide'
      },
      {
        role: 'hideothers'
      },
      {
        role: 'unhide'
      },
      {
        type: 'separator'
      },
      {
        accelerator: 'CmdOrCtrl+Q',
        role: 'quit'
      }
    ]
  }
  template.push(appMenu)
}

/*
* The File Menu
*/
var fileMenu = {
  label: 'File',
  submenu: [
    {
      label: 'New',
      accelerator: 'CmdOrCtrl+N',
      click(){pack.newFile()}
    },
    {
      label: 'Open...',
      accelerator: 'CmdOrCtrl+O',
      click(){pack.openFile()}
    },
    /* TODO: Open recent */
    {
      label: 'Save...',
      accelerator: 'CmdOrCtrl+S',
      click(){pack.saveFile()}
    },
    {
      label: 'Save As...',
      accelerator: 'CmdOrCtrl+Shift+S',
      click(){pack.saveAsFile()}
    },
    {
      label: 'Duplicate',
      accelerator: 'CmdOrCtrl+D',
      click(){pack.copyFile()}
    },
    /* TODO: Rename */
    {
      // Show in filemanager
      label: (() => {
        if (platform == 'darwin') {
          // Finder for macOS
          return 'Show in Finder...'
        }
        else if (platform == 'win32') {
          // Explorer for windows
          return 'Show in Explorer...'
        }
        else {
          // Filemanager for linux and freebsd
          return 'Show in Filemanager...'
        }
      })(),
      click() { pack.showInManager() }
    },
    {
      label: 'Close',
      click(){pack.closeFile()}
    }
  ]
}
// Add exit item for non macOS
if (platform != 'darwin') {
  fileMenu.submenu.push({
    type: 'separator'
  },
  {
    label: 'Exit',
    accelerator: 'CmdOrCtrl+Q',
    role: 'quit'
  }
)}
template.push(fileMenu)

// The Frame Menu
var frameMenu = {
  label: 'Frame',
  submenu: [
    {
      label: 'New',
      accelerator: 'CmdOrCtrl+Alt+N',
      click(){ frame.newFrame() }
    },
    {
      label: 'Duplicate',
      accelerator: 'CmdOrCtrl+Alt+D',
      click(){ frame.copyFrame() }
    },
    {
      label: 'Delete',
      accelerator: 'CmdOrCtrl+Alt+W',
      click(){ frame.deleteFrame() }
    },
    {
      type: 'separator'
    },
    {
      label: 'Fill',
      click(){ matrix.fillPixelsSelectedColor() }
    },
    {
      label: 'Clear',
      click(){ matrix.clearPixels() }
    },
    {
      type: 'separator'
    },
    {
      label: 'Add Text',
      click(){ frameText.enterText() }
    }
  ]
}
template.push(frameMenu)

// The Device Menu
var deviceMenu = {
  label: 'Device',
  submenu: [
    {
      label: 'Connect...',
      click(){ windowMaker.openConnection() }
    },
    {
      label: 'Refresh Output',
      accelerator: 'CmdOrCtrl+R',
      click() { hardware.updateFrame(matrix.getPixelList()) }
    },
    {
      type: 'separator'
    },
    {
      label: 'Play / Pause',
      click(){ player.togglePlayPause() }
    },
    {
      label: 'Toggle LiveUpdate',
      click(){ hardware.toggleLiveUpdate() }
    },
    {
      label: 'Toggle Loop',
      click(){ player.toggleLoop() }
    }
  ]
}
template.push(deviceMenu)

// The View Menu
var viewMenu = {
  label: 'View',
  submenu: [
    {
      role: 'togglefullscreen'
    },
    {
      type: 'separator'
    },
    {
      lable: 'Reset Zoom',
      role: 'resetzoom'
    },
    {
      role: 'zoomin',
      accelerator: 'CmdOrCtrl+='
    },
    {
      role: 'zoomout',
      accelerator: 'CmdOrCtrl+-'
    },
    {
      type: 'separator'
    },
    {
      label: 'Toggle Developer Tools',
      accelerator: platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
      click (item, focusedWindow) {
        if (focusedWindow) focusedWindow.webContents.toggleDevTools()
      }
    }
  ]
}
template.push(viewMenu)

// The Window Menu (macOS)
if (platform == 'darwin') {
  var winMenu = {
    role: 'window',
    submenu: [
      {
        label: 'Close',
        accelerator: 'CmdOrCtrl+W',
        role: 'close'
      },
      {
        label: 'Minimize',
        accelerator: 'CmdOrCtrl+M',
        role: 'minimize'
      },
      {
        label: 'Zoom',
        role: 'zoom'
      },
      {
        type: 'separator'
      },
      {
        label: 'Bring All to Front',
        role: 'front'
      }
    ]
  }
  template.push(winMenu)
}

// The Help Menu
var helpMenu = {
  role: 'help',
  submenu: [
    {
      label: 'Github...',
      click () { require('electron').shell.openExternal('https://www.github.com/flofriday/pixelflow') }
    },
    {
      label: 'Report issue...',
      click () { require('electron').shell.openExternal('https://github.com/flofriday/pixelFlow/issues/new') }
    },
    {
      label: 'License...',
      click () { require('electron').shell.openExternal('https://www.github.com/flofriday/pixelflow/blob/master/LICENSE') }
      /* TODO Add link to handbook */
    }
  ]
}
// Add about item for non macOS
if (platform != 'darwin') {
  helpMenu.submenu.push({
    type: 'separator'
  },
  {
    label: 'About ' + name,
    click () { windowMaker.openAbout() }
  }
)}
template.push(helpMenu)

// Apply the menu
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
<commit_msg>Remove testing code<commit_after>const {remote} = require('electron')
const {Menu, MenuItem} = remote
const electron = require('electron')
const pack = require('../js/pack')
const frame = require('../js/frame')
const matrix = require('../js/mainmatrix')
const frameText = require('../js/frametext')
const player = require('../js/player')
const hardware = require('../js/hardware')
const windowMaker = require('../js/windowmaker')

const platform = process.platform
//const platform = 'win32' // darwin, freebsd, linux, win32

var template = []
const name = 'pixelFlow'

/*
* The App Menu (macOS)
*/
if (platform == 'darwin') {
  var appMenu = {
    label: name,
    submenu: [
      {
        lable: 'About ' + name,
        click() { windowMaker.openAbout() }
      },
      {
        type: 'separator'
      },
      {
        role: 'services',
        submenu: []
      },
      {
        type: 'separator'
      },
      {
        role: 'hide'
      },
      {
        role: 'hideothers'
      },
      {
        role: 'unhide'
      },
      {
        type: 'separator'
      },
      {
        accelerator: 'CmdOrCtrl+Q',
        role: 'quit'
      }
    ]
  }
  template.push(appMenu)
}

/*
* The File Menu
*/
var fileMenu = {
  label: 'File',
  submenu: [
    {
      label: 'New',
      accelerator: 'CmdOrCtrl+N',
      click(){pack.newFile()}
    },
    {
      label: 'Open...',
      accelerator: 'CmdOrCtrl+O',
      click(){pack.openFile()}
    },
    /* TODO: Open recent */
    {
      label: 'Save...',
      accelerator: 'CmdOrCtrl+S',
      click(){pack.saveFile()}
    },
    {
      label: 'Save As...',
      accelerator: 'CmdOrCtrl+Shift+S',
      click(){pack.saveAsFile()}
    },
    {
      label: 'Duplicate',
      accelerator: 'CmdOrCtrl+D',
      click(){pack.copyFile()}
    },
    /* TODO: Rename */
    {
      // Show in filemanager
      label: (() => {
        if (platform == 'darwin') {
          // Finder for macOS
          return 'Show in Finder...'
        }
        else if (platform == 'win32') {
          // Explorer for windows
          return 'Show in Explorer...'
        }
        else {
          // Filemanager for linux and freebsd
          return 'Show in Filemanager...'
        }
      })(),
      click() { pack.showInManager() }
    },
    {
      label: 'Close',
      click(){pack.closeFile()}
    }
  ]
}
// Add exit item for non macOS
if (platform != 'darwin') {
  fileMenu.submenu.push({
    type: 'separator'
  },
  {
    label: 'Exit',
    accelerator: 'CmdOrCtrl+Q',
    role: 'quit'
  }
)}
template.push(fileMenu)

// The Frame Menu
var frameMenu = {
  label: 'Frame',
  submenu: [
    {
      label: 'New',
      accelerator: 'CmdOrCtrl+Alt+N',
      click(){ frame.newFrame() }
    },
    {
      label: 'Duplicate',
      accelerator: 'CmdOrCtrl+Alt+D',
      click(){ frame.copyFrame() }
    },
    {
      label: 'Delete',
      accelerator: 'CmdOrCtrl+Alt+W',
      click(){ frame.deleteFrame() }
    },
    {
      type: 'separator'
    },
    {
      label: 'Fill',
      click(){ matrix.fillPixelsSelectedColor() }
    },
    {
      label: 'Clear',
      click(){ matrix.clearPixels() }
    },
    {
      type: 'separator'
    },
    {
      label: 'Add Text',
      click(){ frameText.enterText() }
    }
  ]
}
template.push(frameMenu)

// The Device Menu
var deviceMenu = {
  label: 'Device',
  submenu: [
    {
      label: 'Connect...',
      click(){ windowMaker.openConnection() }
    },
    {
      label: 'Refresh Output',
      accelerator: 'CmdOrCtrl+R',
      click() { hardware.updateFrame(matrix.getPixelList()) }
    },
    {
      type: 'separator'
    },
    {
      label: 'Play / Pause',
      click(){ player.togglePlayPause() }
    },
    {
      label: 'Toggle LiveUpdate',
      click(){ hardware.toggleLiveUpdate() }
    },
    {
      label: 'Toggle Loop',
      click(){ player.toggleLoop() }
    }
  ]
}
template.push(deviceMenu)

// The View Menu
var viewMenu = {
  label: 'View',
  submenu: [
    {
      role: 'togglefullscreen'
    },
    {
      type: 'separator'
    },
    {
      lable: 'Reset Zoom',
      role: 'resetzoom'
    },
    {
      role: 'zoomin',
      accelerator: 'CmdOrCtrl+='
    },
    {
      role: 'zoomout',
      accelerator: 'CmdOrCtrl+-'
    },
    {
      type: 'separator'
    },
    {
      label: 'Toggle Developer Tools',
      accelerator: platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
      click (item, focusedWindow) {
        if (focusedWindow) focusedWindow.webContents.toggleDevTools()
      }
    }
  ]
}
template.push(viewMenu)

// The Window Menu (macOS)
if (platform == 'darwin') {
  var winMenu = {
    role: 'window',
    submenu: [
      {
        label: 'Close',
        accelerator: 'CmdOrCtrl+W',
        role: 'close'
      },
      {
        label: 'Minimize',
        accelerator: 'CmdOrCtrl+M',
        role: 'minimize'
      },
      {
        label: 'Zoom',
        role: 'zoom'
      },
      {
        type: 'separator'
      },
      {
        label: 'Bring All to Front',
        role: 'front'
      }
    ]
  }
  template.push(winMenu)
}

// The Help Menu
var helpMenu = {
  role: 'help',
  submenu: [
    {
      label: 'Github...',
      click () { require('electron').shell.openExternal('https://www.github.com/flofriday/pixelflow') }
    },
    {
      label: 'Report issue...',
      click () { require('electron').shell.openExternal('https://github.com/flofriday/pixelFlow/issues/new') }
    },
    {
      label: 'License...',
      click () { require('electron').shell.openExternal('https://www.github.com/flofriday/pixelflow/blob/master/LICENSE') }
      /* TODO Add link to handbook */
    }
  ]
}
// Add about item for non macOS
if (platform != 'darwin') {
  helpMenu.submenu.push({
    type: 'separator'
  },
  {
    label: 'About ' + name,
    click () { windowMaker.openAbout() }
  }
)}
template.push(helpMenu)

// Apply the menu
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
<|endoftext|>


<commit_before><commit_msg>style(test): fix style issues for e2e tests<commit_after><|endoftext|>


<commit_before>var async = require('async');
var names = [];

module.exports = function (params, lfm) {
    console.log(params);
    var page = params.page || 1;
    async.forever(
        function (next) {
            lfm.library.getArtists({
                'user': params.user || 'TaggingMachine',
                'page': page
            }, function (err, topArtists) {
                if (err)
                    next(err, null);
                else {
                    async.every(topArtists.artist, function (artist, callback) {
                        if (names.indexOf(artist.name) >= 0)
                            console.log('sas! ', artist.name);
                        else
                            names.push(artist.name);
                        lfm.library.addArtist(artist.name, function (err) {
                            if (err) {
                                console.log(artist.name, err);
                            }
                            else if (params.log)
                                console.log(artist.name, 'was successfully added to library');
                            callback(err);
                        });
                    }, function (result) {
                        params.log && console.log(result);
                        page++;
                        setTimeout(function () {
                            next(err, null)
                        }, 450 + Math.floor(Math.random() * 100) + (Math.random() > .9 ? 1500 : 0));
                    });
                }
            });
        },
        function (err) {
            if (err) {
                return console.log('We\'re in trouble', err);
            }
        }
    );
};<commit_msg>Fixed tcp sockets error, added restarting from last page<commit_after>var async = require('async')
    , fs = require('fs')
    , path = require('path');
var names = [],
    pageFile = path.join(__dirname, "/../.lastpage");

function _t(f, t) {
    return setTimeout(f, t);
}

module.exports = function (params, lfm) {
    var pageFromFile;
    try {
        pageFromFile = fs.readFileSync(pageFile);
    } catch(e){
        fs.writeFileSync(pageFile, params.page || 1);
    }
    var page = params.page || pageFromFile || 1;
    try {
        async.forever(
            function (next) {
                lfm.library.getArtists({
                    'user': params.user || 'TaggingMachine',
                    'page': page
                }, function (err, topArtists) {
                    if (err)
                        next(err, null);
                    else {
                        async.every(topArtists.artist, function (artist, callback) {
                            if (names.indexOf(artist.name) >= 0)
                                console.log('sas! ', artist.name);
                            else
                                names.push(artist.name);
                            lfm.library.addArtist(artist.name, function (err) {
                                if (err) {
                                    console.log(artist.name, err);
                                }
                                else if (params.log)
                                    console.log(artist.name, 'was successfully added to library');
                                _t(function () {
                                    callback(err)
                                }, 300);
                            });
                        }, function (result) {
                            page++;
                            _t(function () {
                                next(err, null)
                            }, 450 + Math.floor(Math.random() * 100) + (Math.random() > .9 ? 1500 : 0));
                        });
                    }
                });
            },
            function (err) {
                if (err) {
                    return console.log('We\'re in trouble', err);
                }
            }
        );
    } catch (e) {
        savePage() ? console.log("page saved") : console.log("page not saved, neh");
        return console.log("ended abnormally, saving page to file. to prevent program from loading last page, just specify --page to 1")
    }
};

process.on('exit', function (code) {
    savePage() ? console.log("page saved") : console.log("page not saved, neh");
    console.log("to prevent program from loading last page, just specify --page to 1")
});

function savePage() {
    return fs.writeFileSync(pageFile, page, null);
}<|endoftext|>


<commit_before><commit_msg>Make sure pubsub is up for fs tests<commit_after><|endoftext|>


<commit_before>import * as Sentry from '@sentry/browser';
import { recordVaosError } from './events';
import environment from 'platform/utilities/environment';

export function captureError(
  err,
  skipRecordEvent = false,
  customTitle,
  extraData,
) {
  let eventErrorKey;

  if (err instanceof Error) {
    Sentry.captureException(err);
    eventErrorKey = err.message;
  } else {
    Sentry.withScope(scope => {
      scope.setExtra('error', err);
      if (extraData) {
        scope.setExtra('extraData', extraData);
      }
      const errorTitle =
        customTitle || err?.errors?.[0]?.title || err?.issue?.[0]?.code || err;
      const message = `vaos_server_error${errorTitle ? `: ${errorTitle}` : ''}`;
      eventErrorKey = message;
      // the apiRequest helper returns the errors array, instead of an exception
      Sentry.captureMessage(message);
    });
  }

  if (!skipRecordEvent) {
    recordVaosError(eventErrorKey);
  }

  if (!environment.isProduction()) {
    // eslint-disable-next-line no-console
    console.error(err);
  }
}

export function getErrorCodes(error) {
  return error?.errors?.map(e => e.code) || [];
}

export function has400LevelError(error) {
  return getErrorCodes(error).some(code => code.startsWith('VAOS_4'));
}
<commit_msg>Set a consistent error title for VAOS server errors (#14775)<commit_after>import * as Sentry from '@sentry/browser';
import { recordVaosError } from './events';
import environment from 'platform/utilities/environment';

export function captureError(
  err,
  skipRecordEvent = false,
  customTitle,
  extraData,
) {
  let eventErrorKey;

  if (err instanceof Error) {
    Sentry.captureException(err);
    eventErrorKey = err.message;
  } else if (err?.issue || err?.errors) {
    Sentry.withScope(scope => {
      scope.setExtra('error', err);
      if (extraData) {
        scope.setExtra('extraData', extraData);
      }
      const errorTitle =
        customTitle ||
        err?.errors?.[0]?.title ||
        err?.issue?.[0]?.diagnostics ||
        err?.errors?.[0]?.code ||
        err?.issue?.[0]?.code ||
        err;
      const message = `vaos_server_error${errorTitle ? `: ${errorTitle}` : ''}`;
      eventErrorKey = message;
      // the apiRequest helper returns the errors array, instead of an exception
      Sentry.captureMessage(message);
    });
  } else {
    Sentry.withScope(scope => {
      scope.setExtra('error', err);
      if (extraData) {
        scope.setExtra('extraData', extraData);
      }
      const message = `vaos_client_error${
        customTitle ? `: ${customTitle}` : ''
      }`;
      eventErrorKey = message;
      // the apiRequest helper returns the errors array, instead of an exception
      Sentry.captureMessage(message);
    });
  }

  if (!skipRecordEvent) {
    recordVaosError(eventErrorKey);
  }

  if (!environment.isProduction()) {
    // eslint-disable-next-line no-console
    console.error(err);
  }
}

export function getErrorCodes(error) {
  return error?.errors?.map(e => e.code) || [];
}

export function has400LevelError(error) {
  return getErrorCodes(error).some(code => code.startsWith('VAOS_4'));
}
<|endoftext|>


<commit_before>// Grouping module
;(function($){
"use strict";
$.jgrid.extend({
	groupingSetup : function () {
		return this.each(function (){
			var $t = this,
			grp = $t.p.groupingView;
			if(grp !== null && ( (typeof grp === 'object') || $.isFunction(grp) ) ) {
				if(!grp.groupField.length) {
					$t.p.grouping = false;
				} else {
					if ( typeof(grp.visibiltyOnNextGrouping) == 'undefined') {
						grp.visibiltyOnNextGrouping = [];
					}
					for(var i=0;i<grp.groupField.length;i++) {
						if(!grp.groupOrder[i]) {
							grp.groupOrder[i] = 'asc';
						}
						if(!grp.groupText[i]) {
							grp.groupText[i] = '{0}';
						}
						if( typeof(grp.groupColumnShow[i]) != 'boolean') {
							grp.groupColumnShow[i] = true;
						}
						if( typeof(grp.groupSummary[i]) != 'boolean') {
							grp.groupSummary[i] = false;
						}
						if(grp.groupColumnShow[i] === true) {
							grp.visibiltyOnNextGrouping[i] = true;
							$($t).jqGrid('showCol',grp.groupField[i]);
						} else {
							grp.visibiltyOnNextGrouping[i] = $("#"+$t.p.id+"_"+grp.groupField[i]).is(":visible");
							$($t).jqGrid('hideCol',grp.groupField[i]);
						}
						grp.sortitems[i] = [];
						grp.sortnames[i] = [];
						grp.summaryval[i] = [];
						if(grp.groupSummary[i]) {
							grp.summary[i] =[];
							var cm = $t.p.colModel;
							for(var j=0, cml = cm.length; j < cml; j++) {
								if(cm[j].summaryType) {
									grp.summary[i].push({nm:cm[j].name,st:cm[j].summaryType, v:''});
								}
							}
						}
					}
				}
			} else {
				$t.p.grouping = false;
			}
		});
	},
	groupingPrepare : function (rData, items, gdata, record) {
		this.each(function(){
			// currently only one level
			// Is this a good idea to do it so!!!!?????
			items[0]  += "";
			var itm = items[0].toString().split(' ').join('');

			var grp = this.p.groupingView, $t= this;
			if(gdata.hasOwnProperty(itm)) {
				gdata[itm].push(rData);
			} else {
				gdata[itm] = [];
				gdata[itm].push(rData);
				grp.sortitems[0].push(itm);
				grp.sortnames[0].push($.trim(items[0].toString()));
				grp.summaryval[0][itm] = $.extend(true,[],grp.summary[0]);
			}
			if(grp.groupSummary[0]) {
				$.each(grp.summaryval[0][itm],function() {
					if ($.isFunction(this.st)) {
						this.v = this.st.call($t, this.v, this.nm, record);
					} else {
						this.v = $($t).jqGrid('groupingCalculations.'+this.st, this.v, this.nm, record);
					}
				});
			}
		});
		return gdata;
	},
	groupingToggle : function(hid){
		this.each(function(){
			var $t = this,
			grp = $t.p.groupingView,
			strpos = hid.lastIndexOf('_'),
			uid = hid.substring(0,strpos+1),
			num = parseInt(hid.substring(strpos+1),10)+1,
			minus = grp.minusicon,
			plus = grp.plusicon,
			tar = $("#"+hid),
			r = tar.length ? tar[0].nextSibling : null,
			tarspan = $("#"+hid+" span."+"tree-wrap-"+$t.p.direction),
			collapsed = false;
			if( tarspan.hasClass(minus) ) {
				if(grp.showSummaryOnHide && grp.groupSummary[0]) {
					if(r){
						while(r) {
							if($(r).hasClass('jqfoot') ) { break; }
							$(r).hide();
							r = r.nextSibling;
						}
					}
				} else  {
					if(r){
						while(r) {
							if($(r).attr('id') ==uid+String(num) ) { break; }
							$(r).hide();
							r = r.nextSibling;
				}
					}
				}
				tarspan.removeClass(minus).addClass(plus);
				collapsed = true;
			} else {
				if(r){
					while(r) {
						if($(r).attr('id') ==uid+String(num) ) { break; }
						$(r).show();
						r = r.nextSibling;
					}
				}
				tarspan.removeClass(plus).addClass(minus);
			}
			$($t).triggerHandler("jqGridGroupingClickGroup", [hid , collapsed]);
			if( $.isFunction($t.p.onClickGroup)) { $t.p.onClickGroup.call($t, hid , collapsed); }

		});
		return false;
	},
	groupingRender : function (grdata, colspans ) {
		return this.each(function(){
			var $t = this,
			grp = $t.p.groupingView,
			str = "", icon = "", hid, pmrtl = grp.groupCollapse ? grp.plusicon : grp.minusicon, gv, cp, ii;
			//only one level for now
			if(!grp.groupDataSorted) {
				// ???? TO BE IMPROVED
				grp.sortitems[0].sort();
				grp.sortnames[0].sort();
				if(grp.groupOrder[0].toLowerCase() == 'desc')
				{
					grp.sortitems[0].reverse();
					grp.sortnames[0].reverse();
				}
			}
			pmrtl += " tree-wrap-"+$t.p.direction;
			ii = 0;
			while(ii < colspans) {
				if($t.p.colModel[ii].name == grp.groupField[0]) {
					cp = ii;
					break;
				}
				ii++;
			}
			$.each(grp.sortitems[0],function(i,n){
				hid = $t.p.id+"ghead_"+i;
				icon = "";
				try {
					gv = $t.formatter(hid, grp.sortnames[0][i], cp, grp.sortitems[0] );
				} catch (egv) {
					gv = grp.sortnames[0][i];
				}
				str += "
"+icon+$.jgrid.format(grp.groupText[0], gv, grdata[n].length)+"
";
				for(var kk=0;kk<grdata[n].length;kk++) {
					str += grdata[n][kk].join('');
				}
				if(grp.groupSummary[0]) {
					var hhdr = "";
					if(grp.groupCollapse && !grp.showSummaryOnHide) {
						hhdr = " style=\"display:none;\"";
					}
					str += "
";
					var fdata = grp.summaryval[0][n],
					cm = $t.p.colModel,
					vv, grlen = grdata[n].length;
					for(var k=0; k<colspans;k++) {
						var tmpdata = " 	",
						tplfld = "{0}";
						$.each(fdata,function(){
							if(this.nm == cm[k].name) {
								if(cm[k].summaryTpl)  {
									tplfld = cm[k].summaryTpl;
								}
								if(this.st == 'avg') {
									if(this.v && grlen > 0) {
										this.v = (this.v/grlen);
									}
								}
								try {
									vv = $t.formatter('', this.v, k, this);
								} catch (ef) {
									vv = this.v;
								}
								tmpdata= ""+$.jgrid.format(tplfld,vv)+ "	";
								return false;
							}
						});
						str += tmpdata;
					}
					str += "
";
				}
			});
			$("#"+$t.p.id+" tbody:first").append(str);
			// free up memory
			str = null;
		});
	},
	groupingGroupBy : function (name, options ) {
		return this.each(function(){
			var $t = this;
			if(typeof(name) == "string") {
				name = [name];
			}
			var grp = $t.p.groupingView;
			$t.p.grouping = true;

			//Set default, in case visibilityOnNextGrouping is undefined
			if (typeof grp.visibiltyOnNextGrouping == "undefined") {
				grp.visibiltyOnNextGrouping = [];
			}
			var i;
			// show previous hidden groups if they are hidden and weren't removed yet
			for(i=0;i<grp.groupField.length;i++) {
				if(!grp.groupColumnShow[i] && grp.visibiltyOnNextGrouping[i]) {
				$($t).jqGrid('showCol',grp.groupField[i]);
				}
			}
			// set visibility status of current group columns on next grouping
			for(i=0;i<name.length;i++) {
				grp.visibiltyOnNextGrouping[i] = $("#"+$t.p.id+"_"+name[i]).is(":visible");
			}
			$t.p.groupingView = $.extend($t.p.groupingView, options || {});
			grp.groupField = name;
			$($t).trigger("reloadGrid");
		});
	},
	groupingRemove : function (current) {
		return this.each(function(){
			var $t = this;
			if(typeof(current) == 'undefined') {
				current = true;
			}
			$t.p.grouping = false;
			if(current===true) {
        var grp = $t.p.groupingView;
        // show previous hidden groups if they are hidden and weren't removed yet
        for(var i=0;i<grp.groupField.length;i++) {
          if (!grp.groupColumnShow[i] && grp.visibiltyOnNextGrouping[i]) {
            $($t).jqGrid('showCol', grp.groupField);
          }
        }
				$("tr.jqgroup, tr.jqfoot","#"+$t.p.id+" tbody:first").remove();
				$("tr.jqgrow:hidden","#"+$t.p.id+" tbody:first").show();
			} else {
				$($t).trigger("reloadGrid");
			}
		});
	},
	groupingCalculations : {
		"sum" : function(v, field, rc) {
			return parseFloat(v||0) + parseFloat((rc[field]||0));
		},
		"min" : function(v, field, rc) {
			if(v==="") {
				return parseFloat(rc[field]||0);
			}
			return Math.min(parseFloat(v),parseFloat(rc[field]||0));
		},
		"max" : function(v, field, rc) {
			if(v==="") {
				return parseFloat(rc[field]||0);
			}
			return Math.max(parseFloat(v),parseFloat(rc[field]||0));
		},
		"count" : function(v, field, rc) {
			if(v==="") {v=0;}
			if(rc.hasOwnProperty(field)) {
				return v+1;
			} else {
				return 0;
			}
		},
		"avg" : function(v, field, rc) {
			// the same as sum, but at end we divide it
			return parseFloat(v||0) + parseFloat((rc[field]||0));
		}
	}
});
})(jQuery);
<commit_msg>Formatting fixes in grouping<commit_after>// Grouping module
;(function($){
"use strict";
$.jgrid.extend({
	groupingSetup : function () {
		return this.each(function (){
			var $t = this,
			grp = $t.p.groupingView;
			if(grp !== null && ( (typeof grp === 'object') || $.isFunction(grp) ) ) {
				if(!grp.groupField.length) {
					$t.p.grouping = false;
				} else {
					if ( typeof(grp.visibiltyOnNextGrouping) == 'undefined') {
						grp.visibiltyOnNextGrouping = [];
					}
					for(var i=0;i<grp.groupField.length;i++) {
						if(!grp.groupOrder[i]) {
							grp.groupOrder[i] = 'asc';
						}
						if(!grp.groupText[i]) {
							grp.groupText[i] = '{0}';
						}
						if( typeof(grp.groupColumnShow[i]) != 'boolean') {
							grp.groupColumnShow[i] = true;
						}
						if( typeof(grp.groupSummary[i]) != 'boolean') {
							grp.groupSummary[i] = false;
						}
						if(grp.groupColumnShow[i] === true) {
							grp.visibiltyOnNextGrouping[i] = true;
							$($t).jqGrid('showCol',grp.groupField[i]);
						} else {
							grp.visibiltyOnNextGrouping[i] = $("#"+$t.p.id+"_"+grp.groupField[i]).is(":visible");
							$($t).jqGrid('hideCol',grp.groupField[i]);
						}
						grp.sortitems[i] = [];
						grp.sortnames[i] = [];
						grp.summaryval[i] = [];
						if(grp.groupSummary[i]) {
							grp.summary[i] =[];
							var cm = $t.p.colModel;
							for(var j=0, cml = cm.length; j < cml; j++) {
								if(cm[j].summaryType) {
									grp.summary[i].push({nm:cm[j].name,st:cm[j].summaryType, v:''});
								}
							}
						}
					}
				}
			} else {
				$t.p.grouping = false;
			}
		});
	},
	groupingPrepare : function (rData, items, gdata, record) {
		this.each(function(){
			// currently only one level
			// Is this a good idea to do it so!!!!?????
			items[0]  += "";
			var itm = items[0].toString().split(' ').join('');

			var grp = this.p.groupingView, $t= this;
			if(gdata.hasOwnProperty(itm)) {
				gdata[itm].push(rData);
			} else {
				gdata[itm] = [];
				gdata[itm].push(rData);
				grp.sortitems[0].push(itm);
				grp.sortnames[0].push($.trim(items[0].toString()));
				grp.summaryval[0][itm] = $.extend(true,[],grp.summary[0]);
			}
			if(grp.groupSummary[0]) {
				$.each(grp.summaryval[0][itm],function() {
					if ($.isFunction(this.st)) {
						this.v = this.st.call($t, this.v, this.nm, record);
					} else {
						this.v = $($t).jqGrid('groupingCalculations.'+this.st, this.v, this.nm, record);
					}
				});
			}
		});
		return gdata;
	},
	groupingToggle : function(hid){
		this.each(function(){
			var $t = this,
			grp = $t.p.groupingView,
			strpos = hid.lastIndexOf('_'),
			uid = hid.substring(0,strpos+1),
			num = parseInt(hid.substring(strpos+1),10)+1,
			minus = grp.minusicon,
			plus = grp.plusicon,
			tar = $("#"+hid),
			r = tar.length ? tar[0].nextSibling : null,
			tarspan = $("#"+hid+" span."+"tree-wrap-"+$t.p.direction),
			collapsed = false;
			if( tarspan.hasClass(minus) ) {
				if(grp.showSummaryOnHide && grp.groupSummary[0]) {
					if(r){
						while(r) {
							if($(r).hasClass('jqfoot') ) { break; }
							$(r).hide();
							r = r.nextSibling;
						}
					}
				} else  {
					if(r){
						while(r) {
							if($(r).attr('id') ==uid+String(num) ) { break; }
							$(r).hide();
							r = r.nextSibling;
						}
					}
				}
				tarspan.removeClass(minus).addClass(plus);
				collapsed = true;
			} else {
				if(r){
					while(r) {
						if($(r).attr('id') ==uid+String(num) ) { break; }
						$(r).show();
						r = r.nextSibling;
					}
				}
				tarspan.removeClass(plus).addClass(minus);
			}
			$($t).triggerHandler("jqGridGroupingClickGroup", [hid , collapsed]);
			if( $.isFunction($t.p.onClickGroup)) { $t.p.onClickGroup.call($t, hid , collapsed); }

		});
		return false;
	},
	groupingRender : function (grdata, colspans ) {
		return this.each(function(){
			var $t = this,
			grp = $t.p.groupingView,
			str = "", icon = "", hid, pmrtl = grp.groupCollapse ? grp.plusicon : grp.minusicon, gv, cp, ii;
			//only one level for now
			if(!grp.groupDataSorted) {
				// ???? TO BE IMPROVED
				grp.sortitems[0].sort();
				grp.sortnames[0].sort();
				if(grp.groupOrder[0].toLowerCase() == 'desc')
				{
					grp.sortitems[0].reverse();
					grp.sortnames[0].reverse();
				}
			}
			pmrtl += " tree-wrap-"+$t.p.direction;
			ii = 0;
			while(ii < colspans) {
				if($t.p.colModel[ii].name == grp.groupField[0]) {
					cp = ii;
					break;
				}
				ii++;
			}
			$.each(grp.sortitems[0],function(i,n){
				hid = $t.p.id+"ghead_"+i;
				icon = "";
				try {
					gv = $t.formatter(hid, grp.sortnames[0][i], cp, grp.sortitems[0] );
				} catch (egv) {
					gv = grp.sortnames[0][i];
				}
				str += "
"+icon+$.jgrid.format(grp.groupText[0], gv, grdata[n].length)+"
";
				for(var kk=0;kk<grdata[n].length;kk++) {
					str += grdata[n][kk].join('');
				}
				if(grp.groupSummary[0]) {
					var hhdr = "";
					if(grp.groupCollapse && !grp.showSummaryOnHide) {
						hhdr = " style=\"display:none;\"";
					}
					str += "
";
					var fdata = grp.summaryval[0][n],
					cm = $t.p.colModel,
					vv, grlen = grdata[n].length;
					for(var k=0; k<colspans;k++) {
						var tmpdata = " 	",
						tplfld = "{0}";
						$.each(fdata,function(){
							if(this.nm == cm[k].name) {
								if(cm[k].summaryTpl)  {
									tplfld = cm[k].summaryTpl;
								}
								if(this.st == 'avg') {
									if(this.v && grlen > 0) {
										this.v = (this.v/grlen);
									}
								}
								try {
									vv = $t.formatter('', this.v, k, this);
								} catch (ef) {
									vv = this.v;
								}
								tmpdata= ""+$.jgrid.format(tplfld,vv)+ "	";
								return false;
							}
						});
						str += tmpdata;
					}
					str += "
";
				}
			});
			$("#"+$t.p.id+" tbody:first").append(str);
			// free up memory
			str = null;
		});
	},
	groupingGroupBy : function (name, options ) {
		return this.each(function(){
			var $t = this;
			if(typeof(name) == "string") {
				name = [name];
			}
			var grp = $t.p.groupingView;
			$t.p.grouping = true;

			//Set default, in case visibilityOnNextGrouping is undefined
			if (typeof grp.visibiltyOnNextGrouping == "undefined") {
				grp.visibiltyOnNextGrouping = [];
			}
			var i;
			// show previous hidden groups if they are hidden and weren't removed yet
			for(i=0;i<grp.groupField.length;i++) {
				if(!grp.groupColumnShow[i] && grp.visibiltyOnNextGrouping[i]) {
				$($t).jqGrid('showCol',grp.groupField[i]);
				}
			}
			// set visibility status of current group columns on next grouping
			for(i=0;i<name.length;i++) {
				grp.visibiltyOnNextGrouping[i] = $("#"+$t.p.id+"_"+name[i]).is(":visible");
			}
			$t.p.groupingView = $.extend($t.p.groupingView, options || {});
			grp.groupField = name;
			$($t).trigger("reloadGrid");
		});
	},
	groupingRemove : function (current) {
		return this.each(function(){
			var $t = this;
			if(typeof(current) == 'undefined') {
				current = true;
			}
			$t.p.grouping = false;
			if(current===true) {
				var grp = $t.p.groupingView;
				// show previous hidden groups if they are hidden and weren't removed yet
				for(var i=0;i<grp.groupField.length;i++) {
				if (!grp.groupColumnShow[i] && grp.visibiltyOnNextGrouping[i]) {
						$($t).jqGrid('showCol', grp.groupField);
					}
				}
				$("tr.jqgroup, tr.jqfoot","#"+$t.p.id+" tbody:first").remove();
				$("tr.jqgrow:hidden","#"+$t.p.id+" tbody:first").show();
			} else {
				$($t).trigger("reloadGrid");
			}
		});
	},
	groupingCalculations : {
		"sum" : function(v, field, rc) {
			return parseFloat(v||0) + parseFloat((rc[field]||0));
		},
		"min" : function(v, field, rc) {
			if(v==="") {
				return parseFloat(rc[field]||0);
			}
			return Math.min(parseFloat(v),parseFloat(rc[field]||0));
		},
		"max" : function(v, field, rc) {
			if(v==="") {
				return parseFloat(rc[field]||0);
			}
			return Math.max(parseFloat(v),parseFloat(rc[field]||0));
		},
		"count" : function(v, field, rc) {
			if(v==="") {v=0;}
			if(rc.hasOwnProperty(field)) {
				return v+1;
			} else {
				return 0;
			}
		},
		"avg" : function(v, field, rc) {
			// the same as sum, but at end we divide it
			return parseFloat(v||0) + parseFloat((rc[field]||0));
		}
	}
});
})(jQuery);
<|endoftext|>


<commit_before>// Copyright 2019, University of Colorado Boulder

/* eslint-disable */

/**
 * Prototyping for https://github.com/phetsims/chipper/issues/820
 *
 * @param {Object} grunt
 * @param {Object} gruntConfig
 */

'use strict';

const execute = require( './execute' );
const fs = require( 'fs' );
const grunt = require( 'grunt' );
const generateDevelopmentHTML = require( './generateDevelopmentHTML' );

const simRepos = [
  'acid-base-solutions',
  'area-builder',
  'area-model-algebra',
  'area-model-decimals',
  'area-model-introduction',
  'area-model-multiplication',
  'arithmetic',
  'atomic-interactions',
  'balancing-act',
  'balancing-chemical-equations',
  'balloons-and-static-electricity',
  'beers-law-lab',
  'bending-light',
  'blackbody-spectrum',
  'blast',
  'build-a-fraction',
  'build-a-molecule',
  'build-an-atom',
  'bumper',
  'buoyancy',
  'calculus-grapher',
  'capacitor-lab-basics',
  'chains',
  'charges-and-fields',
  'circuit-construction-kit-ac',
  'circuit-construction-kit-black-box-study',
  'circuit-construction-kit-dc',
  'circuit-construction-kit-dc-virtual-lab',
  'color-vision',
  'collision-lab',
  'concentration',
  'coulombs-law',
  'curve-fitting',
  'density',
  'diffusion',
  'energy-forms-and-changes',
  'energy-skate-park',
  'energy-skate-park-basics',
  'equality-explorer',
  'equality-explorer-basics',
  'equality-explorer-two-variables',
  'estimation',
  'example-sim',
  'expression-exchange',
  'faradays-law',
  'fluid-pressure-and-flow',
  'forces-and-motion-basics',
  'fraction-comparison',
  'fraction-matcher',
  'fractions-equality',
  'fractions-intro',
  'fractions-mixed-numbers',
  'friction',
  'function-builder',
  'function-builder-basics',
  'gas-properties',
  'gases-intro',
  'gene-expression-essentials',
  'graphing-lines',
  'graphing-quadratics',
  'graphing-slope-intercept',
  'gravity-and-orbits',
  'gravity-force-lab',
  'gravity-force-lab-basics',
  'hookes-law',
  'interaction-dashboard',
  'isotopes-and-atomic-mass',
  'john-travoltage',
  'least-squares-regression',
  'make-a-ten',
  'masses-and-springs',
  'masses-and-springs-basics',
  'models-of-the-hydrogen-atom',
  'molarity',
  'molecules-and-light',
  'molecule-polarity',
  'molecule-shapes',
  'molecule-shapes-basics',
  'natural-selection',
  'neuron',
  'number-line-integers',
  'number-play',
  'ohms-law',
  'optics-lab',
  'pendulum-lab',
  'ph-scale',
  'ph-scale-basics',
  'phet-io-test-sim',
  'plinko-probability',
  'projectile-motion',
  'proportion-playground',
  'reactants-products-and-leftovers',
  'resistance-in-a-wire',
  'rutherford-scattering',
  'simula-rasa',
  'states-of-matter',
  'states-of-matter-basics',
  'trig-tour',
  'under-pressure',
  'unit-rates',
  'vector-addition',
  'vector-addition-equations',
  'wave-interference',
  'wave-on-a-string',
  'waves-intro',
  'wilder'
];

const commonRepos = [
  'area-model-common',
  'axon',
  'brand',
  'circuit-construction-kit-common',
  'density-buoyancy-common',
  'dot',
  'fractions-common',
  'griddle',
  'inverse-square-law-common',
  'joist',
  'kite',
  'mobius',
  'nitroglycerin',
  'phetcommon',
  'phet-core',
  'phet-io',
  'scenery-phet', // has to run first for string replacements
  'scenery',
  'shred',
  'sun',
  'tambo',
  'tandem',
  'twixt',
  'utterance-queue',
  'vegas',
  'vibe'
];
const repos = [
  ...simRepos,
  ...commonRepos
];

const replace = ( str, search, replacement ) => {
  return str.split( search ).join( replacement );
};

const migrateFile = async ( repo, relativeFile ) => {
  if ( relativeFile.endsWith( '/PhetioIDUtils.js' ) ) {
    return;
  }
  if ( relativeFile.endsWith( '/copyWithSortedKeys.js' ) ) {
    return;
  }
  const path = '../' + repo + '/' + relativeFile;

  let contents = fs.readFileSync( path, 'utf-8' );
  contents = replace( contents, '= require( \'string!', `= 'test string';//` );
  contents = replace( contents, '= require( \'ifphetio!', '= function(){return function(){ return function(){}; };}; // ' );

  contents = replace( contents, 'require( \'text!REPOSITORY/package.json\' )', 'JSON.stringify( phet.chipper.packageObject )' );

  if ( contents.includes( 'define( require => {' ) ) {
    contents = replace( contents, `define( require => {`, `` );
    contents = contents.slice( 0, contents.lastIndexOf( '}' ) );
  }

  const returnInherit = contents.lastIndexOf( 'return inherit( ' );
  if ( returnInherit >= 0 ) {
    contents = replace( contents, `return inherit( `, `export default inherit( ` );
  }

  const lastReturn = contents.lastIndexOf( 'return ' );
  if ( lastReturn >= 0 && returnInherit === -1 ) {
    contents = contents.substring( 0, lastReturn ) + 'export default ' + contents.substring( lastReturn + 'return '.length );
  }

  let lines = contents.split( /\r?\n/ );

  let fixMipmap = line => {
    if ( line.trim().startsWith( 'import ' ) && line.indexOf( `from 'mipmap!` ) >= 0 ) {
      const term = line.trim().split( ' ' )[ 1 ];
      const repo = line.substring( line.indexOf( '!' ) + 1, line.indexOf( '/' ) );
      const tail = line.substring( line.indexOf( '/' ) + 1 );
      line = `  import ${term} from 'mipmap!${repo}/../images/${tail}`;
    }
    return line;
  };

  let fixImage = line => {
    if ( line.trim().startsWith( 'import ' ) && line.indexOf( `from 'image!` ) >= 0 ) {
      const term = line.trim().split( ' ' )[ 1 ];
      const repo = line.substring( line.indexOf( '!' ) + 1, line.indexOf( '/' ) );
      const tail = line.substring( line.indexOf( '/' ) + 1 );
      line = `  import ${term} from '${repo}/../images/${tail}`;
    }
    return line;
  };

  let fixSounds = line => {
    if ( line.trim().startsWith( 'import ' ) && line.indexOf( `from 'sound!` ) >= 0 ) {
      const term = line.trim().split( ' ' )[ 1 ];
      const repo = line.substring( line.indexOf( '!' ) + 1, line.indexOf( '/' ) );
      const tail = line.substring( line.indexOf( '/' ) + 1 );
      line = `import ${term} from '${repo}/../sounds/${tail}`;
    }
    return line;
  };

  lines = lines.map( line => {
    if ( line.trim().startsWith( 'const ' ) && line.indexOf( ' = require( ' ) >= 0 ) {
      // const Bounds2 = require( 'DOT/Bounds2' );
      // becomes
      // import Bounds2 from 'DOT/Bounds2';
      line = replace( line, 'const ', 'import ' );
      line = replace( line, ' = require( ', ' from ' );
      line = replace( line, '\' );', '\';' );
    }
    line = fixMipmap( line );
    line = fixImage( line );
    line = fixSounds( line );

    // Trim off indentation
    if ( line.startsWith( '  ' ) ) {
      line = line.slice( 2 );
    }

    return line;
  } );

  // Omit 'use strict' directives
  lines = lines.filter( line => line.trim() !== '\'use strict\';' );

  contents = lines.join( '\n' );

  // Seems to be for inherit.js
  contents = replace( contents, `return inherit;`, `export default inherit;` );
  contents = replace( contents, `' ).default;`, `';` );

  // Specify absolute paths for compilation-free mode
  repos.forEach( repo => {
    let upper = repo.toUpperCase();
    upper = replace( upper, '-', '_' );
    contents = replace( contents, `from '${upper}`, `from '/${repo}/js` );
  } );

  // Any export default that is not the last line (when trimmed) should be turned back into return.

  lines = contents.split( /\r?\n/ );
  for ( var i = 0; i < lines.length - 2; i++ ) {
    if ( lines[ i ].indexOf( 'inherit(' ) === -1 ) {
      lines[ i ] = replace( lines[ i ], 'export default ', 'return ' );
    }

    // import magnifierImage from '/acid-base-solutions/js/../images/magnifier-icon.png';
    if ( lines[ i ].indexOf( 'import ' ) >= 0 && lines[ i ].indexOf( ' from ' ) >= 0 && lines[ i ].indexOf( '.png' ) >= 0 ) {
      lines[ i ] = replace( lines[ i ], '.png', '_png' );
    }

    if ( lines[ i ].indexOf( 'import ' ) >= 0 && lines[ i ].indexOf( ' from ' ) >= 0 && lines[ i ].indexOf( '.mp3' ) >= 0 ) {
      lines[ i ] = replace( lines[ i ], '.mp3', '_mp3' );
    }

    if ( lines[ i ].indexOf( 'import ' ) >= 0 && lines[ i ].indexOf( ' from ' ) >= 0 && lines[ i ].indexOf( '.wav' ) >= 0 ) {
      lines[ i ] = replace( lines[ i ], '.wav', '_wav' );
    }
  }
  contents = lines.join( '\n' );
  contents = replace( contents, `from '/brand/js/`, `from '/brand/phet/js/` );// TODO: how to deal with different brands?

  contents = replace( contents, `return scenery.register( 'SceneryStyle'`, `export default scenery.register( 'SceneryStyle'` );

  // TODO: mipmap plugin
  contents = replace( contents, `import offImage from 'mipmap!SCENERY_PHET/../images/light-bulb-off_png';`, `import offImage from '/scenery-phet/images/light-bulb-off_png';` );
  contents = replace( contents, `import onImage from 'mipmap!SCENERY_PHET/../images/light-bulb-on_png';`, `import onImage from '/scenery-phet/images/light-bulb-on_png';` );
  contents = replace( contents, `require( 'SCENERY/display/BackboneDrawable' );`, `import BackboneDrawable from  '/scenery/js/display/BackboneDrawable'` );

  const stringsToConvertReturnBackToExportDefault = [
    'return AlertableDef;',
    'return RadioButtonGroupAppearance;',
    'return joist.register( \'UpdateState\', Enumeration.byKeys( ['
  ];

  stringsToConvertReturnBackToExportDefault.forEach( string => {
    const withExport = replace( string, 'return ', 'export default ' );
    contents = replace( contents, string, withExport );
  } );

  fs.writeFileSync( path, contents, 'utf-8' );
};

module.exports = async function( repo, cache ) {

  // const repos = fs.readFileSync( '../perennial/data/migrate-repos', 'utf-8' ).trim().split( /\r?\n/ ).map( sim => sim.trim() );

  // Run a subset for fast iteration.
  let myrepos = [ 'acid-base-solutions', ...commonRepos ];
  // let myrepos = repos;
  for ( const repo of myrepos ) {
    console.log( repo );
    let relativeFiles = [];
    grunt.file.recurse( `../${repo}`, ( abspath, rootdir, subdir, filename ) => {
      relativeFiles.push( `${subdir}/${filename}` );
    } );
    relativeFiles = relativeFiles.filter( file => file.startsWith( 'js/' ) ||

                                                  // that's for brand
                                                  file.startsWith( 'phet/js' ) );

    relativeFiles.forEach( ( rel, i ) => {
      migrateFile( repo, rel );
    } );

    if ( simRepos.includes( repo ) ) {
      generateDevelopmentHTML( repo );
    }
  }
};<commit_msg>Use relative paths, see https://github.com/phetsims/chipper/issues/820<commit_after>// Copyright 2019, University of Colorado Boulder

/* eslint-disable */

/**
 * Prototyping for https://github.com/phetsims/chipper/issues/820
 *
 * @param {Object} grunt
 * @param {Object} gruntConfig
 */

'use strict';

const execute = require( './execute' );
const fs = require( 'fs' );
const grunt = require( 'grunt' );
const generateDevelopmentHTML = require( './generateDevelopmentHTML' );

const simRepos = [
  'acid-base-solutions',
  'area-builder',
  'area-model-algebra',
  'area-model-decimals',
  'area-model-introduction',
  'area-model-multiplication',
  'arithmetic',
  'atomic-interactions',
  'balancing-act',
  'balancing-chemical-equations',
  'balloons-and-static-electricity',
  'beers-law-lab',
  'bending-light',
  'blackbody-spectrum',
  'blast',
  'build-a-fraction',
  'build-a-molecule',
  'build-an-atom',
  'bumper',
  'buoyancy',
  'calculus-grapher',
  'capacitor-lab-basics',
  'chains',
  'charges-and-fields',
  'circuit-construction-kit-ac',
  'circuit-construction-kit-black-box-study',
  'circuit-construction-kit-dc',
  'circuit-construction-kit-dc-virtual-lab',
  'color-vision',
  'collision-lab',
  'concentration',
  'coulombs-law',
  'curve-fitting',
  'density',
  'diffusion',
  'energy-forms-and-changes',
  'energy-skate-park',
  'energy-skate-park-basics',
  'equality-explorer',
  'equality-explorer-basics',
  'equality-explorer-two-variables',
  'estimation',
  'example-sim',
  'expression-exchange',
  'faradays-law',
  'fluid-pressure-and-flow',
  'forces-and-motion-basics',
  'fraction-comparison',
  'fraction-matcher',
  'fractions-equality',
  'fractions-intro',
  'fractions-mixed-numbers',
  'friction',
  'function-builder',
  'function-builder-basics',
  'gas-properties',
  'gases-intro',
  'gene-expression-essentials',
  'graphing-lines',
  'graphing-quadratics',
  'graphing-slope-intercept',
  'gravity-and-orbits',
  'gravity-force-lab',
  'gravity-force-lab-basics',
  'hookes-law',
  'interaction-dashboard',
  'isotopes-and-atomic-mass',
  'john-travoltage',
  'least-squares-regression',
  'make-a-ten',
  'masses-and-springs',
  'masses-and-springs-basics',
  'models-of-the-hydrogen-atom',
  'molarity',
  'molecules-and-light',
  'molecule-polarity',
  'molecule-shapes',
  'molecule-shapes-basics',
  'natural-selection',
  'neuron',
  'number-line-integers',
  'number-play',
  'ohms-law',
  'optics-lab',
  'pendulum-lab',
  'ph-scale',
  'ph-scale-basics',
  'phet-io-test-sim',
  'plinko-probability',
  'projectile-motion',
  'proportion-playground',
  'reactants-products-and-leftovers',
  'resistance-in-a-wire',
  'rutherford-scattering',
  'simula-rasa',
  'states-of-matter',
  'states-of-matter-basics',
  'trig-tour',
  'under-pressure',
  'unit-rates',
  'vector-addition',
  'vector-addition-equations',
  'wave-interference',
  'wave-on-a-string',
  'waves-intro',
  'wilder'
];

const commonRepos = [
  'area-model-common',
  'axon',
  'brand',
  'circuit-construction-kit-common',
  'density-buoyancy-common',
  'dot',
  'fractions-common',
  'griddle',
  'inverse-square-law-common',
  'joist',
  'kite',
  'mobius',
  'nitroglycerin',
  'phetcommon',
  'phet-core',
  'phet-io',
  'scenery-phet', // has to run first for string replacements
  'scenery',
  'shred',
  'sun',
  'tambo',
  'tandem',
  'twixt',
  'utterance-queue',
  'vegas',
  'vibe'
];
const repos = [
  ...simRepos,
  ...commonRepos
];

const replace = ( str, search, replacement ) => {
  return str.split( search ).join( replacement );
};

const migrateFile = async ( repo, relativeFile ) => {
  if ( relativeFile.endsWith( '/PhetioIDUtils.js' ) ) {
    return;
  }
  if ( relativeFile.endsWith( '/copyWithSortedKeys.js' ) ) {
    return;
  }
  const path = '../' + repo + '/' + relativeFile;

  let contents = fs.readFileSync( path, 'utf-8' );
  contents = replace( contents, '= require( \'string!', `= 'test string';//` );
  contents = replace( contents, '= require( \'ifphetio!', '= function(){return function(){ return function(){}; };}; // ' );

  contents = replace( contents, 'require( \'text!REPOSITORY/package.json\' )', 'JSON.stringify( phet.chipper.packageObject )' );

  if ( contents.includes( 'define( require => {' ) ) {
    contents = replace( contents, `define( require => {`, `` );
    contents = contents.slice( 0, contents.lastIndexOf( '}' ) );
  }

  const returnInherit = contents.lastIndexOf( 'return inherit( ' );
  if ( returnInherit >= 0 ) {
    contents = replace( contents, `return inherit( `, `export default inherit( ` );
  }

  const lastReturn = contents.lastIndexOf( 'return ' );
  if ( lastReturn >= 0 && returnInherit === -1 ) {
    contents = contents.substring( 0, lastReturn ) + 'export default ' + contents.substring( lastReturn + 'return '.length );
  }

  let lines = contents.split( /\r?\n/ );

  let fixMipmap = line => {
    if ( line.trim().startsWith( 'import ' ) && line.indexOf( `from 'mipmap!` ) >= 0 ) {
      const term = line.trim().split( ' ' )[ 1 ];
      const repo = line.substring( line.indexOf( '!' ) + 1, line.indexOf( '/' ) );
      const tail = line.substring( line.indexOf( '/' ) + 1 );
      line = `  import ${term} from 'mipmap!${repo}/../images/${tail}`;
    }
    return line;
  };

  let fixImage = line => {
    if ( line.trim().startsWith( 'import ' ) && line.indexOf( `from 'image!` ) >= 0 ) {
      const term = line.trim().split( ' ' )[ 1 ];
      const repo = line.substring( line.indexOf( '!' ) + 1, line.indexOf( '/' ) );
      const tail = line.substring( line.indexOf( '/' ) + 1 );
      line = `  import ${term} from '${repo}/../images/${tail}`;
    }
    return line;
  };

  let fixSounds = line => {
    if ( line.trim().startsWith( 'import ' ) && line.indexOf( `from 'sound!` ) >= 0 ) {
      const term = line.trim().split( ' ' )[ 1 ];
      const repo = line.substring( line.indexOf( '!' ) + 1, line.indexOf( '/' ) );
      const tail = line.substring( line.indexOf( '/' ) + 1 );
      line = `import ${term} from '${repo}/../sounds/${tail}`;
    }
    return line;
  };

  lines = lines.map( line => {
    if ( line.trim().startsWith( 'const ' ) && line.indexOf( ' = require( ' ) >= 0 ) {
      // const Bounds2 = require( 'DOT/Bounds2' );
      // becomes
      // import Bounds2 from 'DOT/Bounds2';
      line = replace( line, 'const ', 'import ' );
      line = replace( line, ' = require( ', ' from ' );
      line = replace( line, '\' );', '\';' );
    }
    line = fixMipmap( line );
    line = fixImage( line );
    line = fixSounds( line );

    // Trim off indentation
    if ( line.startsWith( '  ' ) ) {
      line = line.slice( 2 );
    }

    return line;
  } );

  // Omit 'use strict' directives
  lines = lines.filter( line => line.trim() !== '\'use strict\';' );

  contents = lines.join( '\n' );

  // Seems to be for inherit.js
  contents = replace( contents, `return inherit;`, `export default inherit;` );
  contents = replace( contents, `' ).default;`, `';` );

  // Specify absolute paths for compilation-free mode
  repos.forEach( repo => {
    let upper = repo.toUpperCase();
    upper = replace( upper, '-', '_' );
    contents = replace( contents, `from '${upper}`, `from '/${repo}/js` );
  } );

  // Any export default that is not the last line (when trimmed) should be turned back into return.

  lines = contents.split( /\r?\n/ );
  for ( var i = 0; i < lines.length - 2; i++ ) {
    if ( lines[ i ].indexOf( 'inherit(' ) === -1 ) {
      lines[ i ] = replace( lines[ i ], 'export default ', 'return ' );
    }

    // import magnifierImage from '/acid-base-solutions/js/../images/magnifier-icon.png';
    if ( lines[ i ].indexOf( 'import ' ) >= 0 && lines[ i ].indexOf( ' from ' ) >= 0 && lines[ i ].indexOf( '.png' ) >= 0 ) {
      lines[ i ] = replace( lines[ i ], '.png', '_png' );
    }

    if ( lines[ i ].indexOf( 'import ' ) >= 0 && lines[ i ].indexOf( ' from ' ) >= 0 && lines[ i ].indexOf( '.mp3' ) >= 0 ) {
      lines[ i ] = replace( lines[ i ], '.mp3', '_mp3' );
    }

    if ( lines[ i ].indexOf( 'import ' ) >= 0 && lines[ i ].indexOf( ' from ' ) >= 0 && lines[ i ].indexOf( '.wav' ) >= 0 ) {
      lines[ i ] = replace( lines[ i ], '.wav', '_wav' );
    }

    // Map to relative paths for compilation free mode
    const depth = relativeFile.split( '/' ).length;
    const createDots = d => {
      if ( d === 0 ) {
        return './';
      }
      else {
        let s = '';
        for ( let i = 0; i < d; i++ ) {
          s = s + '../';
        }
        return s;
      }
    };
    let key = ` from '/`;
    if ( lines[ i ].indexOf( 'import' ) >= 0 && lines[ i ].indexOf( key ) >= 0 ) {
      const index = lines[ i ].indexOf( key ) + key.length - 1;
      lines[ i ] = lines[ i ].substring( 0, index ) + createDots( depth ) + lines[ i ].substring( index + 1 );
    }

  }
  contents = lines.join( '\n' );
  // contents = replace( contents, `from '/brand/js/`, `from '/brand/phet/js/` );// TODO: how to deal with different brands? https://github.com/phetsims/chipper/issues/820
  contents = replace( contents, `../../brand/js/Brand`, `../../brand/phet/js/Brand` );
  contents = replace( contents, `import brand from '../../../brand/js/../../js/brand';`, `import brand from '../../../brand/js/brand';` );
  contents = replace( contents, `import getLinks from '../../../brand/js/../../js/getLinks';`, `import getLinks from '../../../brand/js/getLinks';` );
  contents = replace( contents, `from '../../brand/js/../images`, `from '../../brand/phet/images` );
  contents = replace( contents, `import brand from '../../brand/js/../../js/brand';`, `import brand from './brand';` );

  contents = replace( contents, `return scenery.register( 'SceneryStyle'`, `export default scenery.register( 'SceneryStyle'` );

  // TODO: mipmap plugin
  contents = replace( contents, `import offImage from 'mipmap!SCENERY_PHET/../images/light-bulb-off_png';`, `import offImage from '/scenery-phet/images/light-bulb-off_png';` );
  contents = replace( contents, `import onImage from 'mipmap!SCENERY_PHET/../images/light-bulb-on_png';`, `import onImage from '/scenery-phet/images/light-bulb-on_png';` );
  contents = replace( contents, `require( 'SCENERY/display/BackboneDrawable' );`, `import BackboneDrawable from  '/scenery/js/display/BackboneDrawable'` );

  const stringsToConvertReturnBackToExportDefault = [
    'return AlertableDef;',
    'return RadioButtonGroupAppearance;',
    'return joist.register( \'UpdateState\', Enumeration.byKeys( ['
  ];

  stringsToConvertReturnBackToExportDefault.forEach( string => {
    const withExport = replace( string, 'return ', 'export default ' );
    contents = replace( contents, string, withExport );
  } );

  fs.writeFileSync( path, contents, 'utf-8' );
};

module.exports = async function( repo, cache ) {

  // const repos = fs.readFileSync( '../perennial/data/migrate-repos', 'utf-8' ).trim().split( /\r?\n/ ).map( sim => sim.trim() );

  // Run a subset for fast iteration.
  let myrepos = [ 'acid-base-solutions', ...commonRepos ];
  // let myrepos = repos;
  for ( const repo of myrepos ) {
    console.log( repo );
    let relativeFiles = [];
    grunt.file.recurse( `../${repo}`, ( abspath, rootdir, subdir, filename ) => {
      relativeFiles.push( `${subdir}/${filename}` );
    } );
    relativeFiles = relativeFiles.filter( file => file.startsWith( 'js/' ) ||

                                                  // that's for brand
                                                  file.startsWith( 'phet/js' ) );

    relativeFiles.forEach( ( rel, i ) => {
      migrateFile( repo, rel );
    } );

    if ( simRepos.includes( repo ) ) {
      generateDevelopmentHTML( repo );
    }
  }
};<|endoftext|>


<commit_before>/*
 * Author: Tyler Russell
 * Contains an Authentication Service that provides functionality such as checking if
 * a user is logged in, logs a user in and out, and a static function that safeguards
 * protected states from unauthenticated users. Contains a service that stores the
 * user object returned from the DB, and checking if a user is authenticated is done
 * by checking the status of SessionService.user.
 * Also contains an app constant called AUTH_EVENTS, which should be used to broadcast
 * auth-related events app wide like: $rootScope.$on('$some-auth-event-name', ...)
 * Will be useful for allowing/denying access to parts of the app when user permissions
 * are implemented.
 */
require('angular').module('ays')
  .constant('AUTH_EVENTS', {
    loginSuccess: 'auth-login-success',
    loginFailed: 'auth-login-failed',
    logoutSuccess: 'auth-logout-success',
    loginWhileSessionValid: 'auth-login-with-valid-session',
    notAuthenticated: 'auth-not-authenticated', // this is broadcasted when a user isn't logged in
    notAuthorized: 'auth-not-authorized',
  })
  .factory('AuthService',
    ['$localStorage', '$sails', 'SessionService', 'HttpPendingRequestsService', '$rootScope', '$state',
    function ($localStorage, $sails, SessionService, HttpPendingRequestsService, $rootScope, $state) {
    var AuthService = {
      getUserAuthStatus: function () {
        // $http/$sails returns a promise, which has a then function, which also returns a promise
        var promise = $sails.get('/api/me')
          .then(function (response) {
            SessionService.user = response.data;
            return response;
          })
          .catch(function (error) {
            return error;
          });
        return promise;
      },
      login: function (credentials) {
        var promise = $sails.post('/api/login', credentials)
          .then(function (response) {
            SessionService.user = response.data;
            return response;
          })
          .catch(function (error) {
            return error;
          });
        return promise;
      },
      isAuthenticated: function () {
        return !!SessionService.user;
      },
      logout: function () {
        var promise = $sails.get('/api/logout')
          .then(function (response) {
            return response;
          })
          .catch(function (error) {
            return error;
          });
        SessionService.destroy();// reset saved user info in front-end no matter what
        return promise;
      },
      initStateGuard: function () {
        // run auth check for each url visited
        $rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState) {
          $localStorage.put('to_state_name', toState.name);
          $localStorage.put('from_state_name', fromState.name);
          AuthService.getUserAuthStatus().then(function (response) {
            if (response.status === 401) {
              if (toState.protected) {
                event.preventDefault();
                HttpPendingRequestsService.cancelAll(); // prevent all http requests
                // if user isnt authenticated and attempts to view a protected state,
                // redirect to login and store the desired view to redirect them back after
                $state.go('login', {toState: toState.name, toParams: toParams});
              }
            } else if (response.status === 200) {
              // if user is authenticated, dont make them log in again
              if (toState.url === '/login') {
                event.preventDefault();
                $state.transitionTo('intro');
              }
            }
          });
        });
      },
      initAppLoad: function () {
        // Handles browser refreshes with localstorage. If there's no from_state_name saved from the
        // initStateGuard method, then the app was just loaded.
        if ($localStorage.get('from_state_name') === '') {
          $state.go($localStorage.get('to_state_name'));
        } else {
          // set up Session Service on app load
          AuthService.getUserAuthStatus().then(function (response) {
            if (response.status === 401) {
              SessionService.user = null;
            } else if (response.status === 200) {
              SessionService.user = response.data;
              $state.go($localStorage.get('intro'));// redirect user
            }
          });
        }
      },
    };
    return AuthService;
  }])
  .service('SessionService', function () {
    this.create = function (user) {
      this.user = user;
    };
    this.destroy = function () {
      this.user = null;
    };
  });
<commit_msg>Improvement to #69 Defect: Browser Refresh Handling<commit_after>/*
 * Author: Tyler Russell
 * Contains an Authentication Service that provides functionality such as checking if
 * a user is logged in, logs a user in and out, and a static function that safeguards
 * protected states from unauthenticated users. Contains a service that stores the
 * user object returned from the DB, and checking if a user is authenticated is done
 * by checking the status of SessionService.user.
 * Also contains an app constant called AUTH_EVENTS, which should be used to broadcast
 * auth-related events app wide like: $rootScope.$on('$some-auth-event-name', ...)
 * Will be useful for allowing/denying access to parts of the app when user permissions
 * are implemented.
 */
require('angular').module('ays')
  .constant('AUTH_EVENTS', {
    loginSuccess: 'auth-login-success',
    loginFailed: 'auth-login-failed',
    logoutSuccess: 'auth-logout-success',
    loginWhileSessionValid: 'auth-login-with-valid-session',
    notAuthenticated: 'auth-not-authenticated', // this is broadcasted when a user isn't logged in
    notAuthorized: 'auth-not-authorized',
  })
  .factory('AuthService',
    ['$localStorage', '$sails', 'SessionService', 'HttpPendingRequestsService', '$rootScope', '$state',
    function ($localStorage, $sails, SessionService, HttpPendingRequestsService, $rootScope, $state) {
    var AuthService = {
      getUserAuthStatus: function () {
        // $http/$sails returns a promise, which has a then function, which also returns a promise
        var promise = $sails.get('/api/me')
          .then(function (response) {
            SessionService.user = response.data;
            return response;
          })
          .catch(function (error) {
            return error;
          });
        return promise;
      },
      login: function (credentials) {
        var promise = $sails.post('/api/login', credentials)
          .then(function (response) {
            SessionService.user = response.data;
            return response;
          })
          .catch(function (error) {
            return error;
          });
        return promise;
      },
      isAuthenticated: function () {
        return !!SessionService.user;
      },
      logout: function () {
        var promise = $sails.get('/api/logout')
          .then(function (response) {
            return response;
          })
          .catch(function (error) {
            return error;
          });
        SessionService.destroy();// reset saved user info in front-end no matter what
        return promise;
      },
      initStateGuard: function () {
        // run auth check for each url visited
        $rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState) {
          $localStorage.put('to_state_name', toState.name);
          $localStorage.put('from_state_name', fromState.name);
          AuthService.getUserAuthStatus().then(function (response) {
            if (response.status === 401) {
              if (toState.protected) {
                event.preventDefault();
                HttpPendingRequestsService.cancelAll(); // prevent all http requests
                // if user isnt authenticated and attempts to view a protected state,
                // redirect to login and store the desired view to redirect them back after
                $state.go('login', {toState: toState.name, toParams: toParams});
              }
            } else if (response.status === 200) {
              // if user is authenticated, dont make them log in again
              if (toState.url === '/login') {
                event.preventDefault();
                $state.transitionTo('intro');
              }
            }
          });
        });
      },
      initAppLoad: function () {
        // Handles browser refreshes with localstorage. If there's no from_state_name saved from the
        // initStateGuard method, then the app was just loaded.
        if ($localStorage.get('from_state_name') === '') {
          $state.go($localStorage.get('to_state_name'));
        } else {
          // set up Session Service on app load
          AuthService.getUserAuthStatus().then(function (response) {
            if (response.status === 401) {
              SessionService.user = null;
            } else if (response.status === 200) {
              SessionService.user = response.data;
              // console.log($localStorage.get('to_state_name'))
              // console.log($localStorage.get('from_state_name'))
              $state.go($localStorage.get('to_state_name'));
            }
          });
        }
      },
    };
    return AuthService;
  }])
  .service('SessionService', function () {
    this.create = function (user) {
      this.user = user;
    };
    this.destroy = function () {
      this.user = null;
    };
  });
<|endoftext|>