<commit_before>/**
 * External dependencies
 */
import { get } from 'lodash';

/**
 * WordPress dependencies
 */
import {
	clearLocalStorage,
	enablePageDialogAccept,
	setBrowserViewport,
} from '@wordpress/e2e-test-utils';

/**
 * Environment variables
 */
const { PUPPETEER_TIMEOUT } = process.env;

/**
 * Set of console logging types observed to protect against unexpected yet
 * handled (i.e. not catastrophic) errors or warnings. Each key corresponds
 * to the Puppeteer ConsoleMessage type, its value the corresponding function
 * on the console global object.
 *
 * @type {Object<string,string>}
 */
const OBSERVED_CONSOLE_MESSAGE_TYPES = {
	warning: 'warn',
	error: 'error',
};

/**
 * Array of page event tuples of [ eventName, handler ].
 *
 * @type {Array}
 */
const pageEvents = [];

// The Jest timeout is increased because these tests are a bit slow
jest.setTimeout( PUPPETEER_TIMEOUT || 100000 );

/**
 * Adds an event listener to the page to handle additions of page event
 * handlers, to assure that they are removed at test teardown.
 */
function capturePageEventsForTearDown() {
	page.on( 'newListener', ( eventName, listener ) => {
		pageEvents.push( [ eventName, listener ] );
	} );
}

/**
 * Removes all bound page event handlers.
 */
function removePageEvents() {
	pageEvents.forEach( ( [ eventName, handler ] ) => {
		page.removeListener( eventName, handler );
	} );
}

/**
 * Adds a page event handler to emit uncaught exception to process if one of
 * the observed console logging types is encountered.
 */
function observeConsoleLogging() {
	page.on( 'console', ( message ) => {
		const type = message.type();
		if ( ! OBSERVED_CONSOLE_MESSAGE_TYPES.hasOwnProperty( type ) ) {
			return;
		}

		let text = message.text();

		// An exception is made for _blanket_ deprecation warnings: Those
		// which log regardless of whether a deprecated feature is in use.
		if ( text.includes( 'This is a global warning' ) ) {
			return;
		}

		// Viewing posts on the front end can result in this error, which
		// has nothing to do with Gutenberg.
		if ( text.includes( 'net::ERR_UNKNOWN_URL_SCHEME' ) ) {
			return;
		}

		// A bug present in WordPress 5.2 will produce console warnings when
		// loading the Dashicons font. These can be safely ignored, as they do
		// not otherwise regress on application behavior. This logic should be
		// removed once the associated ticket has been closed.
		//
		// See: https://core.trac.wordpress.org/ticket/47183
		if (
			text.startsWith( 'Failed to decode downloaded font:' ) ||
			text.startsWith( 'OTS parsing error:' )
		) {
			return;
		}

		const logFunction = OBSERVED_CONSOLE_MESSAGE_TYPES[ type ];

		// As of Puppeteer 1.6.1, `message.text()` wrongly returns an object of
		// type JSHandle for error logging, instead of the expected string.
		//
		// See: https://github.com/GoogleChrome/puppeteer/issues/3397
		//
		// The recommendation there to asynchronously resolve the error value
		// upon a console event may be prone to a race condition with the test
		// completion, leaving a possibility of an error not being surfaced
		// correctly. Instead, the logic here synchronously inspects the
		// internal object shape of the JSHandle to find the error text. If it
		// cannot be found, the default text value is used instead.
		text = get( message.args(), [ 0, '_remoteObject', 'description' ], text );

		// Disable reason: We intentionally bubble up the console message
		// which, unless the test explicitly anticipates the logging via
		// @wordpress/jest-console matchers, will cause the intended test
		// failure.

		// eslint-disable-next-line no-console
		console[ logFunction ]( text );
	} );
}

// Before every test suite run, delete all content created by the test. This ensures
// other posts/comments/etc. aren't dirtying tests and tests don't depend on
// each other's side-effects.
beforeAll( async() => {
	capturePageEventsForTearDown();
	enablePageDialogAccept();
	observeConsoleLogging();
	await setBrowserViewport( 'large' );
} );

afterEach( async() => {
	await clearLocalStorage();
	await setBrowserViewport( 'large' );
} );

afterAll( () => {
	removePageEvents();
} );
<commit_msg>add rest request/response debug helper for e2e<commit_after>/**
 * External dependencies
 */
import { get } from 'lodash';

/**
 * WordPress dependencies
 */
import {
	clearLocalStorage,
	enablePageDialogAccept,
	setBrowserViewport,
} from '@wordpress/e2e-test-utils';

/**
 * Environment variables
 */
const { PUPPETEER_TIMEOUT } = process.env;

/**
 * Set of console logging types observed to protect against unexpected yet
 * handled (i.e. not catastrophic) errors or warnings. Each key corresponds
 * to the Puppeteer ConsoleMessage type, its value the corresponding function
 * on the console global object.
 *
 * @type {Object<string,string>}
 */
const OBSERVED_CONSOLE_MESSAGE_TYPES = {
	warning: 'warn',
	error: 'error',
};

/**
 * Array of page event tuples of [ eventName, handler ].
 *
 * @type {Array}
 */
const pageEvents = [];

// The Jest timeout is increased because these tests are a bit slow
jest.setTimeout( PUPPETEER_TIMEOUT || 100000 );

/**
 * Adds an event listener to the page to handle additions of page event
 * handlers, to assure that they are removed at test teardown.
 */
function capturePageEventsForTearDown() {
	page.on( 'newListener', ( eventName, listener ) => {
		pageEvents.push( [ eventName, listener ] );
	} );
}

/**
 * Removes all bound page event handlers.
 */
function removePageEvents() {
	pageEvents.forEach( ( [ eventName, handler ] ) => {
		page.removeListener( eventName, handler );
	} );
}

/**
 * Adds a page event handler to emit uncaught exception to process if one of
 * the observed console logging types is encountered.
 */
function observeConsoleLogging() {
	page.on( 'console', ( message ) => {
		const type = message.type();
		if ( ! OBSERVED_CONSOLE_MESSAGE_TYPES.hasOwnProperty( type ) ) {
			return;
		}

		let text = message.text();

		// An exception is made for _blanket_ deprecation warnings: Those
		// which log regardless of whether a deprecated feature is in use.
		if ( text.includes( 'This is a global warning' ) ) {
			return;
		}

		// Viewing posts on the front end can result in this error, which
		// has nothing to do with Gutenberg.
		if ( text.includes( 'net::ERR_UNKNOWN_URL_SCHEME' ) ) {
			return;
		}

		// A bug present in WordPress 5.2 will produce console warnings when
		// loading the Dashicons font. These can be safely ignored, as they do
		// not otherwise regress on application behavior. This logic should be
		// removed once the associated ticket has been closed.
		//
		// See: https://core.trac.wordpress.org/ticket/47183
		if (
			text.startsWith( 'Failed to decode downloaded font:' ) ||
			text.startsWith( 'OTS parsing error:' )
		) {
			return;
		}

		const logFunction = OBSERVED_CONSOLE_MESSAGE_TYPES[ type ];

		// As of Puppeteer 1.6.1, `message.text()` wrongly returns an object of
		// type JSHandle for error logging, instead of the expected string.
		//
		// See: https://github.com/GoogleChrome/puppeteer/issues/3397
		//
		// The recommendation there to asynchronously resolve the error value
		// upon a console event may be prone to a race condition with the test
		// completion, leaving a possibility of an error not being surfaced
		// correctly. Instead, the logic here synchronously inspects the
		// internal object shape of the JSHandle to find the error text. If it
		// cannot be found, the default text value is used instead.
		text = get( message.args(), [ 0, '_remoteObject', 'description' ], text );

		// Disable reason: We intentionally bubble up the console message
		// which, unless the test explicitly anticipates the logging via
		// @wordpress/jest-console matchers, will cause the intended test
		// failure.

		// eslint-disable-next-line no-console
		console[ logFunction ]( text );
	} );
}

/**
 * Observe the given REST request.
 */
function observeRestRequest( req ) {
	if ( req.url().match( 'wp-json' ) ) {
		// eslint-disable-next-line no-console
		console.log( '>>>', req.method(), req.url(), req.postData() );
	}
}

/**
 * Observe the given REST response.
 */
async function observeRestResponse( res ) {
	if ( res.url().match( 'wp-json' ) ) {
		const args = [ res.status(), res.request().method(), res.url() ];

		// The response may fail to resolve if the test ends before it completes.
		try {
			args.push( await res.text() );
		} catch ( err ) {} // eslint-disable-line no-empty

		// eslint-disable-next-line no-console
		console.log( ...args );
	}
}

// Before every test suite run, delete all content created by the test. This ensures
// other posts/comments/etc. aren't dirtying tests and tests don't depend on
// each other's side-effects.
beforeAll( async() => {
	capturePageEventsForTearDown();
	enablePageDialogAccept();
	observeConsoleLogging();
	if ( process.env.DEBUG_REST ) {
		page.on( 'request', observeRestRequest );
		page.on( 'response', observeRestResponse );
	}
	await setBrowserViewport( 'large' );
} );

afterEach( async() => {
	await clearLocalStorage();
	await setBrowserViewport( 'large' );
} );

afterAll( () => {
	removePageEvents();
} );
<|endoftext|>


<commit_before>(function(googleUtils) {
  function randomString4() {
    return Math.floor((1 + Math.random()) * 0x10000)
      .toString(16)
      .substring(1);
  };

  function openPhotoSwipe(imageInfos, galleryUid, index, thumbToAnimateFrom) {
    var pswpItems = imageInfos.map(function(imageInfo) {
      return {
        src: imageInfo.url,
        msrc: imageInfo.thumbUrl,
        w: imageInfo.thumbWidth,
        h: imageInfo.thumbHeight,
        pid: encodeURIComponent(imageInfo.url)
      };
    });

    var pswpElement = document.querySelectorAll('.pswp')[0];

    if(thumbToAnimateFrom) {
      var getThumbBoundsFn = function(index) {
        var pageYScroll = window.pageYOffset || document.documentElement.scrollTop;
        var rect = thumbToAnimateFrom.getBoundingClientRect();
        return {x:rect.left, y:rect.top + pageYScroll, w:rect.width};
      }
    }

    var pswpOptions = {
      index: index,
      showHideOpacity: true,
      preload: [1,1],
      getThumbBoundsFn: getThumbBoundsFn,
      galleryUid: galleryUid,
      galleryPIDs: true,
      captionEl: false,
      shareEl: false
    };

    var pswp = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, pswpItems, pswpOptions);

    pswp.listen('imageLoadComplete', function(index, item) {
      for(var i = 0; i < item.container.childNodes.length; ++i) {
        if(item.container.childNodes[i].src == item.src) {
          item.w = item.container.childNodes[i].naturalWidth;
          item.h = item.container.childNodes[i].naturalHeight;
          pswp.updateSize(true);
          break;
        }
      }
    });

    pswp.init();
  };

  function parseHash(hash) {
    var params = {};
    if(hash.length < 6) {
        return params;
    }
    var vars = hash.substring(1).split('&');
    for (var i = 0; i < vars.length; i++) {
        if(!vars[i]) {
            continue;
        }
        var pair = vars[i].split('=');
        if(pair.length < 2) {
            continue;
        }
        params[pair[0]] = pair[1];
    }
    return params;
  };

  var hashArgs = parseHash(window.location.hash);

  var galleries = document.querySelectorAll('.gallery');
  for (var galleryId = 0; galleryId < galleries.length; ++galleryId) {
    (function (gallery) {
      var msnry = new Masonry(gallery, {
        itemSelector: '.grid-item',
        isFitWidth: true
      });

      googleUtils.getImageUrlsForFolder(gallery.getAttribute('data-drive-link'), function(imageUrls) {
        var imageInfos = imageUrls.map(function(imageUrl) {
          return {
            url: imageUrl,
            thumbUrl: googleUtils.getCachedImageUrl(imageUrl, { maxWidth: 240 }),
            thumbHeight: 240,
            thumbWidth: 240
          }
        });
        imageInfos.forEach(function(imageInfo, index) {
          var thumb = document.createElement('img');
          thumb.onload = function() {
            imageInfo.thumbHeight = thumb.naturalHeight;
            imageInfo.thumbWidth = thumb.naturalWidth;
            var anchor = document.createElement('a');
            anchor.href = imageInfo.url;
            anchor.appendChild(thumb);
            var div = document.createElement('div');
            div.className = 'grid-item';
            div.appendChild(anchor);
            gallery.appendChild(div);
            msnry.addItems(div);
            msnry.layout();
            div.onclick = function() {
              openPhotoSwipe(imageInfos, galleryId, index, thumb);
              return false;
            };
          };
          thumb.src = imageInfo.thumbUrl;
        });

        if(hashArgs.gid == galleryId) {
          openPhotoSwipe(imageInfos, galleryId);
        }
      });

    })(galleries[galleryId]);
  };
})(googleUtils);

