<commit_before>const StringUtil = require('../util/string-util');
const log = require('../util/log');

const loadVector_ = function (costume, runtime, rotationCenter, optVersion) {
    return new Promise(resolve => {
        let svgString = costume.asset.decodeText();
        // SVG Renderer load fixes "quirks" associated with Scratch 2 projects
        if (optVersion && optVersion === 2 && !runtime.v2SvgAdapter) {
            log.error('No V2 SVG adapter present; SVGs may not render correctly.');
        } else if (optVersion && optVersion === 2 && runtime.v2SvgAdapter) {
            runtime.v2SvgAdapter.loadString(svgString, true /* fromVersion2 */);
            svgString = runtime.v2SvgAdapter.toString();
            // Put back into storage
            const storage = runtime.storage;
            costume.asset.encodeTextData(svgString, storage.DataFormat.SVG, true);
            costume.assetId = costume.asset.assetId;
            costume.md5 = `${costume.assetId}.${costume.dataFormat}`;
        }
        // createSVGSkin does the right thing if rotationCenter isn't provided, so it's okay if it's
        // undefined here
        costume.skinId = runtime.renderer.createSVGSkin(svgString, rotationCenter);
        costume.size = runtime.renderer.getSkinSize(costume.skinId);
        // Now we should have a rotationCenter even if we didn't before
        if (!rotationCenter) {
            rotationCenter = runtime.renderer.getSkinRotationCenter(costume.skinId);
            costume.rotationCenterX = rotationCenter[0];
            costume.rotationCenterY = rotationCenter[1];
            costume.bitmapResolution = 1;
        }

        resolve(costume);
    });
};

const canvasPool = (function () {
    /**
     * A pool of canvas objects that can be reused to reduce memory
     * allocations. And time spent in those allocations and the later garbage
     * collection.
     */
    class CanvasPool {
        constructor () {
            this.pool = [];
            this.clearSoon = null;
        }

        /**
         * After a short wait period clear the pool to let the VM collect
         * garbage.
         */
        clear () {
            if (!this.clearSoon) {
                this.clearSoon = new Promise(resolve => setTimeout(resolve, 1000))
                    .then(() => {
                        this.pool.length = 0;
                        this.clearSoon = null;
                    });
            }
        }

        /**
         * Return a canvas. Create the canvas if the pool is empty.
         * @returns {HTMLCanvasElement} A canvas element.
         */
        create () {
            return this.pool.pop() || document.createElement('canvas');
        }

        /**
         * Release the canvas to be reused.
         * @param {HTMLCanvasElement} canvas A canvas element.
         */
        release (canvas) {
            this.clear();
            this.pool.push(canvas);
        }
    }

    return new CanvasPool();
}());

/**
 * Return a promise to fetch a bitmap from storage and return it as a canvas
 * If the costume has bitmapResolution 1, it will be converted to bitmapResolution 2 here (the standard for Scratch 3)
 * If the costume has a text layer asset, which is a text part from Scratch 1.4, then this function
 * will merge the two image assets. See the issue LLK/scratch-vm#672 for more information.
 * @param {!object} costume - the Scratch costume object.
 * @param {!Runtime} runtime - Scratch runtime, used to access the v2BitmapAdapter
 * @param {?object} rotationCenter - optionally passed in coordinates for the center of rotation for the image. If
 *     none is given, the rotation center of the costume will be set to the middle of the costume later on.
 * @property {number} costume.bitmapResolution - the resolution scale for a bitmap costume.
 * @returns {?Promise} - a promise which will resolve to an object {canvas, rotationCenter, assetMatchesBase},
 *     or reject on error.
 *     assetMatchesBase is true if the asset matches the base layer; false if it required adjustment
 */
const fetchBitmapCanvas_ = function (costume, runtime, rotationCenter) {
    if (!costume || !costume.asset) {
        return Promise.reject('Costume load failed. Assets were missing.');
    }
    if (!runtime.v2BitmapAdapter) {
        return Promise.reject('No V2 Bitmap adapter present.');
    }

    return Promise.all([costume.asset, costume.textLayerAsset].map(asset => {
        if (!asset) {
            return null;
        }

        if (typeof createImageBitmap !== 'undefined') {
            return createImageBitmap(
                new Blob([asset.data], {type: asset.assetType.contentType})
            );
        }

        return new Promise((resolve, reject) => {
            const image = new Image();
            image.onload = function () {
                resolve(image);
                image.onload = null;
                image.onerror = null;
            };
            image.onerror = function () {
                reject('Costume load failed. Asset could not be read.');
                image.onload = null;
                image.onerror = null;
            };
            image.src = asset.encodeDataURI();
        });
    }))
        .then(([baseImageElement, textImageElement]) => {
            const mergeCanvas = canvasPool.create();

            const scale = costume.bitmapResolution === 1 ? 2 : 1;
            mergeCanvas.width = baseImageElement.width;
            mergeCanvas.height = baseImageElement.height;

            const ctx = mergeCanvas.getContext('2d');
            ctx.drawImage(baseImageElement, 0, 0);
            if (textImageElement) {
                ctx.drawImage(textImageElement, 0, 0);
            }
            // Track the canvas we merged the bitmaps onto separately from the
            // canvas that we receive from resize if scale is not 1. We know
            // resize treats mergeCanvas as read only data. We don't know when
            // resize may use or modify the canvas. So we'll only release the
            // mergeCanvas back into the canvas pool. Reusing the canvas from
            // resize may cause errors.
            let canvas = mergeCanvas;
            if (scale !== 1) {
                canvas = runtime.v2BitmapAdapter.resize(mergeCanvas, canvas.width * scale, canvas.height * scale);
            }

            // By scaling, we've converted it to bitmap resolution 2
            if (rotationCenter) {
                rotationCenter[0] = rotationCenter[0] * scale;
                rotationCenter[1] = rotationCenter[1] * scale;
                costume.rotationCenterX = rotationCenter[0];
                costume.rotationCenterY = rotationCenter[1];
            }
            costume.bitmapResolution = 2;

            // Clean up the costume object
            delete costume.textLayerMD5;
            delete costume.textLayerAsset;

            return {
                canvas,
                mergeCanvas,
                rotationCenter,
                // True if the asset matches the base layer; false if it required adjustment
                assetMatchesBase: scale === 1 && !textImageElement
            };
        })
        .catch(() => {
            // Clean up the text layer properties if it fails to load
            delete costume.textLayerMD5;
            delete costume.textLayerAsset;
        });
};

const loadBitmap_ = function (costume, runtime, _rotationCenter) {
    return fetchBitmapCanvas_(costume, runtime, _rotationCenter)
        .then(fetched => {
            const updateCostumeAsset = function (dataURI) {
                if (!runtime.v2BitmapAdapter) {
                    // TODO: This might be a bad practice since the returned
                    // promise isn't acted on. If this is something we should be
                    // creating a rejected promise for we should also catch it
                    // somewhere and act on that error (like logging).
                    //
                    // Return a rejection to stop executing updateCostumeAsset.
                    return Promise.reject('No V2 Bitmap adapter present.');
                }

                const storage = runtime.storage;
                costume.asset = storage.createAsset(
                    storage.AssetType.ImageBitmap,
                    storage.DataFormat.PNG,
                    runtime.v2BitmapAdapter.convertDataURIToBinary(dataURI),
                    null,
                    true // generate md5
                );
                costume.dataFormat = storage.DataFormat.PNG;
                costume.assetId = costume.asset.assetId;
                costume.md5 = `${costume.assetId}.${costume.dataFormat}`;
            };

            if (!fetched.assetMatchesBase) {
                updateCostumeAsset(fetched.canvas.toDataURL());
            }

            return fetched;
        })
        .then(({canvas, mergeCanvas, rotationCenter}) => {
            // createBitmapSkin does the right thing if costume.bitmapResolution is undefined...
            // TODO: is rotationCenter ever undefined?
            let center;
            if (rotationCenter) {
                center = [
                    rotationCenter[0] / 2,
                    rotationCenter[1] / 2
                ];
            }

            costume.skinId = runtime.renderer.createBitmapSkin(canvas, costume.bitmapResolution, center);
            canvasPool.release(mergeCanvas);
            const renderSize = runtime.renderer.getSkinSize(costume.skinId);
            costume.size = [renderSize[0] * 2, renderSize[1] * 2]; // Actual size, since all bitmaps are resolution 2

            if (!rotationCenter) {
                rotationCenter = runtime.renderer.getSkinRotationCenter(costume.skinId);
                // Actual rotation center, since all bitmaps are resolution 2
                costume.rotationCenterX = rotationCenter[0] * 2;
                costume.rotationCenterY = rotationCenter[1] * 2;
                costume.bitmapResolution = 2;
            }
            return costume;
        });
};

/**
 * Initialize a costume from an asset asynchronously.
 * Do not call this unless there is a renderer attached.
 * @param {!object} costume - the Scratch costume object.
 * @property {int} skinId - the ID of the costume's render skin, once installed.
 * @property {number} rotationCenterX - the X component of the costume's origin.
 * @property {number} rotationCenterY - the Y component of the costume's origin.
 * @property {number} [bitmapResolution] - the resolution scale for a bitmap costume.
 * @property {!Asset} costume.asset - the asset of the costume loaded from storage.
 * @param {!Runtime} runtime - Scratch runtime, used to access the storage module.
 * @param {?int} optVersion - Version of Scratch that the costume comes from. If this is set
 *     to 2, scratch 3 will perform an upgrade step to handle quirks in SVGs from Scratch 2.0.
 * @returns {?Promise} - a promise which will resolve after skinId is set, or null on error.
 */
