<commit_before>/**
 * @file Embedder JS
 *
 * @author Shobhit Sharma <hi@shobh.it>
 */

(function (global, factory) {
  if (typeof define === 'function' && define.amd) {
    define(factory);
  } else if (typeof module === 'object' && module.exports) {
    module.exports = factory();
  } else {
    global.Embedder = window.Embedder = factory();
  }
})(this, function () {
  'use strict';

  /**
   * Embedder Prototype
   *
   * @class
   * @param {object} options Initialize options.
   */
  function Embedder(options) {
    this.options = options || {};

    this.init(this.options);

    return this;
  }

  Embedder.defaults = {
    FACEBOOK: {
      color: '#3b5999',
      SDK: 'https://connect.facebook.net/en_US/sdk.js',
      oEmbed: 'https://www.facebook.com/plugins/post/oembed.json',
      REGEX: /^http[s]*:\/\/[www.]*facebook\.com.*/i
    },
    TWITTER: {
      color: '#55acee',
      SDK: 'https://platform.twitter.com/widgets.js',
      oEmbed: 'https://publish.twitter.com/oembed',
      REGEX: /^http[s]*:\/\/[www.]*twitter\.com.*/i
    },
    INSTAGRAM: {
      color: '#3f729b',
      SDK: 'https://platform.instagram.com/en_US/embeds.js',
      oEmbed: 'https://api.instagram.com/oembed',
      REGEX: /^http[s]*:\/\/[www.]*instagram\.com.*/i
    },
    YOUTUBE: {
      color: '#cd201f',
      SDK: null,
      oEmbed: 'https://www.youtube.com/embed/',
      REGEX: /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=|\?v=)([^#\&\?]*).*/
    }
  };

  /**
   * Embedder Methods
   *
   * @mixin
   * @implements compile
   * @implements transform
   */
  Embedder.prototype = {

    /**
     * @method Facebook Embed
     *
     * @name facebook
     * @function
     * @param {object} options Optional parameters.
     * @return callback
     */
    facebook: function (element, url, options) {
      var embed_uri = Embedder.defaults.FACEBOOK.oEmbed;
      var query = {
        url: encodeURI(url),
        omitscript: true
      };

      if (options.width && parseInt(options.width) > 0) {
        query.maxwidth = options.width;
      }

      embed_uri += '?' + toQueryString(query);

      fetch(embed_uri, function (error, content) {
        if (error) {
          console.error(error);
          return;
        }

        element.appendChild(generateEmbed('facebook', content.html));

        handleSDKLoader('facebook', function () {
          window.FB.XFBML.parse(element);
        });

        element.addEventListener('DOMSubtreeModified', function () {
          automagic(element, {
            scale: true
          });
        });
      });
    },

    /**
     * @method Twitter Embed
     *
     * @name twitter
     * @function
     * @param {object} options Optional parameters.
     * @return callback
     */
    twitter: function (element, url, options) {
      var embed_uri = Embedder.defaults.TWITTER.oEmbed;
      var query = {
        url: encodeURI(url),
        omit_script: 1
      };

      if (options.width && parseInt(options.width) > 0) {
        query.maxwidth = options.width;
      }

      embed_uri += '?' + toQueryString(query);

      fetch(embed_uri, function (error, content) {
        if (error) {
          console.error(error);
          return;
        }

        element.appendChild(generateEmbed('twitter', content.html));

        handleSDKLoader('twitter', function () {
          window.twttr.widgets.load();
        });

        element.addEventListener('DOMSubtreeModified', function () {
          automagic(element, {
            scale: true
          });
        });
      });
    },

    /**
     * @method Instagram Embed
     *
     * @name instagram
     * @function
     * @param {object} options Optional parameters.
     * @return callback
     */
    instagram: function (element, url, options) {
      var embed_uri = Embedder.defaults.INSTAGRAM.oEmbed;
      var query = {
        url: encodeURI(url),
        omitscript: true,
        hidecaption: true
      };

      if (options.width && parseInt(options.width) > 0) {
        query.maxwidth = options.width;
      }

      embed_uri += '?' + toQueryString(query);

      fetch(embed_uri, function (error, content) {
        if (error) {
          console.error(error);
          return;
        }

        element.appendChild(generateEmbed('instagram', content.html));

        handleSDKLoader('instagram', function () {
          window.instgrm.Embeds.process();
        });

        element.addEventListener('DOMSubtreeModified', function () {
          automagic(element, {
            scale: true,
            iframe: true
          });
        });
      });
    },

    /**
     * @method YouTube Embed
     *
     * @name youtube
     * @function
     * @param {object} options Optional parameters.
     * @return callback
     */
    youtube: function (element, url, options) {
      function getYTVideoID(url) {
        var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
        var match = url.match(regExp);
        return (match && match[7].length == 11) ? match[7] : false;
      }

      var embed_uri = Embedder.defaults.YOUTUBE.oEmbed;
      var video_id = '';
      var query = {
        url: encodeURI(url),
        modestbranding: 1,
        autohide: 1,
        showinfo: 0,
        controls: 0
      };
      var width = (options.width && parseInt(options.width || 0) > 10) ? options.width : 600;
      var height = (options.height && parseInt(options.height || 0) > 10) ? options.height : 400;

      if (!getYTVideoID(url)) {
        console.error('Unable to detect Youtube video id.');
        return;
      }

      embed_uri += video_id + '?' + toQueryString(query);

      element.appendChild(generateEmbed('youtube',
        ''
      ));
    }

  };

  /**
   * @method Initialize auth component
   *
   * @name init
   * @function
   * @param {object} options Optional parameters.
   * @return callback
   */
  Embedder.prototype.init = function (options) {
    console.log('Embedder Initialized..', options);
    document.body.appendChild(generateSDK(Embedder.defaults.FACEBOOK.SDK));
    document.body.appendChild(generateSDK(Embedder.defaults.TWITTER.SDK));
    document.body.appendChild(generateSDK(Embedder.defaults.INSTAGRAM.SDK));

    handleSDKLoader('facebook', function () {
      window.FB.init({
        appId: '771604066204777',
        xfbml: true,
        cookie: true,
        version: 'v2.7'
      });
    });
  };

  /**
   * @method Initialize auth component
   *
   * @name init
   * @function
   * @param {object} options Optional parameters.
   * @return callback
   */
  Embedder.prototype.load = function (element, url, options) {
    console.log('Embedder Loaded..', element, url, options);
    options = options || {};

    if (!element || !validateElement(element)) {
      console.error('`element` is either missing or invalid');
      return;
    }

    var source = getURLSource(url);

    if (!source) {
      console.error(new Error('Invalid or Unsupported URL'));
      return;
    }

    this[source](element, url, options);
  };

  /**
   * @method Initialize auth component
   *
   * @name init
   * @function
   * @param {object} options Optional parameters.
   * @return callback
   */
  Embedder.prototype.resize = function (options) {
    console.log('Embedder Loaded..', options);
  };

  /**
   *
   *
   * @param {any} source
   * @returns
   */
  function generateSDK(source) {
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = encodeURI(source);
    script.setAttribute('async', '');
    script.setAttribute('charset', 'utf-8');
    return script;
  }

  /**
   *
   *
   * @param {any} obj
   * @returns
   */
  function validateElement(obj) {
    try {
      return obj instanceof HTMLElement;
    } catch (e) {
      return (typeof obj === "object") &&
        (obj.nodeType === 1) && (typeof obj.style === "object") &&
        (typeof obj.ownerDocument === "object");
    }
  }

  /**
   *
   *
   * @param {any} url
   * @returns
   */
  function getURLSource(url) {
    var type;
    var urlRegExp = /(http|https):\/\/(\w+:{0,1}\w*)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%!\-\/]))?/;

    if (!urlRegExp.test(url)) {
      return;
    }

    if (url.match(Embedder.defaults.FACEBOOK.REGEX)) {
      return 'facebook';
    } else if (url.match(Embedder.defaults.TWITTER.REGEX)) {
      return 'twitter';
    } else if (url.match(Embedder.defaults.INSTAGRAM.REGEX)) {
      return 'instagram';
    } else if (url.match(Embedder.defaults.YOUTUBE.REGEX)) {
      return 'youtube';
    }
  }

  /**
   *
   *
   * @param {any} obj
   * @returns
   */
  function toQueryString(obj) {
    var parts = [];
    for (var i in obj) {
      if (obj.hasOwnProperty(i)) {
        parts.push(encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]));
      }
    }
    return parts.join('&');
  }

  /**
   *
   *
   * @param {any} sdk
   * @param {any} callback
   */
  function handleSDKLoader(source, callback) {
    var count = 0;
    var max_count = 10;

    function check() {
      count++;

      if (count > max_count) {
        return;
      }

      if (source === 'facebook') {
        if (window.FB) {
          return callback();
        }
        setTimeout(check, 100);
      } else if (source === 'twitter') {
        if (window.twttr) {
          return callback();
        }
        setTimeout(check, 100);
      } else if (source === 'instagram') {
        if (window.instgrm) {
          return callback();
        }
        setTimeout(check, 100);
      }
    }

    check();
  }

  /**
   *
   *
   * @param {any} url
   * @param {any} options
   * @param {any} callback
   */
  function fetch(url, options, callback) {
    if (typeof options === 'function') {
      callback = options;
      options = {};
    }
    options = options || {};

    var callbackName = 'jsonp_callback_' + Math.round(100000 * Math.random());
    window[callbackName] = function (data) {
      delete window[callbackName];
      document.body.removeChild(script);
      callback(null, data);
    };

    var script = document.createElement('script');
    script.type = 'application/javascript';
    script.async = true;
    script.src = url + (url.indexOf('?') >= 0 ? '&' : '?') + 'callback=' + callbackName;
    document.body.appendChild(script);
  }

  /**
   *
   *
   * @param {any} html
   * @returns
   */
  function generateEmbed(source, html) {
    var container = document.createElement('div');
    container.setAttribute('data-embed', source);
    container.innerHTML = html;
    return container;
  }

  /**
   *
   *
   * @param {any} el
   * @param {any} className
   * @returns
   */
  function findAncestor(el, className) {
    while ((el = el.parentElement) && !el.classList.contains(className));
    return el;
  }

  /**
   *
   *
   * @param {any} parent
   * @param {any} element
   * @param {any} options
   */
  function automagic(container, options) {
    options = options || {};

    var gutterX, gutterY, translate;
    var embeded = container.querySelectorAll('[data-embed]')[0];
    var containerWidth = parseInt(options.width || container.style.width || container.offsetWidth);
    var containerHeight = parseInt(options.height || container.style.height || container.offsetHeight);
    var embeddedWidth = embeded.offsetWidth;
    var embeddedHeight = embeded.offsetHeight;

    container.style.width = containerWidth + 'px';

    if (options.iframe) {
      var iframe = embeded.querySelectorAll('iframe')[0];
      embeddedWidth = iframe.offsetWidth;
      embeddedHeight = iframe.offsetHeight;
    }

    gutterX = (containerWidth - embeddedWidth) / 2;
    gutterY = (containerHeight - embeddedHeight) / 2;

    translate = 'translate(' + gutterX + 'px,' + gutterY + 'px)';

    if (options.scale) {
      if (embeded.offsetHeight > containerHeight) {
        var scale = containerHeight / embeded.offsetHeight;
        translate += ' scale(' + scale + ')';
      }
    }

    embeded.style.webkitTransform = translate;
    embeded.style.MozTransform = translate;
    embeded.style.msTransform = translate;
    embeded.style.OTransform = translate;
    embeded.style.transform = translate;
  }

  return Embedder;
});
<commit_msg>Fixed twitter adjustments<commit_after>/**
 * @file Embedder JS
 *
 * @author Shobhit Sharma <hi@shobh.it>
 */

