import { getDocument } from 'ssr-window';
import { elementChildren, isObject } from '../../shared/utils.mjs';

export default function Thumb({ swiper, extendParams, on }) {
  extendParams({
    thumbs: {
      swiper: null,
      multipleActiveThumbs: true,
      autoScrollOffset: 0,
      slideThumbActiveClass: 'swiper-slide-thumb-active',
      thumbsContainerClass: 'swiper-thumbs',
    },
  });

  let initialized = false;
  let swiperCreated = false;

  swiper.thumbs = {
    swiper: null,
  };

  function onThumbClick() {
    const thumbsSwiper = swiper.thumbs.swiper;
    if (!thumbsSwiper || thumbsSwiper.destroyed) return;

    const clickedIndex = thumbsSwiper.clickedIndex;
    const clickedSlide = thumbsSwiper.clickedSlide;
    if (clickedSlide && clickedSlide.classList.contains(swiper.params.thumbs.slideThumbActiveClass))
      return;
    if (typeof clickedIndex === 'undefined' || clickedIndex === null) return;
    let slideToIndex;
    if (thumbsSwiper.params.loop) {
      slideToIndex = parseInt(
        thumbsSwiper.clickedSlide.getAttribute('data-swiper-slide-index'),
        10,
      );
    } else {
      slideToIndex = clickedIndex;
    }
    if (swiper.params.loop) {
      swiper.slideToLoop(slideToIndex);
    } else {
      swiper.slideTo(slideToIndex);
    }
  }

  function init() {
    const { thumbs: thumbsParams } = swiper.params;
    if (initialized) return false;
    initialized = true;
    const SwiperClass = swiper.constructor;
    if (thumbsParams.swiper instanceof SwiperClass) {
      swiper.thumbs.swiper = thumbsParams.swiper;
      Object.assign(swiper.thumbs.swiper.originalParams, {
        watchSlidesProgress: true,
        slideToClickedSlide: false,
      });
      Object.assign(swiper.thumbs.swiper.params, {
        watchSlidesProgress: true,
        slideToClickedSlide: false,
      });
      swiper.thumbs.swiper.update();
    } else if (isObject(thumbsParams.swiper)) {
      const thumbsSwiperParams = Object.assign({}, thumbsParams.swiper);
      Object.assign(thumbsSwiperParams, {
        watchSlidesProgress: true,
        slideToClickedSlide: false,
      });
      swiper.thumbs.swiper = new SwiperClass(thumbsSwiperParams);
      swiperCreated = true;
    }
    swiper.thumbs.swiper.el.classList.add(swiper.params.thumbs.thumbsContainerClass);
    swiper.thumbs.swiper.on('tap', onThumbClick);
    return true;
  }

  function update(initial) {
    const thumbsSwiper = swiper.thumbs.swiper;
    if (!thumbsSwiper || thumbsSwiper.destroyed) return;

    const slidesPerView =
      thumbsSwiper.params.slidesPerView === 'auto'
        ? thumbsSwiper.slidesPerViewDynamic()
        : thumbsSwiper.params.slidesPerView;

    // Activate thumbs
    let thumbsToActivate = 1;
    const thumbActiveClass = swiper.params.thumbs.slideThumbActiveClass;

    if (swiper.params.slidesPerView > 1 && !swiper.params.centeredSlides) {
      thumbsToActivate = swiper.params.slidesPerView;
    }

    if (!swiper.params.thumbs.multipleActiveThumbs) {
      thumbsToActivate = 1;
    }

    thumbsToActivate = Math.floor(thumbsToActivate);

    thumbsSwiper.slides.forEach((slideEl) => slideEl.classList.remove(thumbActiveClass));
    if (
      thumbsSwiper.params.loop ||
      (thumbsSwiper.params.virtual && thumbsSwiper.params.virtual.enabled)
    ) {
      for (let i = 0; i < thumbsToActivate; i += 1) {
        elementChildren(
          thumbsSwiper.slidesEl,
          `[data-swiper-slide-index="${swiper.realIndex + i}"]`,
        ).forEach((slideEl) => {
          slideEl.classList.add(thumbActiveClass);
        });
      }
    } else {
      for (let i = 0; i < thumbsToActivate; i += 1) {
        if (thumbsSwiper.slides[swiper.realIndex + i]) {
          thumbsSwiper.slides[swiper.realIndex + i].classList.add(thumbActiveClass);
        }
      }
    }

    const autoScrollOffset = swiper.params.thumbs.autoScrollOffset;
    const useOffset = autoScrollOffset && !thumbsSwiper.params.loop;
    if (swiper.realIndex !== thumbsSwiper.realIndex || useOffset) {
      const currentThumbsIndex = thumbsSwiper.activeIndex;
      let newThumbsIndex;
      let direction;
      if (thumbsSwiper.params.loop) {
        const newThumbsSlide = thumbsSwiper.slides.filter(
          (slideEl) => slideEl.getAttribute('data-swiper-slide-index') === `${swiper.realIndex}`,
        )[0];
        newThumbsIndex = thumbsSwiper.slides.indexOf(newThumbsSlide);

        direction = swiper.activeIndex > swiper.previousIndex ? 'next' : 'prev';
      } else {
        newThumbsIndex = swiper.realIndex;
        direction = newThumbsIndex > swiper.previousIndex ? 'next' : 'prev';
      }
      if (useOffset) {
        newThumbsIndex += direction === 'next' ? autoScrollOffset : -1 * autoScrollOffset;
      }

      if (
        thumbsSwiper.visibleSlidesIndexes &&
        thumbsSwiper.visibleSlidesIndexes.indexOf(newThumbsIndex) < 0
      ) {
        if (thumbsSwiper.params.centeredSlides) {
          if (newThumbsIndex > currentThumbsIndex) {
            newThumbsIndex = newThumbsIndex - Math.floor(slidesPerView / 2) + 1;
          } else {
            newThumbsIndex = newThumbsIndex + Math.floor(slidesPerView / 2) - 1;
          }
        } else if (
          newThumbsIndex > currentThumbsIndex &&
          thumbsSwiper.params.slidesPerGroup === 1
        ) {
          // newThumbsIndex = newThumbsIndex - slidesPerView + 1;
        }
        thumbsSwiper.slideTo(newThumbsIndex, initial ? 0 : undefined);
      }
    }
  }

  on('beforeInit', () => {
    const { thumbs } = swiper.params;
    if (!thumbs || !thumbs.swiper) return;
    if (typeof thumbs.swiper === 'string' || thumbs.swiper instanceof HTMLElement) {
      const document = getDocument();
      const getThumbsElementAndInit = () => {
        const thumbsElement =
          typeof thumbs.swiper === 'string' ? document.querySelector(thumbs.swiper) : thumbs.swiper;
        if (thumbsElement && thumbsElement.swiper) {
          thumbs.swiper = thumbsElement.swiper;
          init();
          update(true);
        } else if (thumbsElement) {
          const onThumbsSwiper = (e) => {
            thumbs.swiper = e.detail[0];
            thumbsElement.removeEventListener('init', onThumbsSwiper);
            init();
            update(true);
            thumbs.swiper.update();
            swiper.update();
          };
          thumbsElement.addEventListener('init', onThumbsSwiper);
        }
        return thumbsElement;
      };

      const watchForThumbsToAppear = () => {
        if (swiper.destroyed) return;
        const thumbsElement = getThumbsElementAndInit();
        if (!thumbsElement) {
          requestAnimationFrame(watchForThumbsToAppear);
        }
      };
      requestAnimationFrame(watchForThumbsToAppear);
    } else {
      init();
      update(true);
    }
  });
  on('slideChange update resize observerUpdate', () => {
    update();
  });
  on('setTransition', (_s, duration) => {
    const thumbsSwiper = swiper.thumbs.swiper;
    if (!thumbsSwiper || thumbsSwiper.destroyed) return;
    thumbsSwiper.setTransition(duration);
  });
  on('beforeDestroy', () => {
    const thumbsSwiper = swiper.thumbs.swiper;
    if (!thumbsSwiper || thumbsSwiper.destroyed) return;
    if (swiperCreated) {
      thumbsSwiper.destroy();
    }
  });

  Object.assign(swiper.thumbs, {
    init,
    update,
  });
}


keep keep keep replace keep keep keep keep keep

#define SHADER_NAME PHASER_MULTI_VS

precision mediump float;

uniform mat4 uProjectionMatrix;

attribute vec2 inPosition;
attribute vec2 inTexCoord;
attribute float inTexId;
attribute float inTintEffect;
attribute vec4 inTint;

varying vec2 outTexCoord;
varying float outTexId;
varying float outTintEffect;
varying vec4 outTint;

void main ()
{
    gl_Position = uProjectionMatrix * vec4(inPosition, 1.0, 1.0);

    outTexCoord = inTexCoord;
    outTexId = inTexId;
    outTint = inTint;
    outTintEffect = inTintEffect;
}


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var Blitter = require('./Blitter');
var BuildGameObject = require('../BuildGameObject');
var GameObjectCreator = require('../GameObjectCreator');
var GetAdvancedValue = require('../../utils/object/GetAdvancedValue');

/**
 * Creates a new Blitter Game Object and returns it.
 *
 * Note: This method will only be available if the Blitter Game Object has been built into Phaser.
 *
 * @method Phaser.GameObjects.GameObjectCreator#blitter
 * @since 3.0.0
 *
 * @param {Phaser.Types.GameObjects.Sprite.SpriteConfig} config - The configuration object this Game Object will use to create itself.
 * @param {boolean} [addToScene] - Add this Game Object to the Scene after creating it? If set this argument overrides the `add` property in the config object.
 *
 * @return {Phaser.GameObjects.Blitter} The Game Object that was created.
 */
GameObjectCreator.register('blitter', function (config, addToScene)
{
    if (config === undefined) { config = {}; }

    var key = GetAdvancedValue(config, 'key', null);
    var frame = GetAdvancedValue(config, 'frame', null);

    var blitter = new Blitter(this.scene, 0, 0, key, frame);

    if (addToScene !== undefined)
    {
        config.add = addToScene;
    }

    BuildGameObject(this.scene, blitter, config);

    return blitter;
});

//  When registering a factory function 'this' refers to the GameObjectCreator context.


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var Length = require('../line/Length');

/**
 * Gets the length of the perimeter of the given triangle.
 * Calculated by adding together the length of each of the three sides.
 *
 * @function Phaser.Geom.Triangle.Perimeter
 * @since 3.0.0
 *
 * @param {Phaser.Geom.Triangle} triangle - The Triangle to get the length from.
 *
 * @return {number} The length of the Triangle.
 */
var Perimeter = function (triangle)
{
    var line1 = triangle.getLineA();
    var line2 = triangle.getLineB();
    var line3 = triangle.getLineC();

    return (Length(line1) + Length(line2) + Length(line3));
};

module.exports = Perimeter;


/**
 * A Text Padding configuration object as used by the Text Style.
 *
 * @typedef {object} Phaser.Types.GameObjects.Text.TextPadding
 * @since 3.18.0
 *
 * @property {number} [x] - If set this value is used for both the left and right padding.
 * @property {number} [y] - If set this value is used for both the top and bottom padding.
 * @property {number} [left] - The amount of padding added to the left of the Text object.
 * @property {number} [right] - The amount of padding added to the right of the Text object.
 * @property {number} [top] - The amount of padding added to the top of the Text object.
 * @property {number} [bottom] - The amount of padding added to the bottom of the Text object.
 */