const loadCostumeFromAsset = function (costume, runtime, optVersion) {
    costume.assetId = costume.asset.assetId;
    const renderer = runtime.renderer;
    if (!renderer) {
        log.error('No rendering module present; cannot load costume: ', costume.name);
        return Promise.resolve(costume);
    }
    const AssetType = runtime.storage.AssetType;
    let rotationCenter;
    // Use provided rotation center and resolution if they are defined. Bitmap resolution
    // should only ever be 1 or 2.
    if (typeof costume.rotationCenterX === 'number' && !isNaN(costume.rotationCenterX) &&
            typeof costume.rotationCenterY === 'number' && !isNaN(costume.rotationCenterY)) {
        rotationCenter = [costume.rotationCenterX, costume.rotationCenterY];
    }
    if (costume.asset.assetType.runtimeFormat === AssetType.ImageVector.runtimeFormat) {
        return loadVector_(costume, runtime, rotationCenter, optVersion)
            .catch(error => {
                log.warn(`Error loading vector image: ${error.name}: ${error.message}`);
                // Use default asset if original fails to load
                costume.assetId = runtime.storage.defaultAssetId.ImageVector;
                costume.asset = runtime.storage.get(costume.assetId);
                costume.md5 = `${costume.assetId}.${AssetType.ImageVector.runtimeFormat}`;
                return loadVector_(costume, runtime);
            });
    }
    return loadBitmap_(costume, runtime, rotationCenter, optVersion);
};

/**
 * Load a costume's asset into memory asynchronously.
 * Do not call this unless there is a renderer attached.
 * @param {!string} md5ext - the MD5 and extension of the costume to be loaded.
 * @param {!object} costume - the Scratch costume object.
 * @property {int} skinId - the ID of the costume's render skin, once installed.
 * @property {number} rotationCenterX - the X component of the costume's origin.
 * @property {number} rotationCenterY - the Y component of the costume's origin.
 * @property {number} [bitmapResolution] - the resolution scale for a bitmap costume.
 * @param {!Runtime} runtime - Scratch runtime, used to access the storage module.
 * @param {?int} optVersion - Version of Scratch that the costume comes from. If this is set
 *     to 2, scratch 3 will perform an upgrade step to handle quirks in SVGs from Scratch 2.0.
 * @returns {?Promise} - a promise which will resolve after skinId is set, or null on error.
 */
const loadCostume = function (md5ext, costume, runtime, optVersion) {
    const idParts = StringUtil.splitFirst(md5ext, '.');
    const md5 = idParts[0];
    const ext = idParts[1].toLowerCase();
    costume.dataFormat = ext;

    if (costume.asset) {
        // Costume comes with asset. It could be coming from camera, image upload, drag and drop, or file
        return loadCostumeFromAsset(costume, runtime, optVersion);
    }

    // Need to load the costume from storage. The server should have a reference to this md5.
    if (!runtime.storage) {
        log.error('No storage module present; cannot load costume asset: ', md5ext);
        return Promise.resolve(costume);
    }

    if (!runtime.storage.defaultAssetId) {
        log.error(`No default assets found`);
        return Promise.resolve(costume);
    }

    const AssetType = runtime.storage.AssetType;
    const assetType = (ext === 'svg') ? AssetType.ImageVector : AssetType.ImageBitmap;

    const costumePromise = runtime.storage.load(assetType, md5, ext);
    if (!costumePromise) {
        log.error(`Couldn't fetch costume asset: ${md5ext}`);
        return;
    }

    let textLayerPromise;
    if (costume.textLayerMD5) {
        textLayerPromise = runtime.storage.load(AssetType.ImageBitmap, costume.textLayerMD5, 'png');
    } else {
        textLayerPromise = Promise.resolve(null);
    }

    return Promise.all([costumePromise, textLayerPromise]).then(assetArray => {
        costume.asset = assetArray[0];
        if (assetArray[1]) {
            costume.textLayerAsset = assetArray[1];
        }
        return loadCostumeFromAsset(costume, runtime, optVersion);
    });
};

module.exports = {
    loadCostume,
    loadCostumeFromAsset
};
<commit_msg>Clarify loadBitmap_ comments<commit_after>const StringUtil = require('../util/string-util');
const log = require('../util/log');

const loadVector_ = function (costume, runtime, rotationCenter, optVersion) {
    return new Promise(resolve => {
        let svgString = costume.asset.decodeText();
        // SVG Renderer load fixes "quirks" associated with Scratch 2 projects
        if (optVersion && optVersion === 2 && !runtime.v2SvgAdapter) {
            log.error('No V2 SVG adapter present; SVGs may not render correctly.');
        } else if (optVersion && optVersion === 2 && runtime.v2SvgAdapter) {
            runtime.v2SvgAdapter.loadString(svgString, true /* fromVersion2 */);
            svgString = runtime.v2SvgAdapter.toString();
            // Put back into storage
            const storage = runtime.storage;
            costume.asset.encodeTextData(svgString, storage.DataFormat.SVG, true);
            costume.assetId = costume.asset.assetId;
            costume.md5 = `${costume.assetId}.${costume.dataFormat}`;
        }
        // createSVGSkin does the right thing if rotationCenter isn't provided, so it's okay if it's
        // undefined here
        costume.skinId = runtime.renderer.createSVGSkin(svgString, rotationCenter);
        costume.size = runtime.renderer.getSkinSize(costume.skinId);
        // Now we should have a rotationCenter even if we didn't before
        if (!rotationCenter) {
            rotationCenter = runtime.renderer.getSkinRotationCenter(costume.skinId);
            costume.rotationCenterX = rotationCenter[0];
            costume.rotationCenterY = rotationCenter[1];
            costume.bitmapResolution = 1;
        }

        resolve(costume);
    });
};

const canvasPool = (function () {
    /**
     * A pool of canvas objects that can be reused to reduce memory
     * allocations. And time spent in those allocations and the later garbage
     * collection.
     */
    class CanvasPool {
        constructor () {
            this.pool = [];
            this.clearSoon = null;
        }

        /**
         * After a short wait period clear the pool to let the VM collect
         * garbage.
         */
        clear () {
            if (!this.clearSoon) {
                this.clearSoon = new Promise(resolve => setTimeout(resolve, 1000))
                    .then(() => {
                        this.pool.length = 0;
                        this.clearSoon = null;
                    });
            }
        }

        /**
         * Return a canvas. Create the canvas if the pool is empty.
         * @returns {HTMLCanvasElement} A canvas element.
         */
        create () {
            return this.pool.pop() || document.createElement('canvas');
        }

        /**
         * Release the canvas to be reused.
         * @param {HTMLCanvasElement} canvas A canvas element.
         */
        release (canvas) {
            this.clear();
            this.pool.push(canvas);
        }
    }

    return new CanvasPool();
}());

/**
 * Return a promise to fetch a bitmap from storage and return it as a canvas
 * If the costume has bitmapResolution 1, it will be converted to bitmapResolution 2 here (the standard for Scratch 3)
 * If the costume has a text layer asset, which is a text part from Scratch 1.4, then this function
 * will merge the two image assets. See the issue LLK/scratch-vm#672 for more information.
 * @param {!object} costume - the Scratch costume object.
 * @param {!Runtime} runtime - Scratch runtime, used to access the v2BitmapAdapter
 * @param {?object} rotationCenter - optionally passed in coordinates for the center of rotation for the image. If
 *     none is given, the rotation center of the costume will be set to the middle of the costume later on.
 * @property {number} costume.bitmapResolution - the resolution scale for a bitmap costume.
 * @returns {?Promise} - a promise which will resolve to an object {canvas, rotationCenter, assetMatchesBase},
 *     or reject on error.
 *     assetMatchesBase is true if the asset matches the base layer; false if it required adjustment
 */
const fetchBitmapCanvas_ = function (costume, runtime, rotationCenter) {
    if (!costume || !costume.asset) {
        return Promise.reject('Costume load failed. Assets were missing.');
    }
    if (!runtime.v2BitmapAdapter) {
        return Promise.reject('No V2 Bitmap adapter present.');
    }

    return Promise.all([costume.asset, costume.textLayerAsset].map(asset => {
        if (!asset) {
            return null;
        }

        if (typeof createImageBitmap !== 'undefined') {
            return createImageBitmap(
                new Blob([asset.data], {type: asset.assetType.contentType})
            );
        }

        return new Promise((resolve, reject) => {
            const image = new Image();
            image.onload = function () {
                resolve(image);
                image.onload = null;
                image.onerror = null;
            };
            image.onerror = function () {
                reject('Costume load failed. Asset could not be read.');
                image.onload = null;
                image.onerror = null;
            };
            image.src = asset.encodeDataURI();
        });
    }))
        .then(([baseImageElement, textImageElement]) => {
            const mergeCanvas = canvasPool.create();

            const scale = costume.bitmapResolution === 1 ? 2 : 1;
            mergeCanvas.width = baseImageElement.width;
            mergeCanvas.height = baseImageElement.height;

            const ctx = mergeCanvas.getContext('2d');
            ctx.drawImage(baseImageElement, 0, 0);
            if (textImageElement) {
                ctx.drawImage(textImageElement, 0, 0);
            }
            // Track the canvas we merged the bitmaps onto separately from the
            // canvas that we receive from resize if scale is not 1. We know
            // resize treats mergeCanvas as read only data. We don't know when
            // resize may use or modify the canvas. So we'll only release the
            // mergeCanvas back into the canvas pool. Reusing the canvas from
            // resize may cause errors.
            let canvas = mergeCanvas;
            if (scale !== 1) {
                canvas = runtime.v2BitmapAdapter.resize(mergeCanvas, canvas.width * scale, canvas.height * scale);
            }

            // By scaling, we've converted it to bitmap resolution 2
            if (rotationCenter) {
                rotationCenter[0] = rotationCenter[0] * scale;
                rotationCenter[1] = rotationCenter[1] * scale;
                costume.rotationCenterX = rotationCenter[0];
                costume.rotationCenterY = rotationCenter[1];
            }
            costume.bitmapResolution = 2;

            // Clean up the costume object
            delete costume.textLayerMD5;
            delete costume.textLayerAsset;

            return {
                canvas,
                mergeCanvas,
                rotationCenter,
                // True if the asset matches the base layer; false if it required adjustment
                assetMatchesBase: scale === 1 && !textImageElement
            };
        })
        .catch(() => {
            // Clean up the text layer properties if it fails to load
            delete costume.textLayerMD5;
            delete costume.textLayerAsset;
        });
};