(function (global, factory) {
  if (typeof define === 'function' && define.amd) {
    define(factory);
  } else if (typeof module === 'object' && module.exports) {
    module.exports = factory();
  } else {
    global.Embedder = window.Embedder = factory();
  }
})(this, function () {
  'use strict';

  /**
   * Embedder Prototype
   *
   * @class
   * @param {object} options Initialize options.
   */
  function Embedder(options) {
    this.options = options || {};

    this.init(this.options);

    return this;
  }

  Embedder.defaults = {
    FACEBOOK: {
      color: '#3b5999',
      SDK: 'https://connect.facebook.net/en_US/sdk.js',
      oEmbed: 'https://www.facebook.com/plugins/post/oembed.json',
      REGEX: /^http[s]*:\/\/[www.]*facebook\.com.*/i
    },
    TWITTER: {
      color: '#55acee',
      SDK: 'https://platform.twitter.com/widgets.js',
      oEmbed: 'https://publish.twitter.com/oembed',
      REGEX: /^http[s]*:\/\/[www.]*twitter\.com.*/i
    },
    INSTAGRAM: {
      color: '#3f729b',
      SDK: 'https://platform.instagram.com/en_US/embeds.js',
      oEmbed: 'https://api.instagram.com/oembed',
      REGEX: /^http[s]*:\/\/[www.]*instagram\.com.*/i
    },
    YOUTUBE: {
      color: '#cd201f',
      SDK: null,
      oEmbed: 'https://www.youtube.com/embed/',
      REGEX: /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=|\?v=)([^#\&\?]*).*/
    }
  };

  /**
   * Embedder Methods
   *
   * @mixin
   * @implements compile
   * @implements transform
   */
  Embedder.prototype = {

    /**
     * @method Facebook Embed
     *
     * @name facebook
     * @function
     * @param {object} options Optional parameters.
     * @return callback
     */
    facebook: function (element, url, options) {
      var embed_uri = Embedder.defaults.FACEBOOK.oEmbed;
      var query = {
        url: encodeURI(url),
        omitscript: true
      };

      if (options.width && parseInt(options.width) > 0) {
        query.maxwidth = options.width;
      }

      embed_uri += '?' + toQueryString(query);

      fetch(embed_uri, function (error, content) {
        if (error) {
          console.error(error);
          return;
        }

        element.appendChild(generateEmbed('facebook', content.html));

        handleSDKLoader('facebook', function () {
          window.FB.XFBML.parse(element);
        });

        element.addEventListener('DOMSubtreeModified', function () {
          automagic(element, {
            scale: true,
            frame: 'fb_iframe_widget'
          });
        });
      });
    },

    /**
     * @method Twitter Embed
     *
     * @name twitter
     * @function
     * @param {object} options Optional parameters.
     * @return callback
     */
    twitter: function (element, url, options) {
      var embed_uri = Embedder.defaults.TWITTER.oEmbed;
      var query = {
        url: encodeURI(url),
        omit_script: 1
      };

      if (options.width && parseInt(options.width) > 0) {
        query.maxwidth = options.width;
      }

      embed_uri += '?' + toQueryString(query);

      fetch(embed_uri, function (error, content) {
        if (error) {
          console.error(error);
          return;
        }

        element.appendChild(generateEmbed('twitter', content.html));

        handleSDKLoader('twitter', function () {
          window.twttr.widgets.load(element);
        });

        element.addEventListener('DOMSubtreeModified', function () {
          automagic(element, {
            scale: true
          });
        });

        automagic(element, {
          scale: true
        });
      });
    },

    /**
     * @method Instagram Embed
     *
     * @name instagram
     * @function
     * @param {object} options Optional parameters.
     * @return callback
     */
    instagram: function (element, url, options) {
      var embed_uri = Embedder.defaults.INSTAGRAM.oEmbed;
      var query = {
        url: encodeURI(url),
        omitscript: true,
        hidecaption: true
      };

      if (options.width && parseInt(options.width) > 0) {
        query.maxwidth = options.width;
      }

      embed_uri += '?' + toQueryString(query);

      fetch(embed_uri, function (error, content) {
        if (error) {
          console.error(error);
          return;
        }

        element.appendChild(generateEmbed('instagram', content.html));

        handleSDKLoader('instagram', function () {
          window.instgrm.Embeds.process();
        });

        element.addEventListener('DOMSubtreeModified', function () {
          automagic(element, {
            scale: true,
            frame: 'iframe'
          });
        });
      });
    },

    /**
     * @method YouTube Embed
     *
     * @name youtube
     * @function
     * @param {object} options Optional parameters.
     * @return callback
     */
    youtube: function (element, url, options) {
      function getYTVideoID(url) {
        var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
        var match = url.match(regExp);
        return (match && match[7].length == 11) ? match[7] : false;
      }

      var embed_uri = Embedder.defaults.YOUTUBE.oEmbed;
      var video_id = '';
      var query = {
        url: encodeURI(url),
        modestbranding: 1,
        autohide: 1,
        showinfo: 0,
        controls: 0
      };
      var width = (options.width && parseInt(options.width || 0) > 10) ? options.width : 600;
      var height = (options.height && parseInt(options.height || 0) > 10) ? options.height : 400;

      if (!getYTVideoID(url)) {
        console.error('Unable to detect Youtube video id.');
        return;
      }

      embed_uri += video_id + '?' + toQueryString(query);

      element.appendChild(generateEmbed('youtube',
        ''
      ));
    }

  };

  /**
   * @method Initialize auth component
   *
   * @name init
   * @function
   * @param {object} options Optional parameters.
   * @return callback
   */
  Embedder.prototype.init = function (options) {
    console.log('Embedder Initialized..', options);
    document.body.appendChild(generateSDK(Embedder.defaults.FACEBOOK.SDK));
    document.body.appendChild(generateSDK(Embedder.defaults.TWITTER.SDK));
    document.body.appendChild(generateSDK(Embedder.defaults.INSTAGRAM.SDK));

    handleSDKLoader('facebook', function () {
      window.FB.init({
        appId: '771604066204777',
        xfbml: true,
        cookie: true,
        version: 'v2.7'
      });
    });
  };

  /**
   * @method Initialize auth component
   *
   * @name init
   * @function
   * @param {object} options Optional parameters.
   * @return callback
   */
  Embedder.prototype.load = function (element, url, options) {
    console.log('Embedder Loaded..', element, url, options);
    options = options || {};

    if (!element || !validateElement(element)) {
      console.error('`element` is either missing or invalid');
      return;
    }

    var source = getURLSource(url);

    if (!source) {
      console.error(new Error('Invalid or Unsupported URL'));
      return;
    }

    this[source](element, url, options);
  };

  /**
   * @method Initialize auth component
   *
   * @name init
   * @function
   * @param {object} options Optional parameters.
   * @return callback
   */
  Embedder.prototype.resize = function (options) {
    console.log('Embedder Loaded..', options);
  };

  /**
   *
   *
   * @param {any} source
   * @returns
   */
  function generateSDK(source) {
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = encodeURI(source);
    script.setAttribute('async', '');
    script.setAttribute('charset', 'utf-8');
    return script;
  }

  /**
   *
   *
   * @param {any} obj
   * @returns
   */
  function validateElement(obj) {
    try {
      return obj instanceof HTMLElement;
    } catch (e) {
      return (typeof obj === "object") &&
        (obj.nodeType === 1) && (typeof obj.style === "object") &&
        (typeof obj.ownerDocument === "object");
    }
  }

  /**
   *
   *
   * @param {any} url
   * @returns
   */
  function getURLSource(url) {
    var type;
    var urlRegExp = /(http|https):\/\/(\w+:{0,1}\w*)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%!\-\/]))?/;

    if (!urlRegExp.test(url)) {
      return;
    }

    if (url.match(Embedder.defaults.FACEBOOK.REGEX)) {
      return 'facebook';
    } else if (url.match(Embedder.defaults.TWITTER.REGEX)) {
      return 'twitter';
    } else if (url.match(Embedder.defaults.INSTAGRAM.REGEX)) {
      return 'instagram';
    } else if (url.match(Embedder.defaults.YOUTUBE.REGEX)) {
      return 'youtube';
    }
  }

  /**
   *
   *
   * @param {any} obj
   * @returns
   */
  function toQueryString(obj) {
    var parts = [];
    for (var i in obj) {
      if (obj.hasOwnProperty(i)) {
        parts.push(encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]));
      }
    }
    return parts.join('&');
  }

  /**
   *
   *
   * @param {any} sdk
   * @param {any} callback
   */
  function handleSDKLoader(source, callback) {
    var count = 0;
    var max_count = 10;

    function check() {
      count++;

      if (count > max_count) {
        return;
      }

      if (source === 'facebook') {
        if (window.FB) {
          return callback();
        }
        setTimeout(check, 100);
      } else if (source === 'twitter') {
        if (window.twttr) {
          return callback();
        }
        setTimeout(check, 100);
      } else if (source === 'instagram') {
        if (window.instgrm) {
          return callback();
        }
        setTimeout(check, 100);
      }
    }

    check();
  }

  /**
   *
   *
   * @param {any} url
   * @param {any} options
   * @param {any} callback
   */
  function fetch(url, options, callback) {
    if (typeof options === 'function') {
      callback = options;
      options = {};
    }
    options = options || {};

    var callbackName = 'jsonp_callback_' + Math.round(100000 * Math.random());
    window[callbackName] = function (data) {
      delete window[callbackName];
      document.body.removeChild(script);
      callback(null, data);
    };

    var script = document.createElement('script');
    script.type = 'application/javascript';
    script.async = true;
    script.src = url + (url.indexOf('?') >= 0 ? '&' : '?') + 'callback=' + callbackName;
    document.body.appendChild(script);
  }

  /**
   *
   *
   * @param {any} html
   * @returns
   */
  function generateEmbed(source, html) {
    var container = document.createElement('div');
    container.setAttribute('data-embed', source);
    container.innerHTML = html;
    return container;
  }

  /**
   *
   *
   * @param {any} el
   * @param {any} className
   * @returns
   */
  function findAncestor(el, className) {
    while ((el = el.parentElement) && !el.classList.contains(className));
    return el;
  }

  /**
   *
   *
   * @param {any} parent
   * @param {any} element
   * @param {any} options
   */
  function automagic(container, options) {
    options = options || {};

    var gutterX, gutterY, translate;
    var embeded = options.frame ?
      container.querySelectorAll(options.frame)[0] :
      container.querySelectorAll('[data-embed]')[0];

    if (!embeded) {
      return;
    }

    var containerWidth = parseInt(options.width || container.style.width || container.offsetWidth);
    var containerHeight = parseInt(options.height || container.style.height || container.offsetHeight);
    var embeddedWidth = parseInt(embeded.style.maxWidth || embeded.style.width || embeded.offsetWidth);
    var embeddedHeight = parseInt(embeded.style.maxHeight || embeded.style.height || embeded.offsetHeight);

    if (!options.frame) {
      embeddedWidth = embeded.firstChild.offsetWidth;
      embeddedHeight = embeded.firstChild.offsetHeight;
    }

    gutterX = (containerWidth - embeddedWidth) / 2;
    gutterY = (containerHeight - embeddedHeight) / 2;

    translate = 'translate(' + gutterX + 'px,' + gutterY + 'px)';

    if (options.scale) {
      if (embeded.offsetHeight > containerHeight) {
        var scale = containerHeight / embeded.offsetHeight;
        translate += ' scale(' + scale + ')';
      }
    }

    embeded.style.webkitTransform = translate;
    embeded.style.MozTransform = translate;
    embeded.style.msTransform = translate;
    embeded.style.OTransform = translate;
    embeded.style.transform = translate;
  }

  return Embedder;
});
<|endoftext|>