module.exports = [
    '#define SHADER_NAME PHASER_MULTI_FS',
    '',
    'precision mediump float;',
    '',
    'uniform sampler2D uMainSampler[%count%];',
    '',
    'varying vec2 outTexCoord;',
    'varying float outTexId;',
    'varying float outTintEffect;',
    'varying vec4 outTint;',
    '',
    'void main ()',
    '{',
    '    vec4 texture;',
    '',
    '    %forloop%',
    '',
    '    vec4 texel = vec4(outTint.bgr * outTint.a, outTint.a);',
    '',
    '    //  Multiply texture tint',
    '    vec4 color = texture * texel;',
    '',
    '    if (outTintEffect == 1.0)',
    '    {',
    '        //  Solid color + texture alpha',
    '        color.rgb = mix(texture.rgb, outTint.bgr * outTint.a, texture.a);',
    '    }',
    '    else if (outTintEffect == 2.0)',
    '    {',
    '        //  Solid color, no texture',
    '        color = texel;',
    '    }',
    '',
    '    gl_FragColor = color;',
    '}',
    ''
].join('\n');


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

/**
 * The Texture Load Error Event.
 *
 * This event is dispatched by the Texture Manager when a texture it requested to load failed.
 * This only happens when base64 encoded textures fail. All other texture types are loaded via the Loader Plugin.
 *
 * Listen to this event from within a Scene using: `this.textures.on('onerror', listener)`.
 *
 * @event Phaser.Textures.Events#ERROR
 * @since 3.0.0
 *
 * @param {string} key - The key of the Texture that failed to load into the Texture Manager.
 */
module.exports = 'onerror';


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var CONST = require('../const');
var Class = require('../utils/Class');
var Frame = require('./Frame');
var TextureSource = require('./TextureSource');

var TEXTURE_MISSING_ERROR = 'Texture "%s" has no frame "%s"';

/**
 * @classdesc
 * A Texture consists of a source, usually an Image from the Cache, and a collection of Frames.
 * The Frames represent the different areas of the Texture. For example a texture atlas
 * may have many Frames, one for each element within the atlas. Where-as a single image would have
 * just one frame, that encompasses the whole image.
 *
 * Every Texture, no matter where it comes from, always has at least 1 frame called the `__BASE` frame.
 * This frame represents the entirety of the source image.
 *
 * Textures are managed by the global TextureManager. This is a singleton class that is
 * responsible for creating and delivering Textures and their corresponding Frames to Game Objects.
 *
 * Sprites and other Game Objects get the texture data they need from the TextureManager.
 *
 * @class Texture
 * @memberof Phaser.Textures
 * @constructor
 * @since 3.0.0
 *
 * @param {Phaser.Textures.TextureManager} manager - A reference to the Texture Manager this Texture belongs to.
 * @param {string} key - The unique string-based key of this Texture.
 * @param {(HTMLImageElement|HTMLCanvasElement|HTMLImageElement[]|HTMLCanvasElement[])} source - An array of sources that are used to create the texture. Usually Images, but can also be a Canvas.
 * @param {number} [width] - The width of the Texture. This is optional and automatically derived from the source images.
 * @param {number} [height] - The height of the Texture. This is optional and automatically derived from the source images.
 */
var Texture = new Class({

    initialize:

    function Texture (manager, key, source, width, height)
    {
        if (!Array.isArray(source))
        {
            source = [ source ];
        }

        /**
         * A reference to the Texture Manager this Texture belongs to.
         *
         * @name Phaser.Textures.Texture#manager
         * @type {Phaser.Textures.TextureManager}
         * @since 3.0.0
         */
        this.manager = manager;

        /**
         * The unique string-based key of this Texture.
         *
         * @name Phaser.Textures.Texture#key
         * @type {string}
         * @since 3.0.0
         */
        this.key = key;

        /**
         * An array of TextureSource instances.
         * These are unique to this Texture and contain the actual Image (or Canvas) data.
         *
         * @name Phaser.Textures.Texture#source
         * @type {Phaser.Textures.TextureSource[]}
         * @since 3.0.0
         */
        this.source = [];

        /**
         * An array of TextureSource data instances.
         * Used to store additional data images, such as normal maps or specular maps.
         *
         * @name Phaser.Textures.Texture#dataSource
         * @type {array}
         * @since 3.0.0
         */
        this.dataSource = [];

        /**
         * A key-value object pair associating the unique Frame keys with the Frames objects.
         *
         * @name Phaser.Textures.Texture#frames
         * @type {object}
         * @since 3.0.0
         */
        this.frames = {};

        /**
         * Any additional data that was set in the source JSON (if any),
         * or any extra data you'd like to store relating to this texture
         *
         * @name Phaser.Textures.Texture#customData
         * @type {object}
         * @since 3.0.0
         */
        this.customData = {};

        /**
         * The name of the first frame of the Texture.
         *
         * @name Phaser.Textures.Texture#firstFrame
         * @type {string}
         * @since 3.0.0
         */
        this.firstFrame = '__BASE';

        /**
         * The total number of Frames in this Texture, including the `__BASE` frame.
         *
         * A Texture will always contain at least 1 frame because every Texture contains a `__BASE` frame by default,
         * in addition to any extra frames that have been added to it, such as when parsing a Sprite Sheet or Texture Atlas.
         *
         * @name Phaser.Textures.Texture#frameTotal
         * @type {number}
         * @default 0
         * @since 3.0.0
         */
        this.frameTotal = 0;

        //  Load the Sources
        for (var i = 0; i < source.length; i++)
        {
            this.source.push(new TextureSource(this, source[i], width, height));
        }
    },

    /**
     * Adds a new Frame to this Texture.
     *
     * A Frame is a rectangular region of a TextureSource with a unique index or string-based key.
     *
     * The name given must be unique within this Texture. If it already exists, this method will return `null`.
     *
     * @method Phaser.Textures.Texture#add
     * @since 3.0.0
     *
     * @param {(number|string)} name - The name of this Frame. The name is unique within the Texture.
     * @param {number} sourceIndex - The index of the TextureSource that this Frame is a part of.
     * @param {number} x - The x coordinate of the top-left of this Frame.
     * @param {number} y - The y coordinate of the top-left of this Frame.
     * @param {number} width - The width of this Frame.
     * @param {number} height - The height of this Frame.
     *
     * @return {?Phaser.Textures.Frame} The Frame that was added to this Texture, or `null` if the given name already exists.
     */
    add: function (name, sourceIndex, x, y, width, height)
    {
        if (this.has(name))
        {
            return null;
        }

        var frame = new Frame(this, name, sourceIndex, x, y, width, height);

        this.frames[name] = frame;

        //  Set the first frame of the Texture (other than __BASE)
        //  This is used to ensure we don't spam the display with entire
        //  atlases of sprite sheets, but instead just the first frame of them
        //  should the dev incorrectly specify the frame index
        if (this.firstFrame === '__BASE')
        {
            this.firstFrame = name;
        }

        this.frameTotal++;

        return frame;
    },

    /**
     * Removes the given Frame from this Texture. The Frame is destroyed immediately.
     *
     * Any Game Objects using this Frame should stop using it _before_ you remove it,
     * as it does not happen automatically.
     *
     * @method Phaser.Textures.Texture#remove
     * @since 3.19.0
     *
     * @param {string} name - The key of the Frame to remove.
     *
     * @return {boolean} True if a Frame with the matching key was removed from this Texture.
     */
    remove: function (name)
    {
        if (this.has(name))
        {
            var frame = this.get(name);

            frame.destroy();

            delete this.frames[name];

            return true;
        }

        return false;
    },

    /**
     * Checks to see if a Frame matching the given key exists within this Texture.
     *
     * @method Phaser.Textures.Texture#has
     * @since 3.0.0
     *
     * @param {string} name - The key of the Frame to check for.
     *
     * @return {boolean} True if a Frame with the matching key exists in this Texture.
     */
    has: function (name)
    {
        return (this.frames[name]);
    },

    /**
     * Gets a Frame from this Texture based on either the key or the index of the Frame.
     *
     * In a Texture Atlas Frames are typically referenced by a key.
     * In a Sprite Sheet Frames are referenced by an index.
     * Passing no value for the name returns the base texture.
     *
     * @method Phaser.Textures.Texture#get
     * @since 3.0.0
     *
     * @param {(string|number)} [name] - The string-based name, or integer based index, of the Frame to get from this Texture.
     *
     * @return {Phaser.Textures.Frame} The Texture Frame.
     */
    get: function (name)
    {
        //  null, undefined, empty string, zero
        if (!name)
        {
            name = this.firstFrame;
        }

        var frame = this.frames[name];

        if (!frame)
        {
            console.warn(TEXTURE_MISSING_ERROR, this.key, name);

            frame = this.frames[this.firstFrame];
        }

        return frame;
    },

    /**
     * Takes the given TextureSource and returns the index of it within this Texture.
     * If it's not in this Texture, it returns -1.
     * Unless this Texture has multiple TextureSources, such as with a multi-atlas, this
     * method will always return zero or -1.
     *
     * @method Phaser.Textures.Texture#getTextureSourceIndex
     * @since 3.0.0
     *
     * @param {Phaser.Textures.TextureSource} source - The TextureSource to check.
     *
     * @return {number} The index of the TextureSource within this Texture, or -1 if not in this Texture.
     */
    getTextureSourceIndex: function (source)
    {
        for (var i = 0; i < this.source.length; i++)
        {
            if (this.source[i] === source)
            {
                return i;
            }
        }

        return -1;
    },

    /**
     * Returns an array of all the Frames in the given TextureSource.
     *
     * @method Phaser.Textures.Texture#getFramesFromTextureSource
     * @since 3.0.0
     *
     * @param {number} sourceIndex - The index of the TextureSource to get the Frames from.
     * @param {boolean} [includeBase=false] - Include the `__BASE` Frame in the output array?
     *
     * @return {Phaser.Textures.Frame[]} An array of Texture Frames.
     */
    getFramesFromTextureSource: function (sourceIndex, includeBase)
    {
        if (includeBase === undefined) { includeBase = false; }

        var out = [];

        for (var frameName in this.frames)
        {
            if (frameName === '__BASE' && !includeBase)
            {
                continue;
            }

            var frame = this.frames[frameName];

            if (frame.sourceIndex === sourceIndex)
            {
                out.push(frame);
            }
        }

        return out;
    },

    /**
     * Returns an array with all of the names of the Frames in this Texture.
     *
     * Useful if you want to randomly assign a Frame to a Game Object, as you can
     * pick a random element from the returned array.
     *
     * @method Phaser.Textures.Texture#getFrameNames
     * @since 3.0.0
     *
     * @param {boolean} [includeBase=false] - Include the `__BASE` Frame in the output array?
     *
     * @return {string[]} An array of all Frame names in this Texture.
     */
    getFrameNames: function (includeBase)
    {
        if (includeBase === undefined) { includeBase = false; }

        var out = Object.keys(this.frames);

        if (!includeBase)
        {
            var idx = out.indexOf('__BASE');

            if (idx !== -1)
            {
                out.splice(idx, 1);
            }
        }

        return out;
    },

    /**
     * Given a Frame name, return the source image it uses to render with.
     *
     * This will return the actual DOM Image or Canvas element.
     *
     * @method Phaser.Textures.Texture#getSourceImage
     * @since 3.0.0
     *
     * @param {(string|number)} [name] - The string-based name, or integer based index, of the Frame to get from this Texture.
     *
     * @return {(HTMLImageElement|HTMLCanvasElement|Phaser.GameObjects.RenderTexture)} The DOM Image, Canvas Element or Render Texture.
     */
    getSourceImage: function (name)
    {
        if (name === undefined || name === null || this.frameTotal === 1)
        {
            name = '__BASE';
        }

        var frame = this.frames[name];

        if (frame)
        {
            return frame.source.image;
        }
        else
        {
            console.warn(TEXTURE_MISSING_ERROR, this.key, name);

            return this.frames['__BASE'].source.image;
        }
    },

    /**
     * Given a Frame name, return the data source image it uses to render with.
     * You can use this to get the normal map for an image for example.
     *
     * This will return the actual DOM Image.
     *
     * @method Phaser.Textures.Texture#getDataSourceImage
     * @since 3.7.0
     *
     * @param {(string|number)} [name] - The string-based name, or integer based index, of the Frame to get from this Texture.
     *
     * @return {(HTMLImageElement|HTMLCanvasElement)} The DOM Image or Canvas Element.
     */
    getDataSourceImage: function (name)
    {
        if (name === undefined || name === null || this.frameTotal === 1)
        {
            name = '__BASE';
        }

        var frame = this.frames[name];
        var idx;

        if (!frame)
        {
            console.warn(TEXTURE_MISSING_ERROR, this.key, name);

            idx = this.frames['__BASE'].sourceIndex;
        }
        else
        {
            idx = frame.sourceIndex;
        }

        return this.dataSource[idx].image;
    },

    /**
     * Adds a data source image to this Texture.
     *
     * An example of a data source image would be a normal map, where all of the Frames for this Texture
     * equally apply to the normal map.
     *
     * @method Phaser.Textures.Texture#setDataSource
     * @since 3.0.0
     *
     * @param {(HTMLImageElement|HTMLCanvasElement|HTMLImageElement[]|HTMLCanvasElement[])} data - The source image.
     */
    setDataSource: function (data)
    {
        if (!Array.isArray(data))
        {
            data = [ data ];
        }

        for (var i = 0; i < data.length; i++)
        {
            var source = this.source[i];

            this.dataSource.push(new TextureSource(this, data[i], source.width, source.height));
        }
    },

    /**
     * Sets the Filter Mode for this Texture.
     *
     * The mode can be either Linear, the default, or Nearest.
     *
     * For pixel-art you should use Nearest.
     *
     * The mode applies to the entire Texture, not just a specific Frame of it.
     *
     * @method Phaser.Textures.Texture#setFilter
     * @since 3.0.0
     *
     * @param {Phaser.Textures.FilterMode} filterMode - The Filter Mode.
     */
    setFilter: function (filterMode)
    {
        var i;

        for (i = 0; i < this.source.length; i++)
        {
            this.source[i].setFilter(filterMode);
        }

        for (i = 0; i < this.dataSource.length; i++)
        {
            this.dataSource[i].setFilter(filterMode);
        }
    },

    /**
     * Destroys this Texture and releases references to its sources and frames.
     *
     * @method Phaser.Textures.Texture#destroy
     * @since 3.0.0
     */
    destroy: function ()
    {
        var i;

        for (i = 0; i < this.source.length; i++)
        {
            this.source[i].destroy();
        }

        for (i = 0; i < this.dataSource.length; i++)
        {
            this.dataSource[i].destroy();
        }

        for (var frameName in this.frames)
        {
            var frame = this.frames[frameName];

            frame.destroy();
        }

        this.source = [];
        this.dataSource = [];
        this.frames = {};

        this.manager.removeKey(this.key);

        var renderer = this.manager.game.renderer;

        if (renderer && renderer.type === CONST.WEBGL)
        {
            renderer.resetTextures(true);
        }

        this.manager = null;
    }

});