const loadBitmap_ = function (costume, runtime, _rotationCenter) {
    return fetchBitmapCanvas_(costume, runtime, _rotationCenter)
        .then(fetched => {
            const updateCostumeAsset = function (dataURI) {
                if (!runtime.v2BitmapAdapter) {
                    // TODO: This might be a bad practice since the returned
                    // promise isn't acted on. If this is something we should be
                    // creating a rejected promise for we should also catch it
                    // somewhere and act on that error (like logging).
                    //
                    // Return a rejection to stop executing updateCostumeAsset.
                    return Promise.reject('No V2 Bitmap adapter present.');
                }

                const storage = runtime.storage;
                costume.asset = storage.createAsset(
                    storage.AssetType.ImageBitmap,
                    storage.DataFormat.PNG,
                    runtime.v2BitmapAdapter.convertDataURIToBinary(dataURI),
                    null,
                    true // generate md5
                );
                costume.dataFormat = storage.DataFormat.PNG;
                costume.assetId = costume.asset.assetId;
                costume.md5 = `${costume.assetId}.${costume.dataFormat}`;
            };

            if (!fetched.assetMatchesBase) {
                updateCostumeAsset(fetched.canvas.toDataURL());
            }

            return fetched;
        })
        .then(({canvas, mergeCanvas, rotationCenter}) => {
            // createBitmapSkin does the right thing if costume.rotationCenter are undefined.
            // That will be the case if you upload a bitmap asset or create one by taking a photo.
            let center;
            if (rotationCenter) {
                // fetchBitmapCanvas will ensure that the costume's bitmap resolution is 2 and its rotation center is
                // scaled to match, so it's okay to always divide by 2.
                center = [
                    rotationCenter[0] / 2,
                    rotationCenter[1] / 2
                ];
            }

            // TODO: costume.bitmapResolution will always be 2 at this point because of fetchBitmapCanvas_, so we don't
            // need to pass it in here.
            costume.skinId = runtime.renderer.createBitmapSkin(canvas, costume.bitmapResolution, center);
            canvasPool.release(mergeCanvas);
            const renderSize = runtime.renderer.getSkinSize(costume.skinId);
            costume.size = [renderSize[0] * 2, renderSize[1] * 2]; // Actual size, since all bitmaps are resolution 2

            if (!rotationCenter) {
                rotationCenter = runtime.renderer.getSkinRotationCenter(costume.skinId);
                // Actual rotation center, since all bitmaps are resolution 2
                costume.rotationCenterX = rotationCenter[0] * 2;
                costume.rotationCenterY = rotationCenter[1] * 2;
                costume.bitmapResolution = 2;
            }
            return costume;
        });
};

/**
 * Initialize a costume from an asset asynchronously.
 * Do not call this unless there is a renderer attached.
 * @param {!object} costume - the Scratch costume object.
 * @property {int} skinId - the ID of the costume's render skin, once installed.
 * @property {number} rotationCenterX - the X component of the costume's origin.
 * @property {number} rotationCenterY - the Y component of the costume's origin.
 * @property {number} [bitmapResolution] - the resolution scale for a bitmap costume.
 * @property {!Asset} costume.asset - the asset of the costume loaded from storage.
 * @param {!Runtime} runtime - Scratch runtime, used to access the storage module.
 * @param {?int} optVersion - Version of Scratch that the costume comes from. If this is set
 *     to 2, scratch 3 will perform an upgrade step to handle quirks in SVGs from Scratch 2.0.
 * @returns {?Promise} - a promise which will resolve after skinId is set, or null on error.
 */
const loadCostumeFromAsset = function (costume, runtime, optVersion) {
    costume.assetId = costume.asset.assetId;
    const renderer = runtime.renderer;
    if (!renderer) {
        log.error('No rendering module present; cannot load costume: ', costume.name);
        return Promise.resolve(costume);
    }
    const AssetType = runtime.storage.AssetType;
    let rotationCenter;
    // Use provided rotation center and resolution if they are defined. Bitmap resolution
    // should only ever be 1 or 2.
    if (typeof costume.rotationCenterX === 'number' && !isNaN(costume.rotationCenterX) &&
            typeof costume.rotationCenterY === 'number' && !isNaN(costume.rotationCenterY)) {
        rotationCenter = [costume.rotationCenterX, costume.rotationCenterY];
    }
    if (costume.asset.assetType.runtimeFormat === AssetType.ImageVector.runtimeFormat) {
        return loadVector_(costume, runtime, rotationCenter, optVersion)
            .catch(error => {
                log.warn(`Error loading vector image: ${error.name}: ${error.message}`);
                // Use default asset if original fails to load
                costume.assetId = runtime.storage.defaultAssetId.ImageVector;
                costume.asset = runtime.storage.get(costume.assetId);
                costume.md5 = `${costume.assetId}.${AssetType.ImageVector.runtimeFormat}`;
                return loadVector_(costume, runtime);
            });
    }
    return loadBitmap_(costume, runtime, rotationCenter, optVersion);
};

/**
 * Load a costume's asset into memory asynchronously.
 * Do not call this unless there is a renderer attached.
 * @param {!string} md5ext - the MD5 and extension of the costume to be loaded.
 * @param {!object} costume - the Scratch costume object.
 * @property {int} skinId - the ID of the costume's render skin, once installed.
 * @property {number} rotationCenterX - the X component of the costume's origin.
 * @property {number} rotationCenterY - the Y component of the costume's origin.
 * @property {number} [bitmapResolution] - the resolution scale for a bitmap costume.
 * @param {!Runtime} runtime - Scratch runtime, used to access the storage module.
 * @param {?int} optVersion - Version of Scratch that the costume comes from. If this is set
 *     to 2, scratch 3 will perform an upgrade step to handle quirks in SVGs from Scratch 2.0.
 * @returns {?Promise} - a promise which will resolve after skinId is set, or null on error.
 */
const loadCostume = function (md5ext, costume, runtime, optVersion) {
    const idParts = StringUtil.splitFirst(md5ext, '.');
    const md5 = idParts[0];
    const ext = idParts[1].toLowerCase();
    costume.dataFormat = ext;

    if (costume.asset) {
        // Costume comes with asset. It could be coming from camera, image upload, drag and drop, or file
        return loadCostumeFromAsset(costume, runtime, optVersion);
    }

    // Need to load the costume from storage. The server should have a reference to this md5.
    if (!runtime.storage) {
        log.error('No storage module present; cannot load costume asset: ', md5ext);
        return Promise.resolve(costume);
    }

    if (!runtime.storage.defaultAssetId) {
        log.error(`No default assets found`);
        return Promise.resolve(costume);
    }

    const AssetType = runtime.storage.AssetType;
    const assetType = (ext === 'svg') ? AssetType.ImageVector : AssetType.ImageBitmap;

    const costumePromise = runtime.storage.load(assetType, md5, ext);
    if (!costumePromise) {
        log.error(`Couldn't fetch costume asset: ${md5ext}`);
        return;
    }

    let textLayerPromise;
    if (costume.textLayerMD5) {
        textLayerPromise = runtime.storage.load(AssetType.ImageBitmap, costume.textLayerMD5, 'png');
    } else {
        textLayerPromise = Promise.resolve(null);
    }

    return Promise.all([costumePromise, textLayerPromise]).then(assetArray => {
        costume.asset = assetArray[0];
        if (assetArray[1]) {
            costume.textLayerAsset = assetArray[1];
        }
        return loadCostumeFromAsset(costume, runtime, optVersion);
    });
};

module.exports = {
    loadCostume,
    loadCostumeFromAsset
};
<|endoftext|>


<commit_before>// Design Basic Game Solo Challenge

// This is a solo challenge

// Your mission description: Think of a game
// Overall mission: transalte that game to javascript
// Goals:
// Characters:
// Objects:
// Functions:

// Pseudocode
// make a function thnat displays the rules as you open the file
//Make a variable player with a board
// make a function to display board
//make a function that marks an ex on each index
//make a function to check if the player won
//
//

// Initial Code
var gameRules = function(){
    console.log("select a position between 1 to 9 \n with this you'll select a position");
  };
gameRules();
console.log("input, number 1 to 9 \n In this format player.answer(1) \n or player.answer(2)")
var player = {
  board: ["","","","","","","","",""],
  display: function(){
    console.log(this.board);
  },
  answer: function(x){
    this.board[x + 1] = "X";
  }

};

player.display();
player.answer(2);
player.display();

// Refactored Code

// Reflection
//
//
//
//
//
//
//
//

<commit_msg>add solo game<commit_after>// Design Basic Game Solo Challenge

// This is a solo challenge

// Your mission description: Think of a game
// Overall mission: transalte that game to javascript
// Goals:
// Characters:
// Objects:
// Functions:

// Pseudocode
// make a function thnat displays the rules as you open the file
//Make a variable player with a board, board will be an array with 9 positions and they will be marked according to the index
//
//make a function that marks an ex on each index
// make a function to display board this will be called after the player changes the board that will be a variable than can be access from all the methods inside the object
//make a function to check if the player won. this funcrtion will contain the winning positions and check if they all have an "X" with conditional statements
/*
add a computer move after each turn that will take a random position from 0 to 8 if the position is not taken
the computerMove will only print the "O" if the spot is available that will be done with a conditional that will check for " "
*/

// Initial Code
var gameRules = function(){
    console.log("select a position between 1 to 9 \n with this you'll select a position");
  };