<commit_msg>Improve transition out of photoswipe<commit_after>(function(googleUtils) {
  function randomString4() {
    return Math.floor((1 + Math.random()) * 0x10000)
      .toString(16)
      .substring(1);
  };

  function openPhotoSwipe(imageInfos, galleryUid, index) {
    var pswpItems = imageInfos.map(function(imageInfo) {
      return {
        src: imageInfo.url,
        msrc: imageInfo.thumbUrl,
        w: imageInfo.thumbWidth,
        h: imageInfo.thumbHeight,
        pid: encodeURIComponent(imageInfo.url)
      };
    });

    var pswpElement = document.querySelectorAll('.pswp')[0];

    var getThumbBoundsFn = function(index) {
      if (imageInfos[index].thumbElement) {
        var pageYScroll = window.pageYOffset || document.documentElement.scrollTop;
        var rect = imageInfos[index].thumbElement.getBoundingClientRect();
        return {x:rect.left, y:rect.top + pageYScroll, w:rect.width};
      } else {
        return { x:0, y:0, w:0 };
      }
    }

    var pswpOptions = {
      index: index,
      showHideOpacity: true,
      preload: [1,1],
      getThumbBoundsFn: getThumbBoundsFn,
      galleryUid: galleryUid,
      galleryPIDs: true,
      captionEl: false,
      shareEl: false
    };

    var pswp = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, pswpItems, pswpOptions);

    pswp.listen('imageLoadComplete', function(index, item) {
      for(var i = 0; i < item.container.childNodes.length; ++i) {
        if(item.container.childNodes[i].src == item.src) {
          item.w = item.container.childNodes[i].naturalWidth;
          item.h = item.container.childNodes[i].naturalHeight;
          pswp.updateSize(true);
          break;
        }
      }
    });

    pswp.init();
  };

  function parseHash(hash) {
    var params = {};
    if(hash.length < 6) {
        return params;
    }
    var vars = hash.substring(1).split('&');
    for (var i = 0; i < vars.length; i++) {
        if(!vars[i]) {
            continue;
        }
        var pair = vars[i].split('=');
        if(pair.length < 2) {
            continue;
        }
        params[pair[0]] = pair[1];
    }
    return params;
  };

  var hashArgs = parseHash(window.location.hash);

  var galleries = document.querySelectorAll('.gallery');
  for (var galleryId = 0; galleryId < galleries.length; ++galleryId) {
    (function (gallery) {
      var msnry = new Masonry(gallery, {
        itemSelector: '.grid-item',
        isFitWidth: true
      });

      googleUtils.getImageUrlsForFolder(gallery.getAttribute('data-drive-link'), function(imageUrls) {
        var imageInfos = imageUrls.map(function(imageUrl) {
          return {
            url: imageUrl,
            thumbUrl: googleUtils.getCachedImageUrl(imageUrl, { maxWidth: 240 }),
            thumbHeight: 240,
            thumbWidth: 240
          }
        });
        imageInfos.forEach(function(imageInfo, index) {
          var thumb = document.createElement('img');
          imageInfo.thumbElement = thumb;
          thumb.onload = function() {
            imageInfo.thumbHeight = thumb.naturalHeight;
            imageInfo.thumbWidth = thumb.naturalWidth;
            var anchor = document.createElement('a');
            anchor.href = imageInfo.url;
            anchor.appendChild(thumb);
            var div = document.createElement('div');
            div.className = 'grid-item';
            div.appendChild(anchor);
            gallery.appendChild(div);
            msnry.appended(div);
            msnry.layout();
            div.onclick = function() {
              openPhotoSwipe(imageInfos, galleryId, index);
              return false;
            };
          };
          thumb.src = imageInfo.thumbUrl;
        });

        if(hashArgs.gid == galleryId) {
          openPhotoSwipe(imageInfos, galleryId);
        }
      });

    })(galleries[galleryId]);
  };
})(googleUtils);

<|endoftext|>


<commit_before>import {
    INSTALL_STATE,
    UPDATE_STATE,
    NORMAL_STATE
} from '../.utils/chrome/extension-state'

const messages = [
    {
        state: INSTALL_STATE,
        value: 'Thank you. This extension is free, but if you want to support development of this or my other projects, [buy me a beer](https://www.google.com)'
    },
    {
        state: UPDATE_STATE,
        value: 'The extension has been successfully updated!'
    }
]

export default messages
<commit_msg>disable message after installation<commit_after>import {
    INSTALL_STATE,
    UPDATE_STATE,
    NORMAL_STATE
} from '../.utils/chrome/extension-state'

const messages = [
    /*{
        state: INSTALL_STATE,
        value: 'Thank you. This extension is free, but if you want to support development of this or my other projects, [buy me a beer](https://www.google.com)'
    },*/
    {
        state: UPDATE_STATE,
        value: 'The extension has been successfully updated!'
    }
]

export default messages
<|endoftext|>


<commit_before>import React from 'react';
import { expect } from 'chai';
import { shallow } from 'enzyme';
import PropForm from '../index';

describe('<PropForm />', () => {
  it('contains h2 header', () => {
    const propForm = shallow(<PropForm />);
    expect(propForm.contains(
Props
)).to.equal(true);
  });
});
<commit_msg>Added PropForm Component Tests<commit_after>import React from 'react';
import { expect } from 'chai';
import sinon from 'sinon';
import { shallow, mount } from 'enzyme';

import PropForm from '../index';
import RandomButton from '../../common/RandomButton';

// controls
const EnumControl = () =>
EnumControl
;
const IntegerControl = ({ onUpdate, min, max }) =>

  Integer Control
  Click
  min: {min}
  max: {max}

;
const StringControl = ({ title }) =>
StringControl {title}
;

// props
const onRandomClick = sinon.spy();
const onVariationPropsChange = sinon.spy();
const variationProps = {
  children: 'some-button-text',
  className: 'btn-class',
  type: 'submit',
};
const metadataWithControls = {
  className: {
    required: false,
    description: '',
    name: 'string',
    control: <IntegerControl min={10} max={100} />,
  },
  type: {
    required: false,
    description: '',
    name: 'enum',
    control: <EnumControl />,
    value: [
      { value: 'submit', computed: false },
      { value: 'reset', computed: false },
      { value: 'button', computed: false },
    ],
  },
  children: {
    required: true,
    description: '',
    name: 'node',
    control: <StringControl title="some-random-title" />,
  },
};

let wrapper;

describe('<PropForm />', () => {
  beforeEach(() => {
    wrapper = shallow(<PropForm
      variationPath="abc"
      variationProps={variationProps}
      onRandomClick={onRandomClick}
      metadataWithControls={metadataWithControls}
      onVariationPropsChange={onVariationPropsChange}
    />);
  });

  it('renders the random button', () => {
    expect(wrapper.containsMatchingElement(<RandomButton />)).to.equal(true);
  });

  it('renders all controls', () => {
    expect(wrapper.containsMatchingElement(<EnumControl />)).to.equal(true);
    expect(wrapper.containsMatchingElement(<IntegerControl />)).to.equal(true);
    expect(wrapper.containsMatchingElement(<StringControl />)).to.equal(true);
  });

  it('calls onRandomClick when clicking on RandomButton', () => {
    // we need to add a static class on the button
    // this will break by the slightest component restructuring
    const randomBtn = wrapper.find('div').children().children().at(1);
    randomBtn.simulate('click');
    sinon.assert.calledOnce(onRandomClick);
  });

  it('control calls onVariationChange', () => {
    wrapper = mount(<PropForm
      variationPath="abc"
      variationProps={variationProps}
      onRandomClick={onRandomClick}
      metadataWithControls={metadataWithControls}
      onVariationPropsChange={onVariationPropsChange}
    />);
    const randomBtn = wrapper.find('#click-int');
    randomBtn.simulate('click');
    sinon.assert.calledOnce(onVariationPropsChange);
  });
});
<|endoftext|>


<commit_before>/*
hinclude.js -- HTML Includes (version 0.9)

Copyright (c) 2005-2011 Mark Nottingham <mnot@pobox.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

------------------------------------------------------------------------------

See http://www.mnot.net/javascript/hinclude/ for documentation.

TODO:
 - check navigator property to see if browser will handle this without
   javascript

------------------------------------------------------------------------------
*/