module.exports = Texture;


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

/**
 * The Loader Plugin Post Process Event.
 *
 * This event is dispatched by the Loader Plugin when the Loader has finished loading everything in the load queue.
 * It is dispatched before the internal lists are cleared and each File is destroyed.
 *
 * Use this hook to perform any last minute processing of files that can only happen once the
 * Loader has completed, but prior to it emitting the `complete` event.
 *
 * Listen to it from a Scene using: `this.load.on('postprocess', listener)`.
 *
 * @event Phaser.Loader.Events#POST_PROCESS
 * @since 3.0.0
 *
 * @param {Phaser.Loader.LoaderPlugin} loader - A reference to the Loader Plugin that dispatched this event.
 */
module.exports = 'postprocess';


#define SHADER_NAME PHASER_MULTI_FS

precision mediump float;

uniform sampler2D uMainSampler[%count%];

varying vec2 outTexCoord;
varying float outTexId;
varying float outTintEffect;
varying vec4 outTint;

void main ()
{
    vec4 texture;

    %forloop%

    vec4 texel = vec4(outTint.bgr * outTint.a, outTint.a);

    //  Multiply texture tint
    vec4 color = texture * texel;

    if (outTintEffect == 1.0)
    {
        //  Solid color + texture alpha
        color.rgb = mix(texture.rgb, outTint.bgr * outTint.a, texture.a);
    }
    else if (outTintEffect == 2.0)
    {
        //  Solid color, no texture
        color = texel;
    }

    gl_FragColor = color;
}


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

/**
 * @namespace Phaser.GameObjects.Particles.Zones
 */

module.exports = {

    DeathZone: require('./DeathZone'),
    EdgeZone: require('./EdgeZone'),
    RandomZone: require('./RandomZone')

};


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

//  Taken from klasse by mattdesl https://github.com/mattdesl/klasse

function hasGetterOrSetter (def)
{
    return (!!def.get && typeof def.get === 'function') || (!!def.set && typeof def.set === 'function');
}

function getProperty (definition, k, isClassDescriptor)
{
    //  This may be a lightweight object, OR it might be a property that was defined previously.

    //  For simple class descriptors we can just assume its NOT previously defined.
    var def = (isClassDescriptor) ? definition[k] : Object.getOwnPropertyDescriptor(definition, k);

    if (!isClassDescriptor && def.value && typeof def.value === 'object')
    {
        def = def.value;
    }

    //  This might be a regular property, or it may be a getter/setter the user defined in a class.
    if (def && hasGetterOrSetter(def))
    {
        if (typeof def.enumerable === 'undefined')
        {
            def.enumerable = true;
        }

        if (typeof def.configurable === 'undefined')
        {
            def.configurable = true;
        }

        return def;
    }
    else
    {
        return false;
    }
}

function hasNonConfigurable (obj, k)
{
    var prop = Object.getOwnPropertyDescriptor(obj, k);

    if (!prop)
    {
        return false;
    }

    if (prop.value && typeof prop.value === 'object')
    {
        prop = prop.value;
    }

    if (prop.configurable === false)
    {
        return true;
    }

    return false;
}

/**
 * Extends the given `myClass` object's prototype with the properties of `definition`.
 *
 * @function extend
 * @ignore
 * @param {Object} ctor The constructor object to mix into.
 * @param {Object} definition A dictionary of functions for the class.
 * @param {boolean} isClassDescriptor Is the definition a class descriptor?
 * @param {Object} [extend] The parent constructor object.
 */
function extend (ctor, definition, isClassDescriptor, extend)
{
    for (var k in definition)
    {
        if (!definition.hasOwnProperty(k))
        {
            continue;
        }

        var def = getProperty(definition, k, isClassDescriptor);

        if (def !== false)
        {
            //  If Extends is used, we will check its prototype to see if the final variable exists.

            var parent = extend || ctor;

            if (hasNonConfigurable(parent.prototype, k))
            {
                //  Just skip the final property
                if (Class.ignoreFinals)
                {
                    continue;
                }

                //  We cannot re-define a property that is configurable=false.
                //  So we will consider them final and throw an error. This is by
                //  default so it is clear to the developer what is happening.
                //  You can set ignoreFinals to true if you need to extend a class
                //  which has configurable=false; it will simply not re-define final properties.
                throw new Error('cannot override final property \'' + k + '\', set Class.ignoreFinals = true to skip');
            }

            Object.defineProperty(ctor.prototype, k, def);
        }
        else
        {
            ctor.prototype[k] = definition[k];
        }
    }
}

/**
 * Applies the given `mixins` to the prototype of `myClass`.
 *
 * @function mixin
 * @ignore
 * @param {Object} myClass The constructor object to mix into.
 * @param {Object|Array<Object>} mixins The mixins to apply to the constructor.
 */
function mixin (myClass, mixins)
{
    if (!mixins)
    {
        return;
    }

    if (!Array.isArray(mixins))
    {
        mixins = [ mixins ];
    }

    for (var i = 0; i < mixins.length; i++)
    {
        extend(myClass, mixins[i].prototype || mixins[i]);
    }
}

/**
 * Creates a new class with the given descriptor.
 * The constructor, defined by the name `initialize`,
 * is an optional function. If unspecified, an anonymous
 * function will be used which calls the parent class (if
 * one exists).
 *
 * You can also use `Extends` and `Mixins` to provide subclassing
 * and inheritance.
 *
 * @class Phaser.Class
 * @constructor
 * @param {Object} definition a dictionary of functions for the class
 * @example
 *
 *      var MyClass = new Phaser.Class({
 *
 *          initialize: function() {
 *              this.foo = 2.0;
 *          },
 *
 *          bar: function() {
 *              return this.foo + 5;
 *          }
 *      });
 */
function Class (definition)
{
    if (!definition)
    {
        definition = {};
    }

    //  The variable name here dictates what we see in Chrome debugger
    var initialize;
    var Extends;

    if (definition.initialize)
    {
        if (typeof definition.initialize !== 'function')
        {
            throw new Error('initialize must be a function');
        }

        initialize = definition.initialize;

        //  Usually we should avoid 'delete' in V8 at all costs.
        //  However, its unlikely to make any performance difference
        //  here since we only call this on class creation (i.e. not object creation).
        delete definition.initialize;
    }
    else if (definition.Extends)
    {
        var base = definition.Extends;

        initialize = function ()
        {
            base.apply(this, arguments);
        };
    }
    else
    {
        initialize = function () {};
    }

    if (definition.Extends)
    {
        initialize.prototype = Object.create(definition.Extends.prototype);
        initialize.prototype.constructor = initialize;

        //  For getOwnPropertyDescriptor to work, we need to act directly on the Extends (or Mixin)

        Extends = definition.Extends;

        delete definition.Extends;
    }
    else
    {
        initialize.prototype.constructor = initialize;
    }

    //  Grab the mixins, if they are specified...
    var mixins = null;

    if (definition.Mixins)
    {
        mixins = definition.Mixins;
        delete definition.Mixins;
    }

    //  First, mixin if we can.
    mixin(initialize, mixins);

    //  Now we grab the actual definition which defines the overrides.
    extend(initialize, definition, true, Extends);

    return initialize;
}

Class.extend = extend;
Class.mixin = mixin;
Class.ignoreFinals = false;

module.exports = Class;


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var Class = require('../utils/Class');
var EventEmitter = require('eventemitter3');
var Events = require('./events');

/**
 * @classdesc
 * A Process Queue maintains three internal lists.
 *
 * The `pending` list is a selection of items which are due to be made 'active' in the next update.
 * The `active` list is a selection of items which are considered active and should be updated.
 * The `destroy` list is a selection of items that were active and are awaiting being destroyed in the next update.
 *
 * When new items are added to a Process Queue they are put in the pending list, rather than being added
 * immediately the active list. Equally, items that are removed are put into the destroy list, rather than
 * being destroyed immediately. This allows the Process Queue to carefully process each item at a specific, fixed
 * time, rather than at the time of the request from the API.
 *
 * @class ProcessQueue
 * @extends Phaser.Events.EventEmitter
 * @memberof Phaser.Structs
 * @constructor
 * @since 3.0.0
 *
 * @generic T
 */