gameRules();
console.log("input, number 1 to 9 \n In this format player.answer(1) \n or player.answer(2)")
var player = {
  board: [" "," "," "," "," "," "," "," "," "],

  answer: function(x){
    this.board[x - 1] = "X";
  },
  display: function(){
    console.log(this.board[0] + "-" + this.board[1] + "-" + this.board[2]);
    console.log(this.board[3] + "-" + this.board[4] + "-" + this.board[5]);
    console.log(this.board[6] + "-" + this.board[7] + "-" + this.board[8]);
  },
  computerMove: function(){
    var move = Math.floor(Math.random() * 9)
    console.log(move);
    if (this.board[move]=== " "){
      this.board[(move)] = "0";
    };
    console.log(this.board);
  },
  win: function (){
    if (this.board[0]=== "X" && this.board[1]=== "X" && this.board[2]=== "X"){
      console.log("You win!");
    } else if (this.board[3]=== "X" && this.board[4]=== "X" && this.board[5]=== "X"){
      console.log("You win!");
    } else if (this.board[6]=== "X" && this.board[7]=== "X" && this.board[8]=== "X"){
      console.log("You win!");
    } else if (this.board[2]=== "X" && this.board[4]=== "X" && this.board[6]=== "X"){
      console.log("You win!");
    } else if (this.board[0]=== "X" && this.board[4]=== "X" && this.board[8]=== "X"){
      console.log("You win!");
    }
  }

};

player.display();
player.answer(8);
player.answer(2);
player.answer(3);
player.display();
player.computerMove();
player.win();

// Refactored Code
var gameRules = function(){
    console.log("select a position between 1 to 9 \n with this you'll select a position");
  };
gameRules();
console.log("input, number 1 to 9 \n In this format player.answer(1) \n or player.answer(2)")
var player = {
  board: [" "," "," "," "," "," "," "," "," "],

  answer: function(x){
    this.board[x - 1] = "X";
  },
  display: function(){
    console.log(this.board[0] + "-" + this.board[1] + "-" + this.board[2]);
    console.log(this.board[3] + "-" + this.board[4] + "-" + this.board[5]);
    console.log(this.board[6] + "-" + this.board[7] + "-" + this.board[8]);
  },
  computerMove: function(){
    var move = Math.floor(Math.random() * 9)
    if (this.board[move]=== " "){
      this.board[(move)] = "0";
    };
    console.log(this.board);
  },
  win: function (){
    if (this.board[0]=== "X" && this.board[1]=== "X" && this.board[2]=== "X"){
      console.log("You win!");
    } else if (this.board[3]=== "X" && this.board[4]=== "X" && this.board[5]=== "X"){
      console.log("You win!");
    } else if (this.board[6]=== "X" && this.board[7]=== "X" && this.board[8]=== "X"){
      console.log("You win!");
    } else if (this.board[2]=== "X" && this.board[4]=== "X" && this.board[6]=== "X"){
      console.log("You win!");
    } else if (this.board[0]=== "X" && this.board[4]=== "X" && this.board[8]=== "X"){
      console.log("You win!");
    }
  }

};

// Reflection
// I didn't want to refactor by using a for loop with the win function because I wanted to make it a single method for clarity, and there are not so many options to win in this game
/*
DESIGN A GAME
In the reflection section of your game.js file, answer the following questions:
• What was the most difficult part of this challenge?
Thinking about what game I was going to create, at the end I just ran out of time and did not complete any of my ideas and ended up setting for tic tac toe. The objects creating it’s ok, but I still have problems printing things in a pretty way on the terminal. Ruby is so much smother for that!
• What did you learn about creating objects and functions that interact with one another?
I learned about the scope of the variables that are created and to use the this.variable to call variables inside other functions.
• Did you learn about any new built-in methods you could use in your refactored solution? If so, what were they and how do they work?
I didn’t use so many built in methods mostly because I ran out of time, I’m traveling at trhe moment, last chance before bootcamp starts. I will most likely redo my work as I get back to NYC
• How can you access and manipulate properties of objects?
You can access them with the dot notation and with ()
 var newPerson = new person(required arguments)
 The "new person()" is the constructor function.
Also it depends on how objects are built.

*/

<|endoftext|>


<commit_before>import React from 'react'
/* eslint-disable no-underscore-dangle */

export const isCompositeComponent = type => typeof type === 'function'
export const isReloadableComponent = type =>
  typeof type === 'function' || typeof type === 'object'

export const getComponentDisplayName = type => {
  const displayName = type.displayName || type.name
  return displayName && displayName !== 'ReactComponent'
    ? displayName
    : 'Component'
}

export const reactLifeCycleMountMethods = [
  'componentWillMount',
  'componentDidMount',
]

export function isReactClass(Component) {
  return !!(
    Component.prototype &&
    (React.Component.prototype.isPrototypeOf(Component.prototype) ||
      // react 14 support
      Component.prototype.isReactComponent ||
      Component.prototype.componentWillMount ||
      Component.prototype.componentWillUnmount ||
      Component.prototype.componentDidMount ||
      Component.prototype.componentDidUnmount ||
      Component.prototype.render)
  )
}

export function isReactClassInstance(Component) {
  return (
    Component && isReactClass({ prototype: Object.getPrototypeOf(Component) })
  )
}

export const getInternalInstance = instance =>
  instance._reactInternalFiber || // React 16
  instance._reactInternalInstance || // React 15
  null

export const updateInstance = instance => {
  const { updater, forceUpdate } = instance
  if (typeof forceUpdate === 'function') {
    instance.forceUpdate()
  } else if (updater && typeof updater.enqueueForceUpdate === 'function') {
    updater.enqueueForceUpdate(instance)
  }
}

export const isFragmentNode = ({ type }) =>
  React.Fragment && type === React.Fragment

const ContextType = React.createContext ? React.createContext() : null
const ConsumerType = ContextType && ContextType.Consumer.$$typeof
const ProviderType = ContextType && ContextType.Provider.$$typeof
const MemoType = React.memo && React.memo(() => null).$$typeof
const LazyType = React.lazy && React.lazy(() => null).$$typeof
const ForwardType = React.forwardRef && React.forwardRef(() => null).$$typeof

export const CONTEXT_CURRENT_VALUE = '_currentValue'

export const isContextConsumer = ({ type }) =>
  type &&
  typeof type === 'object' &&
  type.$$typeof === ConsumerType &&
  ConsumerType
export const isContextProvider = ({ type }) =>
  type &&
  typeof type === 'object' &&
  type.$$typeof === ProviderType &&
  ProviderType
export const isMemoType = ({ type }) =>
  type && typeof type === 'object' && type.$$typeof === MemoType && MemoType
export const isLazyType = ({ type }) =>
  type && typeof type === 'object' && type.$$typeof === LazyType && LazyType
export const isForwardType = ({ type }) =>
  type &&
  typeof type === 'object' &&
  type.$$typeof === ForwardType &&
  ForwardType

export const getContextProvider = type => type && type._context
<commit_msg>Check property before use. Fixes #1163<commit_after>import React from 'react'
/* eslint-disable no-underscore-dangle */

export const isCompositeComponent = type => typeof type === 'function'
export const isReloadableComponent = type =>
  typeof type === 'function' || typeof type === 'object'

export const getComponentDisplayName = type => {
  const displayName = type.displayName || type.name
  return displayName && displayName !== 'ReactComponent'
    ? displayName
    : 'Component'
}

export const reactLifeCycleMountMethods = [
  'componentWillMount',
  'componentDidMount',
]

export function isReactClass(Component) {
  return !!(
    Component.prototype &&
    (React.Component.prototype.isPrototypeOf(Component.prototype) ||
      // react 14 support
      Component.prototype.isReactComponent ||
      Component.prototype.componentWillMount ||
      Component.prototype.componentWillUnmount ||
      Component.prototype.componentDidMount ||
      Component.prototype.componentDidUnmount ||
      Component.prototype.render)
  )
}

export function isReactClassInstance(Component) {
  return (
    Component && isReactClass({ prototype: Object.getPrototypeOf(Component) })
  )
}

export const getInternalInstance = instance =>
  instance._reactInternalFiber || // React 16
  instance._reactInternalInstance || // React 15
  null

export const updateInstance = instance => {
  const { updater, forceUpdate } = instance
  if (typeof forceUpdate === 'function') {
    instance.forceUpdate()
  } else if (updater && typeof updater.enqueueForceUpdate === 'function') {
    updater.enqueueForceUpdate(instance)
  }
}

export const isFragmentNode = ({ type }) =>
  React.Fragment && type === React.Fragment

const ContextType = React.createContext ? React.createContext() : null
const ConsumerType = ContextType && ContextType.Consumer.$$typeof
const ProviderType = ContextType && ContextType.Provider.$$typeof
const MemoType = React.memo && React.memo(() => null).$$typeof
const LazyType = React.lazy && React.lazy(() => null).$$typeof
const ForwardType = React.forwardRef && React.forwardRef(() => null).$$typeof

export const CONTEXT_CURRENT_VALUE = '_currentValue'

export const isContextConsumer = ({ type }) =>
  type &&
  typeof type === 'object' &&
  '$$typeof' in type &&
  type.$$typeof === ConsumerType &&
  ConsumerType
export const isContextProvider = ({ type }) =>
  type &&
  typeof type === 'object' &&
  '$$typeof' in type &&
  type.$$typeof === ProviderType &&
  ProviderType
export const isMemoType = ({ type }) =>
  type &&
  typeof type === 'object' &&
  '$$typeof' in type &&
  type.$$typeof === MemoType &&
  MemoType
export const isLazyType = ({ type }) =>
  type &&
  typeof type === 'object' &&
  '$$typeof' in type &&
  type.$$typeof === LazyType &&
  LazyType
export const isForwardType = ({ type }) =>
  type &&
  typeof type === 'object' &&
  '$$typeof' in type &&
  type.$$typeof === ForwardType &&
  ForwardType

export const getContextProvider = type => type && type._context
<|endoftext|>