var hinclude = {
  set_content_async: function (element, req) {
    if (req.readyState == 4) {
      if (req.status == 200 | req.status == 304) {
        element.innerHTML = req.responseText;
      }
      element.className = "include_" + req.status;
    }
  },

  buffer: new Array(),
  set_content_buffered: function (element, req) {
    if (req.readyState == 4) {
      hinclude.buffer.push(new Array(element, req));
      hinclude.outstanding--;
      if (hinclude.outstanding == 0) {
        hinclude.show_buffered_content();
      }
    }
  },
  show_buffered_content: function () {
    while (hinclude.buffer.length > 0) {
      var include = hinclude.buffer.pop();
      if (include[1].status == 200 | include[1].status == 304) {
        include[0].innerHTML = include[1].responseText;
      }
      include[0].className = "include_" + include[1].status;
    }
  },

  outstanding: 0,
  run: function () {
    var mode = this.get_meta("include_mode", "buffered");
    var callback = function(element, req) {};
    var includes = document.getElementsByTagName("hx:include");
    if (includes.length == 0) { // remove ns for IE
      includes = document.getElementsByTagName("include");
    }
    if (mode == "async") {
      callback = this.set_content_async;
    } else if (mode == "buffered") {
      callback = this.set_content_buffered;
      var timeout = this.get_meta("include_timeout", 2.5) * 1000;
      setTimeout("hinclude.show_buffered_content()", timeout);
    }
    for (var i=0; i < includes.length; i++) {
      this.include(includes[i], includes[i].getAttribute("src"), callback);
    }
  },

  include: function (element, url, incl_cb) {
    scheme = url.substring(0,url.indexOf(":"));
    if (scheme.toLowerCase() == "data") { // just text/plain for now
      data = unescape(url.substring(url.indexOf(",") + 1, url.length));
      element.innerHTML = data;
    } else {
      var req = false;
      if(window.XMLHttpRequest) {
        try {
          req = new XMLHttpRequest();
        } catch(e) {
          req = false;
        }
      } else if (window.ActiveXObject) {
        try {
          req = new ActiveXObject("Microsoft.XMLHTTP");
        } catch(e) {
          req = false;
        }
      }
      if (req) {
        this.outstanding++;
        req.onreadystatechange = function() {
          incl_cb(element, req);
        };
        try {
          req.open("GET", url, true);
          req.send("");
        } catch (e) {
          this.outstanding--;
          alert("Include error: " + url + " (" + e + ")");
        }
      }
    }
  },

  get_meta: function (name, value_default) {
    var metas = document.getElementsByTagName("meta");
    for (var m=0; m < metas.length; m++) {
      var meta_name = metas[m].getAttribute("name");
      if (meta_name == name) {
        return metas[m].getAttribute("content");
      }
    }
    return value_default;
  },

  /*
   * (c)2006 Dean Edwards/Matthias Miller/John Resig
   * Special thanks to Dan Webb's domready.js Prototype extension
   * and Simon Willison's addLoadEvent
   *
   * For more info, see:
   * http://dean.edwards.name/weblog/2006/06/again/
   *
   * Thrown together by Jesse Skinner (http://www.thefutureoftheweb.com/)
   *
   *
   * To use: call addDOMLoadEvent one or more times with functions, ie:
   *
   *    function something() {
   *       // do something
   *    }
   *    addDOMLoadEvent(something);
   *
   *    addDOMLoadEvent(function() {
   *        // do other stuff
   *    });
   */
  addDOMLoadEvent: function(func) {
    if (!window.__load_events) {
      var init = function () {
        // quit if this function has already been called
        if (arguments.callee.done) return;

        // flag this function so we don't do the same thing twice
        arguments.callee.done = true;

        // kill the timer
        if (window.__load_timer) {
          clearInterval(window.__load_timer);
          window.__load_timer = null;
        }

        // execute each function in the stack in the order they were added
        for (var i=0;i < window.__load_events.length;i++) {
          window.__load_events[i]();
        }
        window.__load_events = null;

        // clean up the __ie_onload event
        /*@cc_on @*/
        /*@if (@_win32)
          document.getElementById("__ie_onload").onreadystatechange = "";
        /*@end @*/
      };

      // for Mozilla/Opera9
      if (document.addEventListener) {
        document.addEventListener("DOMContentLoaded", init, false);
      }

      // for Internet Explorer
      /*@cc_on @*/
      /*@if (@_win32)
          document.write(
            "<scr"
            + "ipt id=__ie_onload defer src=javascript:void(0)><\/scr"
            + "ipt>"
          );
          var script = document.getElementById("__ie_onload");
          script.onreadystatechange = function() {
              if (this.readyState == "complete") {
                  init(); // call the onload handler
              }
          };
      /*@end @*/

      // for Safari
      if (/WebKit/i.test(navigator.userAgent)) { // sniff
        window.__load_timer = setInterval(function() {
          if (/loaded|complete/.test(document.readyState)) {
            init(); // call the onload handler
          }
        }, 10);
      }

      // for other browsers
      window.onload = init;

      // create event function stack
      window.__load_events = [];
    }

    // add function to event stack
    window.__load_events.push(func);
  }
}

hinclude.addDOMLoadEvent(function() { hinclude.run(); });
<commit_msg>Add missing semicolon<commit_after>/*
hinclude.js -- HTML Includes (version 0.9)

Copyright (c) 2005-2011 Mark Nottingham <mnot@pobox.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

------------------------------------------------------------------------------

See http://www.mnot.net/javascript/hinclude/ for documentation.

TODO:
 - check navigator property to see if browser will handle this without
   javascript

------------------------------------------------------------------------------
*/

var hinclude = {
  set_content_async: function (element, req) {
    if (req.readyState == 4) {
      if (req.status == 200 | req.status == 304) {
        element.innerHTML = req.responseText;
      }
      element.className = "include_" + req.status;
    }
  },

  buffer: new Array(),
  set_content_buffered: function (element, req) {
    if (req.readyState == 4) {
      hinclude.buffer.push(new Array(element, req));
      hinclude.outstanding--;
      if (hinclude.outstanding == 0) {
        hinclude.show_buffered_content();
      }
    }
  },
  show_buffered_content: function () {
    while (hinclude.buffer.length > 0) {
      var include = hinclude.buffer.pop();
      if (include[1].status == 200 | include[1].status == 304) {
        include[0].innerHTML = include[1].responseText;
      }
      include[0].className = "include_" + include[1].status;
    }
  },

  outstanding: 0,
  run: function () {
    var mode = this.get_meta("include_mode", "buffered");
    var callback = function(element, req) {};
    var includes = document.getElementsByTagName("hx:include");
    if (includes.length == 0) { // remove ns for IE
      includes = document.getElementsByTagName("include");
    }
    if (mode == "async") {
      callback = this.set_content_async;
    } else if (mode == "buffered") {
      callback = this.set_content_buffered;
      var timeout = this.get_meta("include_timeout", 2.5) * 1000;
      setTimeout("hinclude.show_buffered_content()", timeout);
    }
    for (var i=0; i < includes.length; i++) {
      this.include(includes[i], includes[i].getAttribute("src"), callback);
    }
  },

  include: function (element, url, incl_cb) {
    scheme = url.substring(0,url.indexOf(":"));
    if (scheme.toLowerCase() == "data") { // just text/plain for now
      data = unescape(url.substring(url.indexOf(",") + 1, url.length));
      element.innerHTML = data;
    } else {
      var req = false;
      if(window.XMLHttpRequest) {
        try {
          req = new XMLHttpRequest();
        } catch(e) {
          req = false;
        }
      } else if (window.ActiveXObject) {
        try {
          req = new ActiveXObject("Microsoft.XMLHTTP");
        } catch(e) {
          req = false;
        }
      }
      if (req) {
        this.outstanding++;
        req.onreadystatechange = function() {
          incl_cb(element, req);
        };
        try {
          req.open("GET", url, true);
          req.send("");
        } catch (e) {
          this.outstanding--;
          alert("Include error: " + url + " (" + e + ")");
        }
      }
    }
  },

  get_meta: function (name, value_default) {
    var metas = document.getElementsByTagName("meta");
    for (var m=0; m < metas.length; m++) {
      var meta_name = metas[m].getAttribute("name");
      if (meta_name == name) {
        return metas[m].getAttribute("content");
      }
    }
    return value_default;
  },

  /*
   * (c)2006 Dean Edwards/Matthias Miller/John Resig
   * Special thanks to Dan Webb's domready.js Prototype extension
   * and Simon Willison's addLoadEvent
   *
   * For more info, see:
   * http://dean.edwards.name/weblog/2006/06/again/
   *
   * Thrown together by Jesse Skinner (http://www.thefutureoftheweb.com/)
   *
   *
   * To use: call addDOMLoadEvent one or more times with functions, ie:
   *
   *    function something() {
   *       // do something
   *    }
   *    addDOMLoadEvent(something);
   *
   *    addDOMLoadEvent(function() {
   *        // do other stuff
   *    });
   */
  addDOMLoadEvent: function(func) {
    if (!window.__load_events) {
      var init = function () {
        // quit if this function has already been called
        if (arguments.callee.done) return;

        // flag this function so we don't do the same thing twice
        arguments.callee.done = true;

        // kill the timer
        if (window.__load_timer) {
          clearInterval(window.__load_timer);
          window.__load_timer = null;
        }

        // execute each function in the stack in the order they were added
        for (var i=0;i < window.__load_events.length;i++) {
          window.__load_events[i]();
        }
        window.__load_events = null;

        // clean up the __ie_onload event
        /*@cc_on @*/
        /*@if (@_win32)
          document.getElementById("__ie_onload").onreadystatechange = "";
        /*@end @*/
      };

      // for Mozilla/Opera9
      if (document.addEventListener) {
        document.addEventListener("DOMContentLoaded", init, false);
      }

      // for Internet Explorer
      /*@cc_on @*/
      /*@if (@_win32)
          document.write(
            "<scr"
            + "ipt id=__ie_onload defer src=javascript:void(0)><\/scr"
            + "ipt>"
          );
          var script = document.getElementById("__ie_onload");
          script.onreadystatechange = function() {
              if (this.readyState == "complete") {
                  init(); // call the onload handler
              }
          };
      /*@end @*/

      // for Safari
      if (/WebKit/i.test(navigator.userAgent)) { // sniff
        window.__load_timer = setInterval(function() {
          if (/loaded|complete/.test(document.readyState)) {
            init(); // call the onload handler
          }
        }, 10);
      }

      // for other browsers
      window.onload = init;

      // create event function stack
      window.__load_events = [];
    }

    // add function to event stack
    window.__load_events.push(func);
  }
};

hinclude.addDOMLoadEvent(function() { hinclude.run(); });
<|endoftext|>


<commit_before>import 'shelljs/global'
import { version, repository } from '../package.json'

cd('gh-pages')
exec('git init')
exec(`git remote add origin ${repository}`)
exec('git add .')
exec(`git commit -anm "v${version}"`)
exec('git checkout -b gh-pages')
exec('git push origin gh-pages -f')
<commit_msg>Fix publish.js<commit_after>require('shelljs/global')
const { version, repository } = require('../package.json')

cd('gh-pages')
exec('git init')
exec('git add .')
exec(`git commit -anm "v${version}"`)
exec(`git push ${repository} master:gh-pages -f`)
<|endoftext|>


<commit_before>// Load in dependencies
var assert = require('assert'),
    fs = require('fs'),
    sourcemap = require('source-map'),
    charProps = require('char-props'),
    jsmin = require('../'),
    SourceMapConsumer = sourcemap.SourceMapConsumer,
    testFilesDir = __dirname + '/test_files';

function minifySingle() {
  before(function () {
    // Read in the src file
    var params = this.params,
        src = params.src,
        singleSrc = fs.readFileSync(testFilesDir + '/' + src, 'utf8');

    // Save to the code namespace
    this.input = [{'src': src, 'code': singleSrc}];
    this.result = jsmin({'code': singleSrc, 'src': src, 'dest': params.dest});
  });
}

function minifyMulti() {
  before(function () {
    // Localize the src
    var params = this.params,
        src = params.src;

    // Read in the src files
    var srcFiles = src.map(function (filepath) {
      var fileSrc = fs.readFileSync(testFilesDir + '/' + filepath, 'utf8'),
          retObj = {
            'code': fileSrc,
            'src': filepath
          };
      return retObj;
    });

    // Save relevant info
    this.input = srcFiles;
    this.result = jsmin({'input': srcFiles, 'dest': params.dest});
  });
}

function assertMatchesC() {
  it('matches its C-minified counterpart', function () {
    var params = this.params,
        expectedCode = fs.readFileSync(__dirname + '/expected_files/' + params.dest, 'utf8');
    assert.strictEqual(
      this.result.code,
      expectedCode,
      'Minified ' + JSON.stringify(params.src) + ' does not match ' + params.dest
    );
  });
}

function mapAgainstSource() {
  before(function () {
    // Iterate over the input
    var srcPropMap = {};
    this.input.forEach(function (item) {
      srcPropMap[item.src] = charProps(item.code);
    });

    // Generate a consumer and charProps lookups
    var result = this.result;
    this.srcConsumer = new SourceMapConsumer(result.sourcemap);
    this.actualProps = charProps(result.code);
    this.srcPropMap = srcPropMap;
  });
}