<commit_before>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

var DocumentView = this.DocumentView = Base.extend({
	beans: true,

	// TODO: Add bounds parameter that defines position within canvas?
	// Find a good name for these bounds, since #bounds is already the artboard
	// bounds of the visible area.
	initialize: function(canvas) {
		// To go with the convention of never passing document to constructors,
		// in all items, associate the view with the currently active document.
		this._document = paper.document;
		this._scope = this._document._scope;
		// Push it onto document.views and set index:
		this._index = this._document.views.push(this) - 1;
		// Handle canvas argument
		var size;
		if (canvas && canvas instanceof HTMLCanvasElement) {
			this._canvas = canvas;
			var offset = DomElement.getOffset(canvas);
			// If the canvas has the resize attribute, resize the it to fill the
			// window and resize it again whenever the user resizes the window.
			if (canvas.attributes.resize) {
				size = DomElement.getWindowSize().subtract(offset);
				canvas.width = size.width;
				canvas.height = size.height;
				var that = this;
				DomEvent.add(window, {
					resize: function(event) {
						// Only get canvas offset if it's not invisible (size is
						// 0, 0), as otherwise the offset would be wrong.
						if (!DomElement.getSize(canvas).equals([0, 0]))
							offset = DomElement.getOffset(canvas);
						that.setViewSize(
								DomElement.getWindowSize().subtract(offset));
						that.draw();
					}
				});
			} else {
				size = Size.create(canvas.offsetWidth, canvas.offsetHeight);
			}
			// TODO: Test this on IE:
			if (canvas.attributes.stats) {
				this._stats = new Stats();
				// Align top-left to the canvas
				var element = this._stats.domElement,
					style = element.style;
				style.position = 'absolute';
				style.left = offset.x + 'px';
				style.top = offset.y + 'px';
				document.body.appendChild(element);
			}
		} else {
			// 2nd argument onwards could be view size, otherwise use default:
			size = Size.read(arguments, 1);
			if (size.isZero())
				size = new Size(1024, 768);
			this._canvas = CanvasProvider.getCanvas(size);
		}
		this._viewBounds = LinkedRectangle.create(this, 'setViewBounds',
				0, 0, size.width, size.height);
		this._context = this._canvas.getContext('2d');
		this._matrix = new Matrix();
		this._zoom = 1;
		this._events = this._createEvents();
		DomEvent.add(this._canvas, this._events);
		// Make sure the first view is focused for keyboard input straight away
		if (!DocumentView.focused)
			DocumentView.focused = this;
	},

	getDocument: function() {
		return this._document;
	},

	getViewBounds: function() {
		return this._viewBounds;
	},

	setViewBounds: function(bounds) {
		bounds = Rectangle.read(arguments);
		var size = bounds.getSize(),
			delta = size.subtract(this._viewBounds.getSize());
		// TODO: Take into acount bounds.x/y and decide on what grounds to
		// change canvas size. Also, if x/y is not 0, do we need to add that
		// to transform, or is that up to the user?
		this._canvas.width = size.width;
		this._canvas.height = size.height;
		// Call onResize handler on any size change
		if (this.onResize) {
			this.onResize({
				size: size,
				delta: delta
			});
		}
		// Force recalculation
		this._bounds = null;
	},

	getViewSize: function() {
		return this._viewBounds.getSize();
	},

	setViewSize: function(size) {
		this._viewBounds.setSize.apply(this._viewBounds, arguments);
	},

	getBounds: function() {
		if (!this._bounds)
			this._bounds = this._matrix._transformBounds(this._viewBounds);
		return this._bounds;
	},

	getSize: function() {
		return this.getBounds().getSize();
	},

	getCenter: function() {
		return this.getBounds().getCenter();
	},

	setCenter: function(center) {
		this.scrollBy(Point.read(arguments).subtract(this.getCenter()));
	},

	getZoom: function() {
		return this._zoom;
	},

	setZoom: function(zoom) {
		// TODO: Clamp the view between 1/32 and 64, just like Illustrator?
		var mx = new Matrix();
		mx.scale(zoom / this._zoom, this._center);
		this.transform(mx);
		this._zoom = zoom;
	},

	scrollBy: function(point) {
		this.transform(new Matrix().translate(Point.read(arguments).negate()));
	},

	draw: function() {
		if (this._stats)
			this._stats.update();
		// Initial tests conclude that clearing the canvas using clearRect
		// is always faster than setting canvas.width = canvas.width
		// http://jsperf.com/clearrect-vs-setting-width/7
		var bounds = this._viewBounds;
		this._context.clearRect(bounds._x, bounds._y,
				// TODO: +1... what if we have multiple views in one canvas?
				bounds._width + 1, bounds._height + 1);
		this._document.draw(this._context);
	},

	activate: function() {
		this._document.activeView = this;
	},

	remove: function() {
		var res = Base.splice(this._document.views, null, this._index, 1);
		// Uninstall event handlers again for this view.
		DomEvent.remove(this._canvas, this._events);
		this._document = this._scope = this._canvas = this._events = null;
		// Clearing _onFrame makes the frame handler stop automatically.
		this._onFrame = null;
		return !!res.length;
	},

	transform: function(matrix, flags) {
		this._matrix.preConcatenate(matrix);
		// Force recalculation of these values next time they are requested.
		this._bounds = null;
		this._inverse = null;
	},

	_getInverse: function() {
		if (!this._inverse)
			this._inverse = this._matrix.createInverse();
		return this._inverse;
	},

	// TODO: getInvalidBounds
	// TODO: invalidate(rect)
	// TODO: style: artwork / preview / raster / opaque / ink
	// TODO: getShowGrid
	// TODO: getMousePoint
	// TODO: artworkToView(rect)
	artworkToView: function(point) {
		return this._matrix._transformPoint(Point.read(arguments));
	},

	viewToArtwork: function(point) {
		return this._getInverse()._transformPoint(Point.read(arguments));
	},

	/**
	 * Handler to be called whenever a view gets resized.
	 */
	onResize: null,

	/**
	 * Handler to be called on each frame of an animation.
	 */
	getOnFrame: function() {
		return this._onFrame;
	},

	setOnFrame: function(onFrame) {
		this._onFrame = onFrame;
		var that = this,
			running = false,
			before,
			time = 0,
			count = 0;
		function frame() {
			if (!that._onFrame) {
				running = false;
				return;
			}
			// Set the global paper object to the current scope
			paper = that._scope;
			// Request next frame already
			DomEvent.requestAnimationFrame(frame, that._canvas);
			running = true;
			var now = Date.now() / 1000,
			 	delta = before ? now - before : 0;
			that._onFrame({
				delta: delta, // Time elapsed since last redraw in seconds
				time: time += delta, // Time since first call of frame() in seconds
				count: count++
			});
			before = now;
			// Automatically draw view on each frame.
			that.draw();
		};
		// Call the onFrame handler straight away, initializing the sequence
		// of onFrame calls.
		if (!running)
			frame();
	},

	_createEvents: function() {
		var that = this,
			tool,
			timer,
			curPoint,
			dragging = false;

		function viewToArtwork(event) {
			return that.viewToArtwork(DomEvent.getOffset(event));
		}

		function mousedown(event) {
			// Tell the Key class which view should receive keyboard input.
			DocumentView.focused = that;
			if (!(tool = that._scope.tool))
				return;
			curPoint = viewToArtwork(event);
			tool.onHandleEvent('mousedown', curPoint, event);
			if (tool.onMouseDown)
				that.draw();
			if (tool.eventInterval != null)
				timer = setInterval(events.mousemove, tool.eventInterval);
			dragging = true;
		}

		function mousemove(event) {
			if (!(tool = that._scope.tool))
				return;
			// If the event was triggered by a touch screen device, prevent the
			// default behaviour, as it will otherwise scroll the page:
			if (event && event.targetTouches)
				DomEvent.preventDefault(event);
			var point = event && viewToArtwork(event);
			var onlyMove = !!(!tool.onMouseDrag && tool.onMouseMove);
			if (dragging && !onlyMove) {
				curPoint = point || curPoint;
				if (curPoint)
					tool.onHandleEvent('mousedrag', curPoint, event);
				if (tool.onMouseDrag)
					that.draw();
			// PORT: If there is only an onMouseMove handler, also call it when
			// the user is dragging:
			} else if (!dragging || onlyMove) {
				tool.onHandleEvent('mousemove', point, event);
				if (tool.onMouseMove)
					that.draw();
			}
		}

		function mouseup(event) {
			if (!dragging)
				return;
			dragging = false;
			curPoint = null;
			if (tool) {
				if (tool.eventInterval != null)
					timer = clearInterval(timer);
				tool.onHandleEvent('mouseup', viewToArtwork(event), event);
				if (tool.onMouseUp)
					that.draw();
			}
		}

		return {
			mousedown: mousedown,
			mousemove: mousemove,
			mouseup: mouseup,
			touchstart: mousedown,
			touchmove: mousemove,
			touchend: mouseup
		};
	}
});
<commit_msg>Redraw DocumentView in #setViewBounds().<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