var ProcessQueue = new Class({

    Extends: EventEmitter,

    initialize:

    function ProcessQueue ()
    {
        EventEmitter.call(this);

        /**
         * The `pending` list is a selection of items which are due to be made 'active' in the next update.
         *
         * @genericUse {T[]} - [$type]
         *
         * @name Phaser.Structs.ProcessQueue#_pending
         * @type {Array.<*>}
         * @private
         * @default []
         * @since 3.0.0
         */
        this._pending = [];

        /**
         * The `active` list is a selection of items which are considered active and should be updated.
         *
         * @genericUse {T[]} - [$type]
         *
         * @name Phaser.Structs.ProcessQueue#_active
         * @type {Array.<*>}
         * @private
         * @default []
         * @since 3.0.0
         */
        this._active = [];

        /**
         * The `destroy` list is a selection of items that were active and are awaiting being destroyed in the next update.
         *
         * @genericUse {T[]} - [$type]
         *
         * @name Phaser.Structs.ProcessQueue#_destroy
         * @type {Array.<*>}
         * @private
         * @default []
         * @since 3.0.0
         */
        this._destroy = [];

        /**
         * The total number of items awaiting processing.
         *
         * @name Phaser.Structs.ProcessQueue#_toProcess
         * @type {number}
         * @private
         * @default 0
         * @since 3.0.0
         */
        this._toProcess = 0;

        /**
         * If `true` only unique objects will be allowed in the queue.
         *
         * @name Phaser.Structs.ProcessQueue#checkQueue
         * @type {boolean}
         * @since 3.50.0
         */
        this.checkQueue = false;
    },

    /**
     * Adds a new item to the Process Queue.
     *
     * The item is added to the pending list and made active in the next update.
     *
     * @method Phaser.Structs.ProcessQueue#add
     * @since 3.0.0
     *
     * @genericUse {T} - [item]
     * @genericUse {Phaser.Structs.ProcessQueue.<T>} - [$return]
     *
     * @param {*} item - The item to add to the queue.
     *
     * @return {*} The item that was added.
     */
    add: function (item)
    {
        this._pending.push(item);

        this._toProcess++;

        return item;
    },

    /**
     * Removes an item from the Process Queue.
     *
     * The item is added to the pending destroy and fully removed in the next update.
     *
     * @method Phaser.Structs.ProcessQueue#remove
     * @since 3.0.0
     *
     * @genericUse {T} - [item]
     * @genericUse {Phaser.Structs.ProcessQueue.<T>} - [$return]
     *
     * @param {*} item - The item to be removed from the queue.
     *
     * @return {*} The item that was removed.
     */
    remove: function (item)
    {
        this._destroy.push(item);

        this._toProcess++;

        return item;
    },

    /**
     * Removes all active items from this Process Queue.
     *
     * All the items are marked as 'pending destroy' and fully removed in the next update.
     *
     * @method Phaser.Structs.ProcessQueue#removeAll
     * @since 3.20.0
     *
     * @return {this} This Process Queue object.
     */
    removeAll: function ()
    {
        var list = this._active;
        var destroy = this._destroy;
        var i = list.length;

        while (i--)
        {
            destroy.push(list[i]);

            this._toProcess++;
        }

        return this;
    },

    /**
     * Update this queue. First it will process any items awaiting destruction, and remove them.
     *
     * Then it will check to see if there are any items pending insertion, and move them to an
     * active state. Finally, it will return a list of active items for further processing.
     *
     * @method Phaser.Structs.ProcessQueue#update
     * @since 3.0.0
     *
     * @genericUse {T[]} - [$return]
     *
     * @return {Array.<*>} A list of active items.
     */
    update: function ()
    {
        if (this._toProcess === 0)
        {
            //  Quick bail
            return this._active;
        }

        var list = this._destroy;
        var active = this._active;
        var i;
        var item;

        //  Clear the 'destroy' list
        for (i = 0; i < list.length; i++)
        {
            item = list[i];

            //  Remove from the 'active' array
            var idx = active.indexOf(item);

            if (idx !== -1)
            {
                active.splice(idx, 1);

                this.emit(Events.PROCESS_QUEUE_REMOVE, item);
            }
        }

        list.length = 0;

        //  Process the pending addition list
        //  This stops callbacks and out of sync events from populating the active array mid-way during an update

        list = this._pending;

        for (i = 0; i < list.length; i++)
        {
            item = list[i];

            if (!this.checkQueue || (this.checkQueue && active.indexOf(item) === -1))
            {
                active.push(item);

                this.emit(Events.PROCESS_QUEUE_ADD, item);
            }
        }

        list.length = 0;

        this._toProcess = 0;

        //  The owner of this queue can now safely do whatever it needs to with the active list
        return active;
    },

    /**
     * Returns the current list of active items.
     *
     * This method returns a reference to the active list array, not a copy of it.
     * Therefore, be careful to not modify this array outside of the ProcessQueue.
     *
     * @method Phaser.Structs.ProcessQueue#getActive
     * @since 3.0.0
     *
     * @genericUse {T[]} - [$return]
     *
     * @return {Array.<*>} A list of active items.
     */
    getActive: function ()
    {
        return this._active;
    },

    /**
     * The number of entries in the active list.
     *
     * @name Phaser.Structs.ProcessQueue#length
     * @type {number}
     * @readonly
     * @since 3.20.0
     */
    length: {

        get: function ()
        {
            return this._active.length;
        }

    },

    /**
     * Immediately destroys this process queue, clearing all of its internal arrays and resetting the process totals.
     *
     * @method Phaser.Structs.ProcessQueue#destroy
     * @since 3.0.0
     */
    destroy: function ()
    {
        this._toProcess = 0;

        this._pending = [];
        this._active = [];
        this._destroy = [];
    }

});

module.exports = ProcessQueue;


#define SHADER_NAME PHASER_MULTI_VS
precision mediump float;
uniform mat4 uProjectionMatrix;
attribute vec2 inPosition;
attribute vec2 inTexCoord;

keep keep replace keep keep keep keep keep


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

/**
 * A 16 color palette inspired by Japanese computers like the MSX.
 *
 * @name Phaser.Create.Palettes.MSX
 * @since 3.0.0
 *
 * @type {Phaser.Types.Create.Palette}
 */
module.exports = {
    0: '#000',
    1: '#191028',
    2: '#46af45',
    3: '#a1d685',
    4: '#453e78',
    5: '#7664fe',
    6: '#833129',
    7: '#9ec2e8',
    8: '#dc534b',
    9: '#e18d79',
    A: '#d6b97b',
    B: '#e9d8a1',
    C: '#216c4b',
    D: '#d365c8',
    E: '#afaab9',
    F: '#fff'
};


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var GetTilesWithin = require('./GetTilesWithin');

/**
 * For each tile in the given rectangular area (in tile coordinates) of the layer, run the given
 * filter callback function. Any tiles that pass the filter test (i.e. where the callback returns
 * true) will returned as a new array. Similar to Array.prototype.Filter in vanilla JS.
 *
 * @function Phaser.Tilemaps.Components.FilterTiles
 * @since 3.0.0
 *
 * @param {function} callback - The callback. Each tile in the given area will be passed to this
 * callback as the first and only parameter. The callback should return true for tiles that pass the
 * filter.
 * @param {object} context - The context under which the callback should be run.
 * @param {number} tileX - The left most tile index (in tile coordinates) to use as the origin of the area to filter.
 * @param {number} tileY - The top most tile index (in tile coordinates) to use as the origin of the area to filter.
 * @param {number} width - How many tiles wide from the `tileX` index the area will be.
 * @param {number} height - How many tiles tall from the `tileY` index the area will be.
 * @param {Phaser.Types.Tilemaps.FilteringOptions} filteringOptions - Optional filters to apply when getting the tiles.
 * @param {Phaser.Tilemaps.LayerData} layer - The Tilemap Layer to act upon.
 *
 * @return {Phaser.Tilemaps.Tile[]} The filtered array of Tiles.
 */
var FilterTiles = function (callback, context, tileX, tileY, width, height, filteringOptions, layer)
{
    var tiles = GetTilesWithin(tileX, tileY, width, height, filteringOptions, layer);

    return tiles.filter(callback, context);
};

module.exports = FilterTiles;


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

/**
 * The Video Game Object Seeked Event.
 *
 * This event is dispatched when a Video completes seeking to a new point in its timeline.
 *
 * Listen for it from a Video Game Object instance using `Video.on('seeked', listener)`.
 *
 * @event Phaser.GameObjects.Events#VIDEO_SEEKED
 * @since 3.20.0
 *
 * @param {Phaser.GameObjects.Video} video - The Video Game Object which completed seeking.
 */
module.exports = 'seeked';


keep keep keep replace keep keep keep keep

# Working with CSS