function assertAllPositionsMatch() {
  it('matches at all positions', function () {
    // Iterate over each of the characters
    var breaks = this.expectedBreaks || [],
        result = this.result,
        actualCode = result.code,
        actualProps = this.actualProps,
        i = 0,
        len = actualCode.length;
    for (; i < len; i++) {
      // Look up the position of our index
      var actualPosition = {
        'line': actualProps.lineAt(i) + 1,
        'column': actualProps.columnAt(i)
      };

      // Grab the position of the item and its fil
      var srcPosition = this.srcConsumer.originalPositionFor(actualPosition),
          srcFile = srcPosition.source;

      // If we have a source file and we are not at a break spot
      // TODO: Actually figure out `breaks`
      var atBreakSpot = breaks.indexOf(i) > -1;
      if (srcFile && !atBreakSpot) {
        // Grab the srcProps for it
        var srcProps = this.srcPropMap[srcFile];

        // Lookup the character at the src positions
        var srcLine = srcPosition.line - 1,
            srcCol = srcPosition.column,
            srcChar = srcProps.charAt({
              'line': srcLine,
              'column': srcCol
            });

        // Assert that the actual and expected characters are equal
        var actualChar = actualCode.charAt(i);
        assert.strictEqual(actualChar, srcChar, 'The sourcemapped character at index ' + i + ' does not match its original character at line ' + srcLine + ', column ' + srcCol + '.');
      }
    }
  });
}

function isDebuggable() {
  if (process.env.TEST_DEBUG) {
    before(function () {
      var actualCode = this.result.code;
      try { fs.mkdirSync(__dirname + '/actual_files'); } catch (e) {}
      fs.writeFileSync(__dirname + '/actual_files/debug.min.js', actualCode, 'utf8');
    });
  }
}

describe('jQuery', function () {
  before(function jQueryPaths () {
    this.params = {'src': 'jquery.js', 'dest': 'jquery.min.js'};
  });

  describe('minified and sourcemapped (single)', function () {
    minifySingle();
    isDebuggable();

    assertMatchesC();
  });
});

describe('Multiple files', function () {
  before(function multiPaths () {
    this.params = {'src': ['1.js', '2.js', '3.js'], 'dest': 'multi.js'};
    this.expectedBreaks = [52, 70];
  });

  describe('minified and sourcemapped (multi)', function () {
    minifyMulti();
    isDebuggable();

    assertMatchesC();

    describe('mapped against its source', function () {
      mapAgainstSource();

      assertAllPositionsMatch();
    });
  });
});

describe('Multiple nested files', function () {
  before(function () {
    this.params = {
      'src': [
        'nested.js',
        'nested/controllers/controller1.js',
        'nested/controllers/controller2.js',
        'nested/models/model1.js'
      ],
      'dest': 'nested.min.js'
    };
    this.expectedBreaks = [1, 43, 88, 100];
  });

  describe('minified and sourcemapped (multi)', function () {
    minifyMulti();
    isDebuggable();

    assertMatchesC();

    describe('mapped against its source', function () {
      mapAgainstSource();

      assertAllPositionsMatch();
    });
  });
});
<commit_msg>Added test for single file<commit_after>// Load in dependencies
var assert = require('assert'),
    fs = require('fs'),
    sourcemap = require('source-map'),
    charProps = require('char-props'),
    jsmin = require('../'),
    SourceMapConsumer = sourcemap.SourceMapConsumer,
    testFilesDir = __dirname + '/test_files';

function minifySingle() {
  before(function () {
    // Read in the src file
    var params = this.params,
        src = params.src,
        singleSrc = fs.readFileSync(testFilesDir + '/' + src, 'utf8');

    // Save to the code namespace
    this.input = [{'src': src, 'code': singleSrc}];
    this.result = jsmin({'code': singleSrc, 'src': src, 'dest': params.dest});
  });
}

function minifyMulti() {
  before(function () {
    // Localize the src
    var params = this.params,
        src = params.src;

    // Read in the src files
    var srcFiles = src.map(function (filepath) {
      var fileSrc = fs.readFileSync(testFilesDir + '/' + filepath, 'utf8'),
          retObj = {
            'code': fileSrc,
            'src': filepath
          };
      return retObj;
    });

    // Save relevant info
    this.input = srcFiles;
    this.result = jsmin({'input': srcFiles, 'dest': params.dest});
  });
}

function assertMatchesC() {
  it('matches its C-minified counterpart', function () {
    var params = this.params,
        expectedCode = fs.readFileSync(__dirname + '/expected_files/' + params.dest, 'utf8');
    assert.strictEqual(
      this.result.code,
      expectedCode,
      'Minified ' + JSON.stringify(params.src) + ' does not match ' + params.dest
    );
  });
}

function mapAgainstSource() {
  before(function () {
    // Iterate over the input
    var srcPropMap = {};
    this.input.forEach(function (item) {
      srcPropMap[item.src] = charProps(item.code);
    });

    // Generate a consumer and charProps lookups
    var result = this.result;
    this.srcConsumer = new SourceMapConsumer(result.sourcemap);
    this.actualProps = charProps(result.code);
    this.srcPropMap = srcPropMap;
  });
}

function assertAllPositionsMatch() {
  it('matches at all positions', function () {
    // Iterate over each of the characters
    var breaks = this.expectedBreaks || [],
        result = this.result,
        actualCode = result.code,
        actualProps = this.actualProps,
        i = 0,
        len = actualCode.length;
    for (; i < len; i++) {
      // Look up the position of our index
      var actualPosition = {
        'line': actualProps.lineAt(i) + 1,
        'column': actualProps.columnAt(i)
      };

      // Grab the position of the item and its fil
      var srcPosition = this.srcConsumer.originalPositionFor(actualPosition),
          srcFile = srcPosition.source;

      // If we have a source file and we are not at a break spot
      // TODO: Actually figure out `breaks`
      var atBreakSpot = breaks.indexOf(i) > -1;
      if (srcFile && !atBreakSpot) {
        // Grab the srcProps for it
        var srcProps = this.srcPropMap[srcFile];

        // Lookup the character at the src positions
        var srcLine = srcPosition.line - 1,
            srcCol = srcPosition.column,
            srcChar = srcProps.charAt({
              'line': srcLine,
              'column': srcCol
            });

        // Assert that the actual and expected characters are equal
        var actualChar = actualCode.charAt(i);
        assert.strictEqual(actualChar, srcChar, 'The sourcemapped character at index ' + i + ' does not match its original character at line ' + srcLine + ', column ' + srcCol + '.');
      }
    }
  });
}

function isDebuggable() {
  if (process.env.TEST_DEBUG) {
    before(function () {
      var actualCode = this.result.code;
      try { fs.mkdirSync(__dirname + '/actual_files'); } catch (e) {}
      fs.writeFileSync(__dirname + '/actual_files/debug.min.js', actualCode, 'utf8');
    });
  }
}

describe('A single file', function () {
  before(function jQueryPaths () {
    this.params = {'src': '1.js', 'dest': 'single.js'};
  });

  describe('minified and sourcemapped (single)', function () {
    minifySingle();
    isDebuggable();

    assertMatchesC();

    describe('mapped against its source', function () {
      mapAgainstSource();

      assertAllPositionsMatch();
    });
  });
});

describe('jQuery', function () {
  before(function jQueryPaths () {
    this.params = {'src': 'jquery.js', 'dest': 'jquery.min.js'};
  });

  describe('minified and sourcemapped (single)', function () {
    minifySingle();
    isDebuggable();

    assertMatchesC();
  });
});

describe('Multiple files', function () {
  before(function multiPaths () {
    this.params = {'src': ['1.js', '2.js', '3.js'], 'dest': 'multi.js'};
    this.expectedBreaks = [52, 70];
  });

  describe('minified and sourcemapped (multi)', function () {
    minifyMulti();
    isDebuggable();

    assertMatchesC();

    describe('mapped against its source', function () {
      mapAgainstSource();

      assertAllPositionsMatch();
    });
  });
});

describe('Multiple nested files', function () {
  before(function () {
    this.params = {
      'src': [
        'nested.js',
        'nested/controllers/controller1.js',
        'nested/controllers/controller2.js',
        'nested/models/model1.js'
      ],
      'dest': 'nested.min.js'
    };
    this.expectedBreaks = [1, 43, 88, 100];
  });

  describe('minified and sourcemapped (multi)', function () {
    minifyMulti();
    isDebuggable();

    assertMatchesC();

    describe('mapped against its source', function () {
      mapAgainstSource();

      assertAllPositionsMatch();
    });
  });
});
<|endoftext|>


<commit_before>/*
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
 distributed with this work for additional information
 regarding copyright ownership.  The ASF licenses this file
 to you under the Apache License, Version 2.0 (the
 "License"); you may not use this file except in compliance
 with the License.  You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing,
 software distributed under the License is distributed on an
 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */

var shell = require('shelljs'),
    spec = __dirname,
    path = require('path'),
    util = require('util');

    var tests_dir = path.join(spec, '..');

describe('cordova-lib', function() {

    it('objective-c unit tests', function() {
        var return_code = 0;
        var command;

        // check iOS Simulator if running
        command = 'pgrep "iOS Simulator"';
        return_code = shell.exec(command).code;

        // if iOS Simulator is running, kill it
        if (return_code == 0) { // found
            shell.echo('iOS Simulator is running, we\'re going to kill it.');
            return_code = shell.exec('killall "iOS Simulator"').code;
            expect(return_code).toBe(0);
        }

        // run the tests
        command = util.format('xcodebuild test -workspace %s/cordova-ios.xcworkspace -scheme CordovaLibTests -destination "platform=iOS Simulator,name=iPhone 5"', tests_dir);
        shell.echo(command);
        return_code = shell.exec(command).code;
        expect(return_code).toBe(0);
    });
});<commit_msg>CB-7812 - cordova-ios xcode unit-tests are failing from npm test, in Xcode it is fine<commit_after>/*
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
 distributed with this work for additional information
 regarding copyright ownership.  The ASF licenses this file
 to you under the Apache License, Version 2.0 (the
 "License"); you may not use this file except in compliance
 with the License.  You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing,
 software distributed under the License is distributed on an
 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */

var shell = require('shelljs'),
    spec = __dirname,
    path = require('path'),
    util = require('util');

    var tests_dir = path.join(spec, '..');
    var artifacts_dir = path.join(spec, '..', 'CordovaLibTests', 'build');

describe('cordova-lib', function() {

    it('objective-c unit tests', function() {
        var return_code = 0;
        var command;

        // check iOS Simulator if running
        command = 'pgrep "iOS Simulator"';
        return_code = shell.exec(command).code;

        // if iOS Simulator is running, kill it
        if (return_code == 0) { // found
            shell.echo('iOS Simulator is running, we\'re going to kill it.');
            return_code = shell.exec('killall "iOS Simulator"').code;
            expect(return_code).toBe(0);
        }

        // run the tests
        command = util.format('xcodebuild test -workspace %s/cordova-ios.xcworkspace -scheme CordovaLibTests -destination "platform=iOS Simulator,name=iPhone 5" CONFIGURATION_BUILD_DIR="%s"', tests_dir, artifacts_dir);
        shell.echo(command);
        return_code = shell.exec(command).code;
        expect(return_code).toBe(0);
    });
});<|endoftext|>


<commit_before>/* global Event */
import { run } from '@ember/runloop';

import { getOwner } from '@ember/application';
import Component from '@ember/component';
import Service from '@ember/service';
import hbs from 'htmlbars-inline-precompile';
import { moduleForComponent, test } from 'ember-qunit';
import ContextBoundEventListenersMixin from 'ember-lifeline/mixins/dom';
import { find, triggerEvent } from 'ember-native-dom-helpers';