var DocumentView = this.DocumentView = Base.extend({
	beans: true,

	// TODO: Add bounds parameter that defines position within canvas?
	// Find a good name for these bounds, since #bounds is already the artboard
	// bounds of the visible area.
	initialize: function(canvas) {
		// To go with the convention of never passing document to constructors,
		// in all items, associate the view with the currently active document.
		this._document = paper.document;
		this._scope = this._document._scope;
		// Push it onto document.views and set index:
		this._index = this._document.views.push(this) - 1;
		// Handle canvas argument
		var size;
		if (canvas && canvas instanceof HTMLCanvasElement) {
			this._canvas = canvas;
			var offset = DomElement.getOffset(canvas);
			// If the canvas has the resize attribute, resize the it to fill the
			// window and resize it again whenever the user resizes the window.
			if (canvas.attributes.resize) {
				size = DomElement.getWindowSize().subtract(offset);
				canvas.width = size.width;
				canvas.height = size.height;
				var that = this;
				DomEvent.add(window, {
					resize: function(event) {
						// Only get canvas offset if it's not invisible (size is
						// 0, 0), as otherwise the offset would be wrong.
						if (!DomElement.getSize(canvas).equals([0, 0]))
							offset = DomElement.getOffset(canvas);
						that.setViewSize(
								DomElement.getWindowSize().subtract(offset));
					}
				});
			} else {
				size = Size.create(canvas.offsetWidth, canvas.offsetHeight);
			}
			// TODO: Test this on IE:
			if (canvas.attributes.stats) {
				this._stats = new Stats();
				// Align top-left to the canvas
				var element = this._stats.domElement,
					style = element.style;
				style.position = 'absolute';
				style.left = offset.x + 'px';
				style.top = offset.y + 'px';
				document.body.appendChild(element);
			}
		} else {
			// 2nd argument onwards could be view size, otherwise use default:
			size = Size.read(arguments, 1);
			if (size.isZero())
				size = new Size(1024, 768);
			this._canvas = CanvasProvider.getCanvas(size);
		}
		this._viewBounds = LinkedRectangle.create(this, 'setViewBounds',
				0, 0, size.width, size.height);
		this._context = this._canvas.getContext('2d');
		this._matrix = new Matrix();
		this._zoom = 1;
		this._events = this._createEvents();
		DomEvent.add(this._canvas, this._events);
		// Make sure the first view is focused for keyboard input straight away
		if (!DocumentView.focused)
			DocumentView.focused = this;
	},

	getDocument: function() {
		return this._document;
	},

	getViewBounds: function() {
		return this._viewBounds;
	},

	setViewBounds: function(bounds) {
		bounds = Rectangle.read(arguments);
		var size = bounds.getSize(),
			delta = size.subtract(this._viewBounds.getSize());
		// TODO: Take into acount bounds.x/y and decide on what grounds to
		// change canvas size. Also, if x/y is not 0, do we need to add that
		// to transform, or is that up to the user?
		this._canvas.width = size.width;
		this._canvas.height = size.height;
		// Call onResize handler on any size change
		if (this.onResize) {
			this.onResize({
				size: size,
				delta: delta
			});
		}
		// Force recalculation
		this._bounds = null;
		this.draw();
	},

	getViewSize: function() {
		return this._viewBounds.getSize();
	},

	setViewSize: function(size) {
		this._viewBounds.setSize.apply(this._viewBounds, arguments);
	},

	getBounds: function() {
		if (!this._bounds)
			this._bounds = this._matrix._transformBounds(this._viewBounds);
		return this._bounds;
	},

	getSize: function() {
		return this.getBounds().getSize();
	},

	getCenter: function() {
		return this.getBounds().getCenter();
	},

	setCenter: function(center) {
		this.scrollBy(Point.read(arguments).subtract(this.getCenter()));
	},

	getZoom: function() {
		return this._zoom;
	},

	setZoom: function(zoom) {
		// TODO: Clamp the view between 1/32 and 64, just like Illustrator?
		var mx = new Matrix();
		mx.scale(zoom / this._zoom, this._center);
		this.transform(mx);
		this._zoom = zoom;
	},

	scrollBy: function(point) {
		this.transform(new Matrix().translate(Point.read(arguments).negate()));
	},

	draw: function() {
		if (this._stats)
			this._stats.update();
		// Initial tests conclude that clearing the canvas using clearRect
		// is always faster than setting canvas.width = canvas.width
		// http://jsperf.com/clearrect-vs-setting-width/7
		var bounds = this._viewBounds;
		this._context.clearRect(bounds._x, bounds._y,
				// TODO: +1... what if we have multiple views in one canvas?
				bounds._width + 1, bounds._height + 1);
		this._document.draw(this._context);
	},

	activate: function() {
		this._document.activeView = this;
	},

	remove: function() {
		var res = Base.splice(this._document.views, null, this._index, 1);
		// Uninstall event handlers again for this view.
		DomEvent.remove(this._canvas, this._events);
		this._document = this._scope = this._canvas = this._events = null;
		// Clearing _onFrame makes the frame handler stop automatically.
		this._onFrame = null;
		return !!res.length;
	},

	transform: function(matrix, flags) {
		this._matrix.preConcatenate(matrix);
		// Force recalculation of these values next time they are requested.
		this._bounds = null;
		this._inverse = null;
	},

	_getInverse: function() {
		if (!this._inverse)
			this._inverse = this._matrix.createInverse();
		return this._inverse;
	},

	// TODO: getInvalidBounds
	// TODO: invalidate(rect)
	// TODO: style: artwork / preview / raster / opaque / ink
	// TODO: getShowGrid
	// TODO: getMousePoint
	// TODO: artworkToView(rect)
	artworkToView: function(point) {
		return this._matrix._transformPoint(Point.read(arguments));
	},

	viewToArtwork: function(point) {
		return this._getInverse()._transformPoint(Point.read(arguments));
	},

	/**
	 * Handler to be called whenever a view gets resized.
	 */
	onResize: null,

	/**
	 * Handler to be called on each frame of an animation.
	 */
	getOnFrame: function() {
		return this._onFrame;
	},

	setOnFrame: function(onFrame) {
		this._onFrame = onFrame;
		var that = this,
			running = false,
			before,
			time = 0,
			count = 0;
		function frame() {
			if (!that._onFrame) {
				running = false;
				return;
			}
			// Set the global paper object to the current scope
			paper = that._scope;
			// Request next frame already
			DomEvent.requestAnimationFrame(frame, that._canvas);
			running = true;
			var now = Date.now() / 1000,
			 	delta = before ? now - before : 0;
			that._onFrame({
				delta: delta, // Time elapsed since last redraw in seconds
				time: time += delta, // Time since first call of frame() in seconds
				count: count++
			});
			before = now;
			// Automatically draw view on each frame.
			that.draw();
		};
		// Call the onFrame handler straight away, initializing the sequence
		// of onFrame calls.
		if (!running)
			frame();
	},

	_createEvents: function() {
		var that = this,
			tool,
			timer,
			curPoint,
			dragging = false;

		function viewToArtwork(event) {
			return that.viewToArtwork(DomEvent.getOffset(event));
		}

		function mousedown(event) {
			// Tell the Key class which view should receive keyboard input.
			DocumentView.focused = that;
			if (!(tool = that._scope.tool))
				return;
			curPoint = viewToArtwork(event);
			tool.onHandleEvent('mousedown', curPoint, event);
			if (tool.onMouseDown)
				that.draw();
			if (tool.eventInterval != null)
				timer = setInterval(events.mousemove, tool.eventInterval);
			dragging = true;
		}

		function mousemove(event) {
			if (!(tool = that._scope.tool))
				return;
			// If the event was triggered by a touch screen device, prevent the
			// default behaviour, as it will otherwise scroll the page:
			if (event && event.targetTouches)
				DomEvent.preventDefault(event);
			var point = event && viewToArtwork(event);
			var onlyMove = !!(!tool.onMouseDrag && tool.onMouseMove);
			if (dragging && !onlyMove) {
				curPoint = point || curPoint;
				if (curPoint)
					tool.onHandleEvent('mousedrag', curPoint, event);
				if (tool.onMouseDrag)
					that.draw();
			// PORT: If there is only an onMouseMove handler, also call it when
			// the user is dragging:
			} else if (!dragging || onlyMove) {
				tool.onHandleEvent('mousemove', point, event);
				if (tool.onMouseMove)
					that.draw();
			}
		}

		function mouseup(event) {
			if (!dragging)
				return;
			dragging = false;
			curPoint = null;
			if (tool) {
				if (tool.eventInterval != null)
					timer = clearInterval(timer);
				tool.onHandleEvent('mouseup', viewToArtwork(event), event);
				if (tool.onMouseUp)
					that.draw();
			}
		}

		return {
			mousedown: mousedown,
			mousemove: mousemove,
			mouseup: mouseup,
			touchstart: mousedown,
			touchmove: mousemove,
			touchend: mouseup
		};
	}
});
<|endoftext|>


<commit_before>// Localizations for UI text.
// Keys correspond to applicable `lang` values, delimited by an underscore.
// Days and months must be listed in the order they should display.