<commit_before>describe('SharePoint List API Wrapper', function () {
  'use strict';

  it('should have a namespace', function () {
    expect(sputils).to.have.ownProperty('list');
  });

  beforeEach(function () {
    initialize_dom();
  });

  describe('getListByName', function () {
    it('should have correct config settings', function (done) {
      //Mock jQuery ajax
      fetch = function (url, config) {
        expect(config)
          .to.have.deep.property('headers.accept',
                                 'application/json;odata=verbose');
        expect(config)
          .to.have.property('url',
            'http://example.com/_api/Web/Lists/getByTitle(\'Announcements\')/items/');
        expect(config)
          .to.have.property('method', 'GET');

        return stdPromise();
      };

      sputils.list.getListByName("Announcements")
        .then(function (res) {
          done();
        });
    });
  });

  describe('postListByName', function () {
    it('should have correct config settings', function (done) {
      //Mock jQuery ajax
      fetch = function (url, config) {
        expect(config)
          .to.have.deep.property('headers.accept',
                                 'application/json;odata=verbose');
        expect(config)
          .to.have.deep.property('headers.X-RequestDigest',
                                 'TestValue');
        expect(config)
          .to.have.property('url',
            'http://example.com/_api/Web/Lists/getByTitle(\'Announcements\')/items/');
        expect(config)
          .to.have.property('method', 'POST');
        expect(config)
          .to.have.property('body', '{"test":"test"}');

        return stdPromise();
      };

      sputils.list.postListByName("Announcements", { "test": "test" })
        .then(function (res) {
          done();
        });
    });
  });

  describe('getListItemById', function () {
    it('should get an item by its id', function (done) {
      var listName = 'Announcements',
          id = 1,
          result = {d: 'success'},
          expUrl = _spPageContextInfo.webAbsoluteUrl +
            "/_api/Web/Lists/getByTitle('" +
            listName + "')/items/getbyid(" + id + ")";

      fetch = function (url, cfg) {
        expect(url.toLowerCase()).to.equal(expUrl.toLowerCase());
        return stdPromise(result);
      };

      sputils.list.getListItemById(listName, id).then(function (item) {
        done();
        expect(item).to.equal(result.d);
      });
    });
  });

  describe('checkFile', function () {
    it('should check a file out or in', function (done) {
      var fileUrl = window.location.hostname + '/subweb1/list1/doc.txt';
      var checkIns = 0;
      var checkOuts = 0;
      fetch = function () {
        return stdPromise({
          d: {
            GetContextWebInformation: {
              WebFullUrl: window.location.hostname + '/subweb1'
            }
          }
        });
      };

      function Ctor(url) {
        // check that code uses `new`
        var is = this instanceof Ctor;
        expect(is).to.equal(true);
        expect(url).to.equal(window.location.hostname + '/subweb1');

        this.executeQueryAsync = function (resolve, reject) {
          resolve({ });
        }

        this.get_web = function () {
          return {
            getFileByServerRelativeUrl: function (relUrl) {
              expect(relUrl).to.equal('/subweb1/list1/doc.txt');
              return {
                checkIn: function () {
                  checkIns++;
                },
                checkOut: function () {
                  checkOuts++;
                }
              };
            }
          };
        };
      }

      SP = {
        ClientContext: Ctor
      };

      sputils.list.checkFile('out', fileUrl).then(function () {
        expect(checkOuts).to.equal(1);
        return sputils.list.checkFile('in', fileUrl);
      }).then(function () {
        expect(checkIns).to.equal(1);
        done();
      });
    });
  });
});
<commit_msg>Fix jshint error in test<commit_after>describe('SharePoint List API Wrapper', function () {
  'use strict';

  it('should have a namespace', function () {
    expect(sputils).to.have.ownProperty('list');
  });

  beforeEach(function () {
    initialize_dom();
  });

  describe('getListByName', function () {
    it('should have correct config settings', function (done) {
      //Mock jQuery ajax
      fetch = function (url, config) {
        expect(config)
          .to.have.deep.property('headers.accept',
                                 'application/json;odata=verbose');
        expect(config)
          .to.have.property('url',
            'http://example.com/_api/Web/Lists/getByTitle(\'Announcements\')/items/');
        expect(config)
          .to.have.property('method', 'GET');

        return stdPromise();
      };

      sputils.list.getListByName("Announcements")
        .then(function (res) {
          done();
        });
    });
  });

  describe('postListByName', function () {
    it('should have correct config settings', function (done) {
      //Mock jQuery ajax
      fetch = function (url, config) {
        expect(config)
          .to.have.deep.property('headers.accept',
                                 'application/json;odata=verbose');
        expect(config)
          .to.have.deep.property('headers.X-RequestDigest',
                                 'TestValue');
        expect(config)
          .to.have.property('url',
            'http://example.com/_api/Web/Lists/getByTitle(\'Announcements\')/items/');
        expect(config)
          .to.have.property('method', 'POST');
        expect(config)
          .to.have.property('body', '{"test":"test"}');

        return stdPromise();
      };

      sputils.list.postListByName("Announcements", { "test": "test" })
        .then(function (res) {
          done();
        });
    });
  });

  describe('getListItemById', function () {
    it('should get an item by its id', function (done) {
      var listName = 'Announcements',
          id = 1,
          result = {d: 'success'},
          expUrl = _spPageContextInfo.webAbsoluteUrl +
            "/_api/Web/Lists/getByTitle('" +
            listName + "')/items/getbyid(" + id + ")";

      fetch = function (url, cfg) {
        expect(url.toLowerCase()).to.equal(expUrl.toLowerCase());
        return stdPromise(result);
      };

      sputils.list.getListItemById(listName, id).then(function (item) {
        done();
        expect(item).to.equal(result.d);
      });
    });
  });

  describe('checkFile', function () {
    it('should check a file out or in', function (done) {
      var fileUrl = window.location.hostname + '/subweb1/list1/doc.txt';
      var checkIns = 0;
      var checkOuts = 0;
      fetch = function () {
        return stdPromise({
          d: {
            GetContextWebInformation: {
              WebFullUrl: window.location.hostname + '/subweb1'
            }
          }
        });
      };

      function Ctor(url) {
        // check that code uses `new`
        var is = this instanceof Ctor;
        expect(is).to.equal(true);
        expect(url).to.equal(window.location.hostname + '/subweb1');

        this.executeQueryAsync = function (resolve, reject) {
          resolve({ });
        };

        this.get_web = function () {
          return {
            getFileByServerRelativeUrl: function (relUrl) {
              expect(relUrl).to.equal('/subweb1/list1/doc.txt');
              return {
                checkIn: function () {
                  checkIns++;
                },
                checkOut: function () {
                  checkOuts++;
                }
              };
            }
          };
        };
      }

      SP = {
        ClientContext: Ctor
      };

      sputils.list.checkFile('out', fileUrl).then(function () {
        expect(checkOuts).to.equal(1);
        return sputils.list.checkFile('in', fileUrl);
      }).then(function () {
        expect(checkIns).to.equal(1);
        done();
      });
    });
  });
});
<|endoftext|>


<commit_before>/*!
 * OS.js - JavaScript Operating System
 *
 * Copyright (c) 2011-2014, Anders Evenrud <andersevenrud@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author  Anders Evenrud <andersevenrud@gmail.com>
 * @licence Simplified BSD License
 */
(function(Utils, API) {
  'use strict';

  window.OSjs       = window.OSjs       || {};
  OSjs.VFS          = OSjs.VFS          || {};
  OSjs.VFS.Modules  = OSjs.VFS.Modules  || {};

  function internalCall(name, args, callback) {
    API.call('fs', {'method': name, 'arguments': args}, function(res) {
      if ( !res || (typeof res.result === 'undefined') || res.error ) {
        callback(res.error || OSjs._('Fatal error'));
      } else {
        callback(false, res.result);
      }
    }, function(error) {
      callback(error);
    });
  }

  /////////////////////////////////////////////////////////////////////////////
  // API
  /////////////////////////////////////////////////////////////////////////////

  var OSjsStorage = {};
  OSjsStorage.scandir = function(item, callback) {
    internalCall('scandir', [item.path], function(error, result) {
      var list = [];
      if ( result ) {
        result = OSjs.VFS.filterScandir(result, item._opts);
        result.forEach(function(iter) {
          list.push(new OSjs.VFS.File(iter));
        });
      }
      callback(error, list);
    });
  };
  OSjsStorage.write = function(item, data, callback) {
    callback('Unavailable');
  };
  OSjsStorage.read = function(item, callback) {
    var ropts = [item.path];
    if ( item._opts ) {
      ropts.push(item._opts);
    }
    internalCall('read', ropts, callback);
  };
  OSjsStorage.copy = function(src, dest, callback) {
    callback('Unavailable');
  };
  OSjsStorage.move = function(src, dest, callback) {
    callback('Unavailable');
  };
  OSjsStorage.unlink = function(item, callback) {
    callback('Unavailable');
  };
  OSjsStorage.mkdir = function(item, callback) {
    callback('Unavailable');
  };
  OSjsStorage.exists = function(item, callback) {
    callback(false, true);
  };
  OSjsStorage.fileinfo = function(item, callback) {
    callback('Unavailable');
  };
  OSjsStorage.url = function(item, callback) {
    var url = item.path.replace(OSjs.VFS.Modules.OSjs.match, '');
    callback(false, url);
  };

  /////////////////////////////////////////////////////////////////////////////
  // WRAPPERS
  /////////////////////////////////////////////////////////////////////////////

  function makeRequest(name, args, callback) {
    args = args || [];
    callback = callback || {};

    if ( !OSjsStorage[name] ) {
      throw new Error('Invalid OSjsStorage API call name');
    }

    var fargs = args;
    fargs.push(callback);
    OSjsStorage[name].apply(OSjsStorage, fargs);
  }

  /////////////////////////////////////////////////////////////////////////////
  // EXPORTS
  /////////////////////////////////////////////////////////////////////////////

  OSjs.VFS.Modules.OSjs = OSjs.VFS.Modules.OSjs || {
    description: 'OS.js',
    root: 'osjs:///',
    match: /^osjs\:\/\//,
    icon: 'devices/harddrive.png',
    enabled: function() {
      return true;
    },
    request: makeRequest
  };

})(OSjs.Utils, OSjs.API);
<commit_msg>VFS: Added support for osjs:// (2)<commit_after>/*!
 * OS.js - JavaScript Operating System
 *
 * Copyright (c) 2011-2014, Anders Evenrud <andersevenrud@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author  Anders Evenrud <andersevenrud@gmail.com>
 * @licence Simplified BSD License
 */