moduleForComponent('ember-lifeline/mixins/dom', {
  integration: true,

  beforeEach() {
    let testContext = this;
    let name = 'component:under-test';

    this.owner = getOwner(this);
    this.owner.register(name, Component.extend(ContextBoundEventListenersMixin, {
      init() {
        this._super(...arguments);
        testContext.componentInstance = this;
      }
    }));

    this.Component = this.owner.factoryFor ? this.owner.factoryFor(name) : this.owner._lookupFactory(name);
  }
});

[{
  testName: 'addEventListener(_,_,_,undefined)',
  testedOptions: undefined
}, {
  testName: 'addEventListener(_,_,_,{passive:false})',
  testedOptions: { passive: false }
}].forEach(({ testName, testedOptions }) => {

  test(`${testName} ensures arrays are not eagerly allocated`, function(assert) {
    assert.expect(1);

    this.register('template:components/under-test', hbs`<span class="foo"></span>`);
    this.render(hbs`{{under-test}}`);
    let subject = this.componentInstance;

    assert.notOk(subject._listeners);
  });

  test(`${testName} adds event listener to child element`, function(assert) {
    assert.expect(4);

    this.register('template:components/under-test', hbs`<span class="foo"></span>`);
    this.render(hbs`{{under-test}}`);
    let subject = this.componentInstance;

    let calls = 0;
    let hadRunloop = null;
    let handledEvent = null;
    subject.addEventListener('.foo', 'click', (event) => {
      calls++;
      hadRunloop = !!run.currentRunLoop;
      handledEvent = event;
    }, testedOptions);

    subject.element.firstChild.dispatchEvent(new Event('click'));

    assert.equal(calls, 1, 'callback was called');
    assert.ok(hadRunloop, 'callback was called in runloop');
    assert.ok(handledEvent.target, 'callback passed a target');
    assert.equal(handledEvent.target.className, 'foo', 'target has the expected class');
  });

  /*
   * app/views/manager/highlighter.js uses a second argument to the drag
   * handler, "delta". It is unclear if this value comes from a jQuery library
   * or where else. Before this test can be removed one should be certain
   * the codebase only contains uses of addEventListener expecting a single
   * event argument.
   *
   */
  test(`${testName} adds jquery event listener to child element with multiple handler args`, async function(assert) {
    assert.expect(4);

    this.register('template:components/under-test', hbs`<span class="foo"></span>`);
    this.render(hbs`{{under-test}}`);
    let subject = this.componentInstance;

    let calls = 0;
    let hadRunloop = null;
    let handledArgs = null;
    subject.addEventListener('.foo', 'drag', (...args) => {
      calls++;
      hadRunloop = !!run.currentRunLoop;
      handledArgs = args[0];
    }, testedOptions);

    let delta = {};
    await triggerEvent(subject.element.firstChild, 'drag', { details: { delta } });

    assert.equal(calls, 1, 'callback was called');
    assert.ok(hadRunloop, 'callback was called in runloop');
    assert.ok(handledArgs.target, 'callback passed a target');
    assert.equal(handledArgs.details.delta, delta, 'second argument can be present');
  });

  test(`${testName} adds event listener to non-child element`, async function(assert) {
    assert.expect(5);

    this.set('show', true);
    this.render(hbs`{{#if show}}{{under-test}}{{/if}}<span class="foo"></span>`);
    let subject = this.componentInstance;

    let ranCallback = 0;
    let hadRunloop = null;
    let handledEvent = null;
    let element = find('.foo');
    subject.addEventListener(element, 'click', (event) => {
      ranCallback++;
      hadRunloop = !!run.currentRunLoop;
      handledEvent = event;
    }, testedOptions);

    await triggerEvent(element, 'click');

    assert.equal(ranCallback, 1, 'callback was called once');
    assert.ok(hadRunloop, 'callback was called in runloop');
    assert.ok(!!handledEvent.target, 'callback passed a target');
    assert.equal(handledEvent.target.className, 'foo', 'target has the expected class');

    this.set('show', false);

    // Trigger the event on the non-child element again, after the component
    // is removed from DOM. The listener should not fire this time.
    await triggerEvent(element, 'click');

    assert.equal(ranCallback, 1, 'callback was not called a second time');
  });

  test(`${testName} throws when there is no element to attach to`, function(assert) {
    assert.expect(1);

    this.render(hbs`{{under-test}}`);
    let subject = this.componentInstance;

    assert.throws(() => {
      subject.addEventListener('.foo', 'click', () => {}, testedOptions);
    }, /Called \w+ with selector not found in DOM: .foo/);
  });

  test(`${testName} throws when attached before rendering`, function(assert) {
    assert.expect(1);

    let subject = this.Component.create();

    assert.throws(() => {
      subject.addEventListener('.foo', 'click', () => {}, testedOptions);
    }, /Called \w+ with a css selector before the component was rendered/);
  });

  test(`${testName} adds event listener to non-child element in tagless component`, async function(assert) {
    assert.expect(5);

    this.set('show', true);
    this.render(hbs`{{#if show}}{{under-test tagName=""}}{{/if}}<span class="foo"></span>`);
    let subject = this.componentInstance;

    let calls = 0;
    let hadRunloop = null;
    let handledEvent = null;
    subject.addEventListener(find('.foo'), 'click', (event) => {
      calls++;
      hadRunloop = !!run.currentRunLoop;
      handledEvent = event;
    }, testedOptions);

    await triggerEvent('.foo', 'click');

    assert.equal(calls, 1, 'callback was called');
    assert.ok(hadRunloop, 'callback was called in runloop');
    assert.ok(!!handledEvent.target, 'callback passed a target');
    assert.equal(handledEvent.target.className, 'foo', 'target has the expected class');

    this.set('show', false);

    // Trigger the event on the non-child element again, after the component
    // is removed from DOM. The listener should not fire this time.
    await triggerEvent('.foo', 'click');

    assert.equal(calls, 1, 'callback was not called again');
  });

  test(`${testName} throws when using a string selector in a tagless component`, function(assert) {
    assert.expect(1);

    this.render(hbs`{{under-test tagName=""}}<span class="foo"></span>`);
    let subject = this.componentInstance;

    assert.throws(() => {
      subject.addEventListener('.foo', 'click', () => {}, testedOptions);
    }, /Must provide an element/);
  });

  test(`${testName} listeners on different contexts can be torn down without impacting other contexts`, function(assert) {
    assert.expect(2);

    let testContext = this;
    this.register('component:under-test-a', Component.extend(ContextBoundEventListenersMixin, {
      init() {
        this._super(...arguments);
        testContext.subjectA = this;
      }
    }));
    this.register('component:under-test-b', Component.extend(ContextBoundEventListenersMixin, {
      init() {
        this._super(...arguments);
        testContext.subjectB = this;
      }
    }));

    this.set('showA', true);
    this.render(hbs`{{#if showA}}{{under-test-a}}{{/if}}{{under-test-b}}<span class="foo"></span>`);

    let { subjectA, subjectB } = this;

    let target = find('.foo');

    let calls = 0;
    let callback = () => {
      calls++;
    };
    subjectA.addEventListener(target, 'click', callback, testedOptions);
    subjectB.addEventListener(target, 'click', callback, testedOptions);

    target.click();
    assert.equal(calls, 2, 'two callbacks called');

    this.set('showA', false);

    target.click();
    assert.equal(calls, 3, 'one more callback called for remaining context');
  });

  test(`${testName} listeners are called with correct scope`, function(assert) {
    assert.expect(2);

    let testContext = this;
    this.register('component:under-test-a', Component.extend(ContextBoundEventListenersMixin, {
      init() {
        this._super(...arguments);
        testContext.subjectA = this;
      }
    }));
    this.register('component:under-test-b', Component.extend(ContextBoundEventListenersMixin, {
      init() {
        this._super(...arguments);
        testContext.subjectB = this;
      }
    }));

    this.render(hbs`{{under-test-a}}{{under-test-b}}<span class="foo"></span>`);

    let { subjectA, subjectB } = this;

    let target = find('.foo');

    let assertScope = (scope) => {
      return function() {
        assert.equal(this, scope);
      };
    };
    subjectA.addEventListener(target, 'click', assertScope(subjectA), testedOptions);
    subjectB.addEventListener(target, 'click', assertScope(subjectB), testedOptions);

    target.click();
  });

  test(`${testName.replace('add', 'remove')} removes event listener from child element`, async function(assert) {
    assert.expect(1);

    this.register('template:components/under-test', hbs`<span class="foo"></span>`);
    this.render(hbs`{{under-test}}`);
    let subject = this.componentInstance;

    let calls = 0;
    let listener = () => {
      calls++;
    };
    subject.addEventListener('.foo', 'click', listener, testedOptions);

    subject.removeEventListener('.foo', 'click', listener, testedOptions);

    await triggerEvent(subject.element.firstChild, 'click');

    assert.equal(calls, 0, 'callback was not called');
  });

  test(`${testName} adds event listener when an element is passed in from a service and removes listener when instance is destroyed`, async function(assert) {
    assert.expect(5);

    let serviceName = 'service:under-test';
    let owner = getOwner(this);

    owner.register('service:under-test', Service.extend(ContextBoundEventListenersMixin));

    let factory = owner.factoryFor ? owner.factoryFor(serviceName) : owner._lookupFactory(serviceName);
    let subject = factory.create();

    this.render(hbs`<span class="foo"></span>`);

    let calls = 0;
    let hadRunloop = null;
    let handledEvent = null;
    subject.addEventListener(find('.foo'), 'click', (event) => {
      calls++;
      hadRunloop = !!run.currentRunLoop;
      handledEvent = event;
    }, testedOptions);

    await triggerEvent('.foo', 'click');

    assert.equal(calls, 1, 'callback was called');
    assert.ok(hadRunloop, 'callback was called in runloop');
    assert.ok(!!handledEvent.target, 'callback passed a target');
    assert.equal(handledEvent.target.className, 'foo', 'target has the expected class');

    run(() => subject.destroy()); // Listeners should be removed when the service is destroyed

    await triggerEvent('.foo', 'click');

    assert.equal(calls, 1, 'callback is not called again once the instance is destroyed');
  });

  test(`${testName} throws when a css selector is passed in from a service instance`, async function(assert) {
    assert.expect(1);

    let serviceName = 'service:under-test';
    let owner = getOwner(this);

    owner.register('service:under-test', Service.extend(ContextBoundEventListenersMixin));

    let factory = owner.factoryFor ? owner.factoryFor(serviceName) : owner._lookupFactory(serviceName);
    let subject = factory.create();

    assert.throws(() => {
      subject.addEventListener('.foo', 'click', () => {}, testedOptions);
    }, /Must provide an element/);
  });
});

test('addEventListener(_,_,{passive: false}) permits stopPropogation', async function(assert) {
  assert.expect(2);

  this.register('template:components/under-test', hbs`<span class="outer"><span class="inner"></span></span>`);
  this.render(hbs`{{under-test}}`);
  let subject = this.componentInstance;

  let outerCalls = 0;
  subject.addEventListener('.outer', 'click', () => outerCalls++);

  let innerCalls = 0;
  subject.addEventListener('.inner', 'click', (e) => {
    innerCalls++;
    e.stopPropagation();
  }, { passive: false });

  await triggerEvent(subject.element.firstChild.firstChild, 'click', { bubbles: true });

  assert.equal(outerCalls, 0, 'outer callback never fires');
  assert.equal(innerCalls, 1, 'inner callback fires');
});