const locales = {
  'en_en-US_en-UK': {
    days: [
      `Su`,
      `Mo`,
      `Tu`,
      `We`,
      `Th`,
      `Fr`,
      `Sa`
    ],
    months: [
      `January`,
      `February`,
      `March`,
      `April`,
      `May`,
      `June`,
      `July`,
      `August`,
      `September`,
      `October`,
      `November`,
      `December`
    ]
  },
  /* Simplified Chinese */
  'zh_zh-CN': {
    days: [
      `星期天`,
      `星期一`,
      `星期二`,
      `星期三`,
      `星期四`,
      `星期五`,
      `星期六`
    ],
    months: [
      `一月`,
      `二月`,
      `三月`,
      `四月`,
      `五月`,
      `六月`,
      `七月`,
      `八月`,
      `九月`,
      `十月`,
      `十一月`,
      `十二月`
    ]
  },
  /* Simplified Chinese, informal*/
  'zh-Hans_zh-Hans-CN': {
    days: [
      `周日`,
      `周一`,
      `周二`,
      `周三`,
      `周四`,
      `周五`,
      `周六`
    ],
    months: [
      `一月`,
      `二月`,
      `三月`,
      `四月`,
      `五月`,
      `六月`,
      `七月`,
      `八月`,
      `九月`,
      `十月`,
      `十一月`,
      `十二月`
    ]
  },
  /* Traditional Chinese */
  'zh-Hant_zh-Hant-TW': {
    days: [
      `週日`,
      `週一`,
      `週二`,
      `週三`,
      `週四`,
      `週五`,
      `週六`
    ],
    months: [
      `一月`,
      `二月`,
      `三月`,
      `四月`,
      `五月`,
      `六月`,
      `七月`,
      `八月`,
      `九月`,
      `十月`,
      `十一月`,
      `十二月`
    ]
  },
  /* German (Germany) */
  'de_de-DE': {
    days: [
      `Sonntag`,
      `Montag`,
      `Dienstag`,
      `Mittwoch`,
      `Donnerstag`,
      `Freitag`,
      `Samstag`
    ],
    months: [
      `Januar`,
      `Februar`,
      `März`,
      `April`,
      `Mai`,
      `Juni`,
      `Juli`,
      `August`,
      `September`,
      `Oktober`,
      `November`,
      `Dezember`
    ]
  },
  'pt_pt-BR': {
    days: [
      `Seg`,
      `Ter`,
      `Qua`,
      `Qui`,
      `Sex`,
      `Sáb`,
      `Dom`
    ],
    months: [
      `Janeiro`,
      `Fevereiro`,
      `Março`,
      `Abril`,
      `Maio`,
      `Junho`,
      `Julho`,
      `Agosto`,
      `Setembro`,
      `Outubro`,
      `Novembro`,
      `Dezembro`
    ],
    todayLabel: `Hoje`
  },
  'test_test-TEST': {
    days: [
      `Foo`,
      `Mon`,
      `Tue`,
      `Wed`,
      `Thu`,
      `Fri`,
      `Sat`
    ],
    months: [
      `Foo`,
      `February`,
      `March`,
      `April`,
      `May`,
      `June`,
      `July`,
      `August`,
      `September`,
      `October`,
      `November`,
      `December`
    ]
  }
};

export default locales;
<commit_msg>remove label<commit_after>// Localizations for UI text.
// Keys correspond to applicable `lang` values, delimited by an underscore.
// Days and months must be listed in the order they should display.

const locales = {
  'en_en-US_en-UK': {
    days: [
      `Su`,
      `Mo`,
      `Tu`,
      `We`,
      `Th`,
      `Fr`,
      `Sa`
    ],
    months: [
      `January`,
      `February`,
      `March`,
      `April`,
      `May`,
      `June`,
      `July`,
      `August`,
      `September`,
      `October`,
      `November`,
      `December`
    ]
  },
  /* Simplified Chinese */
  'zh_zh-CN': {
    days: [
      `星期天`,
      `星期一`,
      `星期二`,
      `星期三`,
      `星期四`,
      `星期五`,
      `星期六`
    ],
    months: [
      `一月`,
      `二月`,
      `三月`,
      `四月`,
      `五月`,
      `六月`,
      `七月`,
      `八月`,
      `九月`,
      `十月`,
      `十一月`,
      `十二月`
    ]
  },
  /* Simplified Chinese, informal*/
  'zh-Hans_zh-Hans-CN': {
    days: [
      `周日`,
      `周一`,
      `周二`,
      `周三`,
      `周四`,
      `周五`,
      `周六`
    ],
    months: [
      `一月`,
      `二月`,
      `三月`,
      `四月`,
      `五月`,
      `六月`,
      `七月`,
      `八月`,
      `九月`,
      `十月`,
      `十一月`,
      `十二月`
    ]
  },
  /* Traditional Chinese */
  'zh-Hant_zh-Hant-TW': {
    days: [
      `週日`,
      `週一`,
      `週二`,
      `週三`,
      `週四`,
      `週五`,
      `週六`
    ],
    months: [
      `一月`,
      `二月`,
      `三月`,
      `四月`,
      `五月`,
      `六月`,
      `七月`,
      `八月`,
      `九月`,
      `十月`,
      `十一月`,
      `十二月`
    ]
  },
  /* German (Germany) */
  'de_de-DE': {
    days: [
      `Sonntag`,
      `Montag`,
      `Dienstag`,
      `Mittwoch`,
      `Donnerstag`,
      `Freitag`,
      `Samstag`
    ],
    months: [
      `Januar`,
      `Februar`,
      `März`,
      `April`,
      `Mai`,
      `Juni`,
      `Juli`,
      `August`,
      `September`,
      `Oktober`,
      `November`,
      `Dezember`
    ]
  },
  'pt_pt-BR': {
    days: [
      `Seg`,
      `Ter`,
      `Qua`,
      `Qui`,
      `Sex`,
      `Sáb`,
      `Dom`
    ],
    months: [
      `Janeiro`,
      `Fevereiro`,
      `Março`,
      `Abril`,
      `Maio`,
      `Junho`,
      `Julho`,
      `Agosto`,
      `Setembro`,
      `Outubro`,
      `Novembro`,
      `Dezembro`
    ]
  },
  'test_test-TEST': {
    days: [
      `Foo`,
      `Mon`,
      `Tue`,
      `Wed`,
      `Thu`,
      `Fri`,
      `Sat`
    ],
    months: [
      `Foo`,
      `February`,
      `March`,
      `April`,
      `May`,
      `June`,
      `July`,
      `August`,
      `September`,
      `October`,
      `November`,
      `December`
    ]
  }
};

export default locales;
<|endoftext|>


<commit_before>request = require('request');
url = require('url');
colors = require('./googleCalendarColorService')
cheerio = require('cheerio');

function scrapeEvents(studentYear, programmeCode, callback) {
	time = new Date();
	time.setDate(time.getDate + 4)
	feritUrl = 'https://www.ferit.unios.hr/studenti/raspored-nastave-i-ispita/' +
		time.getFullYear() + '-' + (time.getMonth() + 1) +
		'-' + time.getDate() + '/' + studentYear + '-' + programmeCode;

	request.get(feritUrl, (error, response, body) => {
		//TODO: handle error
		const html = cheerio.load(body);
		let anchors = html('[target=_blank]')

		if (anchors == null || anchors == undefined) {
			return 'error with site';
		}

		anchors = anchors.toArray();

		anchors = anchors.reduce(
			(accumulator, currentValue) => {
				var href = currentValue.attribs.href;
				if (href.includes('calendar')) {
					var url_parts = url.parse(href, true);
					var query = url_parts.query;
					query = renameProperties(query)
					query = splitDates(query)
					query = parseColor(query)
					delete query.action;
					accumulator.push(query)

					return accumulator;
				}
				return accumulator;
			}, []);

		return callback(anchors);
	});

}

function scrapeEventsAsync(studentYear, programmeCode) {
	return new Promise((resolve, reject) => {
		time = new Date();
		time.setDate(time.getDate() + 4)
		feritUrl = 'https://www.ferit.unios.hr/studenti/raspored-nastave-i-ispita/' +
			time.getFullYear() + '-' + (time.getMonth() + 1) +
			'-' + time.getDate() + '/' + studentYear + '-' + programmeCode;

		request.get(feritUrl, (error, response, body) => {

			if (error !== null) return reject(error);

			const html = cheerio.load(body);
			let anchors = html("[href*='calendar']");
			if (anchors == null || anchors == undefined || anchors.length == 0) {
				if(feritUrl.endsWith('2-52')){
					return reject('automobilsko jos nema drugu godinu :p')
				}
				return reject(new Error('Site is not loading properly or design has changed, url=' +feritUrl));
			}

			anchors = anchors.toArray();

			//use array map, not reduce,the if statement is no longer needed since we use a better query selector
			anchors = anchors.reduce(
				(accumulator, currentValue) => {
					var href = currentValue.attribs.href;
					if (href.includes('calendar')) {
						var url_parts = url.parse(href, true);
						var query = url_parts.query;
						query = renameProperties(query)
						query = splitDates(query)
						query = parseColor(query)
						delete query.action;
						accumulator.push(query)

						return accumulator;
					}
					return accumulator;
				}, []);

			return resolve(anchors);
		});

	});
}
// properties have wrong names, therefore we have to rename them
function renameProperties(query) {
	Object.defineProperty(query, 'summary',
		Object.getOwnPropertyDescriptor(query, 'text'));
	delete query['text'];

	Object.defineProperty(query, 'description',
		Object.getOwnPropertyDescriptor(query, 'details'));
	delete query['details'];

	return query;
}

function splitDates(query) {
	dates = query.dates.split("/")
	//console.log(dates[0].substring(4, 6))
	//console.log(dates[1].substring(4, 6))
	startDate = new Date(dates[0].substring(0, 4), parseInt(dates[0].substring(4, 6)) - 1, dates[0].substring(6, 8), parseInt(dates[0].substring(9, 11)) + 1, dates[0].substring(11, 13), dates[0].substring(13, 15));
	endDate   = new Date(dates[1].substring(0, 4), parseInt(dates[1].substring(4, 6)) - 1, dates[1].substring(6, 8), parseInt(dates[1].substring(9, 11)) + 1, dates[1].substring(11, 13), dates[1].substring(13, 15));

	//console.log(startDate);
	query.start = { 'dateTime': startDate }
	query.end = { 'dateTime': endDate }
	delete query.dates

	return query;
}

function parseColor(query) {
	if (query.description.includes('Kontrolna zadaća')) {
		query.colorId = colors.kontrolna_zadaca;
	}

	//handle potential wrong function call order
	if (Object.prototype.hasOwnProperty.call(query, 'text')) {
		query = renameProperties(query)
	}

	if (query.summary.includes('predavanja')) {
		query.colorId = colors.predavanja;
	} else if (query.summary.includes('auditorne')) {
		query.colorId = colors.auditorne;
	} else if (query.summary.includes('laboratorijske')) {
		query.colorId = colors.laboratorijske;
	} else if (query.summary.includes('kontstrukcijske')) {
		query.colorId = colors.kontstrukcijske;
	} else if (query.summary.includes('ispitni rok')) {
		query.colorId = colors.ispitni_rok;
	} else if (query.summary.includes('Tjelesna')) {
		query.colorId = colors.ispitni_rok;
	}
	return query;
}

module.exports.scrapeEvents = scrapeEvents;
module.exports.scrapeEventsAsync = scrapeEventsAsync;
<commit_msg>fixed small bug<commit_after>request = require('request');
url = require('url');
colors = require('./googleCalendarColorService')
cheerio = require('cheerio');

