<commit_before>(function (root, factory) {
    'use strict';
    // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, Rhino, and browsers.

    /* istanbul ignore next */
    if (typeof define === 'function' && define.amd) {
        define('stacktrace-gps', ['source-map', 'stackframe'], factory);
    } else if (typeof exports === 'object') {
        module.exports = factory(require('source-map/lib/source-map/source-map-consumer'), require('stackframe'));
    } else {
        root.StackTraceGPS = factory(root.SourceMap, root.StackFrame);
    }
}(this, function (SourceMap, StackFrame) {
    'use strict';

    /**
     * Make a X-Domain request to url and callback.
     *
     * @param url [String]
     * @param callback [Function] to callback on completion
     * @param errback [Function] to callback on error
     */
    function _xdr(url, callback, errback) {
        var req = new XMLHttpRequest();
        req.open('get', url);
        req.onerror = errback;
        req.onreadystatechange = function onreadystatechange() {
            if (req.readyState === 4) {
                if (req.status >= 200 && req.status < 400) {
                    return callback(req.responseText);
                } else {
                    errback(new Error('Unable to retrieve ' + url));
                }
            }
        };
        req.send();
    }

    function _findFunctionName(source, lineNumber, columnNumber) {
        // function {name}({args}) m[1]=name m[2]=args
        var reFunctionDeclaration = /function\s+([^(]*?)\s*\(([^)]*)\)/;
        // {name} = function ({args}) TODO args capture
        var reFunctionExpression = /['"]?([$_A-Za-z][$_A-Za-z0-9]*)['"]?\s*[:=]\s*function\b/;
        // {name} = eval()
        var reFunctionEvaluation = /['"]?([$_A-Za-z][$_A-Za-z0-9]*)['"]?\s*[:=]\s*(?:eval|new Function)\b/;
        var lines = source.split('\n');

        // Walk backwards in the source lines until we find the line which matches one of the patterns above
        var code = '', line, maxLines = Math.min(lineNumber, 20), m, commentPos;
        for (var i = 0; i < maxLines; ++i) {
            // lineNo is 1-based, source[] is 0-based
            line = lines[lineNumber - i - 1];
            commentPos = line.indexOf('//');
            if (commentPos >= 0) {
                line = line.substr(0, commentPos);
            }

            if (line) {
                code = line + code;
                m = reFunctionExpression.exec(code);
                if (m && m[1]) {
                    return m[1];
                }
                m = reFunctionDeclaration.exec(code);
                if (m && m[1]) {
                    return m[1];
                }
                m = reFunctionEvaluation.exec(code);
                if (m && m[1]) {
                    return m[1];
                }
            }
        }
        return undefined;
    }

    function _ensureSupportedEnvironment() {
        if (typeof Object.defineProperty !== 'function' || typeof Object.create !== 'function') {
            throw new Error('Unable to consume source maps in older browsers');
        }
    }

    function _ensureStackFrameIsLegit(stackframe) {
        if (typeof stackframe !== 'object') {
            throw new TypeError('Given StackFrame is not an object');
        } else if (typeof stackframe.fileName !== 'string') {
            throw new TypeError('Given file name is not a String');
        } else if (typeof stackframe.lineNumber !== 'number' || stackframe.lineNumber % 1 !== 0 || stackframe.lineNumber < 1) {
            throw new TypeError('Given line number must be a positive integer');
        } else if (typeof stackframe.columnNumber !== 'number' || stackframe.columnNumber % 1 !== 0 || stackframe.columnNumber < 0) {
            throw new TypeError('Given column number must be a non-negative integer');
        }
        return true;
    }

    function _findSourceMappingURL(source) {
        var m = /\/\/[#@] ?sourceMappingURL=([^\s'"]+)$/.exec(source);
        if (m && m[1]) {
            return m[1];
        } else {
            throw new Error('sourceMappingURL not found');
        }
    }

    function _newLocationInfoFromSourceMap(rawSourceMap, args, lineNumber, columnNumber) {
        var loc = new SourceMap.SourceMapConsumer(rawSourceMap)
            .originalPositionFor({line: lineNumber, column: columnNumber});
        return new StackFrame(loc.name, args, loc.source, loc.line, loc.column);
    }

    /**
     * @param opts: [Object] options.
     *      opts.sourceCache = {url: "Source String"} => preload source cache
     *      opts.offline = True to prevent network requests.
     *              Best effort without sources or source maps.
     */
    return function StackTraceGPS(opts) {
        if (!(this instanceof StackTraceGPS)) {
            return new StackTraceGPS(opts);
        }
        opts = opts || {};

        this.sourceCache = opts.sourceCache || {};

        this.ajax = _xdr;

        this._atob = function (input) {
            if (window && window.atob) {
                return window.atob(input);
            } else if (typeof Buffer !== 'undefined') {
                return new Buffer(input, 'base64').toString('utf-8');
            }
            throw new Error('No base64 decoder available');
        };

        this._get = function _get(location) {
            return new Promise(function (resolve, reject) {
                var isDataUrl = location.substr(0, 5) === 'data:';
                if (this.sourceCache[location]) {
                    resolve(this.sourceCache[location]);
                } else if (opts.offline && !isDataUrl) {
                    reject(new Error('Cannot make network requests in offline mode'));
                } else {
                    if (isDataUrl) {
                        var supportedEncoding = 'application/json;base64';
                        if (location.substr(5, supportedEncoding.length) !== supportedEncoding) {
                            reject(new Error('The encoding of the inline sourcemap is not supported'));
                        } else {
                            var sourceMapStart = 'data:'.length + supportedEncoding.length + ','.length;
                            var encodedSource = location.substr(sourceMapStart);
                            var source = this._atob(encodedSource);
                            this.sourceCache[location] = source;
                            resolve(source);
                        }
                    } else {
                        this.ajax(location, function (source) {
                            this.sourceCache[location] = source;
                            resolve(source);
                        }.bind(this), reject);
                    }
                }
            }.bind(this));
        };

        /**
         * Given a StackFrame, enhance function name and use source maps for a
         * better StackFrame.
         *
         * @param stackframe - {StackFrame}-like object
         *      {fileName: 'path/to/file.js', lineNumber: 100, columnNumber: 5}
         * @return StackFrame with source-mapped location
         */
        this.pinpoint = function StackTraceGPS$$pinpoint(stackframe) {
            return new Promise(function (resolve, reject) {
                this.getMappedLocation(stackframe).then(function (mappedStackFrame) {
                    function resolveMappedStackFrame() {
                        resolve(mappedStackFrame);
                    }

                    this.findFunctionName(mappedStackFrame)
                        .then(resolve, resolveMappedStackFrame)
                        ['catch'](resolveMappedStackFrame);
                }.bind(this), reject);
            }.bind(this));
        };

        /**
         * Given a StackFrame, guess function name from location information.
         *
         * @param stackframe - {StackFrame}-like object
         *      {fileName: 'path/to/file.js', lineNumber: 100, columnNumber: 5}
         * @return StackFrame with guessed function name
         */
        this.findFunctionName = function StackTraceGPS$$findFunctionName(stackframe) {
            return new Promise(function (resolve, reject) {
                _ensureStackFrameIsLegit(stackframe);
                this._get(stackframe.fileName).then(function getSourceCallback(source) {
                    var guessedFunctionName = _findFunctionName(source, stackframe.lineNumber, stackframe.columnNumber);
                    resolve(new StackFrame(guessedFunctionName, stackframe.args, stackframe.fileName, stackframe.lineNumber, stackframe.columnNumber));
                }, reject);
            }.bind(this));
        };

        /**
         * Given a StackFrame, seek source-mapped location and return new enhanced StackFrame.
         *
         * @param stackframe - {StackFrame}-like object
         *      {fileName: 'path/to/file.js', lineNumber: 100, columnNumber: 5}
         * @return StackFrame with source-mapped location
         */
        this.getMappedLocation = function StackTraceGPS$$getMappedLocation(stackframe) {
            return new Promise(function (resolve, reject) {
                _ensureSupportedEnvironment();
                _ensureStackFrameIsLegit(stackframe);

                var fileName = stackframe.fileName;
                this._get(fileName).then(function (source) {
                    var sourceMappingURL = _findSourceMappingURL(source);
                    var isDataUrl = sourceMappingURL.substr(0, 5) === 'data:'

                    if (sourceMappingURL[0] !== '/' && !isDataUrl) {
                        sourceMappingURL = fileName.substring(0, fileName.lastIndexOf('/') + 1) + sourceMappingURL;
                    }
                    this._get(sourceMappingURL).then(function (map) {
                        var lineNumber = stackframe.lineNumber;
                        var columnNumber = stackframe.columnNumber;
                        resolve(_newLocationInfoFromSourceMap(map, stackframe.args, lineNumber, columnNumber));
                    }, reject)['catch'](reject);
                }.bind(this), reject)['catch'](reject);
            }.bind(this));
        };
    };
}));
<commit_msg>Extract sourceContent from source map and inject into cache<commit_after>(function (root, factory) {
    'use strict';
    // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, Rhino, and browsers.

    /* istanbul ignore next */
    if (typeof define === 'function' && define.amd) {
        define('stacktrace-gps', ['source-map', 'stackframe'], factory);
    } else if (typeof exports === 'object') {
        module.exports = factory(require('source-map/lib/source-map/source-map-consumer'), require('stackframe'));
    } else {
        root.StackTraceGPS = factory(root.SourceMap, root.StackFrame);
    }
}(this, function (SourceMap, StackFrame) {
    'use strict';

    /**
     * Make a X-Domain request to url and callback.
     *
     * @param url [String]
     * @param callback [Function] to callback on completion
     * @param errback [Function] to callback on error
     */
    function _xdr(url, callback, errback) {
        var req = new XMLHttpRequest();
        req.open('get', url);
        req.onerror = errback;
        req.onreadystatechange = function onreadystatechange() {
            if (req.readyState === 4) {
                if (req.status >= 200 && req.status < 400) {
                    return callback(req.responseText);
                } else {
                    errback(new Error('Unable to retrieve ' + url));
                }
            }
        };
        req.send();
    }

    function _findFunctionName(source, lineNumber, columnNumber) {
        // function {name}({args}) m[1]=name m[2]=args
        var reFunctionDeclaration = /function\s+([^(]*?)\s*\(([^)]*)\)/;
        // {name} = function ({args}) TODO args capture
        var reFunctionExpression = /['"]?([$_A-Za-z][$_A-Za-z0-9]*)['"]?\s*[:=]\s*function\b/;
        // {name} = eval()
        var reFunctionEvaluation = /['"]?([$_A-Za-z][$_A-Za-z0-9]*)['"]?\s*[:=]\s*(?:eval|new Function)\b/;
        var lines = source.split('\n');

        // Walk backwards in the source lines until we find the line which matches one of the patterns above
        var code = '', line, maxLines = Math.min(lineNumber, 20), m, commentPos;
        for (var i = 0; i < maxLines; ++i) {
            // lineNo is 1-based, source[] is 0-based
            line = lines[lineNumber - i - 1];
            commentPos = line.indexOf('//');
            if (commentPos >= 0) {
                line = line.substr(0, commentPos);
            }

            if (line) {
                code = line + code;
                m = reFunctionExpression.exec(code);
                if (m && m[1]) {
                    return m[1];
                }
                m = reFunctionDeclaration.exec(code);
                if (m && m[1]) {
                    return m[1];
                }
                m = reFunctionEvaluation.exec(code);
                if (m && m[1]) {
                    return m[1];
                }
            }
        }
        return undefined;
    }

    function _ensureSupportedEnvironment() {
        if (typeof Object.defineProperty !== 'function' || typeof Object.create !== 'function') {
            throw new Error('Unable to consume source maps in older browsers');
        }
    }

    function _ensureStackFrameIsLegit(stackframe) {
        if (typeof stackframe !== 'object') {
            throw new TypeError('Given StackFrame is not an object');
        } else if (typeof stackframe.fileName !== 'string') {
            throw new TypeError('Given file name is not a String');
        } else if (typeof stackframe.lineNumber !== 'number' || stackframe.lineNumber % 1 !== 0 || stackframe.lineNumber < 1) {
            throw new TypeError('Given line number must be a positive integer');
        } else if (typeof stackframe.columnNumber !== 'number' || stackframe.columnNumber % 1 !== 0 || stackframe.columnNumber < 0) {
            throw new TypeError('Given column number must be a non-negative integer');
        }
        return true;
    }

    function _findSourceMappingURL(source) {
        var m = /\/\/[#@] ?sourceMappingURL=([^\s'"]+)$/.exec(source);
        if (m && m[1]) {
            return m[1];
        } else {
            throw new Error('sourceMappingURL not found');
        }
    }

    function _extractLocationInfoFromSourceMap(rawSourceMap, args, lineNumber, columnNumber, sourceCache) {
        var mapConsumer = new SourceMap.SourceMapConsumer(rawSourceMap)

        var loc = mapConsumer.originalPositionFor({
          line: lineNumber,
          column: columnNumber
        })

        var mappedSource = mapConsumer.sourceContentFor(loc.source)
        if (mappedSource) {
          sourceCache[loc.source] = mappedSource
        }

        return new StackFrame(loc.name, args, loc.source, loc.line, loc.column)
    }

    /**
     * @param opts: [Object] options.
     *      opts.sourceCache = {url: "Source String"} => preload source cache
     *      opts.offline = True to prevent network requests.
     *              Best effort without sources or source maps.
     */
    return function StackTraceGPS(opts) {
        if (!(this instanceof StackTraceGPS)) {
            return new StackTraceGPS(opts);
        }
        opts = opts || {};

        this.sourceCache = opts.sourceCache || {};

        this.ajax = _xdr;

        this._atob = function (input) {
            if (window && window.atob) {
                return window.atob(input);
            } else if (typeof Buffer !== 'undefined') {
                return new Buffer(input, 'base64').toString('utf-8');
            }
            throw new Error('No base64 decoder available');
        };

        this._get = function _get(location) {
            return new Promise(function (resolve, reject) {
                var isDataUrl = location.substr(0, 5) === 'data:';
                if (this.sourceCache[location]) {
                    resolve(this.sourceCache[location]);
                } else if (opts.offline && !isDataUrl) {
                    reject(new Error('Cannot make network requests in offline mode'));
                } else {
                    if (isDataUrl) {
                        var supportedEncoding = 'application/json;base64';
                        if (location.substr(5, supportedEncoding.length) !== supportedEncoding) {
                            reject(new Error('The encoding of the inline sourcemap is not supported'));
                        } else {
                            var sourceMapStart = 'data:'.length + supportedEncoding.length + ','.length;
                            var encodedSource = location.substr(sourceMapStart);
                            var source = this._atob(encodedSource);
                            this.sourceCache[location] = source;
                            resolve(source);
                        }
                    } else {
                        this.ajax(location, function (source) {
                            this.sourceCache[location] = source;
                            resolve(source);
                        }.bind(this), reject);
                    }
                }
            }.bind(this));
        };

        /**
         * Given a StackFrame, enhance function name and use source maps for a
         * better StackFrame.
         *
         * @param stackframe - {StackFrame}-like object
         *      {fileName: 'path/to/file.js', lineNumber: 100, columnNumber: 5}
         * @return StackFrame with source-mapped location
         */
        this.pinpoint = function StackTraceGPS$$pinpoint(stackframe) {
            return new Promise(function (resolve, reject) {
                this.getMappedLocation(stackframe).then(function (mappedStackFrame) {
                    function resolveMappedStackFrame() {
                        resolve(mappedStackFrame);
                    }

                    this.findFunctionName(mappedStackFrame)
                        .then(resolve, resolveMappedStackFrame)
                        ['catch'](resolveMappedStackFrame);
                }.bind(this), reject);
            }.bind(this));
        };

        /**
         * Given a StackFrame, guess function name from location information.
         *
         * @param stackframe - {StackFrame}-like object
         *      {fileName: 'path/to/file.js', lineNumber: 100, columnNumber: 5}
         * @return StackFrame with guessed function name
         */
        this.findFunctionName = function StackTraceGPS$$findFunctionName(stackframe) {
            return new Promise(function (resolve, reject) {
                _ensureStackFrameIsLegit(stackframe);
                this._get(stackframe.fileName).then(function getSourceCallback(source) {
                    var guessedFunctionName = _findFunctionName(source, stackframe.lineNumber, stackframe.columnNumber);
                    resolve(new StackFrame(guessedFunctionName, stackframe.args, stackframe.fileName, stackframe.lineNumber, stackframe.columnNumber));
                }, reject);
            }.bind(this));
        };

        /**
         * Given a StackFrame, seek source-mapped location and return new enhanced StackFrame.
         *
         * @param stackframe - {StackFrame}-like object
         *      {fileName: 'path/to/file.js', lineNumber: 100, columnNumber: 5}
         * @return StackFrame with source-mapped location
         */
        this.getMappedLocation = function StackTraceGPS$$getMappedLocation(stackframe) {
            return new Promise(function (resolve, reject) {
                _ensureSupportedEnvironment();
                _ensureStackFrameIsLegit(stackframe);

                var sourceCache = this.sourceCache
                var fileName = stackframe.fileName;
                this._get(fileName).then(function (source) {
                    var sourceMappingURL = _findSourceMappingURL(source);
                    var isDataUrl = sourceMappingURL.substr(0, 5) === 'data:'

                    if (sourceMappingURL[0] !== '/' && !isDataUrl) {
                        sourceMappingURL = fileName.substring(0, fileName.lastIndexOf('/') + 1) + sourceMappingURL;
                    }

                    this._get(sourceMappingURL).then(function (map) {
                        var lineNumber = stackframe.lineNumber;
                        var columnNumber = stackframe.columnNumber;
                        resolve(_extractLocationInfoFromSourceMap(map, stackframe.args, lineNumber, columnNumber, sourceCache));
                    }, reject)['catch'](reject);
                }.bind(this), reject)['catch'](reject);
            }.bind(this));
        };
    };
}));
<|endoftext|>


<commit_before>var fs     = require('fs'),
    fsPath = require('path'),
    http   = require('http'),

    dust = require('dust'),

    baseContext = dust.makeBase({});

var mix = function(s, d) {
    for (var i in s) {
        d[i] = s[i]
    }
    return d;
}

module.exports = {
    makeBase: function(obj) {
        baseContext = dust.makeBase(mix(baseContext.global, obj));
        return baseContext;
    }
}

// Loads the named template the first time it's used (it will be cached for
// later calls).
function getView(name, callback) {
    name = name.replace(/\.dust$/, '') + '.dust';
    fs.readFile(fsPath.join(process.cwd(), 'views', name), 'utf8', callback);
}

dust.onLoad = getView;

// This needs a setter TODO
// Disable whitespace compression.
dust.optimizers.format = function (context, node) {
    return node;
};

// Duckpunch Express's res.render() method to use Dust. This is necessary
// because Express doesn't support async template engines by default.
http.ServerResponse.prototype.render = function (view, options, callback) {
    var res = this;

    // Support callback as second arg.
    if (typeof options === 'function') {
        callback = options;
        options  = {};
    }

    callback || (callback = function (err, html) {
        if (err) { res.req.next(err); return; }
        res.send(html);
    });

    options = options ? baseContext.push(options) : baseContext;

    if (res.locals) {
        options = options.push(res.locals);
    }

    // TODO: Figure out a good way to catch parser errors. Currently Dust's
    // parser just throws them instead of passing them to the callback.
    // See https://github.com/akdubya/dustjs/issues#issue/12
    if (res.app.settings.env === 'development') {
        dust.cache = {}; // Reflect template changes without a restart.

        getView(view, function (err, content) {
            if (err) { res.req.next(err); return; }
            dust.renderSource(content, options, callback);
        });
    } else {
        dust.render(view, options, callback);
    }
};

http.ServerResponse.prototype.partial = function (view, options, callback) {
    var res = this,
        req = this.req,
        header = '',
        ct = req.headers['content-type'],
        setHeader = false;

    // Support callback as second arg.
    if (typeof options === 'function') {
        callback = options;
        options  = {};
    }
    if (!callback) {
        setHeader = true;
    }

    var part = fsPath.join(process.cwd(), 'views', 'partials', view + '.dust');

    callback || (callback = function (err, html) {
        if (err) { res.req.next(err); return; }
        res.send(html);
    });
    fsPath.exists(part, function(x) {
        if (x) {
            res.render('partials/' + view, function(err, html) {
                if (err) {
                    callback(err);
                    return;
                }
                var data = html;
                if (setHeader) {
                    if (ct && ct.indexOf(';') > 0) {
                        ct = ct.split(';')[0];
                    }
                    switch (ct) {
                        case 'application/json':
                        case 'text/javascript':
                            header = '.json';
                            data = { html: html };
                            break;
                        case 'text/plain':
                            header = '.txt';
                            break;
                        default:
                            header = '.html';
                            break;
                    }
                    res.contentType(header);
                }
                callback(null, data);
            });

        } else {
            callback({ error: 'Not Found' });
        }
    });

}
<commit_msg>added filters as an export, so they can be extended<commit_after>var fs     = require('fs'),
    fsPath = require('path'),
    http   = require('http'),

    dust = require('dust'),

    baseContext = dust.makeBase({});

var mix = function(s, d) {
    for (var i in s) {
        d[i] = s[i]
    }
    return d;
}

module.exports = {
    filters : dust.filters
  , makeBase: function(obj) {
        baseContext = dust.makeBase(mix(baseContext.global, obj));
        return baseContext;
    }
}

// Loads the named template the first time it's used (it will be cached for
// later calls).
function getView(name, callback) {
    name = name.replace(/\.dust$/, '') + '.dust';
    fs.readFile(fsPath.join(process.cwd(), 'views', name), 'utf8', callback);
}

dust.onLoad = getView;

// This needs a setter TODO
// Disable whitespace compression.
dust.optimizers.format = function (context, node) {
    return node;
};

// Duckpunch Express's res.render() method to use Dust. This is necessary
// because Express doesn't support async template engines by default.
http.ServerResponse.prototype.render = function (view, options, callback) {
    var res = this;

    // Support callback as second arg.
    if (typeof options === 'function') {
        callback = options;
        options  = {};
    }

    callback || (callback = function (err, html) {
        if (err) { res.req.next(err); return; }
        res.send(html);
    });

    options = options ? baseContext.push(options) : baseContext;

    if (res.locals) {
        options = options.push(res.locals);
    }

    // TODO: Figure out a good way to catch parser errors. Currently Dust's
    // parser just throws them instead of passing them to the callback.
    // See https://github.com/akdubya/dustjs/issues#issue/12
    if (res.app.settings.env === 'development') {
        dust.cache = {}; // Reflect template changes without a restart.

        getView(view, function (err, content) {
            if (err) { res.req.next(err); return; }
            dust.renderSource(content, options, callback);
        });
    } else {
        dust.render(view, options, callback);
    }
};

http.ServerResponse.prototype.partial = function (view, options, callback) {
    var res = this,
        req = this.req,
        header = '',
        ct = req.headers['content-type'],
        setHeader = false;

    // Support callback as second arg.
    if (typeof options === 'function') {
        callback = options;
        options  = {};
    }
    if (!callback) {
        setHeader = true;
    }

    var part = fsPath.join(process.cwd(), 'views', 'partials', view + '.dust');

    callback || (callback = function (err, html) {
        if (err) { res.req.next(err); return; }
        res.send(html);
    });
    fsPath.exists(part, function(x) {
        if (x) {
            res.render('partials/' + view, function(err, html) {
                if (err) {
                    callback(err);
                    return;
                }
                var data = html;
                if (setHeader) {
                    if (ct && ct.indexOf(';') > 0) {
                        ct = ct.split(';')[0];
                    }
                    switch (ct) {
                        case 'application/json':
                        case 'text/javascript':
                            header = '.json';
                            data = { html: html };
                            break;
                        case 'text/plain':
                            header = '.txt';
                            break;
                        default:
                            header = '.html';
                            break;
                    }
                    res.contentType(header);
                }
                callback(null, data);
            });

        } else {
            callback({ error: 'Not Found' });
        }
    });

}
<|endoftext|>


<commit_before>const { EventEmitter } = require('events')
const { PassThrough } = require('readable-stream')
const eos = require('end-of-stream')
const path = require('path')
const render = require('render-media')
const streamToBlob = require('stream-to-blob')
const streamToBlobURL = require('stream-to-blob-url')
const streamToBuffer = require('stream-with-known-length-to-buffer')
const FileStream = require('./file-stream')
const queueMicrotask = require('queue-microtask')

class File extends EventEmitter {
  constructor (torrent, file) {
    super()

    this._torrent = torrent
    this._destroyed = false

    this.name = file.name
    this.path = file.path
    this.length = file.length
    this.offset = file.offset

    this.done = false

    const start = file.offset
    const end = start + file.length - 1

    this._startPiece = start / this._torrent.pieceLength | 0
    this._endPiece = end / this._torrent.pieceLength | 0

    if (this.length === 0) {
      this.done = true
      this.emit('done')
    }
  }

  get downloaded () {
    if (!this._torrent.bitfield) return 0

    const { pieces, bitfield, pieceLength } = this._torrent
    const { _startPiece: start, _endPiece: end } = this
    const piece = pieces[start]

    // First piece may have an offset, e.g. irrelevant bytes from the end of
    // the previous file
    const irrelevantFirstPieceBytes = this.offset % pieceLength
    let downloaded = bitfield.get(start)
      ? pieceLength - irrelevantFirstPieceBytes
      : Math.max(pieceLength - irrelevantFirstPieceBytes - piece.missing, 0)

    for (let index = start + 1; index <= end; ++index) {
      if (bitfield.get(index)) {
        // verified data
        downloaded += pieceLength
      } else {
        // "in progress" data
        const piece = pieces[index]
        downloaded += pieceLength - piece.missing
      }
    }

    const irrelevantLastPieceBytes = pieceLength - ((this.offset + this.length) % pieceLength)
    downloaded -= irrelevantLastPieceBytes

    return downloaded
  }

  get progress () {
    return this.length ? this.downloaded / this.length : 0
  }

  select (priority) {
    if (this.length === 0) return
    this._torrent.select(this._startPiece, this._endPiece, priority)
  }

  deselect () {
    if (this.length === 0) return
    this._torrent.deselect(this._startPiece, this._endPiece, false)
  }

  createReadStream (opts) {
    if (this.length === 0) {
      const empty = new PassThrough()
      queueMicrotask(() => {
        empty.end()
      })
      return empty
    }

    const fileStream = new FileStream(this, opts)
    this._torrent.select(fileStream._startPiece, fileStream._endPiece, true, () => {
      fileStream._notify()
    })
    eos(fileStream, () => {
      if (this._destroyed) return
      if (!this._torrent.destroyed) {
        this._torrent.deselect(fileStream._startPiece, fileStream._endPiece, true)
      }
    })
    return fileStream
  }

  getBuffer (cb) {
    streamToBuffer(this.createReadStream(), this.length, cb)
  }

  getBlob (cb) {
    if (typeof window === 'undefined') throw new Error('browser-only method')
    streamToBlob(this.createReadStream(), this._getMimeType())
      .then(
        blob => cb(null, blob),
        err => cb(err)
      )
  }

  getBlobURL (cb) {
    if (typeof window === 'undefined') throw new Error('browser-only method')
    streamToBlobURL(this.createReadStream(), this._getMimeType())
      .then(
        blobUrl => cb(null, blobUrl),
        err => cb(err)
      )
  }

  appendTo (elem, opts, cb) {
    if (typeof window === 'undefined') throw new Error('browser-only method')
    render.append(this, elem, opts, cb)
  }

  renderTo (elem, opts, cb) {
    if (typeof window === 'undefined') throw new Error('browser-only method')
    render.render(this, elem, opts, cb)
  }

  _getMimeType () {
    return render.mime[path.extname(this.name).toLowerCase()]
  }

  _destroy () {
    this._destroyed = true
    this._torrent = null
  }
}

module.exports = File
<commit_msg>Fix file progress sometimes < 0 and > 1<commit_after>const { EventEmitter } = require('events')
const { PassThrough } = require('readable-stream')
const eos = require('end-of-stream')
const path = require('path')
const render = require('render-media')
const streamToBlob = require('stream-to-blob')
const streamToBlobURL = require('stream-to-blob-url')
const streamToBuffer = require('stream-with-known-length-to-buffer')
const FileStream = require('./file-stream')
const queueMicrotask = require('queue-microtask')

class File extends EventEmitter {
  constructor (torrent, file) {
    super()

    this._torrent = torrent
    this._destroyed = false

    this.name = file.name
    this.path = file.path
    this.length = file.length
    this.offset = file.offset

    this.done = false

    const start = file.offset
    const end = start + file.length - 1

    this._startPiece = start / this._torrent.pieceLength | 0
    this._endPiece = end / this._torrent.pieceLength | 0

    if (this.length === 0) {
      this.done = true
      this.emit('done')
    }
  }

  get downloaded () {
    if (!this._torrent.bitfield) return 0

    const { pieces, bitfield, pieceLength, lastPieceLength } = this._torrent
    const { _startPiece: start, _endPiece: end } = this

    const getPieceLength = (pieceIndex) => (
      pieceIndex === pieces.length - 1 ? lastPieceLength : pieceLength
    )

    const getPieceDownloaded = (pieceIndex) => {
      const len = pieceIndex === pieces.length - 1 ? lastPieceLength : pieceLength
      if (bitfield.get(pieceIndex)) {
        // verified data
        return len
      } else {
        // "in progress" data
        return len - pieces[pieceIndex].missing
      }
    }

    let downloaded = 0
    for (let index = start; index <= end; index += 1) {
      const pieceDownloaded = getPieceDownloaded(index)
      downloaded += pieceDownloaded

      if (index === start) {
        // First piece may have an offset, e.g. irrelevant bytes from the end of
        // the previous file
        const irrelevantFirstPieceBytes = this.offset % pieceLength
        downloaded -= Math.min(irrelevantFirstPieceBytes, pieceDownloaded)
      }

      if (index === end) {
        // Last piece may have an offset, e.g. irrelevant bytes from the start
        // of the next file
        const irrelevantLastPieceBytes = getPieceLength(end) - (this.offset + this.length) % pieceLength
        downloaded -= Math.min(irrelevantLastPieceBytes, pieceDownloaded)
      }
    }

    return downloaded
  }

  get progress () {
    return this.length ? this.downloaded / this.length : 0
  }

  select (priority) {
    if (this.length === 0) return
    this._torrent.select(this._startPiece, this._endPiece, priority)
  }

  deselect () {
    if (this.length === 0) return
    this._torrent.deselect(this._startPiece, this._endPiece, false)
  }

  createReadStream (opts) {
    if (this.length === 0) {
      const empty = new PassThrough()
      queueMicrotask(() => {
        empty.end()
      })
      return empty
    }

    const fileStream = new FileStream(this, opts)
    this._torrent.select(fileStream._startPiece, fileStream._endPiece, true, () => {
      fileStream._notify()
    })
    eos(fileStream, () => {
      if (this._destroyed) return
      if (!this._torrent.destroyed) {
        this._torrent.deselect(fileStream._startPiece, fileStream._endPiece, true)
      }
    })
    return fileStream
  }

  getBuffer (cb) {
    streamToBuffer(this.createReadStream(), this.length, cb)
  }

  getBlob (cb) {
    if (typeof window === 'undefined') throw new Error('browser-only method')
    streamToBlob(this.createReadStream(), this._getMimeType())
      .then(
        blob => cb(null, blob),
        err => cb(err)
      )
  }

  getBlobURL (cb) {
    if (typeof window === 'undefined') throw new Error('browser-only method')
    streamToBlobURL(this.createReadStream(), this._getMimeType())
      .then(
        blobUrl => cb(null, blobUrl),
        err => cb(err)
      )
  }

  appendTo (elem, opts, cb) {
    if (typeof window === 'undefined') throw new Error('browser-only method')
    render.append(this, elem, opts, cb)
  }

  renderTo (elem, opts, cb) {
    if (typeof window === 'undefined') throw new Error('browser-only method')
    render.render(this, elem, opts, cb)
  }

  _getMimeType () {
    return render.mime[path.extname(this.name).toLowerCase()]
  }

  _destroy () {
    this._destroyed = true
    this._torrent = null
  }
}

module.exports = File
<|endoftext|>


<commit_before><commit_msg>Fix typo<commit_after><|endoftext|>


<commit_before><commit_msg>Missing colon on mim file. Fixes #4.<commit_after><|endoftext|>


<commit_before><commit_msg>fix a typo, Linklist -> pool<commit_after><|endoftext|>


<commit_before>/**
 * This source code is property of Ideyatech, Inc.
 * All rights reserved.
 *	Needed YUI files:
 *
 *
 *
 *
 *	If you intend to persist the order or state of each widget (thru _supportsPersistState=true) , you will need this library/file(s):
 *
**/

if (!yConnect) {var yConnect = YAHOO.util.Connect;}

if (!yDom) {var yDom = YAHOO.util.Dom;}
if (!yEvent) {var yEvent = YAHOO.util.Event;}
if (!yDDM) {var yDDM = YAHOO.util.DragDropMgr;}
if (!IDEYATECH) {IDEYATECH = {};}
if (!IDEYATECH.example) {IDEYATECH.example = YAHOO.example;}

/**
* Module that handles the drag and drop of widgets.
* @requires YAHOO.util.Dom
* @requires YAHOO.util.Event
* @class widgets
* @namespace IDEYATECH.widgets
**/
IDEYATECH.widgets = function() {
	/*status state of widget */
	const WIDGET_STATUS_REMOVE = 0;
	const WIDGET_STATUS_SHOW = 1;
	const WIDGET_STATUS_MINIMIZE = 2;
	/*Classname marker for widget minimize */
	var _minimizeWidgetClassName = "widget-collapse";
	/*Classname marker for widget show */
	var _showWidgetClassName = "widget-expand";
	/*Classname marker for none DD target Element */
	var _notDDTargetClassName = "not-dd-target";

	/*Do we persist the state draggable objects?*/
	var _supportsPersistState = false;
	/*Default url to call in persisting our widget order*/
	var _urlOrder = "widget-persist.jspx?methodName=saveWidgetOrder&order=";
	/*Default url to call in persisting our widget status*/
	var _urlStatus = "widget-persist.jspx?methodName=saveWidgetStatus&widgetName=";
	/*Does our widgets have a handle? */
	var _supportsHandle = false;
	/*Classname marker for handle */
	var _handleClassName = "tides-dd-handle";
	/*Classname marker for drag and drop widget */
	var _widgetBoxClassName = "widget-box";
	/*Main container name/id of our draggable objects and undraggable targets*/
	var _dashBoardContainerName = "dashboard-main";
	/*Array of DD targets (These are the column in our drag & drop dashboard)*/
	var _ddTargetElems = [];

	/*Default callback*/
	var _callback = {
			  success: function(o) {/*success handler code*/},
			  failure: function(o) {/*failure handler code*/},
			  argument: ['Call: default callback']
			};

	/**
	* Private method that initialize the elements DD target.
    * @method _initDDTargets
    * @param arrElem - array's of target element
    */
	var _initDDTargets = function(arrElem) {
		for ( var i = 0; i < arrElem.length; i++) {
			if (!yDom.hasClass(arrElem[i],_notDDTargetClassName)) {
				new YAHOO.util.DDTarget(arrElem[i].id);
			}
		}
	};

	/**
	* Private method that initialize the drag and drop elements. We put it on the list so that we
	* could easily shared their events. (dragdrop,dragstart,etc)
    * @method _initDDList
    * @param arrElem - array of target element
    */
	var _initDDList = function(arrElem) {
		for ( var i = 0; i < arrElem.length; i++) {
			var el = arrElem[i];
			var ddElem = new IDEYATECH.example.DDList(el.id);
			//does we support handle?
			if (_supportsHandle) {
				//find the handle by getting the class name
				var arrHandle = yDom.getElementsByClassName(_handleClassName,"div",el);
				//get the first of the list
				if (arrHandle[0]) {
					ddElem.setHandleElId(arrHandle[0])
				}//skip if elements doesn't exist
			}
		}
	};

	/**
	* Private method that gets the elements DD target.
    * @method _getDDTargetElems
	* @param el - main div element
    * @return arrElem - array of target element
    */
	var _getDDTargetElems = function(el) {
		var arrElem = yDom.getChildren(el);
		return arrElem;

	};

	/**
	* Private method that gets the elements DD target.
    * @method _getArrayOfDDElements
	* @param arrTargetElem - array of target elements
    * @return arrDDElem - array list of Drag and drop elem
    */
	var _getArrayOfDDElements = function(arrTargetElem) {

		var arrElem = [];
		var ctr = 0;

		for ( var i = 0; i < arrTargetElem.length; i++) {
			var arrTemp = yDom.getChildren(arrTargetElem[i]);
			for (var j=0;j<arrTemp.length;j++) {
				arrElem[ctr] = arrTemp[j];
				ctr++;
			}

		}
		return arrElem;
	};

	return {
		/**
		* Initializer method for our drag and drop class
		* Public core method that is responsible for attaching events to our dashboard
		* @param mainDivId - the main dashboard container
		*/
		init: function (mainDivId) {
			if(mainDivId) {_dashBoardContainerName = mainDivId;}
			var mainDiv = yDom.get(_dashBoardContainerName);
			_ddTargetElems = _getDDTargetElems(mainDiv);
			_initDDTargets(_ddTargetElems);
			var arrayOfDDElements = _getArrayOfDDElements(_ddTargetElems);
			_initDDList(arrayOfDDElements);
		},

		/**
		* Helper public method that saves the status of widget
		* TODO: maybe we could overide this method outside?
		* @param el - target element
		* @param widgetStatus - (WIDGET_STATUS_REMOVE | WIDGET_STATUS_SHOW | WIDGET_STATUS_MINIMIZE)
		*/
		executeSaveStatus: function(el,widgetStatus) {
			if (_supportsPersistState) {
				//get the widget id
				var widgetId = el.parentNode.parentNode.id;

				if (widgetStatus == WIDGET_STATUS_REMOVE) {
					yDom.get(widgetId).parentNode.removeChild(yDom.get(widgetId));
				} else if (widgetStatus == WIDGET_STATUS_SHOW) {
					/*modify event listeners*/
					el.onclick = null;
					el.onclick = function() {IDEYATECH.widgets.executeSaveStatus(this,WIDGET_STATUS_MINIMIZE);}

					yDom.replaceClass(el,_showWidgetClassName,_minimizeWidgetClassName);
					yDom.getNextSibling(el.parentNode).style.display ="";
				} else if (widgetStatus == WIDGET_STATUS_MINIMIZE) {
					/*modify event listeners*/
					el.onclick = null;
					el.onclick = function() {IDEYATECH.widgets.executeSaveStatus(this,WIDGET_STATUS_SHOW);}
					yDom.replaceClass(el,_minimizeWidgetClassName,_showWidgetClassName);
					yDom.getNextSibling(el.parentNode).style.display ="none";
				}
				//avoid memory leak...
				el = null;
				//save state..
				var append = widgetId +"&status=" +widgetStatus;
				yConnect.asyncRequest('GET', _urlStatus+append, IDEYATECH.widgets.getCallback());
			}
		},

		/**
		* Getter method for _widgetBoxClassName
		*/
		getWidgetBoxClassName: function() {
			return _widgetBoxClassName;
		},
		/**
		* Setter method for _widgetBoxClassName
		*/
		setWidgetBoxClassName: function(newClassName) {
			_widgetBoxClassName = newClassName;
		},
		/**
		* Getter method for _handleClassName
		*/
		getHandleClassName: function() {
			return _handleClassName;
		},
		/**
		* Setter method for _handleClassName
		*/
		setHandleClassName: function(newClassName) {
			_handleClassName = newClassName;
		},
		/**
		* do we support persistence?
		*/
		isSupportsPersistState: function() {
			return _supportsPersistState;
		},
		/**
		* Setter method for _supportsPersistState
		*/
		setSupportsPersistState: function(boolVal) {
			_supportsPersistState = boolVal;
		},

		/**
		* do we support widget handle?
		*/
		isSupportsHandle: function() {
			return _supportsHandle;
		},
		/**
		* Setter method for _supportsHandle
		*/
		setSupportsHandle: function(boolVal) {
			_supportsHandle = boolVal;
		},

		/**
		* Getter method for _dashBoardContainerName
		*/
		getDashBoardContainerName: function() {
			return _dashBoardContainerName;
		},
		/**
		* Setter method for _dashBoardContainerName
		*/
		setDashBoardContainerName: function(newDashBoardContainerName) {
			_dashBoardContainerName = newDashBoardContainerName;
		},
		/**
		* Getter method for _ddTargetElems
		*/
		getDDTargetElems: function() {
			return _ddTargetElems;
		},
		/**
		* Setter method for _ddTargetElems
		*/
		setDDTargetElems: function(arrElems) {
			_ddTargetElems = arrElems;
		},

		/**
		* Getter method for _urlOrder
		*/
		getUrlOrder: function() {
			return _urlOrder;
		},
		/**
		* Setter method for _urlOrder
		*/
		setUrlOrder: function(sUrl) {
			_urlOrder = sUrl;
		},
		/**
		* Getter method for _urlStatus
		*/
		getUrlStatus: function() {
			return _urlStatus;
		},
		/**
		* Setter method for _urlStatus
		*/
		setUrlStatus: function(sUrl) {
			_urlStatus = sUrl;
		},

		/**
		* Getter method for _callback
		*/
		getCallback: function() {
			return _callback;
		},
		/**
		* Setter method for callback
		*/
		setCallback: function(myCallback) {
			_callback = myCallback;
		}

	}//end return

}();

/**
* This class handles the Drag and drop objects. Use this on drag and drop elements to provide one way of implementing events
* on the drag and drop functionality. This class uses YAHOO.example module.
* @requires YAHOO.util.Dom
* @class DDList
* @namespace IDEYATECH.example
*/
IDEYATECH.example.DDList = function(id, sGroup, config) {

    IDEYATECH.example.DDList.superclass.constructor.call(this, id, sGroup, config);
	//disable the logging
	//this.logger = this.logger || YAHOO;
	var el = this.getDragEl();
	yDom.setStyle(el, "opacity", 0.67); // The proxy is slightly transparent

	this.goingUp = false;
	this.lastY = 0;

	/*Used in persisting our DD order*/
	this.startColumn = null;
	this.endColumn = null;
	this.isDragOver = false;
};

/**
* This module is extending IDEYATECH.example.DDList to YAHOO.util.DDProxy
* Implement events at YAHOO.util.DDProxy
* @description IDEYATECH.example.DDList extends YAHOO.util.DDProxy
*/
YAHOO.extend(IDEYATECH.example.DDList, YAHOO.util.DDProxy, {

    startDrag: function(x, y) {
        //this.logger.log(this.id + " startDrag");

        // make the proxy look like the source element
        var dragEl = this.getDragEl();
        var clickEl = this.getEl();
        yDom.setStyle(clickEl, "visibility", "hidden");

        dragEl.innerHTML = clickEl.innerHTML;

        yDom.setStyle(dragEl, "color", yDom.getStyle(clickEl, "color"));
        yDom.setStyle(dragEl, "backgroundColor", yDom.getStyle(clickEl, "backgroundColor"));
        yDom.setStyle(dragEl, "border", "2px solid gray");

        /*Used in persisting our DD order*/
        this.startColumn = clickEl.parentNode.id;
		this.isDragOver = false;
    },

    endDrag: function(e) {

        var srcEl = this.getEl();
        var proxy = this.getDragEl();

        // Show the proxy element and animate it to the src element's location
        yDom.setStyle(proxy, "visibility", "");
        var a = new YAHOO.util.Motion(
            proxy, {
                points: {
                    to: yDom.getXY(srcEl)
                }
            },
            0.2,
            YAHOO.util.Easing.easeOut
        )
        var proxyid = proxy.id;
        var thisid = this.id;

        // Hide the proxy and show the source element when finished with the animation
        a.onComplete.subscribe(function() {
                yDom.setStyle(proxyid, "visibility", "hidden");
                yDom.setStyle(thisid, "visibility", "");
            });
        a.animate();
    },

    onDragDrop: function(e, id) {

        // If there is one drop interaction, the li was dropped either on the list,
        // or it was dropped on the current location of the source element.
        if (yDDM.interactionInfo.drop.length === 1) {

            // The position of the cursor at the time of the drop (YAHOO.util.Point)
            var pt = yDDM.interactionInfo.point;

            // The region occupied by the source element at the time of the drop
            var region = yDDM.interactionInfo.sourceRegion;

            // Check to see if we are over the source element's location.  We will
            // append to the bottom of the list once we are sure it was a drop in
            // the negative space (the area of the list without any list items)
            if (!region.intersect(pt)) {
               // var destEl = yDom.get(id);
                var destDD = yDDM.getDDById(id);
               // destEl.appendChild(this.getEl());
                destDD.isEmpty = false;
                yDDM.refreshCache();
            }

        }

        /*Used in persisting our DD order*/
        this.endColumn = id;
        var needToSave = false;
        if (this.isDragOver){needToSave =true;}
        if (this.startColumn != this.endColumn){needToSave =true;}

        //Do we persist the widgets state (shown/hide, order, etc)
        if (IDEYATECH.widgets.isSupportsPersistState() && needToSave) {
        	var arrTargetElem = IDEYATECH.widgets.getDDTargetElems();

        	var arrElem = [];
        	var newArr = [];
			var ctr = 0;

			for ( var i = 0; i < arrTargetElem.length; i++) {
				var arrTemp = yDom.getChildren(arrTargetElem[i]);
				var jTempArr = [];
				for (var j=0;j<arrTemp.length;j++) {
					arrElem[ctr] = arrTemp[j].id;
					jTempArr[j] = arrTemp[j].id;
					ctr++;
				}
				newArr[i] = jTempArr;
			}
			var orderVal = newArr.join("|");
			//save the order
			yConnect.asyncRequest('GET', IDEYATECH.widgets.getUrlOrder() + orderVal, IDEYATECH.widgets.getCallback());
        }
    },

    onDrag: function(e) {

        // Keep track of the direction of the drag for use during onDragOver
        var y = yEvent.getPageY(e);

        if (y < this.lastY) {
            this.goingUp = true;
        } else if (y > this.lastY) {
            this.goingUp = false;
        }

        this.lastY = y;
    },

    onDragOver: function(e, id) {

        var srcEl = this.getEl();
        var destEl = yDom.get(id);

        // We are only concerned with div's that have class = _widgetBoxClassName
        if (destEl.nodeName.toLowerCase() == "div" && yDom.hasClass(destEl,IDEYATECH.widgets.getWidgetBoxClassName())) {
            var orig_p = srcEl.parentNode;
            var p = destEl.parentNode;

            if (this.goingUp) {
                p.insertBefore(srcEl, destEl); // insert above
            } else {
                p.insertBefore(srcEl, destEl.nextSibling); // insert below
            }
            yDDM.refreshCache();
            /*Used in persisting our DD order*/
            this.isDragOver = true;
        }
    }
});
<commit_msg>Reverted back widgets.js to jquery <commit_after>/**
 * This source code is property of Ideyatech, Inc.
 * All rights reserved.
 *
**/

/**
*
* Module that handles the drag and drop of widgets.
*
* @requires jQuery($), jQuery UI & sortable/draggable UI modules
* @class widgets
* @namespace IDEYATECH.widgets
**/
IDEYATECH.widgets = function() {
	/*status state of widget */
	const WIDGET_STATUS_REMOVE = 0;
	const WIDGET_STATUS_SHOW = 1;
	const WIDGET_STATUS_MINIMIZE = 2;
	/*Classname marker for widget minimize */
	var _minimizeWidgetClassName = "widget-collapse";
	/*Classname marker for widget show */
	var _showWidgetClassName = "widget-expand";
	/*Classname marker for none DD target Element */
	var _notDDTargetClassName = "not-dd-target";

	/*Default url to call in persisting our widget order*/
	var _urlOrder = "widget-persist.jspx?methodName=saveWidgetOrder&order=";
	/*Default url to call in persisting our widget status*/
	var _urlStatus = "widget-persist.jspx?methodName=saveWidgetStatus&widgetName=";

	return {
		/**
		* Method that saves the status of a user's widget.
		* REMOVE - 0
		* SHOW (EXPAND) - 1
		* COLLAPSE (MINIMIZE) - 2
		*
		* @param el - target element
		* @param widgetStatus - (WIDGET_STATUS_REMOVE | WIDGET_STATUS_SHOW | WIDGET_STATUS_MINIMIZE)
		*/
		executeSaveStatus: function(el,widgetStatus) {
			//get the widget name
			var widgetName = el.parentNode.id;
			//avoid memory leak...
			el = null;
			//save state..
			var append = widgetName +"&status=" +widgetStatus;
			$.ajax({
				url: _urlStatus+append
			});
		},

		/**
		 * Method that saves the order of the user's widgets.
		 *
		 * @param event - the event that was caught
		 * @param el - the element that triggered the event
		 */
		executeOrderUpdate: function(event, el){
			if(event.target == el){
            	var object = el;
    			var widgetArrParameter;
    			setTimeout(function() {
    				widgetArrParameter = iNettuts.getWidgetArrangement(object);
    				//alert("\\|");
    				//alert(IDEYATECH.widgets.getUrlOrder()+widgetArrParameter);
    				$.ajax({
    					type: "POST",
    					url: IDEYATECH.widgets.getUrlOrder()+widgetArrParameter
    				});
    			}, 500);
            }
		},

		/**
		* Getter method for _urlOrder
		*/
		getUrlOrder: function() {
			return _urlOrder;
		},
		/**
		* Setter method for _urlOrder
		*/
		setUrlOrder: function(sUrl) {
			_urlOrder = sUrl;
		},
		/**
		* Getter method for _urlStatus
		*/
		getUrlStatus: function() {
			return _urlStatus;
		},
		/**
		* Setter method for _urlStatus
		*/
		setUrlStatus: function(sUrl) {
			_urlStatus = sUrl;
		}

	}//end return
}();

/**
 * @author Script from NETTUTS.com [by James Padolsey], modified by Ideyatech, Inc.
 * Module that builds the dashboard.
 * @requires jQuery($), jQuery UI & sortable/draggable UI modules, jquery-ui-personalized-1.6rc2.min.js
 */
var iNettuts = {

    jQuery : $,

    settings : {
        columns : '.column',
        widgetSelector: '.widget',
        handleSelector: '.widget-head',
        contentSelector: '.widget-content',
        widgetDefault : {
            movable: true,
            removable: true,
            collapsible: true,
            editable: true,
            collapsed: false,
            colorClasses : ['color-yellow', 'color-red', 'color-blue', 'color-white', 'color-orange', 'color-green']
        },
        widgetIndividual : {
            intro : {
                movable: false,
                removable: false,
                collapsible: false,
                editable: false
            },
            collapse : {
            	collapsed: true
            }
        }
    },

    init : function () {
        this.addWidgetControls();
        this.makeSortable();
    },

    getWidgetSettings : function (id) {
        var $ = this.jQuery,
            settings = this.settings;
        return (id&&settings.widgetIndividual[id]) ? $.extend({},settings.widgetDefault,settings.widgetIndividual[id]) : settings.widgetDefault;
    },

    addWidgetControls : function () {
        var iNettuts = this,
            $ = this.jQuery,
            settings = this.settings;

        $(settings.widgetSelector, $(settings.columns)).each(function () {
            var thisWidgetSettings = iNettuts.getWidgetSettings(this.id);

			if (thisWidgetSettings.removable) {
                $('Close').mousedown(function (e) {
                    e.stopPropagation();
                }).click(function () {
					$(this).parents(settings.widgetSelector).animate({
						opacity: 0
					},function () {
						$(this).wrap('
').parent().slideUp(function () {
							$(this).remove();
						});
					});
					IDEYATECH.widgets.executeSaveStatus(this, '0');
                    return false;
                }).prependTo($(settings.handleSelector, this));
            }
			if(thisWidgetSettings.collapsible) {
				if (thisWidgetSettings.collapsed) {
					$('Show').mousedown(function (e) {
	                    e.stopPropagation();
	                }).toggle(function () {
	                    $(this).css({backgroundPosition: ''})
	                        .parents(settings.widgetSelector)
	                            .find(settings.contentSelector).show();
	                    IDEYATECH.widgets.executeSaveStatus(this, '1');
	                    $(this).attr('title','Hide');
	                    return false;
	                },function () {
						$(this).css({backgroundPosition: '-38px 0'})
	                        .parents(settings.widgetSelector)
	                            .find(settings.contentSelector).hide();
						IDEYATECH.widgets.executeSaveStatus(this, '2');
	                    $(this).attr('title','Show');
						//alert(this.parentNode.id+"HIDE");
	                    return false;
	                }).appendTo($(settings.handleSelector,this));

					$(this).find(".collapse").css({backgroundPosition: '-38px 0'});
					$(this).find(".widget-content").hide();
				} else {
					$('Hide').mousedown(function (e) {
	                    e.stopPropagation();
	                }).toggle(function () {
	                    $(this).css({backgroundPosition: '-38px 0'})
	                        .parents(settings.widgetSelector)
	                            .find(settings.contentSelector).hide();
	                    IDEYATECH.widgets.executeSaveStatus(this, '2');
	                    $(this).attr('title','Show');
	                    return false;
	                },function () {
	                    $(this).css({backgroundPosition: ''})
	                        .parents(settings.widgetSelector)
	                            .find(settings.contentSelector).show();
	                    IDEYATECH.widgets.executeSaveStatus(this, '1');
	                    $(this).attr('title','Hide');
	                    return false;
	                }).appendTo($(settings.handleSelector,this));
				}
			}
        });
    },

    getWidgetArrangement : function (object) {
    	var arrangement = "";
        var columns = $(object).parent().parent().parent().delay(800).find('ul').each(function(){
			$(this).find(".widget-head").each(function(){
				arrangement += $(this).attr('id') + ",";
			});
			arrangement = arrangement.substring(0, arrangement.length - 1);
			arrangement += "|";
		});
        //arrangement = arrangement.substring(0, arrangement.length - 1);
        return arrangement;
    },

    makeSortable : function () {
        var iNettuts = this,
            $ = this.jQuery,
            settings = this.settings,
            $sortableItems = (function () {
                var notSortable = '';
                $(settings.widgetSelector,$(settings.columns)).each(function (i) {
                    if (!iNettuts.getWidgetSettings(this.id).movable) {
                        if(!this.id) {
                            this.id = 'widget-no-id-' + i;
                        }
                        notSortable += '#' + this.id + ',';
                    }
                });
                return $('> li:not(' + notSortable + ')', settings.columns);
            })();

        $sortableItems.find(settings.handleSelector).css({
            cursor: 'move'
        }).mousedown(function (e) {
            $sortableItems.css({width:''});
            $(this).parent().css({
                width: $(this).parent().width() + 'px'
            });
        }).mouseup(function (e) {
            if(!$(this).parent().hasClass('dragging')) {
            	$(this).parent().css({
                    width: $(this).parent().width() + 'px'});
            } else {
                $(settings.columns).sortable('disable');
            }
            IDEYATECH.widgets.executeOrderUpdate(e, this);
        });

        $(settings.columns).sortable({
            items: $sortableItems,
            connectWith: $(settings.columns),
            handle: settings.handleSelector,
            placeholder: 'widget-placeholder',
            forcePlaceholderSize: true,
            revert: 300,
            delay: 100,
            opacity: 0.8,
            containment: 'document',
            start: function (e,ui) {
                $(ui.helper).addClass('dragging');
            },
            stop: function (e,ui) {
                $(ui.item).css({width:''}).removeClass('dragging');
                $(settings.columns).sortable('enable');
            }
        });
    }
};

<|endoftext|>


<commit_before>/* global window */

window.deprecationWorkflow = window.deprecationWorkflow || {};
window.deprecationWorkflow.config = {
  workflow: [
    { handler: 'silence', matchId: 'computed-property.volatile' },
    { handler: 'silence', matchId: 'ember-metal.get-with-default' },
    { handler: 'silence', matchId: 'ember-string.htmlsafe-ishtmlsafe' },
  ],
};
<commit_msg>Silence noisy deprecations<commit_after>/* global window */

window.deprecationWorkflow = window.deprecationWorkflow || {};
window.deprecationWorkflow.config = {
  workflow: [
    { handler: 'silence', matchId: 'computed-property.volatile' },
    { handler: 'silence', matchId: 'ember-metal.get-with-default' },
    { handler: 'silence', matchId: 'ember-string.htmlsafe-ishtmlsafe' },
    { handler: 'silence', matchId: 'implicit-injections' }, //https://github.com/simplabs/ember-simple-auth/issues/2302
    { handler: 'silence', matchId: 'manager-capabilities.modifiers-3-13' }, //https://github.com/emberjs/ember-render-modifiers/issues/32
    { handler: 'silence', matchId: 'this-property-fallback' }, //Lots of these in ember-file-upload we have linting to ensure we don't add any ourselves
  ],
};
<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Internal dependencies
 */
import { visitDashboard } from '../../utils';

describe('Document Title', () => {
  it('should update the document title during navigation', async () => {
    await visitDashboard();

    await expect(page).toMatch('My Stories');
    await expect(await page.title()).toStartWith('My Stories');

    await expect(page).toClick('a', { text: 'Explore Templates' });

    await expect(page).toMatch('Viewing all templates');
    await expect(await page.title()).toStartWith('Explore Templates');

    const firstTemplate = await expect(page).toMatchElement(
      '[data-testid="template-grid-item-1"]'
    );
    await expect(firstTemplate).toClick('a', { text: 'View' });
    await expect(await page.title()).toStartWith('Template Details');

    await expect(page).toClick('a', { text: 'Close' });

    await expect(page).toMatch('Viewing all templates');
    await expect(await page.title()).toStartWith('Explore Templates');
  });
});
<commit_msg>Update e2e test from View to See Details.<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Internal dependencies
 */
import { visitDashboard } from '../../utils';

describe('Document Title', () => {
  it('should update the document title during navigation', async () => {
    await visitDashboard();

    await expect(page).toMatch('My Stories');
    await expect(await page.title()).toStartWith('My Stories');

    await expect(page).toClick('a', { text: 'Explore Templates' });

    await expect(page).toMatch('Viewing all templates');
    await expect(await page.title()).toStartWith('Explore Templates');

    const firstTemplate = await expect(page).toMatchElement(
      '[data-testid="template-grid-item-1"]'
    );
    await expect(firstTemplate).toClick('a', { text: 'See Details' });
    await expect(await page.title()).toStartWith('Template Details');

    await expect(page).toClick('a', { text: 'Close' });

    await expect(page).toMatch('Viewing all templates');
    await expect(await page.title()).toStartWith('Explore Templates');
  });
});
<|endoftext|>


<commit_before>var reverseIndex = Object.create(null);

function createReverseIndex() {
  videoCaptions.forEach(function (captions, i) {
    var currentTime = 0;
    var prevWord = "";
    var prevprevWord = "";
    captions.forEach(function (caption) {
      caption.text.split(/\s+/).forEach(function (word) {
        word = word.replace(/[\W_]+/g,"").toLowerCase(); // Remove all non-alphanumeric characters
        if (word) {
          reverseIndex[word] = (reverseIndex[word] || []);
          reverseIndex[word].push({
            videoIndex: i,
            startTime: currentTime,
            snippet: caption.text
          });
          if (prevWord.length) {
            reverseIndex[prevWord + " " + word] = (reverseIndex[prevWord + " " + word] || []);
            reverseIndex[prevWord + " " + word].push({
              videoIndex: i,
              startTime: currentTime,
              snippet: caption.text
            });
            if (prevprevWord.length) {
              reverseIndex[prevprevWord + " " + prevWord + " " + word] = (reverseIndex[prevprevWord + " " + prevWord + " " + word] || []);
              reverseIndex[prevprevWord + " " + prevWord + " " + word].push({
                videoIndex: i,
                startTime: currentTime,
                snippet: caption.text
              });
            }
            prevprevWord = prevWord;
          }
          prevWord = word;
        }
      });
      prevWord = "";
      currentTime += (caption.width / 64) + (2/64);
    });
  });
}

a = new Date();
createReverseIndex();
console.log (new Date() - a);

$(document).ready(function () {
  bindEventListeners();
  $(".search-box").focus();
});

/*
  Binds event listeners on input elements
*/
function bindEventListeners() {
  var debouncedInputKeypress = debounce(inputKeypress, 200);
  $(".search-box").off().keyup(debouncedInputKeypress);
  $(".search-box").keyup(); // Trigger event to account for auto fill
}

/*
  Helper debounce function
*/
function debounce (func, wait, immediate) {
  var timeout;
  return function() {
    var context = this, args = arguments;
    var later = function() {
      timeout = null;
      if (!immediate) func.apply(context, args);
    };
    var callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
    if (callNow) func.apply(context, args);
  };
}

/*
  Send a search event to GA
*/
function sendGAEvent() {
  var searchQuery = $(".search-box").val();
  if (searchQuery.length) {
    ga('send', 'event', 'homepage', 'search', searchQuery);
  }
}

var debouncedSendGAEvent = debounce(sendGAEvent, 1000);

/*
  Captures the input keypresses and reacts accordingly
*/
function inputKeypress(e) {
  debouncedSendGAEvent();
  $(".search-results-container").empty();
  var query = $(".search-box").val().toLowerCase();

  query = query.trim().replace(/[^a-zA-Z\d\s:]+/g,""); // Remove all non-alphanumeric characters
  var results = Object.create(null);
  if (reverseIndex[query]) {
    reverseIndex[query].forEach(function (match) {
      if (!results[match.snippet]) {
        var snippet = match.snippet.toLowerCase();
        var query = $(".search-box").val().toLowerCase();
        query.split(/\s+/).forEach(function (word) {
          snippet = updateHaystack(snippet, word);
        });
        var template = '
' + snippet + '
';
        $(".search-results-container").append(template);
        results[match.snippet] = true;
      }
    });
  }

  var prevWord = "";
  var prevprevWord = "";
  query.trim().split(/\s+/).forEach(function (word) {
    if (reverseIndex[word]) {
      if (prevWord && reverseIndex[prevWord + " " + word]) {
        if (prevprevWord && reverseIndex[prevprevWord + " " + prevWord + " " + word]) {
          reverseIndex[prevprevWord + " " + prevWord + " " + word].forEach(function (match) {
            if (!results[match.snippet]) {
              var snippet = match.snippet.toLowerCase();
              var query = $(".search-box").val().toLowerCase();
              query.split(/\s+/).forEach(function (word) {
                snippet = updateHaystack(snippet, word);
              });
              var template = '
' + snippet + '
';
              $(".search-results-container").append(template);
              results[match.snippet] = true;
            }
          });
        }
        reverseIndex[prevWord + " " + word].forEach(function (match) {
          if (!results[match.snippet]) {
            var snippet = match.snippet.toLowerCase();
            var query = $(".search-box").val().toLowerCase();
            query.split(/\s+/).forEach(function (word) {
              snippet = updateHaystack(snippet, word);
            });
            var template = '
' + snippet + '
';
            $(".search-results-container").append(template);
            results[match.snippet] = true;
          }
        });
        prevprevWord = prevWord;
      }
      reverseIndex[word].forEach(function (match) {
        if (!results[match.snippet]) {
          var snippet = match.snippet.toLowerCase();
          var query = $(".search-box").val().toLowerCase();
          query.split(/\s+/).forEach(function (word) {
            snippet = updateHaystack(snippet, word);
          });
          var template = '
' + snippet + '
';
          $(".search-results-container").append(template);
          results[match.snippet] = true;
        }
      });
      prevWord = word;
    }
  });
}

/*
  Bolds a needle in the input
*/
function updateHaystack(input, needle) {
  return input.replace(new RegExp('(^|[^a-zA-Z\d\s:])(' + escapeRegExp(needle) + ')([^a-zA-Z\d\s:]|$)','ig'), '$1$2$3');
}

/*
  Escapes a regular expression string
*/
function escapeRegExp(str) {
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}<commit_msg>Refactor search algorithm<commit_after>var reverseIndex = Object.create(null);

function createReverseIndex() {
  videoCaptions.forEach(function (captions, i) {
    var currentTime = 0;
    var prevWord = "";
    var prevprevWord = "";
    captions.forEach(function (caption) {
      caption.text.split(/\s+/).forEach(function (word) {
        word = word.replace(/[\W_]+/g,"").toLowerCase(); // Remove all non-alphanumeric characters
        if (word) {
          reverseIndex[word] = (reverseIndex[word] || []);
          reverseIndex[word].push({
            videoIndex: i,
            startTime: currentTime,
            snippet: caption.text
          });
          if (prevWord.length) {
            reverseIndex[prevWord + " " + word] = (reverseIndex[prevWord + " " + word] || []);
            reverseIndex[prevWord + " " + word].push({
              videoIndex: i,
              startTime: currentTime,
              snippet: caption.text
            });
            if (prevprevWord.length) {
              reverseIndex[prevprevWord + " " + prevWord + " " + word] = (reverseIndex[prevprevWord + " " + prevWord + " " + word] || []);
              reverseIndex[prevprevWord + " " + prevWord + " " + word].push({
                videoIndex: i,
                startTime: currentTime,
                snippet: caption.text
              });
            }
            prevprevWord = prevWord;
          }
          prevWord = word;
        }
      });
      prevWord = "";
      currentTime += (caption.width / 64) + (2/64);
    });
  });
}

a = new Date();
createReverseIndex();
console.log (new Date() - a);

$(document).ready(function () {
  bindEventListeners();
  $(".search-box").focus();
});

/*
  Binds event listeners on input elements
*/
function bindEventListeners() {
  var debouncedInputKeypress = debounce(inputKeypress, 200);
  $(".search-box").off().keyup(debouncedInputKeypress);
  $(".search-box").keyup(); // Trigger event to account for auto fill
}

/*
  Helper debounce function
*/
function debounce (func, wait, immediate) {
  var timeout;
  return function() {
    var context = this, args = arguments;
    var later = function() {
      timeout = null;
      if (!immediate) func.apply(context, args);
    };
    var callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
    if (callNow) func.apply(context, args);
  };
}

/*
  Send a search event to GA
*/
function sendGAEvent() {
  var searchQuery = $(".search-box").val();
  if (searchQuery.length) {
    ga('send', 'event', 'homepage', 'search', searchQuery);
  }
}

var debouncedSendGAEvent = debounce(sendGAEvent, 1000);

/*
  Captures the input keypresses and reacts accordingly
*/
function inputKeypress(e) {
  debouncedSendGAEvent();
  $(".search-results-container").empty();
  var query = $(".search-box").val().toLowerCase();

  query = query.trim().replace(/[^a-zA-Z\d\s:]+/g,""); // Remove all non-alphanumeric characters
  var results = Object.create(null);
  if (reverseIndex[query]) {
    reverseIndex[query].forEach(function (match) {
      if (!results[match.snippet]) {
        var snippet = match.snippet.toLowerCase();
        var query = $(".search-box").val().toLowerCase();
        query.trim().split(/\s+/).forEach(function (word) {
          snippet = updateHaystack(snippet, word);
        });
        var template = '
' + snippet + '
';
        $(".search-results-container").append(template);
        results[match.snippet] = true;
      }
    });
  }

  query = query.trim().split(/\s+/);

  var subStrings = [];
  for (var i = 0; i < query.length; i++) {
    for (var j = i; j < query.length; j++) {
      subStrings.push(query.slice(i, j+1).join(" "));
    }
  }

  subStrings = subStrings.sort(function (a,b) {
    return b.length - a.length;
  });

  subStrings.forEach(function (subString) {
    var query = subString;
    if (reverseIndex[query]) {
      reverseIndex[query].forEach(function (match) {
        if (!results[match.snippet]) {
          var snippet = match.snippet.toLowerCase();
          var query = $(".search-box").val().toLowerCase();
          query.trim().split(/\s+/).forEach(function (word) {
            snippet = updateHaystack(snippet, word);
          });
          var template = '
' + snippet + '
';
          $(".search-results-container").append(template);
          results[match.snippet] = true;
        }
      });
    }
  });
}

/*
  Bolds a needle in the input
*/
function updateHaystack(input, needle) {
  return input.replace(new RegExp('(^|[^a-zA-Z\d\s:])(' + escapeRegExp(needle) + ')([^a-zA-Z\d\s:]|$)','ig'), '$1$2$3');
}

/*
  Escapes a regular expression string
*/
function escapeRegExp(str) {
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}<|endoftext|>


<commit_before>/**
 * WordPress dependencies
 */
import { createNewPost, dragAndResize } from '@wordpress/e2e-test-utils';

/**
 * Internal dependencies
 */
import {
	activateExperience,
	deactivateExperience,
	selectBlockByClassName,
	insertBlock,
} from '../../utils';

/**
 * Rotates the selected block from its default position.
 */
async function rotateSelectedBlock() {
	const rotationHandle = await page.$( '.wp-block.is-selected .rotatable-box-wrap__handle' );
	await dragAndResize( rotationHandle, { x: 250, y: 0 } );
}

/**
 * Get selected block's top and left position values.
 *
 * @return {Promise<{positionLeft:number, positionTop:number}>} Block position.
 */
// eslint-disable-next-line require-await
async function getSelectedBlockPosition() {
	return page.evaluate( () => {
		const el = document.querySelector( '.wp-block.is-selected' );
		return {
			positionLeft: el.style.left,
			positionTop: el.style.top,
		};
	} );
}

/**
 * Returns the selected block's width and height.
 *
 * @returns {Promise<{width: number, height: number}>} Block dimensions.
 */
// eslint-disable-next-line require-await
async function getSelectedBlockDimensions() {
	return page.evaluate( () => {
		const el = document.querySelector( '.wp-block.is-selected' );
		return {
			width: el.clientWidth,
			height: el.clientHeight,
		};
	} );
}

describe( 'Resizing', () => {
	beforeAll( async () => {
		await activateExperience( 'stories' );
	} );

	afterAll( async () => {
		await deactivateExperience( 'stories' );
	} );

	describe( 'Text block', () => {
		beforeEach( async () => {
			await createNewPost( { postType: 'amp_story' } );
			// Select the Text block inserted by default.
			await selectBlockByClassName( 'wp-block-amp-story-text' );
		} );

		const defaultWidth = 250;
		const textBlockMinWidth = 40;

		it( 'it should not resize smaller than the set minimum width and height', async () => {
			const textBlockMinHeight = 30;
			let height, width;
			const resizableHandleBottom = await page.$( '.wp-block.is-selected .components-resizable-box__handle-bottom' );
			await dragAndResize( resizableHandleBottom, { x: 0, y: -250 } );
			height = await page.evaluate( () => document.querySelector( '.wp-block.is-selected' ).clientHeight );
			expect( height ).toStrictEqual( textBlockMinHeight );

			const resizableHandleTop = await page.$( '.wp-block.is-selected .components-resizable-box__handle-top' );
			await dragAndResize( resizableHandleTop, { x: 0, y: 250 } );
			height = await page.evaluate( () => document.querySelector( '.wp-block.is-selected' ).clientHeight );
			expect( height ).toStrictEqual( textBlockMinHeight );

			const resizableHandleLeft = await page.$( '.wp-block.is-selected .components-resizable-box__handle-left' );
			await dragAndResize( resizableHandleLeft, { x: 300, y: 0 } );
			width = await page.evaluate( () => document.querySelector( '.wp-block.is-selected' ).clientWidth );
			expect( width ).toStrictEqual( textBlockMinWidth );

			const resizableHandleRight = await page.$( '.wp-block.is-selected .components-resizable-box__handle-right' );
			await dragAndResize( resizableHandleRight, { x: -300, y: 0 } );
			width = await page.evaluate( () => document.querySelector( '.wp-block.is-selected' ).clientWidth );
			expect( width ).toStrictEqual( textBlockMinWidth );
		} );

		it( 'should not change the block position when resizing from left handle and minimum width has been reached', async () => {
			const resizableHandleLeft = await page.$( '.wp-block.is-selected .components-resizable-box__handle-left' );
			await dragAndResize( resizableHandleLeft, { x: defaultWidth - textBlockMinWidth, y: 0 } );
			const width = await page.evaluate( () => document.querySelector( '.wp-block.is-selected' ).clientWidth );
			expect( width ).toStrictEqual( textBlockMinWidth );

			const positionLeft = await page.evaluate( () => document.querySelector( '.wp-block.is-selected' ).style.left );
			expect( positionLeft ).toContain( '%' );

			// Drag the resizer more.
			await dragAndResize( resizableHandleLeft, { x: 300, y: 0 } );
			const positionLeftAfter = await page.evaluate( () => document.querySelector( '.wp-block.is-selected' ).style.left );
			// Verify that that the positionLeft has not changed.
			expect( positionLeftAfter ).toStrictEqual( positionLeft );
		} );

		it( 'should change the width and height correctly when resizing from topLeft corner', async () => {
			const resizableHandleTopLeft = await page.$( '.wp-block.is-selected .components-resizable-box__handle-left.components-resizable-box__handle-top' );
			await dragAndResize( resizableHandleTopLeft, { x: -100, y: -100 } );
			const { width, height } = await getSelectedBlockDimensions();
			expect( width ).toStrictEqual( 350 );
			expect( height ).toStrictEqual( 160 );
		} );
	} );

	describe( 'Rotated Text block', () => {
		beforeEach( async () => {
			await createNewPost( { postType: 'amp_story' } );
			// Select the Text block inserted by default.
			await selectBlockByClassName( 'wp-block-amp-story-text' );
			await rotateSelectedBlock();
		} );

		it( 'should change the top and left position correctly when resizing a rotated block: left', async () => {
			const handle = await page.$( '.wp-block.is-selected .components-resizable-box__handle-left' );
			await dragAndResize( handle, { x: 100, y: 0 } );

			const { positionLeft, positionTop } = await getSelectedBlockPosition();
			expect( positionLeft ).toStrictEqual( '9.84%' );
			expect( positionTop ).toStrictEqual( '7.69%' );
		} );

		it( 'should change the top and left position correctly when resizing a rotated block: topLeft', async () => {
			const handle = await page.$( '.wp-block.is-selected .components-resizable-box__handle-left.components-resizable-box__handle-top' );
			await dragAndResize( handle, { x: 100, y: -100 } );

			const { positionLeft, positionTop } = await getSelectedBlockPosition();
			expect( positionLeft ).toStrictEqual( '32.8%' );
			expect( positionTop ).toStrictEqual( '-2.76%' );
		} );

		it( 'should change the top and left position correctly when resizing a rotated block: top', async () => {
			const handle = await page.$( '.wp-block.is-selected .components-resizable-box__handle-top' );
			await dragAndResize( handle, { x: 0, y: -100 } );

			const { positionLeft, positionTop } = await getSelectedBlockPosition();
			expect( positionLeft ).toStrictEqual( '1.07%' );
			expect( positionTop ).toStrictEqual( '7%' );
		} );

		it( 'should change the top and left position correctly when resizing a rotated block: topRight', async () => {
			const handle = await page.$( '.wp-block.is-selected .components-resizable-box__handle-right.components-resizable-box__handle-top' );
			await dragAndResize( handle, { x: -100, y: 100 } );

			const { positionLeft, positionTop } = await getSelectedBlockPosition();
			expect( positionLeft ).toStrictEqual( '5%' );
			expect( positionTop ).toStrictEqual( '10%' );
		} );

		it( 'should change the top and left position correctly when resizing a rotated block: right', async () => {
			const handle = await page.$( '.wp-block.is-selected .components-resizable-box__handle-right' );
			await dragAndResize( handle, { x: -100, y: 0 } );

			const { positionLeft, positionTop } = await getSelectedBlockPosition();
			expect( positionLeft ).toStrictEqual( '5%' );
			expect( positionTop ).toStrictEqual( '10%' );
		} );

		it( 'should change the top and left position correctly when resizing a rotated block: bottomRight', async () => {
			const handle = await page.$( '.wp-block.is-selected .components-resizable-box__handle-right.components-resizable-box__handle-bottom' );
			await dragAndResize( handle, { x: 100, y: 100 } );

			const { positionLeft, positionTop } = await getSelectedBlockPosition();
			expect( positionLeft ).toStrictEqual( '5%' );
			expect( positionTop ).toStrictEqual( '10%' );
		} );

		it( 'should change the top and left position correctly when resizing a rotated block: bottom', async () => {
			const handle = await page.$( '.wp-block.is-selected .components-resizable-box__handle-bottom' );
			await dragAndResize( handle, { x: 0, y: -100 } );

			const { positionLeft, positionTop } = await getSelectedBlockPosition();
			expect( positionLeft ).toStrictEqual( '1.07%' );
			expect( positionTop ).toStrictEqual( '11.68%' );
		} );

		it( 'should change the top and left position correctly when resizing a rotated block: bottomLeft', async () => {
			const handle = await page.$( '.wp-block.is-selected .components-resizable-box__handle-left.components-resizable-box__handle-bottom' );
			await dragAndResize( handle, { x: -100, y: -100 } );

			const { positionLeft, positionTop } = await getSelectedBlockPosition();
			expect( positionLeft ).toStrictEqual( '14.03%' );
			expect( positionTop ).toStrictEqual( '5.78%' );
		} );
	} );

	describe( 'Author block', () => {
		beforeEach( async () => {
			await createNewPost( { postType: 'amp_story' } );
			await insertBlock( 'Author' );
			// Select the Text block inserted by default.
			await selectBlockByClassName( 'wp-block-amp-amp-story-post-author' );
			await rotateSelectedBlock();
		} );

		it( 'should change the top and left position correctly when resizing a rotated block: bottomLeft', async () => {
			const handle = await page.$( '.wp-block.is-selected .components-resizable-box__handle-left.components-resizable-box__handle-bottom' );
			await dragAndResize( handle, { x: -100, y: -100 } );

			const { positionLeft, positionTop } = await getSelectedBlockPosition();
			expect( positionLeft ).toStrictEqual( '15.5%' );
			expect( positionTop ).toStrictEqual( '15.24%' );
		} );

		it( 'should change the top and left position correctly when resizing a rotated block: topLeft', async () => {
			const handle = await page.$( '.wp-block.is-selected .components-resizable-box__handle-left.components-resizable-box__handle-top' );
			await dragAndResize( handle, { x: 100, y: -100 } );

			const { positionLeft, positionTop } = await getSelectedBlockPosition();
			expect( positionLeft ).toStrictEqual( '31.32%' );
			expect( positionTop ).toStrictEqual( '8.04%' );
		} );
	} );
} );
<commit_msg>Update assertions for failing resizing tests<commit_after>/**
 * WordPress dependencies
 */
import { createNewPost, dragAndResize } from '@wordpress/e2e-test-utils';

/**
 * Internal dependencies
 */
import {
	activateExperience,
	deactivateExperience,
	selectBlockByClassName,
	insertBlock,
} from '../../utils';

/**
 * Rotates the selected block from its default position.
 */
async function rotateSelectedBlock() {
	const rotationHandle = await page.$( '.wp-block.is-selected .rotatable-box-wrap__handle' );
	await dragAndResize( rotationHandle, { x: 250, y: 0 } );
}

/**
 * Get selected block's top and left position values.
 *
 * @return {Promise<{positionLeft:number, positionTop:number}>} Block position.
 */
// eslint-disable-next-line require-await
async function getSelectedBlockPosition() {
	return page.evaluate( () => {
		const el = document.querySelector( '.wp-block.is-selected' );
		return {
			positionLeft: el.style.left,
			positionTop: el.style.top,
		};
	} );
}

/**
 * Returns the selected block's width and height.
 *
 * @returns {Promise<{width: number, height: number}>} Block dimensions.
 */
// eslint-disable-next-line require-await
async function getSelectedBlockDimensions() {
	return page.evaluate( () => {
		const el = document.querySelector( '.wp-block.is-selected' );
		return {
			width: el.clientWidth,
			height: el.clientHeight,
		};
	} );
}

describe( 'Resizing', () => {
	beforeAll( async () => {
		await activateExperience( 'stories' );
	} );

	afterAll( async () => {
		await deactivateExperience( 'stories' );
	} );

	describe( 'Text block', () => {
		beforeEach( async () => {
			await createNewPost( { postType: 'amp_story' } );
			// Select the Text block inserted by default.
			await selectBlockByClassName( 'wp-block-amp-story-text' );
		} );

		const defaultWidth = 250;
		const textBlockMinWidth = 40;

		it( 'it should not resize smaller than the set minimum width and height', async () => {
			const textBlockMinHeight = 30;
			let height, width;
			const resizableHandleBottom = await page.$( '.wp-block.is-selected .components-resizable-box__handle-bottom' );
			await dragAndResize( resizableHandleBottom, { x: 0, y: -250 } );
			height = await page.evaluate( () => document.querySelector( '.wp-block.is-selected' ).clientHeight );
			expect( height ).toStrictEqual( textBlockMinHeight );

			const resizableHandleTop = await page.$( '.wp-block.is-selected .components-resizable-box__handle-top' );
			await dragAndResize( resizableHandleTop, { x: 0, y: 250 } );
			height = await page.evaluate( () => document.querySelector( '.wp-block.is-selected' ).clientHeight );
			expect( height ).toStrictEqual( textBlockMinHeight );

			const resizableHandleLeft = await page.$( '.wp-block.is-selected .components-resizable-box__handle-left' );
			await dragAndResize( resizableHandleLeft, { x: 300, y: 0 } );
			width = await page.evaluate( () => document.querySelector( '.wp-block.is-selected' ).clientWidth );
			expect( width ).toStrictEqual( textBlockMinWidth );

			const resizableHandleRight = await page.$( '.wp-block.is-selected .components-resizable-box__handle-right' );
			await dragAndResize( resizableHandleRight, { x: -300, y: 0 } );
			width = await page.evaluate( () => document.querySelector( '.wp-block.is-selected' ).clientWidth );
			expect( width ).toStrictEqual( textBlockMinWidth );
		} );

		it( 'should not change the block position when resizing from left handle and minimum width has been reached', async () => {
			const resizableHandleLeft = await page.$( '.wp-block.is-selected .components-resizable-box__handle-left' );
			await dragAndResize( resizableHandleLeft, { x: defaultWidth - textBlockMinWidth, y: 0 } );
			const width = await page.evaluate( () => document.querySelector( '.wp-block.is-selected' ).clientWidth );
			expect( width ).toStrictEqual( textBlockMinWidth );

			const positionLeft = await page.evaluate( () => document.querySelector( '.wp-block.is-selected' ).style.left );
			expect( positionLeft ).toContain( '%' );

			// Drag the resizer more.
			await dragAndResize( resizableHandleLeft, { x: 300, y: 0 } );
			const positionLeftAfter = await page.evaluate( () => document.querySelector( '.wp-block.is-selected' ).style.left );
			// Verify that that the positionLeft has not changed.
			expect( positionLeftAfter ).toStrictEqual( positionLeft );
		} );

		it( 'should change the width and height correctly when resizing from topLeft corner', async () => {
			const resizableHandleTopLeft = await page.$( '.wp-block.is-selected .components-resizable-box__handle-left.components-resizable-box__handle-top' );
			await dragAndResize( resizableHandleTopLeft, { x: -100, y: -100 } );
			const { width, height } = await getSelectedBlockDimensions();
			expect( width ).toStrictEqual( 350 );
			expect( height ).toStrictEqual( 160 );
		} );
	} );

	describe( 'Rotated Text block', () => {
		beforeEach( async () => {
			await createNewPost( { postType: 'amp_story' } );
			// Select the Text block inserted by default.
			await selectBlockByClassName( 'wp-block-amp-story-text' );
			await rotateSelectedBlock();
		} );

		it( 'should change the top and left position correctly when resizing a rotated block: left', async () => {
			const handle = await page.$( '.wp-block.is-selected .components-resizable-box__handle-left' );
			await dragAndResize( handle, { x: 100, y: 0 } );

			const { positionLeft, positionTop } = await getSelectedBlockPosition();
			expect( positionLeft ).toStrictEqual( '9.84%' );
			expect( positionTop ).toStrictEqual( '7.69%' );
		} );

		it( 'should change the top and left position correctly when resizing a rotated block: topLeft', async () => {
			const handle = await page.$( '.wp-block.is-selected .components-resizable-box__handle-left.components-resizable-box__handle-top' );
			await dragAndResize( handle, { x: 100, y: -100 } );

			const { positionLeft, positionTop } = await getSelectedBlockPosition();
			expect( positionLeft ).toStrictEqual( '32.8%' );
			expect( positionTop ).toStrictEqual( '-2.76%' );
		} );

		it( 'should change the top and left position correctly when resizing a rotated block: top', async () => {
			const handle = await page.$( '.wp-block.is-selected .components-resizable-box__handle-top' );
			await dragAndResize( handle, { x: 0, y: -100 } );

			const { positionLeft, positionTop } = await getSelectedBlockPosition();
			expect( positionLeft ).toStrictEqual( '1.07%' );
			expect( positionTop ).toStrictEqual( '7%' );
		} );

		it( 'should change the top and left position correctly when resizing a rotated block: topRight', async () => {
			const { positionLeft: positionLeftBefore, positionTop: positionTopBefore } = await getSelectedBlockPosition();
			expect( positionLeftBefore ).toStrictEqual( '5%' );
			expect( positionTopBefore ).toStrictEqual( '10%' );

			const handle = await page.$( '.wp-block.is-selected .components-resizable-box__handle-right.components-resizable-box__handle-top' );
			await dragAndResize( handle, { x: -100, y: 100 } );

			const { positionLeft, positionTop } = await getSelectedBlockPosition();
			expect( positionLeft ).toStrictEqual( '8.3%' );
			expect( positionTop ).toStrictEqual( '12.59%' );
		} );

		it( 'should change the top and left position correctly when resizing a rotated block: right', async () => {
			const { positionLeft: positionLeftBefore, positionTop: positionTopBefore } = await getSelectedBlockPosition();
			expect( positionLeftBefore ).toStrictEqual( '5%' );
			expect( positionTopBefore ).toStrictEqual( '10%' );

			const handle = await page.$( '.wp-block.is-selected .components-resizable-box__handle-right' );
			await dragAndResize( handle, { x: -100, y: 0 } );

			const { positionLeft, positionTop } = await getSelectedBlockPosition();
			expect( positionLeft ).toStrictEqual( '7.8%' );
			expect( positionTop ).toStrictEqual( '12.21%' );
		} );

		it( 'should change the top and left position correctly when resizing a rotated block: bottomRight', async () => {
			const { positionLeft: positionLeftBefore, positionTop: positionTopBefore } = await getSelectedBlockPosition();
			expect( positionLeftBefore ).toStrictEqual( '5%' );
			expect( positionTopBefore ).toStrictEqual( '10%' );

			const handle = await page.$( '.wp-block.is-selected .components-resizable-box__handle-right.components-resizable-box__handle-bottom' );
			await dragAndResize( handle, { x: 100, y: 100 } );

			const { positionLeft, positionTop } = await getSelectedBlockPosition();
			expect( positionLeft ).toStrictEqual( '30.9%' );
			expect( positionTop ).toStrictEqual( '7.91%' );
		} );

		it( 'should change the top and left position correctly when resizing a rotated block: bottom', async () => {
			const handle = await page.$( '.wp-block.is-selected .components-resizable-box__handle-bottom' );
			await dragAndResize( handle, { x: 0, y: -100 } );

			const { positionLeft, positionTop } = await getSelectedBlockPosition();
			expect( positionLeft ).toStrictEqual( '1.07%' );
			expect( positionTop ).toStrictEqual( '11.68%' );
		} );

		it( 'should change the top and left position correctly when resizing a rotated block: bottomLeft', async () => {
			const handle = await page.$( '.wp-block.is-selected .components-resizable-box__handle-left.components-resizable-box__handle-bottom' );
			await dragAndResize( handle, { x: -100, y: -100 } );

			const { positionLeft, positionTop } = await getSelectedBlockPosition();
			expect( positionLeft ).toStrictEqual( '14.03%' );
			expect( positionTop ).toStrictEqual( '5.78%' );
		} );
	} );

	describe( 'Author block', () => {
		beforeEach( async () => {
			await createNewPost( { postType: 'amp_story' } );
			await insertBlock( 'Author' );
			// Select the Text block inserted by default.
			await selectBlockByClassName( 'wp-block-amp-amp-story-post-author' );
			await rotateSelectedBlock();
		} );

		it( 'should change the top and left position correctly when resizing a rotated block: bottomLeft', async () => {
			const handle = await page.$( '.wp-block.is-selected .components-resizable-box__handle-left.components-resizable-box__handle-bottom' );
			await dragAndResize( handle, { x: -100, y: -100 } );

			const { positionLeft, positionTop } = await getSelectedBlockPosition();
			expect( positionLeft ).toStrictEqual( '15.5%' );
			expect( positionTop ).toStrictEqual( '15.24%' );
		} );

		it( 'should change the top and left position correctly when resizing a rotated block: topLeft', async () => {
			const handle = await page.$( '.wp-block.is-selected .components-resizable-box__handle-left.components-resizable-box__handle-top' );
			await dragAndResize( handle, { x: 100, y: -100 } );

			const { positionLeft, positionTop } = await getSelectedBlockPosition();
			expect( positionLeft ).toStrictEqual( '31.32%' );
			expect( positionTop ).toStrictEqual( '8.04%' );
		} );
	} );
} );
<|endoftext|>