test('addEventListener(_,_,{once: true}) is only called once', async function(assert) {
  assert.expect(2);

  this.register('template:components/under-test', hbs`<span class="foo"></span>`);
  this.render(hbs`{{under-test}}`);
  let subject = this.componentInstance;

  let calls = 0;
  let listener = () => {
    calls++;
  };
  let element = find('.foo');

  subject.addEventListener('.foo', 'click', listener, { once: true });

  await triggerEvent(element, 'click');
  assert.equal(calls, 1, 'callback was called once');

  await triggerEvent(element, 'click');
  assert.equal(calls, 1, 'callback was called once');
});
<commit_msg>Adding extra assertion to ensure willDestroy is called<commit_after>/* global Event */
import { run } from '@ember/runloop';

import { getOwner } from '@ember/application';
import Component from '@ember/component';
import Service from '@ember/service';
import hbs from 'htmlbars-inline-precompile';
import { moduleForComponent, test } from 'ember-qunit';
import ContextBoundEventListenersMixin from 'ember-lifeline/mixins/dom';
import { find, triggerEvent } from 'ember-native-dom-helpers';

moduleForComponent('ember-lifeline/mixins/dom', {
  integration: true,

  beforeEach() {
    let testContext = this;
    let name = 'component:under-test';

    this.owner = getOwner(this);
    this.owner.register(name, Component.extend(ContextBoundEventListenersMixin, {
      init() {
        this._super(...arguments);
        testContext.componentInstance = this;
      }
    }));

    this.Component = this.owner.factoryFor ? this.owner.factoryFor(name) : this.owner._lookupFactory(name);
  }
});

[{
  testName: 'addEventListener(_,_,_,undefined)',
  testedOptions: undefined
}, {
  testName: 'addEventListener(_,_,_,{passive:false})',
  testedOptions: { passive: false }
}].forEach(({ testName, testedOptions }) => {

  test(`${testName} ensures arrays are not eagerly allocated`, function(assert) {
    assert.expect(1);

    this.register('template:components/under-test', hbs`<span class="foo"></span>`);
    this.render(hbs`{{under-test}}`);
    let subject = this.componentInstance;

    assert.notOk(subject._listeners);
  });

  test(`${testName} adds event listener to child element`, function(assert) {
    assert.expect(4);

    this.register('template:components/under-test', hbs`<span class="foo"></span>`);
    this.render(hbs`{{under-test}}`);
    let subject = this.componentInstance;

    let calls = 0;
    let hadRunloop = null;
    let handledEvent = null;
    subject.addEventListener('.foo', 'click', (event) => {
      calls++;
      hadRunloop = !!run.currentRunLoop;
      handledEvent = event;
    }, testedOptions);

    subject.element.firstChild.dispatchEvent(new Event('click'));

    assert.equal(calls, 1, 'callback was called');
    assert.ok(hadRunloop, 'callback was called in runloop');
    assert.ok(handledEvent.target, 'callback passed a target');
    assert.equal(handledEvent.target.className, 'foo', 'target has the expected class');
  });

  /*
   * app/views/manager/highlighter.js uses a second argument to the drag
   * handler, "delta". It is unclear if this value comes from a jQuery library
   * or where else. Before this test can be removed one should be certain
   * the codebase only contains uses of addEventListener expecting a single
   * event argument.
   *
   */
  test(`${testName} adds jquery event listener to child element with multiple handler args`, async function(assert) {
    assert.expect(4);

    this.register('template:components/under-test', hbs`<span class="foo"></span>`);
    this.render(hbs`{{under-test}}`);
    let subject = this.componentInstance;

    let calls = 0;
    let hadRunloop = null;
    let handledArgs = null;
    subject.addEventListener('.foo', 'drag', (...args) => {
      calls++;
      hadRunloop = !!run.currentRunLoop;
      handledArgs = args[0];
    }, testedOptions);

    let delta = {};
    await triggerEvent(subject.element.firstChild, 'drag', { details: { delta } });

    assert.equal(calls, 1, 'callback was called');
    assert.ok(hadRunloop, 'callback was called in runloop');
    assert.ok(handledArgs.target, 'callback passed a target');
    assert.equal(handledArgs.details.delta, delta, 'second argument can be present');
  });

  test(`${testName} adds event listener to non-child element`, async function(assert) {
    assert.expect(5);

    this.set('show', true);
    this.render(hbs`{{#if show}}{{under-test}}{{/if}}<span class="foo"></span>`);
    let subject = this.componentInstance;

    let ranCallback = 0;
    let hadRunloop = null;
    let handledEvent = null;
    let element = find('.foo');
    subject.addEventListener(element, 'click', (event) => {
      ranCallback++;
      hadRunloop = !!run.currentRunLoop;
      handledEvent = event;
    }, testedOptions);

    await triggerEvent(element, 'click');

    assert.equal(ranCallback, 1, 'callback was called once');
    assert.ok(hadRunloop, 'callback was called in runloop');
    assert.ok(!!handledEvent.target, 'callback passed a target');
    assert.equal(handledEvent.target.className, 'foo', 'target has the expected class');

    this.set('show', false);

    // Trigger the event on the non-child element again, after the component
    // is removed from DOM. The listener should not fire this time.
    await triggerEvent(element, 'click');

    assert.equal(ranCallback, 1, 'callback was not called a second time');
  });

  test(`${testName} throws when there is no element to attach to`, function(assert) {
    assert.expect(1);

    this.render(hbs`{{under-test}}`);
    let subject = this.componentInstance;

    assert.throws(() => {
      subject.addEventListener('.foo', 'click', () => {}, testedOptions);
    }, /Called \w+ with selector not found in DOM: .foo/);
  });

  test(`${testName} throws when attached before rendering`, function(assert) {
    assert.expect(1);

    let subject = this.Component.create();

    assert.throws(() => {
      subject.addEventListener('.foo', 'click', () => {}, testedOptions);
    }, /Called \w+ with a css selector before the component was rendered/);
  });

  test(`${testName} adds event listener to non-child element in tagless component`, async function(assert) {
    assert.expect(5);

    this.set('show', true);
    this.render(hbs`{{#if show}}{{under-test tagName=""}}{{/if}}<span class="foo"></span>`);
    let subject = this.componentInstance;

    let calls = 0;
    let hadRunloop = null;
    let handledEvent = null;
    subject.addEventListener(find('.foo'), 'click', (event) => {
      calls++;
      hadRunloop = !!run.currentRunLoop;
      handledEvent = event;
    }, testedOptions);

    await triggerEvent('.foo', 'click');

    assert.equal(calls, 1, 'callback was called');
    assert.ok(hadRunloop, 'callback was called in runloop');
    assert.ok(!!handledEvent.target, 'callback passed a target');
    assert.equal(handledEvent.target.className, 'foo', 'target has the expected class');

    this.set('show', false);

    // Trigger the event on the non-child element again, after the component
    // is removed from DOM. The listener should not fire this time.
    await triggerEvent('.foo', 'click');

    assert.equal(calls, 1, 'callback was not called again');
  });

  test(`${testName} throws when using a string selector in a tagless component`, function(assert) {
    assert.expect(1);

    this.render(hbs`{{under-test tagName=""}}<span class="foo"></span>`);
    let subject = this.componentInstance;

    assert.throws(() => {
      subject.addEventListener('.foo', 'click', () => {}, testedOptions);
    }, /Must provide an element/);
  });

  test(`${testName} listeners on different contexts can be torn down without impacting other contexts`, function(assert) {
    assert.expect(2);

    let testContext = this;
    this.register('component:under-test-a', Component.extend(ContextBoundEventListenersMixin, {
      init() {
        this._super(...arguments);
        testContext.subjectA = this;
      }
    }));
    this.register('component:under-test-b', Component.extend(ContextBoundEventListenersMixin, {
      init() {
        this._super(...arguments);
        testContext.subjectB = this;
      }
    }));

    this.set('showA', true);
    this.render(hbs`{{#if showA}}{{under-test-a}}{{/if}}{{under-test-b}}<span class="foo"></span>`);

    let { subjectA, subjectB } = this;

    let target = find('.foo');

    let calls = 0;
    let callback = () => {
      calls++;
    };
    subjectA.addEventListener(target, 'click', callback, testedOptions);
    subjectB.addEventListener(target, 'click', callback, testedOptions);

    target.click();
    assert.equal(calls, 2, 'two callbacks called');

    this.set('showA', false);

    target.click();
    assert.equal(calls, 3, 'one more callback called for remaining context');
  });

  test(`${testName} listeners are called with correct scope`, function(assert) {
    assert.expect(2);

    let testContext = this;
    this.register('component:under-test-a', Component.extend(ContextBoundEventListenersMixin, {
      init() {
        this._super(...arguments);
        testContext.subjectA = this;
      }
    }));
    this.register('component:under-test-b', Component.extend(ContextBoundEventListenersMixin, {
      init() {
        this._super(...arguments);
        testContext.subjectB = this;
      }
    }));

    this.render(hbs`{{under-test-a}}{{under-test-b}}<span class="foo"></span>`);

    let { subjectA, subjectB } = this;

    let target = find('.foo');

    let assertScope = (scope) => {
      return function() {
        assert.equal(this, scope);
      };
    };
    subjectA.addEventListener(target, 'click', assertScope(subjectA), testedOptions);
    subjectB.addEventListener(target, 'click', assertScope(subjectB), testedOptions);

    target.click();
  });

  test(`${testName.replace('add', 'remove')} removes event listener from child element`, async function(assert) {
    assert.expect(1);

    this.register('template:components/under-test', hbs`<span class="foo"></span>`);
    this.render(hbs`{{under-test}}`);
    let subject = this.componentInstance;

    let calls = 0;
    let listener = () => {
      calls++;
    };
    subject.addEventListener('.foo', 'click', listener, testedOptions);

    subject.removeEventListener('.foo', 'click', listener, testedOptions);

    await triggerEvent(subject.element.firstChild, 'click');

    assert.equal(calls, 0, 'callback was not called');
  });

  test(`${testName} adds event listener when an element is passed in from a service and removes listener when instance is destroyed`, async function(assert) {
    assert.expect(5);

    let serviceName = 'service:under-test';
    let owner = getOwner(this);

    owner.register('service:under-test', Service.extend(ContextBoundEventListenersMixin));

    let factory = owner.factoryFor ? owner.factoryFor(serviceName) : owner._lookupFactory(serviceName);
    let subject = factory.create();

    this.render(hbs`<span class="foo"></span>`);

    let calls = 0;
    let hadRunloop = null;
    let handledEvent = null;
    subject.addEventListener(find('.foo'), 'click', (event) => {
      calls++;
      hadRunloop = !!run.currentRunLoop;
      handledEvent = event;
    }, testedOptions);

    await triggerEvent('.foo', 'click');

    assert.equal(calls, 1, 'callback was called');
    assert.ok(hadRunloop, 'callback was called in runloop');
    assert.ok(!!handledEvent.target, 'callback passed a target');
    assert.equal(handledEvent.target.className, 'foo', 'target has the expected class');

    run(() => subject.destroy()); // Listeners should be removed when the service is destroyed

    await triggerEvent('.foo', 'click');

    assert.equal(calls, 1, 'callback is not called again once the instance is destroyed');
    assert.notOk(subject._listeners);
  });

  test(`${testName} throws when a css selector is passed in from a service instance`, async function(assert) {
    assert.expect(1);

    let serviceName = 'service:under-test';
    let owner = getOwner(this);

    owner.register('service:under-test', Service.extend(ContextBoundEventListenersMixin));

    let factory = owner.factoryFor ? owner.factoryFor(serviceName) : owner._lookupFactory(serviceName);
    let subject = factory.create();

    assert.throws(() => {
      subject.addEventListener('.foo', 'click', () => {}, testedOptions);
    }, /Must provide an element/);
  });
});