function scrapeEvents(studentYear, programmeCode, callback) {
	time = new Date();
	time.setDate(time.getDate + 4)
	feritUrl = 'https://www.ferit.unios.hr/studenti/raspored-nastave-i-ispita/' +
		time.getFullYear() + '-' + (time.getMonth() + 1) +
		'-' + time.getDate() + '/' + studentYear + '-' + programmeCode;

	request.get(feritUrl, (error, response, body) => {
		//TODO: handle error
		const html = cheerio.load(body);
		let anchors = html('[target=_blank]')

		if (anchors == null || anchors == undefined) {
			return 'error with site';
		}

		anchors = anchors.toArray();

		anchors = anchors.reduce(
			(accumulator, currentValue) => {
				var href = currentValue.attribs.href;
				if (href.includes('calendar')) {
					var url_parts = url.parse(href, true);
					var query = url_parts.query;
					query = renameProperties(query)
					query = splitDates(query)
					query = parseColor(query)
					delete query.action;
					accumulator.push(query)

					return accumulator;
				}
				return accumulator;
			}, []);

		return callback(anchors);
	});

}

function scrapeEventsAsync(studentYear, programmeCode) {
	return new Promise((resolve, reject) => {
		time = new Date();
		time.setDate(time.getDate() + 4)
		feritUrl = 'https://www.ferit.unios.hr/studenti/raspored-nastave-i-ispita/' +
			time.getFullYear() + '-' + (time.getMonth() + 1) +
			'-' + time.getDate() + '/' + studentYear + '-' + programmeCode;

		request.get(feritUrl, (error, response, body) => {

			if (error !== null) return reject(error);

			const html = cheerio.load(body);
			let anchors = html("[href*='calendar']");
			if (anchors == null || anchors == undefined || anchors.length == 0) {
				if(feritUrl.endsWith('2-52')){
					return reject('automobilsko jos nema drugu godinu :p')
				}
				return reject(new Error('Site is not loading properly or design has changed, url=' +feritUrl));
			}

			anchors = anchors.toArray();

			//use array map, not reduce,the if statement is no longer needed since we use a better query selector
			anchors = anchors.reduce(
				(accumulator, currentValue) => {
					var href = currentValue.attribs.href;
					if (href.includes('calendar')) {
						var url_parts = url.parse(href, true);
						var query = url_parts.query;
						query = renameProperties(query)
						query = splitDates(query)
						query = parseColor(query)
						delete query.action;
						accumulator.push(query)

						return accumulator;
					}
					return accumulator;
				}, []);

			return resolve(anchors);
		});

	});
}
// properties have wrong names, therefore we have to rename them
function renameProperties(query) {
	Object.defineProperty(query, 'summary',
		Object.getOwnPropertyDescriptor(query, 'text'));
	delete query['text'];

	Object.defineProperty(query, 'description',
		Object.getOwnPropertyDescriptor(query, 'details'));
	delete query['details'];

	return query;
}

function splitDates(query) {
	dates = query.dates.split("/")
	//console.log(dates[0].substring(4, 6))
	//console.log(dates[1].substring(4, 6))
	startDate = new Date(dates[0].substring(0, 4), parseInt(dates[0].substring(4, 6)) - 1, dates[0].substring(6, 8), parseInt(dates[0].substring(9, 11)) + 1, dates[0].substring(11, 13), dates[0].substring(13, 15));
	endDate   = new Date(dates[1].substring(0, 4), parseInt(dates[1].substring(4, 6)) - 1, dates[1].substring(6, 8), parseInt(dates[1].substring(9, 11)) + 1, dates[1].substring(11, 13), dates[1].substring(13, 15));

	//console.log(startDate);
	query.start = { 'dateTime': startDate }
	query.end = { 'dateTime': endDate }
	delete query.dates

	return query;
}

function parseColor(query) {
	if (query.description.includes('Kontrolna zadaća')) {
		query.colorId = colors.kontrolna_zadaca;
	}

	//handle potential wrong function call order
	if (Object.prototype.hasOwnProperty.call(query, 'text')) {
		query = renameProperties(query)
	}

	if (query.summary.includes('predavanja')) {
		query.colorId = colors.predavanja;
	} else if (query.summary.includes('auditorne')) {
		query.colorId = colors.auditorne;
	} else if (query.summary.includes('laboratorijske')) {
		query.colorId = colors.laboratorijske;
	} else if (query.summary.includes('konstrukcijske')) {
		query.colorId = colors.konstrukcijske;
	} else if (query.summary.includes('ispitni rok')) {
		query.colorId = colors.ispitni_rok;
	} else if (query.summary.includes('Tjelesna')) {
		query.colorId = colors.ispitni_rok;
	}
	return query;
}

module.exports.scrapeEvents = scrapeEvents;
module.exports.scrapeEventsAsync = scrapeEventsAsync;
<|endoftext|>


<commit_before>/**
* Stage by Grant Skinner. Dec 5, 2010
* Visit www.gskinner.com/blog for documentation, updates and more free code.
*
*
* Copyright (c) 2010 Grant Skinner
*
* 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.
**/