(function(Utils, API) {
  'use strict';

  window.OSjs       = window.OSjs       || {};
  OSjs.VFS          = OSjs.VFS          || {};
  OSjs.VFS.Modules  = OSjs.VFS.Modules  || {};

  function internalCall(name, args, callback) {
    API.call('fs', {'method': name, 'arguments': args}, function(res) {
      if ( !res || (typeof res.result === 'undefined') || res.error ) {
        callback(res.error || OSjs._('Fatal error'));
      } else {
        callback(false, res.result);
      }
    }, function(error) {
      callback(error);
    });
  }

  /////////////////////////////////////////////////////////////////////////////
  // API
  /////////////////////////////////////////////////////////////////////////////

  var OSjsStorage = {};
  OSjsStorage.scandir = function(item, callback) {
    internalCall('scandir', [item.path], function(error, result) {
      var list = [];
      if ( result ) {
        result = OSjs.VFS.filterScandir(result, item._opts);
        result.forEach(function(iter) {
          list.push(new OSjs.VFS.File(iter));
        });
      }
      callback(error, list);
    });
  };
  OSjsStorage.write = function(item, data, callback) {
    callback('Unavailable');
  };
  OSjsStorage.read = function(item, callback) {
    callback('Unavailable. Use download()');
  };
  OSjsStorage.copy = function(src, dest, callback) {
    callback('Unavailable');
  };
  OSjsStorage.move = function(src, dest, callback) {
    callback('Unavailable');
  };
  OSjsStorage.unlink = function(item, callback) {
    callback('Unavailable');
  };
  OSjsStorage.mkdir = function(item, callback) {
    callback('Unavailable');
  };
  OSjsStorage.exists = function(item, callback) {
    callback(false, true);
  };
  OSjsStorage.fileinfo = function(item, callback) {
    callback('Unavailable');
  };
  OSjsStorage.url = function(item, callback) {
    var url = item.path.replace(OSjs.VFS.Modules.OSjs.match, '');
    callback(false, url);
  };

  /////////////////////////////////////////////////////////////////////////////
  // WRAPPERS
  /////////////////////////////////////////////////////////////////////////////

  function makeRequest(name, args, callback) {
    args = args || [];
    callback = callback || {};

    if ( !OSjsStorage[name] ) {
      throw new Error('Invalid OSjsStorage API call name');
    }

    var fargs = args;
    fargs.push(callback);
    OSjsStorage[name].apply(OSjsStorage, fargs);
  }

  /////////////////////////////////////////////////////////////////////////////
  // EXPORTS
  /////////////////////////////////////////////////////////////////////////////

  OSjs.VFS.Modules.OSjs = OSjs.VFS.Modules.OSjs || {
    description: 'OS.js',
    root: 'osjs:///',
    match: /^osjs\:\/\//,
    icon: 'devices/harddrive.png',
    enabled: function() {
      return true;
    },
    request: makeRequest
  };

})(OSjs.Utils, OSjs.API);
<|endoftext|>


<commit_before>var tap = require('../tap');

tap.count(8);

tap.ok("1234567890".substring(3, 6) == "456", 'substring 1')
tap.ok("abc".substring(0, 0) == "", 'substring 2')
tap.ok("ababababab".indexOf('a') == 0, 'indexOf')
tap.ok("ababababab".lastIndexOf('a') == 8, 'lastIndexOf')
tap.ok("a,b,c,d,e".split(',').length == 5, 'split (string)')
console.log("#", "a,b,c,d,e".split(/,/));
tap.ok("a,b,c,d,e".split(/,/).length == 5, 'split (regexp)')
tap.ok("abc".slice(0,0) == "", 'slice 1')
tap.ok("abc".slice(0,1) == "a", 'slice 2')
<commit_msg>a couple important (failing!) string tests<commit_after>var tap = require('../tap');

tap.count(10);

tap.ok("1234567890".substring(3, 6) == "456", 'substring 1')
tap.ok("abc".substring(0, 0) == "", 'substring 2')
tap.ok("ababababab".indexOf('a') == 0, 'indexOf')
tap.ok("ababababab".lastIndexOf('a') == 8, 'lastIndexOf')
tap.ok("a,b,c,d,e".split(',').length == 5, 'split (string)')
console.log("#", "a,b,c,d,e".split(/,/));
tap.ok("a,b,c,d,e".split(/,/).length == 5, 'split (regexp)')
tap.ok("abc".slice(0,0) == "", 'slice 1')
tap.ok("abc".slice(0,1) == "a", 'slice 2')
tap.ok("abc"[0] == "a", 'index 1')
tap.ok("abc"['1'] == "b", 'index 2')
<|endoftext|>


<commit_before>/*! customSelect: a jQuery UI widget to select items and ranges
    http://github.com/rixth/customSelect
*/

/*jshint browser: true, jquery: true, indent: 2, white: true, curly: true, forin: true, noarg: true, immed: true, newcap: true, noempty: true */