test('addEventListener(_,_,{passive: false}) permits stopPropogation', async function(assert) {
  assert.expect(2);

  this.register('template:components/under-test', hbs`<span class="outer"><span class="inner"></span></span>`);
  this.render(hbs`{{under-test}}`);
  let subject = this.componentInstance;

  let outerCalls = 0;
  subject.addEventListener('.outer', 'click', () => outerCalls++);

  let innerCalls = 0;
  subject.addEventListener('.inner', 'click', (e) => {
    innerCalls++;
    e.stopPropagation();
  }, { passive: false });

  await triggerEvent(subject.element.firstChild.firstChild, 'click', { bubbles: true });

  assert.equal(outerCalls, 0, 'outer callback never fires');
  assert.equal(innerCalls, 1, 'inner callback fires');
});

test('addEventListener(_,_,{once: true}) is only called once', async function(assert) {
  assert.expect(2);

  this.register('template:components/under-test', hbs`<span class="foo"></span>`);
  this.render(hbs`{{under-test}}`);
  let subject = this.componentInstance;

  let calls = 0;
  let listener = () => {
    calls++;
  };
  let element = find('.foo');

  subject.addEventListener('.foo', 'click', listener, { once: true });

  await triggerEvent(element, 'click');
  assert.equal(calls, 1, 'callback was called once');

  await triggerEvent(element, 'click');
  assert.equal(calls, 1, 'callback was called once');
});
<|endoftext|>


<commit_before>#!/usr/bin/env node
// Copyright 2021 Ben Trask
// MIT licensed

var net = require('net')
var http = require('http');
var JSONParse = require('jsonparse');
var hx = require('./hximport');

log("Importer started");
process.on("exit", function() {
        log("Importer exiting");
});
process.on("uncaughtException", function(err) {
        log("Importer error");
	console.log(err);
        throw err;
});
function log(str) {
        console.log((new Date).toISOString()+": "+str);
}

var local = net.createConnection("./import.sock");
var remote = new URL(process.argv[2]);
var start = parseInt(process.argv[3] || "1", 10);
var end = 1000000000000;
getNext();

var count = 0;
var total = 0;
var timer = setInterval(function() {
	log('Importing '+count+' per second ('+total+' total; '+start+' timestamp)');
	count = 0;
}, 1000);

function getNext() {

var parser = new JSONParse();

remote.pathname = '/api/dump/';
remote.search = '?start='+start+'&duration='+(end-start);
log('Connecting to '+remote.href);

var req = http.get(remote.href);
var res = null;
req.on('error', function(err) {
	log('Request error');
	console.log(err);
	getNext();
});
req.on('response', function(arg) {
	res = arg;
//	log(res.statusCode);
	if(200 != res.statusCode) throw new Error('Bad response status '+res.statusCode);
//	res.pipe(process.stdout);
	res.on('error', function(err) {
		log('Response error');
		console.log(err);
		getNext();
	});
	res.on('data', function(buf) {
//		process.stdout.write(buf);
		parser.write(buf);
	});
	res.on('end', function() {
		clearInterval(timer);
		log('Dump ended?');
//		parser.end();
	});
});
req.end();

parser.onValue = function(val) {
	if(this.stack.length != 1) return;
	var obj = {
		time: val.timestamp,
		url: val.url,
		status: val.status,
		type: val.type,
		length: val.length,
		digests: {},
	};
	for(var i = 0; i < val.hashes.length; i++) {
		var hash = /^([^-]+)-(.*)$/.exec(val.hashes[i]);
		obj.digests[hash[1]] = Buffer.from(hash[2], 'base64');
	}
//	log(obj);
	var go = hx.write_response(local, obj);
	if(!go) {
		res.pause();
		local.once('drain', function() {
			res.resume();
		});
	}

	start = Math.max(start, val.timestamp);
	count++;
	total++;
};

}

<commit_msg>Dump importer improvements.<commit_after>#!/usr/bin/env node
// Copyright 2021 Ben Trask
// MIT licensed

var net = require('net')
var http = require('http');
var JSONParse = require('jsonparse');
var hx = require('./hximport');

log("Importer started");
process.on("exit", function() {
        log("Importer exiting");
});
process.on("uncaughtException", function(err) {
        log("Importer error");
	console.log(err);
        throw err;
});
process.on('SIGHUP', log);
function log(str) {
        console.log((new Date).toISOString()+": "+str);
}

var remote = new URL(process.argv[2]);
var start = parseInt(process.argv[3] || "1", 10);
var local = process.argv[4] || './import.sock';
var end = 1000000000000;
getNext();

var count = 0;
var total = 0;
var timer = setInterval(function() {
	log('Importing '+count+' per second ('+total+' total; '+start+' timestamp)');
	count = 0;
}, 1000);

function getNext() {

var parser = new JSONParse();

remote.pathname = '/api/dump/';
remote.search = '?start='+start+'&duration='+(end-start);
log('Connecting to '+remote.href);

var req = http.get(remote.href);
var res = null;
req.on('error', function(err) {
	log('Request error');
	console.log(err);
	getNext();
});
req.on('response', function(arg) {
	res = arg;
//	log(res.statusCode);
	if(200 != res.statusCode) throw new Error('Bad response status '+res.statusCode);
	res.on('error', function(err) {
		log('Response error');
		console.log(err);
		getNext();
	});
	res.on('data', function(buf) {
		parser.write(buf);
	});
	res.on('end', function() {
		clearInterval(timer);
		log('Dump ended?');
//		parser.end();
	});
});
req.end();

var socket = net.createConnection(local);
socket.on('error', function(err) {
	log('Socket error');
	console.log(err);
	req.destroy();
	if(res) res.destroy();
	getNext();
});

parser.onValue = function(val) {
	if(this.stack.length != 1) return;
	var obj = {
		time: val.timestamp,
		url: val.url,
		status: val.status,
		type: val.type,
		length: val.length,
		digests: {},
	};
	for(var i = 0; i < val.hashes.length; i++) {
		var hash = /^([^-]+)-(.*)$/.exec(val.hashes[i]);
		obj.digests[hash[1]] = Buffer.from(hash[2], 'base64');
	}
//	log(obj);
	var go = hx.write_response(socket, obj);
	if(!go) {
		res.pause();
		socket.once('drain', function() {
			res.resume();
		});
	}

	start = Math.max(start, val.timestamp);
	count++;
	total++;
};

}

<|endoftext|>


<commit_before>import assert from 'assert';
import mongoose from 'mongoose';
import fp from 'mostly-func';

const defaultOptions = {
  trash: null,         // trashable field
  classify: null,      // classify position by a specified field
  unshift: false       // insert at first
};

export default function (schema, options) {
  options = fp.assignAll(defaultOptions, options);

  if (!schema.get('position')) {
    schema.add({ position: { type: Number } });
  }

  schema.index({ position: 1 });

  const preUpdate = function (item, Model, next) {

    const classifyQuery = function (query) {
      if (options.classify) {
        assert(item[options.classify], 'classify field is not provided with item');
        query.where(options.classify).eq(item[options.classify]);
      }
      return query;
    };

    const addLast = function (done) {
      let query = Model.findOne();
      if (options.trash) {
        query.where(options.trash, null);
      }
      classifyQuery(query).sort('-position').then(max => {
        item.position = (max && max.position) ? max.position + 1 : 0;
        done();
      });
    };

    const addFirst = function (done) {
      let query = Model.where('position').exists();
      classifyQuery(query).setOptions({ multi: true })
        .update({
          $inc: { position: 1 }
        }, err => {
          if (err) {
            console.error('sortable $inc error:', err);
            addLast(done);
          } else {
            item.position = 0;
            done();
          }
        });
    };

    // if item has the delete field
    if (options.trash && item[options.trash] !== undefined) {
      if (item[options.trash]) {
        return next();
      } else {
        if (options.unshift === true) {
          return addFirst(next);
        } else {
          return addLast(next);
        }
      }
    }

    if (fp.isValid(item.position)) {
      return next();
    } else {
      if (options.unshift === true) {
        return addFirst(next);
      } else {
        return addLast(next);
      }
    }
  };

  // TODO function model like pre('update')
  schema.pre('save', function (next) {
    let item = this;
    const Model = mongoose.model(item.constructor.modelName);
    preUpdate(item, Model, next);
  });

  schema.pre('update', function (next) {
    const update = this.getUpdate();
    if (this.model && update && update.$set) {
      if (update.$inc && !fp.isNil(update.$inc.position)) {
        return next();
      }
      preUpdate(update.$set, this.model, next);
    } else {
      return next();
    }
  });

  // TODO function model like pre('update')
  schema.pre('findOneAndUpdate', function (next) {
    let item = this.getUpdate();
    const Model = mongoose.model(this.model.modelName);
    preUpdate(item, Model, next);
  });

}<commit_msg>Fix checking classify field<commit_after>import assert from 'assert';
import mongoose from 'mongoose';
import fp from 'mostly-func';

const defaultOptions = {
  trash: null,         // trashable field
  classify: null,      // classify position by a specified field
  unshift: false       // insert at first
};

export default function (schema, options) {
  options = fp.assignAll(defaultOptions, options);

  if (!schema.get('position')) {
    schema.add({ position: { type: Number } });
  }

  schema.index({ position: 1 });

  const preUpdate = function (item, Model, next) {

    const classifyQuery = function (query) {
      if (options.classify) {
        assert(options.classify in item, 'classify field is not provided with item');
        query.where(options.classify).eq(item[options.classify]);
      }
      return query;
    };

    const addLast = function (done) {
      let query = Model.findOne();
      if (options.trash) {
        query.where(options.trash, null);
      }
      classifyQuery(query).sort('-position').then(max => {
        item.position = (max && max.position) ? max.position + 1 : 0;
        done();
      });
    };

    const addFirst = function (done) {
      let query = Model.where('position').exists();
      classifyQuery(query).setOptions({ multi: true })
        .update({
          $inc: { position: 1 }
        }, err => {
          if (err) {
            console.error('sortable $inc error:', err);
            addLast(done);
          } else {
            item.position = 0;
            done();
          }
        });
    };

    // if item has the delete field
    if (options.trash && item[options.trash] !== undefined) {
      if (item[options.trash]) {
        return next();
      } else {
        if (options.unshift === true) {
          return addFirst(next);
        } else {
          return addLast(next);
        }
      }
    }

    if (fp.isValid(item.position)) {
      return next();
    } else {
      if (options.unshift === true) {
        return addFirst(next);
      } else {
        return addLast(next);
      }
    }
  };

  // TODO function model like pre('update')
  schema.pre('save', function (next) {
    let item = this;
    const Model = mongoose.model(item.constructor.modelName);
    preUpdate(item, Model, next);
  });

  schema.pre('update', function (next) {
    const update = this.getUpdate();
    if (this.model && update && update.$set) {
      if (update.$inc && !fp.isNil(update.$inc.position)) {
        return next();
      }
      preUpdate(update.$set, this.model, next);
    } else {
      return next();
    }
  });

  // TODO function model like pre('update')
  schema.pre('findOneAndUpdate', function (next) {
    let item = this.getUpdate();
    const Model = mongoose.model(this.model.modelName);
    preUpdate(item, Model, next);
  });

}<|endoftext|>