(function(window) {

/**
* Constructs a Stage object with the specified target canvas.
* @param canvas The canvas the stage will render to.
* @class A stage is the root level Container for a display list. Each time its tick method is called, it will render its display list to its target canvas.
* @augments Container
**/
function Stage(canvas) {
  this.initialize(canvas);
}
var p = Stage.prototype = new Container();

// public properties:
	/** Indicates whether the stage should automatically clear the canvas before each render. You can set this to false to manually control clearing (for generative art, or when pointing multiple stages at the same canvas for example). **/
	p.autoClear = true;
	/** The canvas the stage will render to. Multiple stages can share a single canvas, but you must disable autoClear for all but the first stage that will be ticked (or they will clear each other's render). **/
	p.canvas = null;
	p.mouseX = null;
	p.mouseY = null;
	p.mouseEventsEnabled = false;
	p.onMouseMove = null;
	p.onMouseUp = null;
	p.onMouseDown = null;

// private properties:
	/** @private **/
	p._tmpCanvas = null;
	p._activeMouseEvent = null;

// constructor:
	/** @private **/
	p.Container_initialize = p.initialize;
	/** @private **/
	p.initialize = function(canvas) {
		this.Container_initialize();
		this.canvas = canvas;
		this.mouseChildren = true;

		var o = this;
		if (window.addEventListener) {
			window.addEventListener("mouseup", function(e) { o._handleMouseUp(e); }, false);
		} else if (document.addEventListener) {
			document.addEventListener("mouseup", function(e) { o._handleMouseUp(e); }, false);
		}

		canvas.addEventListener("mousemove", function(e) { o._handleMouseMove(e); }, false);
		canvas.addEventListener("mousedown", function(e) { o._handleMouseDown(e); }, false);
	}

// public methods:
	/**
	* Each time the update method is called, the stage will tick any descendants exposing a tick method (ex. BitmapSequence) and render its entire display list to the canvas.
	**/
	p.update = function() {
		if (this.canvas == null) { return; }
		var ctx = this.canvas.getContext("2d");
		if (this.autoClear) { this.clear(); }
		this.updateContext(ctx);
		this.draw(ctx);
		this.revertContext();
	}

	/**
	* Calls the update method. Useful for adding stage as a listener to Ticker directly.
	**/
	p.tick = p.update;

	/**
	* Clears the target canvas. Useful if autoClear is set to false.
	**/
	p.clear = function() {
		if (this.canvas == null) { return; }
		this.canvas.getContext("2d").clearRect(0,0,this.canvas.width,this.canvas.height);
	}

	/**
	* Returns an array of all display objects under the specified canvas coordinates that are in this stage's display list. This routine ignores any display objects with mouseEnabled set to false (the default) or that are inside containers with mouseChildren set to false (the default). The array will be sorted in order of visual depth, with the top-most display object at index 0. This uses shape based hit detection, and can be an expensive operation to run, so it is best to use it carefully. For example, if testing for objects under the mouse, test on tick (instead of on mousemove), and only if the mouse's position has changed.
	* @param x The x coordinate to test.
	* @param y The y coordinate to test.
	**/
	p.getObjectsUnderPoint = function(x,y) {
		var arr = [];
		this._getObjectsUnderPoint(x,y,arr);
		return arr;
	}

	/**
	* Similar to getObjectsUnderPoint(), but returns only the top-most display object. This runs significantly faster than getObjectsUnderPoint(), but is still an expensive operation. See getObjectsUnderPoint() for more information.
	* @param x The x coordinate to test.
	* @param y The y coordinate to test.
	**/
	p.getObjectUnderPoint = function(x,y) {
		return this._getObjectsUnderPoint(x,y);
	}

	/**
	* Returns a data url that contains a Base64 encoded image of the contents of the stage. The returned data url can be
	* specified as the src value of an image element.
	* @param backgroundColor The background color to be used for the generated image. The value can be any value HTML color
	* value, including HEX colors, rgb and rgba. The default value is a transparent background.
	* @param mimeType The MIME type of the image format to be create. The default is "image/png". If an unknown MIME type
	* is passed in, or if the browser does not support the specified MIME type, the default value will be used.
	* @returns a Base64 encoded image.
	* @type String
	**/
	p.toImageData = function(backgroundColor, mimeType) {
		if(!mimeType) {
			mimeType = "image/png";
		}

		var ctx = this.canvas.getContext('2d');
		var w = this.canvas.width;
		var h = this.canvas.height;

		var data;

		if(backgroundColor) {

			//get the current ImageData for the canvas.
			data = ctx.getImageData(0, 0, w, h);

			//store the current globalCompositeOperation
			var compositeOperation = ctx.globalCompositeOperation;

			//set to draw behind current content
			ctx.globalCompositeOperation = "destination-over";

			//set background color
			ctx.fillStyle = backgroundColor;

			//draw background on entire canvas
			ctx.fillRect(0,0,w,h);
		}

		//get the image data from the canvas
		var imageData = this.canvas.toDataURL(mimeType);

		if(backgroundColor) {
			//clear the canvas
			ctx.clearRect (0,0,w,h);

			//restore it with original settings
			ctx.putImageData(data, 0,0);

			//reset the globalCompositeOperation to what it was
			ctx.globalCompositeOperation = compositeOperation;
		}

		return imageData;
	}

	p.clone = function() {
		var o = new Stage(null);
		this.cloneProps(o);
		return o;
	}

	p.toString = function() {
		return "[Stage (name="+  this.name +")]";
	}

// private methods:
	/** @private **/
	p._Container_getObjectsUnderPoint = p._getObjectsUnderPoint;
	/** @private **/
	p._getObjectsUnderPoint = function(x,y,arr) {
		if (this._tmpCanvas == null) { this._tmpCanvas = document.createElement("canvas"); }
		this._tmpCanvas.width = this.canvas.width;
		this._tmpCanvas.height = this.canvas.height;

		var ctx = this._tmpCanvas.getContext("2d");

		this.updateContext(ctx,true);
		var results = this._Container_getObjectsUnderPoint(x,y,ctx,arr);
		this.revertContext();

		return results;
	}

	p._handleMouseMove = function(e) {
		if (!this.canvas) {
			this.mouseX = this.mouseY = null;
			return;
		}
		this.mouseX = e.pageX-this.canvas.offsetLeft;
		this.mouseY = e.pageY-this.canvas.offsetTop;

		var evt = new MouseEvent("onMouseMove", this.mouseX, this.mouseY);
		if (this.onMouseMove) { this.onMouseMove(evt); }
		if (this._activeMouseEvent && this._activeMouseEvent.onMouseMove) { this._activeMouseEvent.onMouseMove(evt); }
	}

	p._handleMouseUp = function(e) {
		var evt = new MouseEvent("onMouseUp", this.mouseX, this.mouseY);
		if (this.onMouseUp) { this.onMouseUp(evt); }
		if (this._activeMouseEvent && this._activeMouseEvent.onMouseUp) { this._activeMouseEvent.onMouseUp(evt); }
	}

	p._handleMouseDown = function(e) {
		if (this.onMouseDown) { this.onMouseDown(new MouseEvent("onMouseDown", this.mouseX, this.mouseY)); }
	}

window.Stage = Stage;
}(window));<commit_msg>renamed toImageData to toDataURL (since it returns a data url.<commit_after>/**
* Stage by Grant Skinner. Dec 5, 2010
* Visit www.gskinner.com/blog for documentation, updates and more free code.
*
*
* Copyright (c) 2010 Grant Skinner
*
* 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.
**/

(function(window) {

/**
* Constructs a Stage object with the specified target canvas.
* @param canvas The canvas the stage will render to.
* @class A stage is the root level Container for a display list. Each time its tick method is called, it will render its display list to its target canvas.
* @augments Container
**/
function Stage(canvas) {
  this.initialize(canvas);
}
var p = Stage.prototype = new Container();

// public properties:
	/** Indicates whether the stage should automatically clear the canvas before each render. You can set this to false to manually control clearing (for generative art, or when pointing multiple stages at the same canvas for example). **/
	p.autoClear = true;
	/** The canvas the stage will render to. Multiple stages can share a single canvas, but you must disable autoClear for all but the first stage that will be ticked (or they will clear each other's render). **/
	p.canvas = null;
	p.mouseX = null;
	p.mouseY = null;
	p.mouseEventsEnabled = false;
	p.onMouseMove = null;
	p.onMouseUp = null;
	p.onMouseDown = null;

// private properties:
	/** @private **/
	p._tmpCanvas = null;
	p._activeMouseEvent = null;

// constructor:
	/** @private **/
	p.Container_initialize = p.initialize;
	/** @private **/
	p.initialize = function(canvas) {
		this.Container_initialize();
		this.canvas = canvas;
		this.mouseChildren = true;

		var o = this;
		if (window.addEventListener) {
			window.addEventListener("mouseup", function(e) { o._handleMouseUp(e); }, false);
		} else if (document.addEventListener) {
			document.addEventListener("mouseup", function(e) { o._handleMouseUp(e); }, false);
		}

		canvas.addEventListener("mousemove", function(e) { o._handleMouseMove(e); }, false);
		canvas.addEventListener("mousedown", function(e) { o._handleMouseDown(e); }, false);
	}

// public methods:
	/**
	* Each time the update method is called, the stage will tick any descendants exposing a tick method (ex. BitmapSequence) and render its entire display list to the canvas.
	**/
	p.update = function() {
		if (this.canvas == null) { return; }
		var ctx = this.canvas.getContext("2d");
		if (this.autoClear) { this.clear(); }
		this.updateContext(ctx);
		this.draw(ctx);
		this.revertContext();
	}

	/**
	* Calls the update method. Useful for adding stage as a listener to Ticker directly.
	**/
	p.tick = p.update;

	/**
	* Clears the target canvas. Useful if autoClear is set to false.
	**/
	p.clear = function() {
		if (this.canvas == null) { return; }
		this.canvas.getContext("2d").clearRect(0,0,this.canvas.width,this.canvas.height);
	}

	/**
	* Returns an array of all display objects under the specified canvas coordinates that are in this stage's display list. This routine ignores any display objects with mouseEnabled set to false (the default) or that are inside containers with mouseChildren set to false (the default). The array will be sorted in order of visual depth, with the top-most display object at index 0. This uses shape based hit detection, and can be an expensive operation to run, so it is best to use it carefully. For example, if testing for objects under the mouse, test on tick (instead of on mousemove), and only if the mouse's position has changed.
	* @param x The x coordinate to test.
	* @param y The y coordinate to test.
	**/
	p.getObjectsUnderPoint = function(x,y) {
		var arr = [];
		this._getObjectsUnderPoint(x,y,arr);
		return arr;
	}

	/**
	* Similar to getObjectsUnderPoint(), but returns only the top-most display object. This runs significantly faster than getObjectsUnderPoint(), but is still an expensive operation. See getObjectsUnderPoint() for more information.
	* @param x The x coordinate to test.
	* @param y The y coordinate to test.
	**/
	p.getObjectUnderPoint = function(x,y) {
		return this._getObjectsUnderPoint(x,y);
	}

	/**
	* Returns a data url that contains a Base64 encoded image of the contents of the stage. The returned data url can be
	* specified as the src value of an image element.
	* @param backgroundColor The background color to be used for the generated image. The value can be any value HTML color
	* value, including HEX colors, rgb and rgba. The default value is a transparent background.
	* @param mimeType The MIME type of the image format to be create. The default is "image/png". If an unknown MIME type
	* is passed in, or if the browser does not support the specified MIME type, the default value will be used.
	* @returns a Base64 encoded image.
	* @type String
	**/
	p.toDataURL = function(backgroundColor, mimeType) {
		if(!mimeType) {
			mimeType = "image/png";
		}

		var ctx = this.canvas.getContext('2d');
		var w = this.canvas.width;
		var h = this.canvas.height;

		var data;

		if(backgroundColor) {

			//get the current ImageData for the canvas.
			data = ctx.getImageData(0, 0, w, h);

			//store the current globalCompositeOperation
			var compositeOperation = ctx.globalCompositeOperation;

			//set to draw behind current content
			ctx.globalCompositeOperation = "destination-over";

			//set background color
			ctx.fillStyle = backgroundColor;

			//draw background on entire canvas
			ctx.fillRect(0,0,w,h);
		}

		//get the image data from the canvas
		var dataURL = this.canvas.toDataURL(mimeType);

		if(backgroundColor) {
			//clear the canvas
			ctx.clearRect (0,0,w,h);

			//restore it with original settings
			ctx.putImageData(data, 0,0);

			//reset the globalCompositeOperation to what it was
			ctx.globalCompositeOperation = compositeOperation;
		}

		return dataURL;
	}

	p.clone = function() {
		var o = new Stage(null);
		this.cloneProps(o);
		return o;
	}

	p.toString = function() {
		return "[Stage (name="+  this.name +")]";
	}

// private methods:
	/** @private **/
	p._Container_getObjectsUnderPoint = p._getObjectsUnderPoint;
	/** @private **/
	p._getObjectsUnderPoint = function(x,y,arr) {
		if (this._tmpCanvas == null) { this._tmpCanvas = document.createElement("canvas"); }
		this._tmpCanvas.width = this.canvas.width;
		this._tmpCanvas.height = this.canvas.height;

		var ctx = this._tmpCanvas.getContext("2d");

		this.updateContext(ctx,true);
		var results = this._Container_getObjectsUnderPoint(x,y,ctx,arr);
		this.revertContext();

		return results;
	}

	p._handleMouseMove = function(e) {
		if (!this.canvas) {
			this.mouseX = this.mouseY = null;
			return;
		}
		this.mouseX = e.pageX-this.canvas.offsetLeft;
		this.mouseY = e.pageY-this.canvas.offsetTop;

		var evt = new MouseEvent("onMouseMove", this.mouseX, this.mouseY);
		if (this.onMouseMove) { this.onMouseMove(evt); }
		if (this._activeMouseEvent && this._activeMouseEvent.onMouseMove) { this._activeMouseEvent.onMouseMove(evt); }
	}

	p._handleMouseUp = function(e) {
		var evt = new MouseEvent("onMouseUp", this.mouseX, this.mouseY);
		if (this.onMouseUp) { this.onMouseUp(evt); }
		if (this._activeMouseEvent && this._activeMouseEvent.onMouseUp) { this._activeMouseEvent.onMouseUp(evt); }
	}

	p._handleMouseDown = function(e) {
		if (this.onMouseDown) { this.onMouseDown(new MouseEvent("onMouseDown", this.mouseX, this.mouseY)); }
	}

window.Stage = Stage;
}(window));<|endoftext|>


<commit_before>import debug from 'debug';
import fs from 'fs-promise';
import inquirer from 'inquirer';
import ora from 'ora';
import path from 'path';
import pify from 'pify';
import program from 'commander';
import rimraf from 'rimraf';
import { spawn as yarnOrNPMSpawn, hasYarn } from 'yarn-or-npm';

import initGit from './init/init-git';
import { deps, devDeps } from './init/init-npm';

import installDepList from './util/install-dependencies';

import './util/terminate';

const d = debug('electron-forge:import');

const main = async () => {
  let dir = process.cwd();
  program
    .version(require('../package.json').version)
    .arguments('[name]')
    .action((name) => {
      if (!name) return;
      if (path.isAbsolute(name)) {
        dir = name;
      } else {
        dir = path.resolve(dir, name);
      }
    })
    .parse(process.argv);

  d(`Attempting to import project in: ${dir}`);
  if (!await fs.exists(dir) || !await fs.exists(path.resolve(dir, 'package.json'))) {
    console.error(`We couldn't find a project in: ${dir}`.red);
    process.exit(1);
  }

  const { confirm } = await inquirer.createPromptModule()({
    type: 'confirm',
    name: 'confirm',
    message: `WARNING: We will now attempt to import: "${dir}".  This will involve modifying some files, are you sure you want to continue?`,
  });
  if (!confirm) {
    process.exit(1);
  }

  await initGit(dir);

  const packageJSONPath = path.resolve(dir, 'package.json');
  let packageJSON = JSON.parse(await fs.readFile(packageJSONPath, 'utf8'));
  if (packageJSON.config && packageJSON.config.forge) {
    console.warn('It looks like this project is already configured for "electron-forge"'.green);
    const { shouldContinue } = await inquirer.createPromptModule()({
      type: 'confirm',
      name: 'shouldContinue',
      message: 'Are you sure you want to continue?',
    });
    if (!shouldContinue) {
      process.exit(0);
    }
  }

  const { shouldChangeMain } = await inquirer.createPromptModule()({
    type: 'confirm',
    name: 'shouldChangeMain',
    message: 'Do you want us to change the "main" attribute of your package.json?  If you are currently using babel and pointint to a "build" directory say yes.', // eslint-disable-line
  });
  if (shouldChangeMain) {
    const { newMain } = await inquirer.createPromptModule()({
      type: 'input',
      name: 'newMain',
      default: packageJSON.main,
      message: 'Enter the relative path to your uncompiled main file',
    });
    packageJSON.main = newMain;
  }

  packageJSON.dependencies = packageJSON.dependencies || {};
  packageJSON.devDependencies = packageJSON.devDependencies || {};

  const keys = Object.keys(packageJSON.dependencies).concat(Object.keys(packageJSON.devDependencies));
  let electronName;
  for (const key of keys) {
    if (key === 'electron' || key === 'electron-prebuilt') {
      delete packageJSON.dependencies[key];
      delete packageJSON.devDependencies[key];
      electronName = key;
    }
  }

  const writeChanges = async () => {
    const writeSpinner = ora.ora('Writing modified package.json file').start();
    await fs.writeFile(packageJSONPath, `${JSON.stringify(packageJSON, null, 2)}\n`);
    writeSpinner.succeed();
  };

  let electronVersion;
  if (electronName) {
    electronVersion = JSON.parse(await fs.readFile(path.resolve(dir, 'node_modules', electronName, 'package.json'))).version;
    packageJSON.devDependencies['electron-prebuilt-compile'] = electronVersion;
  }

  await writeChanges();

  if (electronName) {
    const pruneSpinner = ora.ora('Pruning deleted modules').start();
    await new Promise((resolve) => {
      d('attempting to prune node_modules in:', dir);
      const child = yarnOrNPMSpawn(hasYarn() ? [] : ['prune'], {
        cwd: dir,
        stdio: 'ignore',
      });
      child.on('exit', () => resolve());
    });
    pruneSpinner.succeed();

    const installSpinner = ora.ora('Installing dependencies').start();

    await pify(rimraf)(path.resolve(dir, 'node_modules/.bin/electron'));
    await pify(rimraf)(path.resolve(dir, 'node_modules/.bin/electron.cmd'));
    await pify(rimraf)(path.resolve(dir, 'node_modules', electronName));

    d('installing dependencies');
    await installDepList(dir, deps);
    d('installing devDependencies');
    await installDepList(dir, devDeps, true);
    d('installing electron-prebuilt-compile');
    await installDepList(dir, [`electron-prebuilt-compile@${electronVersion}`], false, true);
    installSpinner.succeed();
  }

  packageJSON = JSON.parse(await fs.readFile(packageJSONPath, 'utf8'));

  packageJSON.config = packageJSON.config || {};
  packageJSON.config.forge = JSON.parse(await fs.readFile(path.resolve(__dirname, '../tmpl/package.json'))).config.forge;

  await writeChanges();

  const gitignoreSpinner = ora.ora('Fixing .gitignore').start();
  if (await fs.exists(path.resolve(dir, '.gitignore'))) {
    const gitignore = await fs.readFile(path.resolve(dir, '.gitignore'));
    if (!gitignore.includes('out')) {
      await fs.writeFile(path.resolve(dir, '.gitignore'), `${gitignore}\nout/`);
    }
  }
  gitignoreSpinner.succeed();
};

main();
<commit_msg>feat(importer): move babel config in existing project to .compilerc<commit_after>import debug from 'debug';
import fs from 'fs-promise';
import inquirer from 'inquirer';
import ora from 'ora';
import path from 'path';
import pify from 'pify';
import program from 'commander';
import rimraf from 'rimraf';
import { spawn as yarnOrNPMSpawn, hasYarn } from 'yarn-or-npm';

import initGit from './init/init-git';
import { deps, devDeps } from './init/init-npm';

import installDepList from './util/install-dependencies';

import './util/terminate';

const d = debug('electron-forge:import');

const main = async () => {
  let dir = process.cwd();
  program
    .version(require('../package.json').version)
    .arguments('[name]')
    .action((name) => {
      if (!name) return;
      if (path.isAbsolute(name)) {
        dir = name;
      } else {
        dir = path.resolve(dir, name);
      }
    })
    .parse(process.argv);

  d(`Attempting to import project in: ${dir}`);
  if (!await fs.exists(dir) || !await fs.exists(path.resolve(dir, 'package.json'))) {
    console.error(`We couldn't find a project in: ${dir}`.red);
    process.exit(1);
  }

  const { confirm } = await inquirer.createPromptModule()({
    type: 'confirm',
    name: 'confirm',
    message: `WARNING: We will now attempt to import: "${dir}".  This will involve modifying some files, are you sure you want to continue?`,
  });
  if (!confirm) {
    process.exit(1);
  }

  await initGit(dir);

  const packageJSONPath = path.resolve(dir, 'package.json');
  let packageJSON = JSON.parse(await fs.readFile(packageJSONPath, 'utf8'));
  if (packageJSON.config && packageJSON.config.forge) {
    console.warn('It looks like this project is already configured for "electron-forge"'.green);
    const { shouldContinue } = await inquirer.createPromptModule()({
      type: 'confirm',
      name: 'shouldContinue',
      message: 'Are you sure you want to continue?',
    });
    if (!shouldContinue) {
      process.exit(0);
    }
  }

  const { shouldChangeMain } = await inquirer.createPromptModule()({
    type: 'confirm',
    name: 'shouldChangeMain',
    message: 'Do you want us to change the "main" attribute of your package.json?  If you are currently using babel and pointint to a "build" directory say yes.', // eslint-disable-line
  });
  if (shouldChangeMain) {
    const { newMain } = await inquirer.createPromptModule()({
      type: 'input',
      name: 'newMain',
      default: packageJSON.main,
      message: 'Enter the relative path to your uncompiled main file',
    });
    packageJSON.main = newMain;
  }

  packageJSON.dependencies = packageJSON.dependencies || {};
  packageJSON.devDependencies = packageJSON.devDependencies || {};

  const keys = Object.keys(packageJSON.dependencies).concat(Object.keys(packageJSON.devDependencies));
  let electronName;
  for (const key of keys) {
    if (key === 'electron' || key === 'electron-prebuilt') {
      delete packageJSON.dependencies[key];
      delete packageJSON.devDependencies[key];
      electronName = key;
    }
  }

  const writeChanges = async () => {
    const writeSpinner = ora.ora('Writing modified package.json file').start();
    await fs.writeFile(packageJSONPath, `${JSON.stringify(packageJSON, null, 2)}\n`);
    writeSpinner.succeed();
  };

  let electronVersion;
  if (electronName) {
    electronVersion = JSON.parse(await fs.readFile(path.resolve(dir, 'node_modules', electronName, 'package.json'))).version;
    packageJSON.devDependencies['electron-prebuilt-compile'] = electronVersion;
  }

  await writeChanges();

  if (electronName) {
    const pruneSpinner = ora.ora('Pruning deleted modules').start();
    await new Promise((resolve) => {
      d('attempting to prune node_modules in:', dir);
      const child = yarnOrNPMSpawn(hasYarn() ? [] : ['prune'], {
        cwd: dir,
        stdio: 'ignore',
      });
      child.on('exit', () => resolve());
    });
    pruneSpinner.succeed();

    const installSpinner = ora.ora('Installing dependencies').start();

    await pify(rimraf)(path.resolve(dir, 'node_modules/.bin/electron'));
    await pify(rimraf)(path.resolve(dir, 'node_modules/.bin/electron.cmd'));
    await pify(rimraf)(path.resolve(dir, 'node_modules', electronName));

    d('installing dependencies');
    await installDepList(dir, deps);
    d('installing devDependencies');
    await installDepList(dir, devDeps, true);
    d('installing electron-prebuilt-compile');
    await installDepList(dir, [`electron-prebuilt-compile@${electronVersion}`], false, true);
    installSpinner.succeed();
  }

  packageJSON = JSON.parse(await fs.readFile(packageJSONPath, 'utf8'));

  packageJSON.config = packageJSON.config || {};
  packageJSON.config.forge = JSON.parse(await fs.readFile(path.resolve(__dirname, '../tmpl/package.json'))).config.forge;

  await writeChanges();

  const gitignoreSpinner = ora.ora('Fixing .gitignore').start();
  if (await fs.exists(path.resolve(dir, '.gitignore'))) {
    const gitignore = await fs.readFile(path.resolve(dir, '.gitignore'));
    if (!gitignore.includes('out')) {
      await fs.writeFile(path.resolve(dir, '.gitignore'), `${gitignore}\nout/`);
    }
  }
  gitignoreSpinner.succeed();

  let babelConfig = packageJSON.babel;
  const babelPath = path.resolve(dir, '.babelrc');
  if (!babelConfig && await fs.exists(babelPath)) {
    babelConfig = JSON.parse(await fs.readFile(babelPath, 'utf8'));
  }

  if (babelConfig) {
    const babelSpinner = ora.ora('Porting original babel config').start();

    let compileConfig = {};
    const compilePath = path.resolve(dir, '.compilerc');
    if (await fs.exists(compilePath)) {
      compileConfig = JSON.parse(await fs.readFile(compilePath, 'utf8'));
    }

    await fs.writeFile(compilePath, JSON.stringify(Object.assign(compileConfig, {
      'application/javascript': babelConfig,
    }, null, 2)));

    babelSpinner.succeed();
    console.info('NOTE: You might be able to remove your `.compilerc` file completely if you are only using the `es2015` and `react` presets'.yellow);
  }
  /* eslint-disable prefer-template */
  console.info('\n\nWe have ATTEMPTED to convert your app to be in a format that electron-forge understands.\nNothing much will have changed but we added the' +
  ' "electron-prebuilt-compile" '.cyan +
  'dependency.  This is the dependency you must version bump to get newer versions of Electron.\n\n' +
  'We also tried to import any build tooling you already had but we can\'t get everything.  You might need to convert any CLI/gulp/grunt tasks yourself.\n\n' +
  'Also please note if you are using `preload` scripts you need to follow the steps outlined at https://github.com/electron-userland/electron-forge/wiki/Using-\'preload\'-scripts\n\n' +
  'Thanks for using ' + 'electron-forge'.green + '!!!');
};

main();
<|endoftext|>