(function ($) {
  var openClass = 'ui-customSelect-open',
      disabledClass = 'ui-customRange-disabled',
      eventPrefix = 'customselect';

  $.widget("ui.customSelect", {
    options: {
      placeholder: 'Please select some items'
    },
    _create: function () {
      var self = this,
          select = this.element,
          root, rootHtml = [],
          isOpen = false;

      if (!select.is('select')) {
        throw new TypeError("jquery.customSelect expects a <select> element.");
      }

      self.rootId = select.attr('id') + '_customSelect'

      // Create the base HTML, the window and dropdown
      rootHtml.push('
');
      rootHtml.push('
');
      rootHtml.push('
▼
');
      rootHtml.push('
▲
');
      rootHtml.push('
');
      rootHtml.push('

');
      rootHtml.push('
');

      // Place ourselves
      this.root = root = $(rootHtml.join('')).attr('id', self.rootId);
      select.after(root).hide();

      this.window = root.find('.ui-customSelect-window span');
      this.list = root.find('ul');

      self._createFromSelect();
      self._setWindowText();

      // Bind events
      self.window.parent().click(function (event) {
        self._trigger(isOpen ? 'blur' : 'focus', event);
      });

      root.delegate('li>input', 'change', function (event) {
        self._setWindowText();
        select.val(self.val()).trigger('change');
        self._trigger('change', event);
      });

      select.bind(eventPrefix + 'focus', function () {
        if (!root.hasClass(disabledClass)) {
          isOpen = true;
          root.addClass(openClass);

          // Close when a click is detected on something other than the widget
          $(document).bind('click.customRange' + self.rootId, function (event) {
            if (!$.contains(root[0], event.target)) {
              self._trigger('blur');
            }
          });
        }
      }).bind(eventPrefix + 'blur', function () {
        $(document).unbind('click.customRange' + self.rootId);
        isOpen = false;
        root.removeClass(openClass);
      }).bind(eventPrefix + 'disabled', function () {
        root.addClass(disabledClass);
        if (isOpen) {
          self._trigger('blur');
        }
      }).bind(eventPrefix + 'enabled', function () {
        root.removeClass(disabledClass);
      });
    },
    val: function () {
      var result = this.root.find('input:checked').map(function () {
        return this.value;
      }).toArray();
      return this.isMultiple ? result : result[0];
    },
    friendlyVal: function () {
      return this.root.find('input:checked+label').map(function () {
        return this.innerHTML;
      }).toArray();
    },
    _setWindowText: function () {
      var value = this.friendlyVal();
      this.window.html(value.length ? value.join(', ') : (this.options.placeholder || ''));
    },
    _createFromSelect: function () {
      var self = this,
          idCounter = 0;

      self.isMultiple = self.element.attr('multiple')
      self.list.empty();

      this.element.children().each(function () {
        var element = this,
            id = self.rootId + '_' + (idCounter++),
            label = '' + element.innerHTML + '',
            input;
        if (self.isMultiple) {
          input = $('<input id="' + id + '" type="checkbox" value="' + element.value + '">');
        } else {
          input = $('<input id="' + id + '" name="' + self.rootId + '_radio" type="radio" value="' + element.value + '">');
        }

        if (element.selected) {
          input.attr('checked', true);
        }

        self.list.append($('

').append(input).append(' ').append(label));
      });
    },
    reload: function () {
      this._createFromSelect();
    },
    _setOption: function (name, value) {
      if (name === 'disabled') {
        this._trigger((value ? 'dis' : 'en') + 'abled');
      }
    },
    destroy: function () {
      $.Widget.prototype.destroy.apply(this, arguments);
      $(document).unbind('click.customRange' + this.rootId);
      this.root.remove();
      this.element.show();
    }
  });
}(jQuery));<commit_msg>A fix for fail-y IE's fail change handling<commit_after>/*! customSelect: a jQuery UI widget to select items and ranges
    http://github.com/rixth/customSelect
*/

/*jshint browser: true, jquery: true, indent: 2, white: true, curly: true, forin: true, noarg: true, immed: true, newcap: true, noempty: true */

(function ($) {
  var openClass = 'ui-customSelect-open',
      disabledClass = 'ui-customRange-disabled',
      eventPrefix = 'customselect';

  $.widget("ui.customSelect", {
    options: {
      placeholder: 'Please select some items'
    },
    _create: function () {
      var self = this,
          select = this.element,
          root, rootHtml = [],
          isOpen = false;

      if (!select.is('select')) {
        throw new TypeError("jquery.customSelect expects a <select> element.");
      }

      self.rootId = select.attr('id') + '_customSelect'

      // Create the base HTML, the window and dropdown
      rootHtml.push('
');
      rootHtml.push('
');
      rootHtml.push('
▼
');
      rootHtml.push('
▲
');
      rootHtml.push('
');
      rootHtml.push('

');
      rootHtml.push('
');

      // Place ourselves
      this.root = root = $(rootHtml.join('')).attr('id', self.rootId);
      select.after(root).hide();

      this.window = root.find('.ui-customSelect-window span');
      this.list = root.find('ul');

      self._createFromSelect();
      self._setWindowText();

      // Bind events
      self.window.parent().click(function (event) {
        self._trigger(isOpen ? 'blur' : 'focus', event);
      });

      root.delegate('li>input', 'change', function (event) {
        self._setWindowText();
        select.val(self.val()).trigger('change');
        self._trigger('change', event);
      });

      if ($.browser.msie && $.browser.version < 9) {
        $('input').bind('click', function (event) {
          this.checked = !this.checked;
          $(this).trigger('change');
        });
      }

      select.bind(eventPrefix + 'focus', function () {
        if (!root.hasClass(disabledClass)) {
          isOpen = true;
          root.addClass(openClass);

          // Close when a click is detected on something other than the widget
          $(document).bind('click.customRange' + self.rootId, function (event) {
            if (!$.contains(root[0], event.target)) {
              self._trigger('blur');
            }
          });
        }
      }).bind(eventPrefix + 'blur', function () {
        $(document).unbind('click.customRange' + self.rootId);
        isOpen = false;
        root.removeClass(openClass);
      }).bind(eventPrefix + 'disabled', function () {
        root.addClass(disabledClass);
        if (isOpen) {
          self._trigger('blur');
        }
      }).bind(eventPrefix + 'enabled', function () {
        root.removeClass(disabledClass);
      });
    },
    val: function () {
      var result = this.root.find('input:checked').map(function () {
        return this.value;
      }).toArray();
      return this.isMultiple ? result : result[0];
    },
    friendlyVal: function () {
      return this.root.find('input:checked+label').map(function () {
        return this.innerHTML;
      }).toArray();
    },
    _setWindowText: function () {
      var value = this.friendlyVal();
      this.window.html(value.length ? value.join(', ') : (this.options.placeholder || ''));
    },
    _createFromSelect: function () {
      var self = this,
          idCounter = 0;

      self.isMultiple = self.element.attr('multiple')
      self.list.empty();

      this.element.children().each(function () {
        var element = this,
            id = self.rootId + '_' + (idCounter++),
            label = '' + element.innerHTML + '',
            input;
        if (self.isMultiple) {
          input = $('<input id="' + id + '" type="checkbox" value="' + element.value + '">');
        } else {
          input = $('<input id="' + id + '" name="' + self.rootId + '_radio" type="radio" value="' + element.value + '">');
        }

        if (element.selected) {
          input.attr('checked', true);
        }

        self.list.append($('

').append(input).append(' ').append(label));
      });
    },
    reload: function () {
      this._createFromSelect();
    },
    _setOption: function (name, value) {
      if (name === 'disabled') {
        this._trigger((value ? 'dis' : 'en') + 'abled');
      }
    },
    destroy: function () {
      $.Widget.prototype.destroy.apply(this, arguments);
      $(document).unbind('click.customRange' + this.rootId);
      this.root.remove();
      this.element.show();
    }
  });
}(jQuery));<|endoftext|>


<commit_before>/*
 * This file is part of the BenGorCookies library.
 *
 * (c) Beñat Espiña <benatespina@gmail.com>
 * (c) Gorka Laucirica <gorka.lauzirika@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

'use strict';

class GoogleTagManager {
  constructor(id = false) {
    this.id = id;
    this.element = document.createElement('div');
    this.element.setAttribute('id', 'bengor-cookies-gtm');
  }

  insertHTML() {
    if (this.id === false || this.element.innerHTML) {
      return;
    }

    this.element.innerHTML =
      '' +
      '';

    const body = document.getElementsByTagName('BODY')[0];
    body.insertBefore(this.element, body.firstChild);
  }
}

export default GoogleTagManager;
<commit_msg>Removed duplicate and unused old renderer<commit_after><|endoftext|>


<commit_before>// (C) Copyright 2014-2015 Hewlett-Packard Development Company, L.P.

var React = require('react');
var CloseIcon = require('../../img/icons/close');
var KeyboardAccelerators = require('../mixins/KeyboardAccelerators');
var DOMUtils = require('../utils/DOM');
var Button = require('./Button');

var CLASS_ROOT = "layer";

var LayerOverlay = React.createClass({

  propTypes: {
    align: React.PropTypes.oneOf(['center', 'top', 'bottom', 'left', 'right']),
    closer: React.PropTypes.oneOfType([
      React.PropTypes.node,
      React.PropTypes.bool
    ]),
    flush: React.PropTypes.bool,
    hidden: React.PropTypes.bool,
    peek: React.PropTypes.bool,
    onClose: React.PropTypes.func,
    router: React.PropTypes.func,
    a11yCloserTitle: React.PropTypes.string
  },

  childContextTypes: {
    router: React.PropTypes.func
  },

  mixins: [KeyboardAccelerators],

  getChildContext: function () {
    return {router: this.props.router};
  },

  componentDidMount: function () {

    var items = this.refs.background.getDOMNode().getElementsByTagName('*');
    var firstFocusable = DOMUtils.getBestFirstFocusable(items);
    if (firstFocusable) {
      firstFocusable.focus();
    }

    if (this.props.onClose) {
      this.startListeningToKeyboard({
        tab: this._processTab,
        esc: this.props.onClose
      });
    }
  },

  componentWillUnmount: function() {
    var appElement = document.querySelectorAll('div.app')[0];
    if (appElement) { // unit tests don't have an app
      appElement.classList.remove('app--layered');
      window.scroll(0, this._appScrollY);
    }

    if (this.props.onClose) {
      this.stopListeningToKeyboard({
        tab: this._processTab,
        esc: this.props.onClose
      });
    }
  },

  _processTab: function (event) {
    var items = this.refs.background.getDOMNode().getElementsByTagName('*');

    items = DOMUtils.filterByFocusable(items);

    if (event.shiftKey) {
      if (event.target === items[0]) {
        items[items.length - 1].focus();
        event.preventDefault();
      }
    } else {
      if (event.target === items[items.length - 1]) {
        items[0].focus();
        event.preventDefault();
      }
    }
  },

  render: function () {
    var classes = [CLASS_ROOT];
    if (this.props.align) {
      classes.push(CLASS_ROOT + "--align-" + this.props.align);
    }
    if (this.props.flush) {
      classes.push(CLASS_ROOT + "--flush");
    }
    if (this.props.hidden) {
      classes.push(CLASS_ROOT + "--hidden");
    }
    if (this.props.peek) {
      classes.push(CLASS_ROOT + "--peek");
    }
    if (this.props.className) {
      classes.push(this.props.className);
    }

    var closer = null;
    if (this.props.closer) {
      classes.push(CLASS_ROOT + "--closeable");

      closer = (

          <Button type='icon' onClick={this.props.onClose}>
            <CloseIcon a11yTitle={this.props.a11yCloserTitle} />
          </Button>

      );
    }

    return (

          {closer}
          {this.props.children}

    );
  }
});

var Layer = React.createClass({

  propTypes: {
    align: React.PropTypes.oneOf(['center', 'top', 'bottom', 'left', 'right']),
    closer: React.PropTypes.oneOfType([
      React.PropTypes.node,
      React.PropTypes.bool
    ]),
    flush: React.PropTypes.bool,
    hidden: React.PropTypes.bool,
    peek: React.PropTypes.bool,
    onClose: React.PropTypes.func
  },

  contextTypes: {
    router: React.PropTypes.func
  },

  getDefaultProps: function () {
    return {
      align: 'center'
    };
  },

  componentDidMount: function () {
    this._originalFocusedElement = document.activeElement;
    this._addOverlay();
    this._renderOverlay();
  },

  componentDidUpdate: function () {
    this._renderOverlay();
  },

  componentWillUnmount: function () {

    if (this._originalFocusedElement) {
      this._originalFocusedElement.focus();
    }

    this._removeOverlay();
  },

  _addOverlay: function () {
    var overlay = document.createElement('div');
    if (this.props.id) {
      overlay.id = this.props.id;
    }
    if (overlay.classList) {
      overlay.classList.add('layer__overlay');
    } else {
      // unit test version
      overlay.className = 'layer__overlay';
    }
    this._overlay = document.body.insertBefore(overlay, document.body.firstChild);
    this._overlay = overlay;
  },

  _handleAriaHidden: function (hideOverlay) {
    this._overlay.setAttribute('aria-hidden', hideOverlay);

    Array.prototype.forEach.call(document.body.childNodes, function (currentChild) {
      if (currentChild !== this._overlay &&
        currentChild.nodeType === 1 &&
        currentChild.id !== 'skip-link-layer' &&
        currentChild.tagName.toLowerCase() !== 'script') {
        currentChild.setAttribute('aria-hidden', !hideOverlay);
      }
    }.bind(this));
  },

  _renderOverlay: function () {
    var content = (<LayerOverlay {...this.props} router={this.context.router} />);
    React.render(content, this._overlay);

    if (this.props.hidden) {
      if (this._overlay.classList) {
        this._overlay.classList.add('layer__overlay--hidden');
      } else {
        this._overlay.className = 'layer__overlay layer__overlay--hidden';
      }

      this._handleAriaHidden(true);
    } else {
      if (this._overlay.classList) {
        this._overlay.classList.remove('layer__overlay--hidden');
      } else {
        this._overlay.className = 'layer__overlay';
      }

      this._handleAriaHidden(false);
    }
  },

  _removeOverlay: function () {
    this._handleAriaHidden(true);

    React.unmountComponentAtNode(this._overlay);
    document.body.removeChild(this._overlay);
    this._overlay = null;
  },

  render: function () {
    return ();
  }

});

module.exports = Layer;
<commit_msg>Added clear button back.<commit_after>// (C) Copyright 2014-2015 Hewlett-Packard Development Company, L.P.

var React = require('react');
var CloseIcon = require('./icons/Clear');
var KeyboardAccelerators = require('../mixins/KeyboardAccelerators');
var DOMUtils = require('../utils/DOM');
var Button = require('./Button');

var CLASS_ROOT = "layer";

var LayerOverlay = React.createClass({

  propTypes: {
    align: React.PropTypes.oneOf(['center', 'top', 'bottom', 'left', 'right']),
    closer: React.PropTypes.oneOfType([
      React.PropTypes.node,
      React.PropTypes.bool
    ]),
    flush: React.PropTypes.bool,
    hidden: React.PropTypes.bool,
    peek: React.PropTypes.bool,
    onClose: React.PropTypes.func,
    router: React.PropTypes.func,
    a11yCloserTitle: React.PropTypes.string
  },

  childContextTypes: {
    router: React.PropTypes.func
  },

  mixins: [KeyboardAccelerators],

  getChildContext: function () {
    return {router: this.props.router};
  },

  componentDidMount: function () {

    var items = this.refs.background.getDOMNode().getElementsByTagName('*');
    var firstFocusable = DOMUtils.getBestFirstFocusable(items);
    if (firstFocusable) {
      firstFocusable.focus();
    }

    if (this.props.onClose) {
      this.startListeningToKeyboard({
        tab: this._processTab,
        esc: this.props.onClose
      });
    }
  },

  componentWillUnmount: function() {
    var appElement = document.querySelectorAll('div.app')[0];
    if (appElement) { // unit tests don't have an app
      appElement.classList.remove('app--layered');
      window.scroll(0, this._appScrollY);
    }

    if (this.props.onClose) {
      this.stopListeningToKeyboard({
        tab: this._processTab,
        esc: this.props.onClose
      });
    }
  },

  _processTab: function (event) {
    var items = this.refs.background.getDOMNode().getElementsByTagName('*');

    items = DOMUtils.filterByFocusable(items);

    if (event.shiftKey) {
      if (event.target === items[0]) {
        items[items.length - 1].focus();
        event.preventDefault();
      }
    } else {
      if (event.target === items[items.length - 1]) {
        items[0].focus();
        event.preventDefault();
      }
    }
  },

  render: function () {
    var classes = [CLASS_ROOT];
    if (this.props.align) {
      classes.push(CLASS_ROOT + "--align-" + this.props.align);
    }
    if (this.props.flush) {
      classes.push(CLASS_ROOT + "--flush");
    }
    if (this.props.hidden) {
      classes.push(CLASS_ROOT + "--hidden");
    }
    if (this.props.peek) {
      classes.push(CLASS_ROOT + "--peek");
    }
    if (this.props.className) {
      classes.push(this.props.className);
    }

    var closer = null;
    if (this.props.closer) {
      classes.push(CLASS_ROOT + "--closeable");

      closer = (

          <Button type='icon' onClick={this.props.onClose}>
            <CloseIcon a11yTitle={this.props.a11yCloserTitle} />
          </Button>

      );
    }

    return (

          {closer}
          {this.props.children}

    );
  }
});

var Layer = React.createClass({

  propTypes: {
    align: React.PropTypes.oneOf(['center', 'top', 'bottom', 'left', 'right']),
    closer: React.PropTypes.oneOfType([
      React.PropTypes.node,
      React.PropTypes.bool
    ]),
    flush: React.PropTypes.bool,
    hidden: React.PropTypes.bool,
    peek: React.PropTypes.bool,
    onClose: React.PropTypes.func
  },

  contextTypes: {
    router: React.PropTypes.func
  },

  getDefaultProps: function () {
    return {
      align: 'center'
    };
  },

  componentDidMount: function () {
    this._originalFocusedElement = document.activeElement;
    this._addOverlay();
    this._renderOverlay();
  },

  componentDidUpdate: function () {
    this._renderOverlay();
  },

  componentWillUnmount: function () {

    if (this._originalFocusedElement) {
      this._originalFocusedElement.focus();
    }

    this._removeOverlay();
  },

  _addOverlay: function () {
    var overlay = document.createElement('div');
    if (this.props.id) {
      overlay.id = this.props.id;
    }
    if (overlay.classList) {
      overlay.classList.add('layer__overlay');
    } else {
      // unit test version
      overlay.className = 'layer__overlay';
    }
    this._overlay = document.body.insertBefore(overlay, document.body.firstChild);
    this._overlay = overlay;
  },

  _handleAriaHidden: function (hideOverlay) {
    this._overlay.setAttribute('aria-hidden', hideOverlay);

    Array.prototype.forEach.call(document.body.childNodes, function (currentChild) {
      if (currentChild !== this._overlay &&
        currentChild.nodeType === 1 &&
        currentChild.id !== 'skip-link-layer' &&
        currentChild.tagName.toLowerCase() !== 'script') {
        currentChild.setAttribute('aria-hidden', !hideOverlay);
      }
    }.bind(this));
  },

  _renderOverlay: function () {
    var content = (<LayerOverlay {...this.props} router={this.context.router} />);
    React.render(content, this._overlay);

    if (this.props.hidden) {
      if (this._overlay.classList) {
        this._overlay.classList.add('layer__overlay--hidden');
      } else {
        this._overlay.className = 'layer__overlay layer__overlay--hidden';
      }

      this._handleAriaHidden(true);
    } else {
      if (this._overlay.classList) {
        this._overlay.classList.remove('layer__overlay--hidden');
      } else {
        this._overlay.className = 'layer__overlay';
      }

      this._handleAriaHidden(false);
    }
  },

  _removeOverlay: function () {
    this._handleAriaHidden(true);

    React.unmountComponentAtNode(this._overlay);
    document.body.removeChild(this._overlay);
    this._overlay = null;
  },

  render: function () {
    return ();
  }

});

module.exports = Layer;
<|endoftext|>


<commit_before>var cl=require('../lib/opencl'),
    should=require('chai').should(),
    util=require('util'),
    log=console.log;

describe("Sampler", function() {
  describe("#createSampler", function() {

  });
  describe("#retainSampler", function() {

  });
  describe("#releaseSampler", function() {

  });
  describe("#getSamplerInfo", function() {

  });
})
<commit_msg>[Tests] Sampler tests<commit_after>var cl = require('../lib/opencl'),
  should = require('chai').should(),
  util = require('util'),
  withContext = require("../lib/test_utils").withContext,
  assert = require("chai").assert,
  chai = require("chai"),
  log = console.log;

describe("Sampler", function () {
  describe("#createSampler", function () {

    var f = cl.createSampler;

    it("should create a sampler when passed valid arguments", function () {
      withContext(function (context) {
        var sampler = f(context, cl.TRUE, cl.ADDRESS_NONE, cl.FILTER_LINEAR);
        assert.isObject(sampler);
        assert.isNotNull(sampler);
        cl.releaseSampler(sampler);
      });
    });

    it("should throw cl.INVALID_CONTEXT when passed an invalid context", function () {
      f.bind(f, null, cl.TRUE, cl.ADDRESS_NONE, cl.FILTER_LINEAR).should.throw(cl.INVALID_CONTEXT.message);
    });

  });

  describe("#retainSampler", function () {

    var f = cl.retainSampler;

    it("should increase the reference count when passed a valid argument", function () {
      withContext(function (context) {
        var sampler = cl.createSampler(context, cl.TRUE, cl.ADDRESS_NONE, cl.FILTER_LINEAR);
        var count = cl.getSamplerInfo(sampler, cl.SAMPLER_REFERENCE_COUNT);
        assert.isNumber(count);
        assert.strictEqual(count, 1);

        f(sampler);

        count = cl.getSamplerInfo(sampler, cl.SAMPLER_REFERENCE_COUNT);
        assert.isNumber(count);
        assert.strictEqual(count, 2);

        cl.releaseSampler(sampler);
        cl.releaseSampler(sampler);
      })
    });
  });

  describe("#releaseSampler", function () {

    var f = cl.releaseSampler;

    it("should decrease reference count when passed a valid argument", function () {
      withContext(function (context) {
        var sampler = cl.createSampler(context, cl.TRUE, cl.ADDRESS_NONE, cl.FILTER_LINEAR);
        var count = cl.getSamplerInfo(sampler, cl.SAMPLER_REFERENCE_COUNT);
        assert.isNumber(count);
        assert.strictEqual(count, 1);
        f(sampler);
      });
    });
  });

  describe("#getSamplerInfo", function () {

    var f = cl.getSamplerInfo;

    it("should return CL_SAMPLER_REFERENCE_COUNT", function() {
      withContext(function(context) {
        var sampler = cl.createSampler(context, cl.TRUE, cl.ADDRESS_NONE, cl.FILTER_LINEAR);
        var ret = f(sampler, cl.SAMPLER_REFERENCE_COUNT);

        assert.isNumber(ret);
        assert.strictEqual(1, ret);

        cl.releaseSampler(sampler);
      })
    });

    it("should return CL_SAMPLER_NORMALIZED_COORDS", function() {
      withContext(function(context) {
        var sampler = cl.createSampler(context, cl.TRUE, cl.ADDRESS_NONE, cl.FILTER_LINEAR);
        var ret = f(sampler, cl.SAMPLER_NORMALIZED_COORDS);

        assert.isBoolean(ret);
        assert.isTrue(ret);

        cl.releaseSampler(sampler);
      })
    });

    it("should return CL_SAMPLER_ADDRESSING_MODE", function() {
      withContext(function(context) {
        var sampler = cl.createSampler(context, cl.TRUE, cl.ADDRESS_NONE, cl.FILTER_LINEAR);
        var ret = f(sampler, cl.SAMPLER_ADDRESSING_MODE);

        assert.isNumber(ret);
        assert.strictEqual(ret, cl.ADDRESS_NONE);

        cl.releaseSampler(sampler);
      })
    });

    it("should return CL_SAMPLER_FILTER_MODE", function() {
      withContext(function(context) {
        var sampler = cl.createSampler(context, cl.TRUE, cl.ADDRESS_NONE, cl.FILTER_LINEAR);
        var ret = f(sampler, cl.SAMPLER_FILTER_MODE);

        assert.isNumber(ret);
        assert.strictEqual(ret, cl.FILTER_LINEAR);

        cl.releaseSampler(sampler);
      })
    });

  });
});
<|endoftext|>