Vue CLI projects comes with support for [PostCSS](http://postcss.org/), [CSS Modules](https://github.com/css-modules/css-modules) and pre-processors including [Sass](https://sass-lang.com/), [Less](http://lesscss.org/) and [Stylus](http://stylus-lang.com/).

## Referencing Assets

All compiled CSS are processed by [css-loader](https://github.com/webpack-contrib/css-loader), which parses `url()` and resolves them as module requests. This means you can refer to assets using relative paths based on the local file structure. Note if you want to reference a file inside an npm dependency or via webpack alias, the path must be prefixed with `~` to avoid ambiguity. See [Static Asset Handling](./html-and-static-assets.md#static-assets-handling) for more details.

## Pre-Processors

You can select pre-processors (Sass/Less/Stylus) when creating the project. If you did not do so, the internal webpack config is still pre-configured to handle all of them. You just need to manually install the corresponding webpack loaders:

``` bash
# Sass
npm install -D sass-loader node-sass

# Less
npm install -D less-loader less

# Stylus
npm install -D stylus-loader stylus
```

Then you can import the corresponding file types, or use them in `*.vue` files with:

``` vue
<style lang="scss">
$color: red;
</style>
```

### Automatic imports

If you want to automatically import files (for colors, variables, mixins...), you can use the [style-resources-loader](https://github.com/yenshih/style-resources-loader). Here is an example for stylus that imports `./src/styles/imports.styl` in every SFC and every stylus files:

```js
// vue.config.js
const path = require('path')

module.exports = {
  chainWebpack: config => {
    const types = ['vue-modules', 'vue', 'normal-modules', 'normal']
    types.forEach(type => addStyleResource(config.module.rule('stylus').oneOf(type)))
  },
}

function addStyleResource (rule) {
  rule.use('style-resource')
    .loader('style-resources-loader')
    .options({
      patterns: [
        path.resolve(__dirname, './src/styles/imports.styl'),
      ],
    })
}
```

You can also use the [vue-cli-plugin-style-resources-loader](https://www.npmjs.com/package/vue-cli-plugin-style-resources-loader).

## PostCSS

Vue CLI uses PostCSS internally.

You can configure PostCSS via `.postcssrc` or any config source supported by [postcss-load-config](https://github.com/michael-ciniawsky/postcss-load-config), and configure [postcss-loader](https://github.com/postcss/postcss-loader) via `css.loaderOptions.postcss` in `vue.config.js`.

The [autoprefixer](https://github.com/postcss/autoprefixer) plugin is enabled by default. To configure the browser targets, use the [browserslist](../guide/browser-compatibility.html#browserslist) field in `package.json`.

::: tip Note on Vendor-prefixed CSS Rules
In the production build, Vue CLI optimizes your CSS and will drop unnecessary vendor-prefixed CSS rules based on your browser targets. With `autoprefixer` enabled by default, you should always use only non-prefixed CSS rules.
:::

## CSS Modules

You can [use CSS Modules in `*.vue` files](https://vue-loader.vuejs.org/en/features/css-modules.html) out of the box with `<style module>`.

To import CSS or other pre-processor files as CSS Modules in JavaScript, the filename should end with `.module.(css|less|sass|scss|styl)`:

``` js
import styles from './foo.module.css'
// works for all supported pre-processors as well
import sassStyles from './foo.module.scss'
```

If you want to drop the `.module` in the filenames, set `css.modules` to `true` in `vue.config.js`:

``` js
// vue.config.js
module.exports = {
  css: {
    modules: true
  }
}
```

If you wish to customize the generated CSS modules class names, you can do so via `css.loaderOptions.css` in `vue.config.js`. All `css-loader` options are supported here, for example `localIdentName` and `camelCase`:

``` js
// vue.config.js
module.exports = {
  css: {
    loaderOptions: {
      css: {
        localIdentName: '[name]-[hash]',
        camelCase: 'only'
      }
    }
  }
}
```

## Passing Options to Pre-Processor Loaders

Sometimes you may want to pass options to the pre-processor's webpack loader. You can do that using the `css.loaderOptions` option in `vue.config.js`. For example, to pass some shared global variables to all your Sass/Less styles:

``` js
// vue.config.js
module.exports = {
  css: {
    loaderOptions: {
      // pass options to sass-loader
      sass: {
        // @/ is an alias to src/
        // so this assumes you have a file named `src/variables.scss`
        data: `@import "~@/variables.scss";`
      },
      // pass Less.js Options to less-loader
      less:{
        // http://lesscss.org/usage/#less-options-strict-units `Global Variables`
        // `primary` is global variables fields name
        globalVars: {
          primary: '#fff'
        }
      }
    }
  }
}
```

Loaders which can be configured via `loaderOptions` include:

- [css-loader](https://github.com/webpack-contrib/css-loader)
- [postcss-loader](https://github.com/postcss/postcss-loader)
- [sass-loader](https://github.com/webpack-contrib/sass-loader)
- [less-loader](https://github.com/webpack-contrib/less-loader)
- [stylus-loader](https://github.com/shama/stylus-loader)

::: tip
This is preferred over manually tapping into specific loaders using `chainWebpack`, because these options need to be applied in multiple locations where the corresponding loader is used.
:::


query pluginLogo ($id: ID!) {
  pluginLogo: plugin (id: $id) {
    id
    logo
  }
}


#import "./pluginActionResultFragment.gql"

subscription pluginActionResolved {
  pluginActionResolved {
    ...pluginActionResult
  }
}


If you want to automatically import files (for colors, variables, mixins...), you can use the [style-resources-loader](https://github.com/yenshih/style-resources-loader). Here is an example for stylus that imports `./src/styles/imports.styl` in every SFC and every stylus files:

keep keep keep add keep keep keep keep keep

Note that when using Dart Sass, **synchronous compilation is twice as fast as asynchronous compilation** by default, due to the overhead of asynchronous callbacks. To avoid this overhead, you can use the [fibers](https://www.npmjs.com/package/fibers) package to call asynchronous importers from the synchronous code path. To enable this, simply install `fibers` as a project dependency:

Please also be aware, as it's a native module, there may be compatibility issues vary on the OS and build environment. In that case, please run `npm uninstall -D fibers` to fix the problem.


jest.setTimeout(50000)

const path = require('path')
const portfinder = require('portfinder')
const { createServer } = require('http-server')
const { defaultPreset } = require('@vue/cli/lib/options')
const create = require('@vue/cli-test-utils/createTestProject')
const launchPuppeteer = require('@vue/cli-test-utils/launchPuppeteer')

let server, browser
test('pwa', async () => {
  // it's ok to mutate here since jest loads each test in a separate vm
  defaultPreset.plugins['@vue/cli-plugin-pwa'] = {}
  const project = await create('pwa-build', defaultPreset)
  expect(project.has('src/registerServiceWorker.js')).toBe(true)

  const { stdout } = await project.run('vue-cli-service build')
  expect(stdout).toMatch('Build complete.')

  expect(project.has('dist/index.html')).toBe(true)
  expect(project.has('dist/favicon.ico')).toBe(true)
  expect(project.has('dist/js')).toBe(true)
  expect(project.has('dist/css')).toBe(true)

  // PWA specific files
  expect(project.has('dist/manifest.json')).toBe(true)
  expect(project.has('dist/img/icons/android-chrome-512x512.png')).toBe(true)

  // Make sure the base preload/prefetch are not affected
  const index = await project.read('dist/index.html')

  // should split and preload app.js & vendor.js
  expect(index).toMatch(/<link [^>]+js\/app[^>]+\.js rel=preload as=script>/)
  expect(index).toMatch(/<link [^>]+js\/chunk-vendors[^>]+\.js rel=preload as=script>/)
  // should preload css
  expect(index).toMatch(/<link [^>]+app[^>]+\.css rel=preload as=style>/)

  // PWA specific directives
  expect(index).toMatch(`<link rel=manifest href=/manifest.json>`)
  // favicon is not minified because it's technically a comment
  expect(index).toMatch(`<!--[if IE]><link rel="icon" href="/favicon.ico"><![endif]-->`)
  expect(index).toMatch(`<meta name=apple-mobile-web-app-capable content=no>`)

  // should import service worker script
  const main = await project.read('src/main.js')
  expect(main).toMatch(`import './registerServiceWorker'`)

  const port = await portfinder.getPortPromise()
  server = createServer({ root: path.join(project.dir, 'dist') })

  await new Promise((resolve, reject) => {
    server.listen(port, err => {
      if (err) return reject(err)
      resolve()
    })
  })

  const launched = await launchPuppeteer(`http://localhost:${port}/`)
  browser = launched.browser

  // workbox plugin fetches scripts from CDN so it takes a while...
  await new Promise(r => setTimeout(r, process.env.CI ? 5000 : 2000))
  const logs = launched.logs
  expect(logs.some(msg => msg.match(/Content has been cached for offline use/))).toBe(true)
  expect(logs.some(msg => msg.match(/App is being served from cache by a service worker/))).toBe(true)
})

afterAll(async () => {
  if (browser) {
    await browser.close()
  }
  if (server) {
    server.close()
  }
})


const { createSchema, validate } = require('@vue/cli-shared-utils')

const schema = createSchema(joi => joi.object({
  baseUrl: joi.string().allow(''),
  publicPath: joi.string().allow(''),
  outputDir: joi.string(),
  assetsDir: joi.string().allow(''),
  indexPath: joi.string(),
  filenameHashing: joi.boolean(),
  runtimeCompiler: joi.boolean(),
  transpileDependencies: joi.array(),
  productionSourceMap: joi.boolean(),
  parallel: joi.boolean(),
  devServer: joi.object(),
  pages: joi.object().pattern(
    /\w+/,
    joi.alternatives().try([
      joi.string().required(),
      joi.array().items(joi.string().required()),

      joi.object().keys({
        entry: joi.alternatives().try([
          joi.string().required(),
          joi.array().items(joi.string().required())
        ]).required()
      }).unknown(true)
    ])
  ),
  crossorigin: joi.string().valid(['', 'anonymous', 'use-credentials']),
  integrity: joi.boolean(),

  // css
  css: joi.object({
    modules: joi.boolean(),
    extract: joi.alternatives().try(joi.boolean(), joi.object()),
    sourceMap: joi.boolean(),
    loaderOptions: joi.object({
      css: joi.object(),
      sass: joi.object(),
      less: joi.object(),
      stylus: joi.object(),
      postcss: joi.object()
    })
  }),

  // webpack
  chainWebpack: joi.func(),
  configureWebpack: joi.alternatives().try(
    joi.object(),
    joi.func()
  ),

  // known runtime options for built-in plugins
  lintOnSave: joi.any().valid([true, false, 'error']),
  pwa: joi.object(),

  // 3rd party plugin options
  pluginOptions: joi.object()
}))

exports.validate = (options, cb) => {
  validate(options, schema, cb)
}

// #2110
// https://github.com/nodejs/node/issues/19022
// in some cases cpus() returns undefined, and may simply throw in the future
function hasMultipleCores () {
  try {
    return require('os').cpus().length > 1
  } catch (e) {
    return false
  }
}

exports.defaults = () => ({
  // project deployment base
  publicPath: '/',
  // for compatibility concern. TODO: remove in v4.
  baseUrl: '/',

  // where to output built files
  outputDir: 'dist',

  // where to put static assets (js/css/img/font/...)
  assetsDir: '',

  // filename for index.html (relative to outputDir)
  indexPath: 'index.html',

  // whether filename will contain hash part
  filenameHashing: true,

  // boolean, use full build?
  runtimeCompiler: false,

  // deps to transpile
  transpileDependencies: [/* string or regex */],

  // sourceMap for production build?
  productionSourceMap: !process.env.VUE_CLI_TEST,

  // use thread-loader for babel & TS in production build
  // enabled by default if the machine has more than 1 cores
  parallel: hasMultipleCores(),

  // multi-page config
  pages: undefined,

  // <script type="module" crossorigin="use-credentials">
  // #1656, #1867, #2025
  crossorigin: undefined,

  // subresource integrity
  integrity: false,

  css: {
    // extract: true,
    // modules: false,
    // localIdentName: '[name]_[local]_[hash:base64:5]',
    // sourceMap: false,
    // loaderOptions: {}
  },

  // whether to use eslint-loader
  lintOnSave: true,

  devServer: {
  /*
    open: process.platform === 'darwin',
    host: '0.0.0.0',
    port: 8080,
    https: false,
    hotOnly: false,
    proxy: null, // string | Object
    before: app => {}
  */
  }
})


export default {
  connected: true,
  loading: 0,
  darkMode: false,
  currentProjectId: null
}


const generateWithPlugin = require('@vue/cli-test-utils/generateWithPlugin')

test('node sass (legacy)', async () => {
  const { pkg, files } = await generateWithPlugin([
    {
      id: '@vue/cli-service',
      apply: require('../generator'),
      options: {
        cssPreprocessor: 'sass'
      }
    }
  ])

  expect(files['src/App.vue']).toMatch('<style lang="scss">')
  expect(pkg).toHaveProperty(['devDependencies', 'node-sass'])
})

test('node sass', async () => {
  const { pkg, files } = await generateWithPlugin([
    {
      id: '@vue/cli-service',
      apply: require('../generator'),
      options: {
        cssPreprocessor: 'node-sass'
      }
    }
  ])

  expect(files['src/App.vue']).toMatch('<style lang="scss">')
  expect(pkg).toHaveProperty(['devDependencies', 'node-sass'])
})

test('dart sass', async () => {
  const { pkg, files } = await generateWithPlugin([
    {
      id: '@vue/cli-service',
      apply: require('../generator'),
      options: {
        cssPreprocessor: 'dart-sass'
      }
    }
  ])

  expect(files['src/App.vue']).toMatch('<style lang="scss">')
  expect(pkg).toHaveProperty(['devDependencies', 'sass'])
  expect(pkg).toHaveProperty(['devDependencies', 'fibers'])
})


$padding-item = 16px
$font-mono = 'Roboto Mono', monospace
$ease = cubic-bezier(0.075, 0.820, 0.165, 1.000)


export function getImageUrl (url) {
  // Fix images in development
  if (process.env.VUE_APP_CLI_UI_DEV && url.charAt(0) === '/') {
    return `http://localhost:${process.env.VUE_APP_GRAPHQL_PORT}${url}`
  }
  return url
}


module.exports = (api, options) => {
  api.chainWebpack(webpackConfig => {
    if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') {
      webpackConfig
        .devtool('cheap-module-eval-source-map')
        .output
          .publicPath(options.publicPath)

      webpackConfig
        .plugin('hmr')
          .use(require('webpack/lib/HotModuleReplacementPlugin'))

      // https://github.com/webpack/webpack/issues/6642
      webpackConfig
        .output
          .globalObject('this')

      if (!process.env.VUE_CLI_TEST && options.devServer.progress !== false) {
        webpackConfig
          .plugin('progress')
          .use(require('webpack/lib/ProgressPlugin'))
      }
    }
  })
}


keep keep keep keep replace keep keep keep keep


import Vue from 'vue'

const vm = new Vue({
  data: {
    documentVisible: !document.hidden,
    documentFocus: document.hasFocus()
  }
})

document.addEventListener('visibilitychange', () => {
  vm.documentVisible = !document.hidden
}, false)

window.addEventListener('focus', () => {
  vm.documentFocus = true
})

window.addEventListener('blur', () => {
  vm.documentFocus = false
})

// @vue/component
export default {
  computed: {
    documentVisible () {
      return vm.documentVisible
    },

    documentFocus () {
      return vm.documentFocus
    }
  }
}


<template>

      <VueIcon icon="cached"/>

{{ $t('org.vue.components.file-diff-view.files-changed') }}

{{ fileDiffs && fileDiffs.length }}

      <transition name="vue-ui-fade">
        <VueLoadingIndicator
          v-if="loading && fileDiffs.length"
          class="small accent"
        />
      </transition>

      <VueInput
        v-model="search"
        icon-left="search"
        :placeholder="$t('org.vue.components.file-diff-view.search-file')"
      />
      <VueButton
        :icon-left="allCollapsed ? 'keyboard_arrow_down' : 'keyboard_arrow_up'"
        :label="$t(`org.vue.components.file-diff-view.actions.${allCollapsed ? 'expand-all' : 'collapse-all'}`)"
        @click="setCollapsedToAll(!allCollapsed)"
      />
      <VueButton
        icon-left="refresh"
        class="icon-button"
        @click="refresh()"
      />

        <VueIcon icon="error" class="empty-icon"/>
        {{ $t('org.vue.components.file-diff-view.error') }}

        <VueIcon icon="check_circle" class="empty-icon"/>
        {{ $t('org.vue.components.file-diff-view.empty') }}

      <template v-else>
        <FileDiff
          v-for="fileDiff of filteredList"
          :key="fileDiff.id"
          :file-diff="fileDiff"
          :collapsed="!!collapsed[fileDiff.id]"
          @update:collapsed="value => $set(collapsed, fileDiff.id, value)"
        />
      </template>

      <template v-if="!error && fileDiffs && fileDiffs.length">
        <VueButton
          icon-left="vertical_align_bottom"
          :label="$t('org.vue.components.file-diff-view.actions.commit')"
          class="big primary"
          @click="showCommitModal = true"
        />
        <VueButton
          :label="$t('org.vue.components.file-diff-view.actions.skip')"
          class="big"
          data-testid="skip-button"
          @click="skip()"
        />
      </template>
      <template v-else>
        <VueButton
          icon-left="done"
          :label="$t('org.vue.components.file-diff-view.actions.continue')"
          class="big primary"
          data-testid="skip-button"
          @click="skip()"
        />
        <VueButton
          :label="$t('org.vue.components.file-diff-view.actions.refresh')"
          icon-left="refresh"
          class="big"
          @click="refresh()"
        />
      </template>

    <transition name="vue-ui-fade">
      <VueLoadingIndicator
        v-if="loading && !fileDiffs.length"
        class="accent big overlay"
      />
    </transition>

    <VueModal
      v-if="showCommitModal"
      :title="$t('org.vue.components.file-diff-view.modals.commit.title')"
      class="medium"
      @close="showCommitModal = false"
    >

        <VueFormField
          :title="$t('org.vue.components.file-diff-view.modals.commit.input')"
          :subtitle="$t('org.vue.components.file-diff-view.modals.commit.subtitle')"
        >
          <VueInput
            v-model="commitMessage"
            icon-left="local_offer"
            v-focus
            @keyup.enter="commitMessage && commit()"
          />
        </VueFormField>

        <VueButton
          :label="$t('org.vue.components.file-diff-view.modals.commit.actions.cancel')"
          class="flat"
          @click="showCommitModal = false"
        />
        <VueButton
          :label="$t('org.vue.components.file-diff-view.modals.commit.actions.commit')"
          class="primary"
          icon-left="vertical_align_bottom"
          :disabled="!commitMessage"
          @click="commit()"
        />

    </VueModal>

</template>


keep keep keep keep keep replace replace replace keep keep keep keep

/**
 * marked - A markdown parser (https://github.com/chjj/marked)
 * Copyright (c) 2011-2012, Christopher Jeffrey. (MIT Licensed)
 */

;(function() {

/**
 * Block-Level Grammar
 */

var block = {
  newline: /^\n+/,
  code: /^( {4}[^\n]+\n*)+/,
  fences: noop,
  hr: /^( *[\-*_]){3,} *(?:\n+|$)/,
  heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
  lheading: /^([^\n]+)\n *(=|-){3,} *\n*/,
  blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/,
  list: /^( *)([*+-]|\d+\.) [^\0]+?(?:\n{2,}(?! )(?!\1bullet)\n*|\s*$)/,
  html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,
  def: /^ *\[([^\]]+)\]: *([^\s]+)(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
  paragraph: /^([^\n]+\n?(?!body))+\n*/,
  text: /^[^\n]+/
};

block.list = replace(block.list)
  ('bullet', /(?:[*+-](?!(?: *[-*]){2,})|\d+\.)/)
  ();

block.html = replace(block.html)
  ('comment', //)
  ('closed', /<(tag)[^\0]+?<\/\1>/)
  ('closing', /<tag(?!:\/|@)\b(?:"[^"]*"|'[^']*'|[^'">])*?>/)
  (/tag/g, tag())
  ();

block.paragraph = (function() {
  var paragraph = block.paragraph.source
    , body = [];

  (function push(rule) {
    rule = block[rule] ? block[rule].source : rule;
    body.push(rule.replace(/(^|[^\[])\^/g, '$1'));
    return push;
  })
  ('hr')
  ('heading')
  ('lheading')
  ('blockquote')
  ('<' + tag())
  ('def');

  return new
    RegExp(paragraph.replace('body', body.join('|')));
})();

block.normal = {
  fences: block.fences,
  paragraph: block.paragraph
};

block.gfm = {
  fences: /^ *``` *(\w+)? *\n([^\0]+?)\s*``` *(?:\n+|$)/,
  paragraph: /^/
};

block.gfm.paragraph = replace(block.paragraph)
  ('(?!', '(?!' + block.gfm.fences.source.replace(/(^|[^\[])\^/g, '$1') + '|')
  ();

/**
 * Block Lexer
 */

block.lexer = function(src) {
  var tokens = [];

  tokens.links = {};

  src = src
    .replace(/\r\n|\r/g, '\n')
    .replace(/\t/g, '    ');

  return block.token(src, tokens, true);
};

block.token = function(src, tokens, top) {
  var src = src.replace(/^ +$/gm, '')
    , next
    , loose
    , cap
    , item
    , space
    , i
    , l;

  while (src) {
    // newline
    if (cap = block.newline.exec(src)) {
      src = src.substring(cap[0].length);
      if (cap[0].length > 1) {
        tokens.push({
          type: 'space'
        });
      }
    }

    // code
    if (cap = block.code.exec(src)) {
      src = src.substring(cap[0].length);
      cap = cap[0].replace(/^ {4}/gm, '');
      tokens.push({
        type: 'code',
        text: !options.pedantic
          ? cap.replace(/\n+$/, '')
          : cap
      });
      continue;
    }

    // fences (gfm)
    if (cap = block.fences.exec(src)) {
      src = src.substring(cap[0].length);
      tokens.push({
        type: 'code',
        lang: cap[1],
        text: cap[2]
      });
      continue;
    }

    // heading
    if (cap = block.heading.exec(src)) {
      src = src.substring(cap[0].length);
      tokens.push({
        type: 'heading',
        depth: cap[1].length,
        text: cap[2]
      });
      continue;
    }

    // lheading
    if (cap = block.lheading.exec(src)) {
      src = src.substring(cap[0].length);
      tokens.push({
        type: 'heading',
        depth: cap[2] === '=' ? 1 : 2,
        text: cap[1]
      });
      continue;
    }

    // hr
    if (cap = block.hr.exec(src)) {
      src = src.substring(cap[0].length);
      tokens.push({
        type: 'hr'
      });
      continue;
    }

    // blockquote
    if (cap = block.blockquote.exec(src)) {
      src = src.substring(cap[0].length);

      tokens.push({
        type: 'blockquote_start'
      });

      cap = cap[0].replace(/^ *> ?/gm, '');

      // Pass `top` to keep the current
      // "toplevel" state. This is exactly
      // how markdown.pl works.
      block.token(cap, tokens, top);

      tokens.push({
        type: 'blockquote_end'
      });

      continue;
    }

    // list
    if (cap = block.list.exec(src)) {
      src = src.substring(cap[0].length);

      tokens.push({
        type: 'list_start',
        ordered: isFinite(cap[2])
      });

      // Get each top-level item.
      cap = cap[0].match(
        /^( *)([*+-]|\d+\.) [^\n]*(?:\n(?!\1(?:[*+-]|\d+\.) )[^\n]*)*/gm
      );

      next = false;
      l = cap.length;
      i = 0;

      for (; i < l; i++) {
        item = cap[i];

        // Remove the list item's bullet
        // so it is seen as the next token.
        space = item.length;
        item = item.replace(/^ *([*+-]|\d+\.) +/, '');

        // Outdent whatever the
        // list item contains. Hacky.
        if (~item.indexOf('\n ')) {
          space -= item.length;
          item = !options.pedantic
            ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
            : item.replace(/^ {1,4}/gm, '');
        }

        // Determine whether item is loose or not.
        // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
        // for discount behavior.
        loose = next || /\n\n(?!\s*$)/.test(item);
        if (i !== l - 1) {
          next = item[item.length-1] === '\n';
          if (!loose) loose = next;
        }

        tokens.push({
          type: loose
            ? 'loose_item_start'
            : 'list_item_start'
        });

        // Recurse.
        block.token(item, tokens);

        tokens.push({
          type: 'list_item_end'
        });
      }

      tokens.push({
        type: 'list_end'
      });

      continue;
    }

    // html
    if (cap = block.html.exec(src)) {
      src = src.substring(cap[0].length);
      tokens.push({
        type: 'html',
        pre: cap[1] === 'pre',
        text: cap[0]
      });
      continue;
    }

    // def
    if (top && (cap = block.def.exec(src))) {
      src = src.substring(cap[0].length);
      tokens.links[cap[1].toLowerCase()] = {
        href: cap[2],
        title: cap[3]
      };
      continue;
    }

    // top-level paragraph
    if (top && (cap = block.paragraph.exec(src))) {
      src = src.substring(cap[0].length);
      tokens.push({
        type: 'paragraph',
        text: cap[0]
      });
      continue;
    }

    // text
    if (cap = block.text.exec(src)) {
      // Top-level should never reach here.
      src = src.substring(cap[0].length);
      tokens.push({
        type: 'text',
        text: cap[0]
      });
      continue;
    }
  }

  return tokens;
};

/**
 * Inline Processing
 */

var inline = {
  escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
  autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
  url: noop,
  tag: /^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
  link: /^!?\[(inside)\]\(href\)/,
  reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
  nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
  strong: /^__([^\0]+?)__(?!_)|^\*\*([^\0]+?)\*\*(?!\*)/,
  em: /^\b_((?:__|[^\0])+?)_\b|^\*((?:\*\*|[^\0])+?)\*(?!\*)/,
  code: /^(`+)([^\0]*?[^`])\1(?!`)/,
  br: /^ {2,}\n(?!\s*$)/,
  text: /^[^\0]+?(?=[\\<!\[_*`]| {2,}\n|$)/
};

inline._linkInside = /(?:\[[^\]]*\]|[^\]]|\](?=[^\[]*\]))*/;
inline._linkHref = /\s*<?([^\s]*?)>?(?:\s+['"]([^\0]*?)['"])?\s*/;

inline.link = replace(inline.link)
  ('inside', inline._linkInside)
  ('href', inline._linkHref)
  ();

inline.reflink = replace(inline.reflink)
  ('inside', inline._linkInside)
  ();

inline.normal = {
  url: inline.url,
  strong: inline.strong,
  em: inline.em,
  text: inline.text
};

inline.pedantic = {
  strong: /^__(?=\S)([^\0]*?\S)__(?!_)|^\*\*(?=\S)([^\0]*?\S)\*\*(?!\*)/,
  em: /^_(?=\S)([^\0]*?\S)_(?!_)|^\*(?=\S)([^\0]*?\S)\*(?!\*)/
};

inline.gfm = {
  url: /^(https?:\/\/[^\s]+[^.,:;"')\]\s])/,
  text: /^[^\0]+?(?=[\\<!\[_*`]|https?:\/\/| {2,}\n|$)/
};

/**
 * Inline Lexer
 */

inline.lexer = function(src) {
  var out = ''
    , links = tokens.links
    , link
    , text
    , href
    , cap;

  while (src) {
    // escape
    if (cap = inline.escape.exec(src)) {
      src = src.substring(cap[0].length);
      out += cap[1];
      continue;
    }

    // autolink
    if (cap = inline.autolink.exec(src)) {
      src = src.substring(cap[0].length);
      if (cap[2] === '@') {
        text = cap[1][6] === ':'
          ? mangle(cap[1].substring(7))
          : mangle(cap[1]);
        href = mangle('mailto:') + text;
      } else {
        text = escape(cap[1]);
        href = text;
      }
      out += ''
        + text
        + '';
      continue;
    }

    // url (gfm)
    if (cap = inline.url.exec(src)) {
      src = src.substring(cap[0].length);
      text = escape(cap[1]);
      href = text;
      out += ''
        + text
        + '';
      continue;
    }

    // tag
    if (cap = inline.tag.exec(src)) {
      src = src.substring(cap[0].length);
      out += options.sanitize
        ? escape(cap[0])
        : cap[0];
      continue;
    }

    // link
    if (cap = inline.link.exec(src)) {
      src = src.substring(cap[0].length);
      out += outputLink(cap, {
        href: cap[2],
        title: cap[3]
      });
      continue;
    }

    // reflink, nolink
    if ((cap = inline.reflink.exec(src))
        || (cap = inline.nolink.exec(src))) {
      src = src.substring(cap[0].length);
      link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
      link = links[link.toLowerCase()];
      if (!link || !link.href) {
        out += cap[0][0];
        src = cap[0].substring(1) + src;
        continue;
      }
      out += outputLink(cap, link);
      continue;
    }

    // strong
    if (cap = inline.strong.exec(src)) {
      src = src.substring(cap[0].length);
      out += ''
        + inline.lexer(cap[2] || cap[1])
        + '';
      continue;
    }

    // em
    if (cap = inline.em.exec(src)) {
      src = src.substring(cap[0].length);
      out += ''
        + inline.lexer(cap[2] || cap[1])
        + '';
      continue;
    }

    // code
    if (cap = inline.code.exec(src)) {
      src = src.substring(cap[0].length);
      out += ''
        + escape(cap[2], true)
        + '';
      continue;
    }

    // br
    if (cap = inline.br.exec(src)) {
      src = src.substring(cap[0].length);
      out += '
';
      continue;
    }

    // text
    if (cap = inline.text.exec(src)) {
      src = src.substring(cap[0].length);
      out += escape(cap[0]);
      continue;
    }
  }

  return out;
};

var outputLink = function(cap, link) {
  if (cap[0][0] !== '!') {
    return ''
      + inline.lexer(cap[1])
      + '';
  } else {
    return '';
  }
};

/**
 * Parsing
 */

var tokens
  , token;

var next = function() {
  return token = tokens.pop();
};

var tok = function() {
  switch (token.type) {
    case 'space': {
      return '';
    }
    case 'hr': {
      return '
\n';
    }
    case 'heading': {
      return '<h'
        + token.depth
        + '>'
        + inline.lexer(token.text)
        + '</h'
        + token.depth
        + '>\n';
    }
    case 'code': {
      if (!token.escaped) {
        token.text = options.highlight
          ? options.highlight(token.text, token.lang)
          : escape(token.text, true);
      }
      return '
'
        + token.text
        + '
\n';
    }
    case 'blockquote_start': {
      var body = '';

      while (next().type !== 'blockquote_end') {
        body += tok();
      }

      return '
\n'
        + body
        + '
\n';
    }
    case 'list_start': {
      var type = token.ordered ? 'ol' : 'ul'
        , body = '';

      while (next().type !== 'list_end') {
        body += tok();
      }

      return '<'
        + type
        + '>\n'
        + body
        + '</'
        + type
        + '>\n';
    }
    case 'list_item_start': {
      var body = '';

      while (next().type !== 'list_item_end') {
        body += token.type === 'text'
          ? parseText()
          : tok();
      }

      return '
'
        + body
        + '
\n';
    }
    case 'loose_item_start': {
      var body = '';

      while (next().type !== 'list_item_end') {
        body += tok();
      }

      return '
'
        + body
        + '
\n';
    }
    case 'html': {
      if (options.sanitize) {
        return inline.lexer(token.text);
      }
      return !token.pre && !options.pedantic
        ? inline.lexer(token.text)
        : token.text;
    }
    case 'paragraph': {
      return '
'
        + inline.lexer(token.text)
        + '
\n';
    }
    case 'text': {
      return '
'
        + parseText()
        + '
\n';
    }
  }
};

var parseText = function() {
  var body = token.text
    , top;

  while ((top = tokens[tokens.length-1])
         && top.type === 'text') {
    body += '\n' + next().text;
  }

  return inline.lexer(body);
};

var parse = function(src) {
  tokens = src.reverse();

  var out = '';
  while (next()) {
    out += tok();
  }

  tokens = null;
  token = null;

  return out;
};

/**
 * Helpers
 */

var escape = function(html, encode) {
  return html
    .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
    .replace(/</g, '<')
    .replace(/>/g, '>')
    .replace(/"/g, '"')
    .replace(/'/g, ''');
};

var mangle = function(text) {
  var out = ''
    , l = text.length
    , i = 0
    , ch;

  for (; i < l; i++) {
    ch = text.charCodeAt(i);
    if (Math.random() > 0.5) {
      ch = 'x' + ch.toString(16);
    }
    out += '&#' + ch + ';';
  }

  return out;
};

function tag() {
  var tag = '(?!(?:'
    + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
    + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
    + '|span|br|wbr|ins|del|img)\\b)\\w+';

  return tag;
}

function replace(regex) {
  regex = regex.source;
  return function self(name, val) {
    if (!name) return new RegExp(regex);
    regex = regex.replace(name, val.source || val);
    return self;
  };
}

function noop() {}
noop.exec = noop;

/**
 * Marked
 */

var marked = function(src, opt) {
  setOptions(opt);
  return parse(block.lexer(src));
};

/**
 * Options
 */

var options
  , defaults;

var setOptions = function(opt) {
  if (!opt) opt = defaults;
  if (options === opt) return;
  options = opt;

  if (options.gfm) {
    block.fences = block.gfm.fences;
    block.paragraph = block.gfm.paragraph;
    inline.text = inline.gfm.text;
    inline.url = inline.gfm.url;
  } else {
    block.fences = block.normal.fences;
    block.paragraph = block.normal.paragraph;
    inline.text = inline.normal.text;
    inline.url = inline.normal.url;
  }

  if (options.pedantic) {
    inline.em = inline.pedantic.em;
    inline.strong = inline.pedantic.strong;
  } else {
    inline.em = inline.normal.em;
    inline.strong = inline.normal.strong;
  }
};

marked.options =
marked.setOptions = function(opt) {
  defaults = opt;
  setOptions(opt);
  return marked;
};

marked.options({
  gfm: true,
  pedantic: false,
  sanitize: false,
  highlight: null
});

/**
 * Expose
 */

marked.parser = function(src, opt) {
  setOptions(opt);
  return parse(src);
};

marked.lexer = function(src, opt) {
  setOptions(opt);
  return block.lexer(src);
};

marked.parse = marked;

if (typeof module !== 'undefined') {
  module.exports = marked;
} else {
  this.marked = marked;
}

}).call(this);


In Markdown 1.0.0 and earlier. Version
8. This line turns into a list item.
Because a hard-wrapped line in the
middle of a paragraph looked like a
list item.

Here's one with a bullet.
* criminey.


hello world
    how are you
    how are you

hello world

how are you

hello world

hello world

how are you

hello world

how are you

hello world

how are you

hello world
* how are you

hello world

how are you

hello world
how are you

hello world

hello

hello


+ '</h'
+ token.depth
+ '>\n';
}
case 'code': {
if (!token.escaped) {

token.code = options.highlight(token.text, token.lang);

if (token.code != null && token.code !== token.text) {

# marked

A full-featured markdown parser and compiler, written in javascript.
Built for speed.

## Benchmarks

node v0.4.x

``` bash
$ node test --bench
marked completed in 12071ms.
showdown (reuse converter) completed in 27387ms.
showdown (new converter) completed in 75617ms.
markdown-js completed in 70069ms.
```

node v0.6.x

``` bash
$ node test --bench
marked completed in 6448ms.
marked (gfm) completed in 7357ms.
marked (pedantic) completed in 6092ms.
discount completed in 7314ms.
showdown (reuse converter) completed in 16018ms.
showdown (new converter) completed in 18234ms.
markdown-js completed in 24270ms.
```

__Marked is now faster than Discount, which is written in C.__

For those feeling skeptical: These benchmarks run the entire markdown test suite
1000 times. The test suite tests every feature. It doesn't cater to specific
aspects.

## Install

``` bash
$ npm install marked
```

## Another Javascript Markdown Parser

The point of marked was to create a markdown compiler where it was possible to
frequently parse huge chunks of markdown without having to worry about
caching the compiled output somehow...or blocking for an unnecesarily long time.

marked is very concise and still implements all markdown features. It is also
now fully compatible with the client-side.

marked more or less passes the official markdown test suite in its
entirety. This is important because a surprising number of markdown compilers
cannot pass more than a few tests. It was very difficult to get marked as
compliant as it is. It could have cut corners in several areas for the sake
of performance, but did not in order to be exactly what you expect in terms
of a markdown rendering. In fact, this is why marked could be considered at a
disadvantage in the benchmarks above.

Along with implementing every markdown feature, marked also implements
[GFM features](http://github.github.com/github-flavored-markdown/).

## Options

marked has 4 different switches which change behavior.

- __pedantic__: Conform to obscure parts of `markdown.pl` as much as possible.
  Don't fix any of the original markdown bugs or poor behavior.
- __gfm__: Enable github flavored markdown (enabled by default).
- __sanitize__: Sanitize the output. Ignore any HTML that has been input.
- __highlight__: A callback to highlight code blocks.

None of the above are mutually exclusive/inclusive.

## Usage

``` js
// Set default options
marked.setOptions({
  gfm: true,
  pedantic: false,
  sanitize: true,
  // callback for code highlighter
  highlight: function(code, language) {
    if (language === 'js') {
      code = highlight(code);
    }
    return code;
  }
});
console.log(marked('i am using __markdown__.'));
```

You also have direct access to the lexer and parser if you so desire.

``` js
var tokens = marked.lexer(text);
console.log(marked.parser(tokens));
```

``` bash
$ node
> require('marked').lexer('> i am using marked.')
[ { type: 'blockquote_start' },
  { type: 'paragraph',
    text: 'i am using marked.' },
  { type: 'blockquote_end' },
  links: {} ]
```

## CLI

``` bash
$ marked -o hello.html
hello world
^D
$ cat hello.html
<p>hello world</p>
```

## License

Copyright (c) 2011-2012, Christopher Jeffrey. (MIT License)

See LICENSE for more info.


Just a URL.

URL and title.

URL and title.

URL and title.

URL and title.

Empty.


keep replace replace replace keep keep keep keep


Paragraph one.

<!-- This is a simple comment -->

<!--
	This is another comment.
-->

Paragraph two.

<!-- one comment block -- -- with two comments -->

The end.


This is the simple case.

This one has a line
break.

This one has a line
break with a line-ending space.

this and the other


* TilemapLayer - Fixed unmatched `context.save` and `context.restore` calls (thanks @MortimerGoro #1934)

* DeviceButton would try to set `altKey`, `shiftKey` and `ctrlKey` even for Joypads (thanks @zatch #1939)

/**
* @author       Richard Davey <rich@photonstorm.com>
* @author       @karlmacklin <tacklemcclean@gmail.com>
* @copyright    2015 Photon Storm Ltd.
* @license      {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/

/**
* DeviceButtons belong to both `Phaser.Pointer` and `Phaser.SinglePad` (Gamepad) instances.
*
* For Pointers they represent the various buttons that can exist on mice and pens, such as the left button, right button,
* middle button and advanced buttons like back and forward.
*
* Access them via `Pointer.leftbutton`, `Pointer.rightButton` and so on.
*
* On Gamepads they represent all buttons on the pad: from shoulder buttons to action buttons.
*
* At the time of writing this there are device limitations you should be aware of:
*
* - On Windows, if you install a mouse driver, and its utility software allows you to customize button actions
*   (e.g., IntelliPoint and SetPoint), the middle (wheel) button, the 4th button, and the 5th button might not be set,
*   even when they are pressed.
* - On Linux (GTK), the 4th button and the 5th button are not supported.
* - On Mac OS X 10.5 there is no platform API for implementing any advanced buttons.
*
* @class Phaser.DeviceButton
* @constructor
* @param {Phaser.Pointer|Phaser.SinglePad} parent - A reference to the parent of this button. Either a Pointer or a Gamepad.
* @param {number} buttonCode - The button code this DeviceButton is responsible for.
*/
Phaser.DeviceButton = function (parent, buttonCode) {

    /**
    * @property {Phaser.Pointer|Phaser.SinglePad} parent - A reference to the Pointer or Gamepad that owns this button.
    */
    this.parent = parent;

    /**
    * @property {Phaser.Game} game - A reference to the currently running game.
    */
    this.game = parent.game;

    /**
    * @property {object} event - The DOM event that caused the change in button state.
    * @default
    */
    this.event = null;

    /**
    * @property {boolean} isDown - The "down" state of the button.
    * @default
    */
    this.isDown = false;

    /**
    * @property {boolean} isUp - The "up" state of the button.
    * @default
    */
    this.isUp = true;

    /**
    * @property {number} timeDown - The timestamp when the button was last pressed down.
    * @default
    */
    this.timeDown = 0;

    /**
    * If the button is down this value holds the duration of that button press and is constantly updated.
    * If the button is up it holds the duration of the previous down session.
    * The value is stored in milliseconds.
    * @property {number} duration
    * @default
    */
    this.duration = 0;

    /**
    * @property {number} timeUp - The timestamp when the button was last released.
    * @default
    */
    this.timeUp = 0;

    /**
    * Gamepad only.
    * If a button is held down this holds down the number of times the button has 'repeated'.
    * @property {number} repeats
    * @default
    */
    this.repeats = 0;

    /**
    * True if the alt key was held down when this button was last pressed or released.
    * Not supported on Gamepads.
    * @property {boolean} altKey
    * @default
    */
    this.altKey = false;

    /**
    * True if the shift key was held down when this button was last pressed or released.
    * Not supported on Gamepads.
    * @property {boolean} shiftKey
    * @default
    */
    this.shiftKey = false;

    /**
    * True if the control key was held down when this button was last pressed or released.
    * Not supported on Gamepads.
    * @property {boolean} ctrlKey
    * @default
    */
    this.ctrlKey = false;

    /**
    * @property {number} value - Button value. Mainly useful for checking analog buttons (like shoulder triggers) on Gamepads.
    * @default
    */
    this.value = 0;

    /**
    * @property {number} buttonCode - The buttoncode of this button if a Gamepad, or the DOM button event value if a Pointer.
    */
    this.buttonCode = buttonCode;

    /**
    * This Signal is dispatched every time this DeviceButton is pressed down.
    * It is only dispatched once (until the button is released again).
    * When dispatched it sends 2 arguments: A reference to this DeviceButton and the value of the button.
    * @property {Phaser.Signal} onDown
    */
    this.onDown = new Phaser.Signal();

    /**
    * This Signal is dispatched every time this DeviceButton is released from a down state.
    * It is only dispatched once (until the button is pressed again).
    * When dispatched it sends 2 arguments: A reference to this DeviceButton and the value of the button.
    * @property {Phaser.Signal} onUp
    */
    this.onUp = new Phaser.Signal();

    /**
    * Gamepad only.
    * This Signal is dispatched every time this DeviceButton changes floating value (between, but not exactly, 0 and 1).
    * When dispatched it sends 2 arguments: A reference to this DeviceButton and the value of the button.
    * @property {Phaser.Signal} onFloat
    */
    this.onFloat = new Phaser.Signal();

};

Phaser.DeviceButton.prototype = {

    /**
    * Called automatically by Phaser.Pointer and Phaser.SinglePad.
    * Handles the button down state.
    *
    * @method Phaser.DeviceButton#start
    * @protected
    * @param {object} [event] - The DOM event that triggered the button change.
    * @param {number} [value] - The button value. Only get for Gamepads.
    */
    start: function (event, value) {

        if (this.isDown)
        {
            return;
        }

        this.isDown = true;
        this.isUp = false;
        this.timeDown = this.game.time.time;
        this.duration = 0;
        this.repeats = 0;

        this.event = event;
        this.value = value;

        this.altKey = event.altKey;
        this.shiftKey = event.shiftKey;
        this.ctrlKey = event.ctrlKey;

        this.onDown.dispatch(this, value);

    },

    /**
    * Called automatically by Phaser.Pointer and Phaser.SinglePad.
    * Handles the button up state.
    *
    * @method Phaser.DeviceButton#stop
    * @protected
    * @param {object} [event] - The DOM event that triggered the button change.
    * @param {number} [value] - The button value. Only get for Gamepads.
    */
    stop: function (event, value) {

        if (this.isUp)
        {
            return;
        }

        this.isDown = false;
        this.isUp = true;
        this.timeUp = this.game.time.time;

        this.event = event;
        this.value = value;

        this.altKey = event.altKey;
        this.shiftKey = event.shiftKey;
        this.ctrlKey = event.ctrlKey;

        this.onUp.dispatch(this, value);

    },

    /**
    * Called automatically by Phaser.SinglePad.
    *
    * @method Phaser.DeviceButton#padFloat
    * @protected
    * @param {number} value - Button value
    */
    padFloat: function (value) {

        this.value = value;

        this.onFloat.dispatch(this, value);

    },

    /**
    * Returns the "just pressed" state of this button.
    * Just pressed is considered true if the button was pressed down within the duration given (default 250ms).
    *
    * @method Phaser.DeviceButton#justPressed
    * @param {number} [duration=250] - The duration in ms below which the button is considered as being just pressed.
    * @return {boolean} True if the button is just pressed otherwise false.
    */
    justPressed: function (duration) {

        duration = duration || 250;

        return (this.isDown && (this.timeDown + duration) > this.game.time.time);

    },

    /**
    * Returns the "just released" state of this button.
    * Just released is considered as being true if the button was released within the duration given (default 250ms).
    *
    * @method Phaser.DeviceButton#justReleased
    * @param {number} [duration=250] - The duration in ms below which the button is considered as being just released.
    * @return {boolean} True if the button is just released otherwise false.
    */
    justReleased: function (duration) {

        duration = duration || 250;

        return (this.isUp && (this.timeUp + duration) > this.game.time.time);

    },

    /**
    * Resets this DeviceButton, changing it to an isUp state and resetting the duration and repeats counters.
    *
    * @method Phaser.DeviceButton#reset
    */
    reset: function () {

        this.isDown = false;
        this.isUp = true;

        this.timeDown = this.game.time.time;
        this.duration = 0;
        this.repeats = 0;

        this.altKey = false;
        this.shiftKey = false;
        this.ctrlKey = false;

    },

    /**
    * Destroys this DeviceButton, this disposes of the onDown, onUp and onFloat signals
    * and clears the parent and game references.
    *
    * @method Phaser.DeviceButton#destroy
    */
    destroy: function () {

        this.onDown.dispose();
        this.onUp.dispose();
        this.onFloat.dispose();

        this.parent = null;
        this.game = null;

    }

};

Phaser.DeviceButton.prototype.constructor = Phaser.DeviceButton;

/**
* How long the button has been held down.
* If not currently down it returns -1.
*
* @name Phaser.DeviceButton#duration
* @property {number} duration
* @readonly
*/
Object.defineProperty(Phaser.DeviceButton.prototype, "duration", {

    get: function () {

        if (this.isUp)
        {
            return -1;
        }

        return this.game.time.time - this.timeDown;

    }

});


Phaser.Key

keycode

The key code this Key is responsible for.

If you need more fine-grained control over the handling of specific keys you can create and use Phaser.Key objects.

justPressed

True if the key is just pressed otherwise false.

Returns the "just pressed" state of the Key. Just pressed is considered true if the key was pressed down within the duration given.

duration

The duration below which the key is considered as being just pressed.

justReleased

True if the key is just released otherwise false.

Returns the "just released" state of the Key. Just released is considered as being true if the key was released within the duration given.

duration

The duration below which the key is considered as being just released.

reset

Resets the state of this Key. This sets isDown to false, isUp to true, resets the time to be the current time and clears any callbacks\nassociated with the onDown and onUp events and nulls the onHoldCallback if set.

hard

A soft reset won't reset any events or callbacks that are bound to this Key. A hard reset will.

processKeyDown

Called automatically by Phaser.Keyboard.

altKey

The down state of the ALT key, if pressed at the same time as this key.

ctrlKey

The down state of the CTRL key, if pressed at the same time as this key.

duration

If the key is down this value holds the duration of that key press and is constantly updated.\nIf the key is up it holds the duration of the previous down session.

The number of milliseconds this key has been held down for.

enabled

An enabled key processes its update and dispatches events. You can toggle this at run-time to disable a key without deleting it.

game

A reference to the currently running game.

onDown

This Signal is dispatched every time this Key is pressed down. It is only dispatched once (until the key is released again).

onHoldCallback

A callback that is called while this Key is held down. Warning: Depending on refresh rate that could be 60+ times per second.

onHoldContext

The context under which the onHoldCallback will be called.

repeats

If a key is held down this holds down the number of times the key has 'repeated'.

shiftKey

The down state of the SHIFT key, if pressed at the same time as this key.

timeDown

The timestamp when the key was last pressed down. This is based on Game.time.now.

timeUp

The timestamp when the key was last released. This is based on Game.time.now.