<commit_before>(function($){

  window.addWikiFormattingToolbar = function(textarea) {
    if ((document.selection == undefined)
     && (textarea.setSelectionRange == undefined)) {
      return;
    }

    var toolbar = document.createElement("div");
    toolbar.className = "wikitoolbar";

    function addButton(id, title, fn) {
      var a = document.createElement("a");
      a.href = "#";
      a.id = id;
      a.title = title;
      a.onclick = function() { try { fn() } catch (e) { } return false };
      a.tabIndex = 400;
      toolbar.appendChild(a);
    }

    function encloseSelection(prefix, suffix) {
      textarea.focus();
      var start, end, sel, scrollPos, subst;
      if (document.selection != undefined) {
        sel = document.selection.createRange().text;
      } else if (textarea.setSelectionRange != undefined) {
        start = textarea.selectionStart;
        end = textarea.selectionEnd;
        scrollPos = textarea.scrollTop;
        sel = textarea.value.substring(start, end);
      }
      if (sel.match(/ $/)) { // exclude ending space char, if any
        sel = sel.substring(0, sel.length - 1);
        suffix = suffix + " ";
      }
      subst = prefix + sel + suffix;
      if (document.selection != undefined) {
        var range = document.selection.createRange().text = subst;
        textarea.caretPos -= suffix.length;
      } else if (textarea.setSelectionRange != undefined) {
        textarea.value = textarea.value.substring(0, start) + subst +
                         textarea.value.substring(end);
        if (sel) {
          textarea.setSelectionRange(start + subst.length, start + subst.length);
        } else {
          textarea.setSelectionRange(start + prefix.length, start + prefix.length);
        }
        textarea.scrollTop = scrollPos;
      }
    }

    addButton("strong", _("Bold text: '''Example'''"), function() {
      encloseSelection("'''", "'''");
    });
    addButton("em", _("Italic text: ''Example''"), function() {
      encloseSelection("''", "''");
    });
    addButton("heading", _("Heading: == Example =="), function() {
      encloseSelection("\n== ", " ==\n", "Heading");
    });
    addButton("link", _("Link: [http://www.example.com/ Example]"), function() {
      encloseSelection("[", "]");
    });
    addButton("code", _("Code block: {{{ example }}}"), function() {
      encloseSelection("\n{{{\n", "\n}}}\n");
    });
    addButton("hr", _("Horizontal rule: ----"), function() {
      encloseSelection("\n----\n", "");
    });
    addButton("np", _("New paragraph"), function() {
      encloseSelection("\n\n", "");
    });
    addButton("br", _("Line break: [[BR]]"), function() {
      encloseSelection("[[BR]]\n", "");
    });
    addButton("img", _("Image: [[Image()]]"), function() {
      encloseSelection("[[Image(", ")]]");
    });

    $(textarea).before(toolbar);
  }

  // Add toolbar to all <textarea> elements on the page with the class 'wikitext'.
  $(document).ready(function() {
    $("textarea.wikitext").each(function() { addWikiFormattingToolbar(this) });
  });

})(jQuery);
<commit_msg>1.0.2dev: Disable wikitoolbar on `disabled` and `readonly` elements. Refs #11560.<commit_after>(function($){

  window.addWikiFormattingToolbar = function(textarea) {
    if ((document.selection == undefined)
     && (textarea.setSelectionRange == undefined)) {
      return;
    }

    var toolbar = document.createElement("div");
    toolbar.className = "wikitoolbar";

    function addButton(id, title, fn) {
      var a = document.createElement("a");
      a.href = "#";
      a.id = id;
      a.title = title;
      a.onclick = function() {
        if ($(textarea).prop("disabled") === false &&
            $(textarea).prop("readonly") === false) {
          try { fn() } catch (e) { }
        }
        return false;
      };
      a.tabIndex = 400;
      toolbar.appendChild(a);
    }

    function encloseSelection(prefix, suffix) {
      textarea.focus();
      var start, end, sel, scrollPos, subst;
      if (document.selection != undefined) {
        sel = document.selection.createRange().text;
      } else if (textarea.setSelectionRange != undefined) {
        start = textarea.selectionStart;
        end = textarea.selectionEnd;
        scrollPos = textarea.scrollTop;
        sel = textarea.value.substring(start, end);
      }
      if (sel.match(/ $/)) { // exclude ending space char, if any
        sel = sel.substring(0, sel.length - 1);
        suffix = suffix + " ";
      }
      subst = prefix + sel + suffix;
      if (document.selection != undefined) {
        var range = document.selection.createRange().text = subst;
        textarea.caretPos -= suffix.length;
      } else if (textarea.setSelectionRange != undefined) {
        textarea.value = textarea.value.substring(0, start) + subst +
                         textarea.value.substring(end);
        if (sel) {
          textarea.setSelectionRange(start + subst.length, start + subst.length);
        } else {
          textarea.setSelectionRange(start + prefix.length, start + prefix.length);
        }
        textarea.scrollTop = scrollPos;
      }
    }

    addButton("strong", _("Bold text: '''Example'''"), function() {
      encloseSelection("'''", "'''");
    });
    addButton("em", _("Italic text: ''Example''"), function() {
      encloseSelection("''", "''");
    });
    addButton("heading", _("Heading: == Example =="), function() {
      encloseSelection("\n== ", " ==\n", "Heading");
    });
    addButton("link", _("Link: [http://www.example.com/ Example]"), function() {
      encloseSelection("[", "]");
    });
    addButton("code", _("Code block: {{{ example }}}"), function() {
      encloseSelection("\n{{{\n", "\n}}}\n");
    });
    addButton("hr", _("Horizontal rule: ----"), function() {
      encloseSelection("\n----\n", "");
    });
    addButton("np", _("New paragraph"), function() {
      encloseSelection("\n\n", "");
    });
    addButton("br", _("Line break: [[BR]]"), function() {
      encloseSelection("[[BR]]\n", "");
    });
    addButton("img", _("Image: [[Image()]]"), function() {
      encloseSelection("[[Image(", ")]]");
    });

    $(textarea).before(toolbar);
  }

  // Add toolbar to all <textarea> elements on the page with the class 'wikitext'.
  $(document).ready(function() {
    $("textarea.wikitext").each(function() { addWikiFormattingToolbar(this) });
  });

})(jQuery);
<|endoftext|>


<commit_before>require('babel-polyfill')
const mongo = require('./helpers/mongo.js')
const chalk = require('chalk')
const requester = require('gw2e-requester')
const itemWorker = require('./workers/item.js')
const gemWorker = require('./workers/gem.js')
const skinWorker = require('./workers/skin.js')
const recipeWorker = require('./workers/recipe.js')

function log (string, error = false) {
  let formatting = error ? chalk.red.bold : chalk.green.bold
  console.log(formatting('\n-'.repeat(string.length + 4)))
  console.log(formatting('| ' + string.toUpperCase() + ' |'))
  console.log(formatting('-'.repeat(string.length + 4) + '\n'))
}

// Connect to the DB and get working! :)
mongo.connect().then(async () => {
  // Find all entries in the database where the last sell price is not known
  // and search through gw2spidy to see if they have any old prices for it
  async function loadLastKnownSellPrices () {
    let items = await mongo.collection('items').find(
      {lang: 'en', 'tradable': true, 'sell.quantity': 0, 'sell.last_known': false},
      {_id: 0, id: 1, name: 1}
    ).toArray()

    for (var i in items) {
      let item = items[i]
      let price = await loadLastKnownSellPrice(item.id)
      console.log('Price for "' + item.name + '" (' + item.id + '): ', price)
      await mongo.collection('items').update(
        {id: item.id},
        {$set: {'sell.last_known': price}},
        {multi: true}
      )
    }
  }

  async function loadLastKnownSellPrice (id) {
    let page = await requester.single('http://www.gw2spidy.com/api/v0.9/json/listings/' + id + '/sell/1')
    page = page.last_page

    // Go through all pages in reverse, and find the first entry
    // where the price indicates, that the item was in the tradingpost
    while (page > 0) {
      let pageContent = await requester.single('http://www.gw2spidy.com/api/v0.9/json/listings/' + id + '/sell/' + page)
      pageContent = pageContent.results.reverse()
      let price = pageContent.find(c => c.unit_price > 0)

      if (price) {
        return price.unit_price
      }

      page--
    }

    return false
  }

  try {
    await mongo.dropDatabase()
    log('Cleared database')

    await gemWorker.initialize()
    log('Gem worker done')

    await itemWorker.initialize()
    log('Item worker done')

    await loadLastKnownSellPrices()
    log('Importing old last known prices done')

    await skinWorker.initialize()
    log('Skin worker done')

    await recipeWorker.initialize()
    log('Recipe worker done')

    log('Rebuild complete')
    process.exit()
  } catch (e) {
    log('Error happened while rebuilding:\n' + e.stack, true)
    process.exit(1)
  }
})
<commit_msg>Fix formatting for rebuild<commit_after>require('babel-polyfill')
const mongo = require('./helpers/mongo.js')
const chalk = require('chalk')
const requester = require('gw2e-requester')
const itemWorker = require('./workers/item.js')
const gemWorker = require('./workers/gem.js')
const skinWorker = require('./workers/skin.js')
const recipeWorker = require('./workers/recipe.js')

function log (string, error = false) {
  let formatting = error ? chalk.red.bold : chalk.green.bold
  console.log(formatting('\n' + '-'.repeat(string.length + 4)))
  console.log(formatting('| ' + string.toUpperCase() + ' |'))
  console.log(formatting('-'.repeat(string.length + 4) + '\n'))
}

// Connect to the DB and get working! :)
mongo.connect().then(async () => {
  // Find all entries in the database where the last sell price is not known
  // and search through gw2spidy to see if they have any old prices for it
  async function loadLastKnownSellPrices () {
    let items = await mongo.collection('items').find(
      {lang: 'en', 'tradable': true, 'sell.quantity': 0, 'sell.last_known': false},
      {_id: 0, id: 1, name: 1}
    ).toArray()

    for (var i in items) {
      let item = items[i]
      let price = await loadLastKnownSellPrice(item.id)
      console.log('Price for "' + item.name + '" (' + item.id + '): ', price)
      await mongo.collection('items').update(
        {id: item.id},
        {$set: {'sell.last_known': price}},
        {multi: true}
      )
    }
  }

  async function loadLastKnownSellPrice (id) {
    let page = await requester.single('http://www.gw2spidy.com/api/v0.9/json/listings/' + id + '/sell/1')
    page = page.last_page

    // Go through all pages in reverse, and find the first entry
    // where the price indicates, that the item was in the tradingpost
    while (page > 0) {
      let pageContent = await requester.single('http://www.gw2spidy.com/api/v0.9/json/listings/' + id + '/sell/' + page)
      pageContent = pageContent.results.reverse()
      let price = pageContent.find(c => c.unit_price > 0)

      if (price) {
        return price.unit_price
      }

      page--
    }

    return false
  }

  try {
    await mongo.dropDatabase()
    log('Cleared database')

    await gemWorker.initialize()
    log('Gem worker done')

    await itemWorker.initialize()
    log('Item worker done')

    await loadLastKnownSellPrices()
    log('Importing old last known prices done')

    await skinWorker.initialize()
    log('Skin worker done')

    await recipeWorker.initialize()
    log('Recipe worker done')

    log('Rebuild complete')
    process.exit()
  } catch (e) {
    log('Error happened while rebuilding:\n' + e.stack, true)
    process.exit(1)
  }
})
<|endoftext|>