<commit_before>class MapFactory {
    constructor(canvasName, mapWidth, mapHeight, tileWidth, tileHeight) {
        var _self = this;

        this.tileWidth = typeof tileWidth === "number" ? Math.abs(tileWidth) : 0;
        this.tileHeight = typeof tileHeight === "number" ? Math.abs(tileHeight) : 0;
        this.mapWidth = typeof mapWidth === "number" ? Math.abs(mapWidth) : 0;
        this.mapHeight = typeof mapHeight === "number" ? Math.abs(mapHeight) : 0;
        this.viewOffsetI = 0;
        this.viewOffsetJ = 0;
        this["mmh"] = 16;

        var currOffsetI = 0;
        var currOffsetJ = 0;
        var crsrOffsetI = 0;
        var crsrOffsetJ = 0;

        var canvas = this["canvas"] = document.getElementById(canvasName);
        var context = this["context"] = canvas.getContext('2d');
        var assetBackground = this["assetBackground"] = new Image();
        var assetForeground = this["assetForeground"] = new Image();

        //-------------------------------//
        this.updateMapVisibleSize();
        //-------------------------------//
        canvas.addEventListener("mousedown", function (ev) {
            if (ev.button !== 0) {
                return true;
            }
            crsrOffsetI = Math.trunc(ev.offsetX / _self.tileWidth);
            crsrOffsetJ = Math.trunc(ev.offsetY / _self.tileHeight);
            currOffsetI = _self.viewOffsetI;
            currOffsetJ = _self.viewOffsetJ;

            canvas.style.cursor = "move";
        });
        canvas.addEventListener("mousemove", function (ev) {
            if (ev.which !== 1) {
                return true;
            }
            var mapVisibleWidth = _self["mapVisibleWidth"];
            var mapVisibleHeight = _self["mapVisibleHeight"];

            var tempOffsetI = Math.trunc(ev.offsetX / _self.tileWidth);
            var tempOffsetJ = Math.trunc(ev.offsetY / _self.tileHeight);
            var update = false;

            if (crsrOffsetI !== tempOffsetI) {
                _self.viewOffsetI = Math.max(crsrOffsetI - tempOffsetI + currOffsetI, 0);
                update = true;
            }
            if (crsrOffsetJ !== tempOffsetJ) {
                _self.viewOffsetJ = Math.max(crsrOffsetJ - tempOffsetJ + currOffsetJ, 0);
                update = true;
            }
            console.log("I Crsr: [" + crsrOffsetI + "] Temp: [" + tempOffsetI + "] View: [" + _self.viewOffsetI + "]");
            console.log("J Crsr: [" + crsrOffsetJ + "] Temp: [" + tempOffsetJ + "] View: [" + _self.viewOffsetJ + "]");

            if (update && _self.viewOffsetI >= 0 && _self.viewOffsetJ >= 0 && _self.viewOffsetI + mapVisibleWidth < _self.mapWidth && _self.viewOffsetJ + mapVisibleHeight < _self.mapHeight) {
                _self.drawBackground();
                _self.drawForeground();
            }
            canvas.style.cursor = "move";
        });
        canvas.addEventListener("mouseup", function (ev) {
            canvas.style.cursor = "initial";
        });
        //-------------------------------//
        window.addEventListener("resize", function (ev) {
            _self.updateMapVisibleSize();

            _self.drawBackground();
            _self.drawForeground();
        });
        //-------------------------------//
        assetBackground.onload = function (ev) {
            _self.drawBackground();
        };
        assetForeground.onload = function (ev) {
            _self.drawForeground();
        };
    }
}

MapFactory.prototype.mapMinimumHeight = function (numberOfTiles) {
    if (typeof numberOfTiles === 'number') {
        if (this["mmh"] !== numberOfTiles) {
            this["mmh"] = numberOfTiles;

            this.updateMapVisibleSize();
            this.drawBackground();
            this.drawForeground();
        }
    }
    return this["mmh"];
};

MapFactory.prototype.foregroundAsset = function (url) {
    var assetForeground = this["assetForeground"];
    if (typeof url === 'string') {
        assetForeground.src = url;
    }
    return assetForeground.src;
};

MapFactory.prototype.backgroundAsset = function (url) {
    var assetBackground = this["assetBackground"];
    if (typeof url === 'string') {
        assetBackground.src = url;
    }
    return assetBackground.src;
};

MapFactory.prototype.updateMapVisibleSize = function () {
    var bb = this["canvas"].parentNode.getBoundingClientRect();

    this["mapVisibleWidth"] = Math.min(Math.trunc((bb.right - bb.left) / this.tileWidth) - 1, this.mapWidth);
    this["mapVisibleHeight"] = Math.min(this["mmh"], this.mapHeight);

    this["canvas"].width = this["mapVisibleWidth"] * this.tileWidth;
    this["canvas"].height = this["mapVisibleHeight"] * this.tileHeight;
};

MapFactory.prototype.backgroundAssetMapping = function (callback) {
    if (typeof callback === 'function') {
        this["bac"] = callback;
    }
    return this["bac"];
};

MapFactory.prototype.foregroundAssetMapping = function (callback) {
    if (typeof callback === 'function') {
        this["fac"] = callback;
    }
    return this["fac"];
};

MapFactory.prototype.drawBackground = function () {
    this["context"].fillStyle = "white";
    this["context"].fillRect(0, 0, this["canvas"].clientWidth, this["canvas"].clientHeight);

    var mapVisibleWidth = this["mapVisibleWidth"];
    var mapVisibleHeight = this["mapVisibleHeight"];
    var bac = this["bac"];

    if (this["assetBackground"].src && bac && typeof bac === "function") {
        for (var i = this.viewOffsetI; i < mapVisibleWidth + this.viewOffsetI; i++) {
            for (var j = this.viewOffsetJ; j < mapVisibleHeight + this.viewOffsetJ; j++) {
                var coor = bac(i, j);
                if (coor && typeof coor.x === 'number' && typeof coor.y === 'number') {
                    this.drawBackgroundTile(coor.x, coor.y, i, j);
                }
            }
        }
    }
};

MapFactory.prototype.drawForeground = function() {
    var mapVisibleWidth = this["mapVisibleWidth"];
    var mapVisibleHeight = this["mapVisibleHeight"];
    var fac = this["fac"];

    if (this["assetForeground"].src && fac && typeof fac === "function") {
        for (var i = this.viewOffsetI; i < mapVisibleWidth + this.viewOffsetI; i++) {
            for (var j = this.viewOffsetJ; j < mapVisibleHeight + this.viewOffsetJ; j++) {
                var coor = fac(i, j);
                if (coor && typeof coor.x === 'number' && typeof coor.y === 'number') {
                    this.drawForegroundTile(coor.x, coor.y, i, j);
                }
            }
        }
    }
};

MapFactory.prototype.drawBackgroundTile = function (sourceX, sourceY, i, j) {
    var destX = (i - this.viewOffsetI) * this.tileWidth;
    var destY = (j - this.viewOffsetJ) * this.tileHeight;

    this["context"].drawImage(this["assetBackground"], sourceX, sourceY, this.tileWidth, this.tileHeight, destX, destY, this.tileWidth, this.tileHeight);
};
MapFactory.prototype.drawForegroundTile = function (sourceX, sourceY, i, j) {
    var destX = (i - this.viewOffsetI) * this.tileWidth;
    var destY = (j - this.viewOffsetJ) * this.tileHeight;

    this["context"].drawImage(this["assetForeground"], sourceX, sourceY, this.tileWidth, this.tileHeight, destX, destY, this.tileWidth, this.tileHeight);
};
<commit_msg>Rename several variables<commit_after>// https://vxresource.wordpress.com/category/resources/tilesets/
// Write your Javascript code.

class MapFactory {
    constructor(canvasName, mapColumns, mapRows, tileWidth, tileHeight) {
        var _self = this;

        this.tileWidth = typeof tileWidth === "number" ? Math.abs(tileWidth) : 0;
        this.tileHeight = typeof tileHeight === "number" ? Math.abs(tileHeight) : 0;
        this.mapColumns = typeof mapColumns === "number" ? Math.abs(mapColumns) : 0;
        this.mapRows = typeof mapRows === "number" ? Math.abs(mapRows) : 0;
        this.viewOffsetI = 0;
        this.viewOffsetJ = 0;
        this["mvr"] = 16;

        var currOffsetI = 0;
        var currOffsetJ = 0;
        var crsrOffsetI = 0;
        var crsrOffsetJ = 0;

        var canvas = this["canvas"] = document.getElementById(canvasName);
        var context = this["context"] = canvas.getContext('2d');
        var assetBackground = this["assetBackground"] = new Image();
        var assetForeground = this["assetForeground"] = new Image();

        //-------------------------------//
        this.updateMapVisibleSize();
        //-------------------------------//
        canvas.addEventListener("mousedown", function (ev) {
            if (ev.button !== 0) {
                return true;
            }
            crsrOffsetI = Math.trunc(ev.offsetX / _self.tileWidth);
            crsrOffsetJ = Math.trunc(ev.offsetY / _self.tileHeight);
            currOffsetI = _self.viewOffsetI;
            currOffsetJ = _self.viewOffsetJ;

            canvas.style.cursor = "move";
        });
        canvas.addEventListener("mousemove", function (ev) {
            if (ev.which !== 1) {
                return true;
            }
            var mapVisibleColumns = _self["mapVisibleColumns"];
            var mapVisibleRows = _self["mapVisibleRows"];

            var tempOffsetI = Math.trunc(ev.offsetX / _self.tileWidth);
            var tempOffsetJ = Math.trunc(ev.offsetY / _self.tileHeight);
            var update = false;

            if (crsrOffsetI !== tempOffsetI) {
                _self.viewOffsetI = Math.max(crsrOffsetI - tempOffsetI + currOffsetI, 0);
                update = true;
            }
            if (crsrOffsetJ !== tempOffsetJ) {
                _self.viewOffsetJ = Math.max(crsrOffsetJ - tempOffsetJ + currOffsetJ, 0);
                update = true;
            }
            console.log("I Crsr: [" + crsrOffsetI + "] Temp: [" + tempOffsetI + "] View: [" + _self.viewOffsetI + "]");
            console.log("J Crsr: [" + crsrOffsetJ + "] Temp: [" + tempOffsetJ + "] View: [" + _self.viewOffsetJ + "]");

            if (update && _self.viewOffsetI >= 0 && _self.viewOffsetJ >= 0 && _self.viewOffsetI + mapVisibleColumns < _self.mapColumns && _self.viewOffsetJ + mapVisibleRows < _self.mapRows) {
                _self.drawBackground();
                _self.drawForeground();
            }
            canvas.style.cursor = "move";
        });
        canvas.addEventListener("mouseup", function (ev) {
            canvas.style.cursor = "initial";
        });
        //-------------------------------//
        window.addEventListener("resize", function (ev) {
            _self.updateMapVisibleSize();
            _self.drawBackground();
            _self.drawForeground();
        });
        //-------------------------------//
        assetBackground.onload = function (ev) {
            _self.drawBackground();
        };
        assetForeground.onload = function (ev) {
            _self.drawForeground();
        };
    }
}

MapFactory.prototype.fixedMapVisibleRows = function (numberOfTiles) {
    if (typeof numberOfTiles === 'number') {
        if (this["mvr"] !== numberOfTiles) {
            this["mvr"] = numberOfTiles;

            this.updateMapVisibleSize();
            this.drawBackground();
            this.drawForeground();
        }
    }
    return this["mvr"];
};

MapFactory.prototype.foregroundAsset = function (url) {
    var assetForeground = this["assetForeground"];
    if (typeof url === 'string') {
        assetForeground.src = url;
    }
    return assetForeground.src;
};

MapFactory.prototype.backgroundAsset = function (url) {
    var assetBackground = this["assetBackground"];
    if (typeof url === 'string') {
        assetBackground.src = url;
    }
    return assetBackground.src;
};

MapFactory.prototype.updateMapVisibleSize = function () {
    var bb = this["canvas"].parentNode.getBoundingClientRect();

    this["mapVisibleColumns"] = Math.min(Math.trunc((bb.right - bb.left) / this.tileWidth) - 1, this.mapColumns);
    this["mapVisibleRows"] = Math.min(this["mvr"], this.mapRows);

    this["canvas"].width = this["mapVisibleColumns"] * this.tileWidth;
    this["canvas"].height = this["mapVisibleRows"] * this.tileHeight;
};

MapFactory.prototype.backgroundAssetMapping = function (callback) {
    if (typeof callback === 'function') {
        this["bac"] = callback;
    }
    return this["bac"];
};

MapFactory.prototype.foregroundAssetMapping = function (callback) {
    if (typeof callback === 'function') {
        this["fac"] = callback;
    }
    return this["fac"];
};

MapFactory.prototype.drawBackground = function () {
    this["context"].fillStyle = "white";
    this["context"].fillRect(0, 0, this["canvas"].clientWidth, this["canvas"].clientHeight);

    var mapVisibleColumns = this["mapVisibleColumns"];
    var mapVisibleRows = this["mapVisibleRows"];
    var bac = this["bac"];

    if (this["assetBackground"].src && bac && typeof bac === "function") {
        for (var i = this.viewOffsetI; i < mapVisibleColumns + this.viewOffsetI; i++) {
            for (var j = this.viewOffsetJ; j < mapVisibleRows + this.viewOffsetJ; j++) {
                var coor = bac(i, j);
                if (coor && typeof coor.x === 'number' && typeof coor.y === 'number') {
                    this.drawBackgroundTile(coor.x, coor.y, i, j);
                }
            }
        }
    }
};

MapFactory.prototype.drawForeground = function() {
    var mapVisibleColumns = this["mapVisibleColumns"];
    var mapVisibleRows = this["mapVisibleRows"];
    var fac = this["fac"];

    if (this["assetForeground"].src && fac && typeof fac === "function") {
        for (var i = this.viewOffsetI; i < mapVisibleColumns + this.viewOffsetI; i++) {
            for (var j = this.viewOffsetJ; j < mapVisibleRows + this.viewOffsetJ; j++) {
                var coor = fac(i, j);
                if (coor && typeof coor.x === 'number' && typeof coor.y === 'number') {
                    this.drawForegroundTile(coor.x, coor.y, i, j);
                }
            }
        }
    }
};

MapFactory.prototype.drawBackgroundTile = function (sourceX, sourceY, i, j) {
    var destX = (i - this.viewOffsetI) * this.tileWidth;
    var destY = (j - this.viewOffsetJ) * this.tileHeight;

    this["context"].drawImage(this["assetBackground"], sourceX, sourceY, this.tileWidth, this.tileHeight, destX, destY, this.tileWidth, this.tileHeight);
};
MapFactory.prototype.drawForegroundTile = function (sourceX, sourceY, i, j) {
    var destX = (i - this.viewOffsetI) * this.tileWidth;
    var destY = (j - this.viewOffsetJ) * this.tileHeight;

    this["context"].drawImage(this["assetForeground"], sourceX, sourceY, this.tileWidth, this.tileHeight, destX, destY, this.tileWidth, this.tileHeight);
};
<|endoftext|>


<commit_before>import {assert} from 'chai';
import pipeline from '../lib/pipeline';
import PipelineLoggerMiddleware from '../lib/middlewares/logger';
import {makeRoundNumberHandler, toNumberHandler} from '../lib/middlewares/number';

let RoundNumberPipelineMiddleware = {
  type: 'pipeline',
  name: 'RoundNumberPipelineMiddleware',
  post: makeRoundNumberHandler()
};

let RoundNumberPipeMiddleware = {
  type: 'pipe',
  name: 'RoundNumberPipeMiddleware',
  post: makeRoundNumberHandler()
};

let ToNumberPipelineMiddleware = {
  type: 'pipeline',
  name: 'ToNumberPipelineMiddleware',
  pre: toNumberHandler
};

describe('pipeline', function () {
  it('应该正确运行非异步方法', function () {
    let except = pipeline('10',
      {
        name: 'pipeline1',
        middlewares: [ToNumberPipelineMiddleware]
      })
      .flow(v => {
        if (typeof v !== 'number') throw new TypeError('not a number');
        return v;
      })
      .flow(v => -v)
      .flow(v => 1/v)
      .finish();
    assert.equal(except, -0.1);
  });

  it('应该正确运行异步方法', function (done) {
    let asyncPipe = data => {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve(data * 2);
        }, 10);
      });
    };
    let promise = pipeline(10,
      {
        name: 'pipeline2',
        middlewares: [RoundNumberPipelineMiddleware]
        // middlewares: [RoundNumberPipelineMiddleware, PipelineLoggerMiddleware]
      })
      .flow(v => -v)
      .flowAsync(asyncPipe)
      .flow(v => 1/v)
      .flowAsync(asyncPipe)
      .flow(v => v * 3)
      .finish();
    assert.ok(promise instanceof Promise, '异步结果返回 Promise 对象');

    let except;
    promise
      .then(data => {
        except = data;
      });
    setTimeout(() => {
      assert.equal(except, -0.3);
      done();
    }, 30);
  });

  it('可以正确用 flowMap 处理对象', function () {
    let except = pipeline({1: 10, 2: 20, 3: 30})
    // let except = pipeline({1: 10, 2: 20, 3: 30}, {middlewares: [PipelineLoggerMiddleware]})
      .flowMap({handle: v => 1/v, filter: v => v < 30})
      .flowReduce({
        handle: (pre, cur) => pre + cur,
        initialValue: 0,
        middlewares: [RoundNumberPipeMiddleware]
      })
      .finish();
    assert.equal(except, 0.15);
  });

  // it('应该正确处理异步管道出错', function (done) {});

  it('可以正确执行同步方法 flowMap 和 flowReduce', function () {
    let except = pipeline(10)
    // let except = pipeline(10, {middlewares: [PipelineLoggerMiddleware]})
      .flow(v => [1*v, 2*v, 3*v])
      .flowMap({handle: v => 1/v, filter: v => v < 30})
      .flowReduce({
        handle: (pre, cur) => pre + cur,
        initialValue: 0,
        middlewares: [RoundNumberPipeMiddleware]
      })
      .finish();
    assert.equal(except, 0.15);
  });

  it('可以使用 handles 传递多个处理函数执行 flowMap ', function () {
    let except = pipeline(10)
    // let except = pipeline(10, {middlewares: [PipelineLoggerMiddleware]})
      .flow(v => [1*v, 2*v, 3*v])
      .flowMap({handles: [v => 1 / v, v => 1 / v + 1, v => 1 / v + 2], filter: v => v < 30})
      .flowReduce({
        handle: (pre, cur) => pre + cur,
        initialValue: 0,
        middlewares: [RoundNumberPipeMiddleware]
      })
      .finish();
    assert.equal(except, 1.15);
  });

  it('可以正确执行 flowMapAsync', function (done) {
    let asyncPipe = data => {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve(data * 2);
        }, 10);
      });
    };

    let promise = pipeline([10, 20, 30])
    // let promise = pipeline([10, 20, 30], {middlewares: [PipelineLoggerMiddleware]})
      .flowMapAsync({handle: asyncPipe, filter: v => v < 30})
      .flowReduce({
        handle: (pre, cur) => pre + cur,
        initialValue: 0,
        middlewares: [RoundNumberPipeMiddleware]
      })
      .finish();

    let except;
    promise
      .then(data => {
        except = data;
      });
    setTimeout(() => {
      assert.equal(except, 60);
      done();
    }, 30);
  });

});
<commit_msg>有多个 handler 时 flowMapAsync 测试<commit_after>import {assert} from 'chai';
import pipeline from '../lib/pipeline';
import PipelineLoggerMiddleware from '../lib/middlewares/logger';
import {makeRoundNumberHandler, toNumberHandler} from '../lib/middlewares/number';

let RoundNumberPipelineMiddleware = {
  type: 'pipeline',
  name: 'RoundNumberPipelineMiddleware',
  post: makeRoundNumberHandler()
};

let RoundNumberPipeMiddleware = {
  type: 'pipe',
  name: 'RoundNumberPipeMiddleware',
  post: makeRoundNumberHandler()
};

let ToNumberPipelineMiddleware = {
  type: 'pipeline',
  name: 'ToNumberPipelineMiddleware',
  pre: toNumberHandler
};

describe('pipeline', function () {
  it('应该正确运行非异步方法', function () {
    let except = pipeline('10',
      {
        name: 'pipeline1',
        middlewares: [ToNumberPipelineMiddleware]
      })
      .flow(v => {
        if (typeof v !== 'number') throw new TypeError('not a number');
        return v;
      })
      .flow(v => -v)
      .flow(v => 1/v)
      .finish();
    assert.equal(except, -0.1);
  });

  it('应该正确运行异步方法', function (done) {
    let asyncPipe = data => {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve(data * 2);
        }, 10);
      });
    };
    let promise = pipeline(10,
      {
        name: 'pipeline2',
        middlewares: [RoundNumberPipelineMiddleware]
        // middlewares: [RoundNumberPipelineMiddleware, PipelineLoggerMiddleware]
      })
      .flow(v => -v)
      .flowAsync(asyncPipe)
      .flow(v => 1/v)
      .flowAsync(asyncPipe)
      .flow(v => v * 3)
      .finish();
    assert.ok(promise instanceof Promise, '异步结果返回 Promise 对象');

    let except;
    promise
      .then(data => {
        except = data;
      });
    setTimeout(() => {
      assert.equal(except, -0.3);
      done();
    }, 30);
  });

  it('可以正确用 flowMap 处理对象', function () {
    let except = pipeline({1: 10, 2: 20, 3: 30})
    // let except = pipeline({1: 10, 2: 20, 3: 30}, {middlewares: [PipelineLoggerMiddleware]})
      .flowMap({handle: v => 1/v, filter: v => v < 30})
      .flowReduce({
        handle: (pre, cur) => pre + cur,
        initialValue: 0,
        middlewares: [RoundNumberPipeMiddleware]
      })
      .finish();
    assert.equal(except, 0.15);
  });

  // it('应该正确处理异步管道出错', function (done) {});

  it('可以正确执行同步方法 flowMap 和 flowReduce', function () {
    let except = pipeline(10)
    // let except = pipeline(10, {middlewares: [PipelineLoggerMiddleware]})
      .flow(v => [1*v, 2*v, 3*v])
      .flowMap({handle: v => 1/v, filter: v => v < 30})
      .flowReduce({
        handle: (pre, cur) => pre + cur,
        initialValue: 0,
        middlewares: [RoundNumberPipeMiddleware]
      })
      .finish();
    assert.equal(except, 0.15);
  });

  it('可以使用 handles 传递多个处理函数执行 flowMap ', function () {
    let except = pipeline(10)
    // let except = pipeline(10, {middlewares: [PipelineLoggerMiddleware]})
      .flow(v => [1*v, 2*v, 3*v])
      .flowMap({handles: [v => 1 / v, v => 1 / v + 1, v => 1 / v + 2], filter: v => v < 30})
      .flowReduce({
        handle: (pre, cur) => pre + cur,
        initialValue: 0,
        middlewares: [RoundNumberPipeMiddleware]
      })
      .finish();
    assert.equal(except, 1.15);
  });

  it('可以正确执行只有一个 handler 的 flowMapAsync', function (done) {
    let asyncPipe = data => {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve(data * 2);
        }, 10);
      });
    };

    let promise = pipeline([10, 20, 30])
    // let promise = pipeline([10, 20, 30], {middlewares: [PipelineLoggerMiddleware]})
      .flowMapAsync({handle: asyncPipe, filter: v => v < 30})
      .flowReduce({
        handle: (pre, cur) => pre + cur,
        initialValue: 0,
        middlewares: [RoundNumberPipeMiddleware]
      })
      .finish();

    let except;
    promise
      .then(data => {
        except = data;
      });
    setTimeout(() => {
      assert.equal(except, 60);
      done();
    }, 30);
  });

  it('可以正确执行有多个 handler 的 flowMapAsync', function (done) {
    let async2Times = data => {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve(data * 2);
        }, 10);
      });
    };

    let asyncHalf = data => {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve(data * 0.5);
        }, 10);
      });
    };

    let promise = pipeline([10, 20, 30])
    // let promise = pipeline([10, 20, 30], {middlewares: [PipelineLoggerMiddleware]})
      .flowMapAsync({handles: [async2Times, null, asyncHalf]})
      .flowReduce({
        handle: (pre, cur) => pre + cur,
        initialValue: 0,
        middlewares: [RoundNumberPipeMiddleware]
      })
      .finish();

    let except;
    promise
      .then(data => {
        except = data;
      });
    setTimeout(() => {
      assert.equal(except, 35);
      done();
    }, 30);
  });

});
<|endoftext|>


<commit_before>$('document').ready(function() {
	requirejs([
		RELATIVE_PATH + '/css/assets/vendor/masonry.js',
		RELATIVE_PATH + '/css/assets/vendor/imagesLoaded.js',
	], function(Masonry, imagesLoaded) {
		var fixed = localStorage.getItem('fixed') || 0,
			masonry;

		function doMasonry() {
			if($('.home').length) {
				masonry = new Masonry('.row.home > div', {
					itemSelector: '.category-item',
					columnWidth: '.category-item'
				});

				$('.row.home > div p img').imagesLoaded(function() {
					masonry.layout();
				});
			}
		}

		function resize(fixed) {
			fixed = parseInt(fixed, 10);
			$('.container').toggleClass('container-fluid', fixed !== 1).toggleClass('container', fixed === 1);

			$('.container').bind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function() {
				localStorage.setItem('fixed', fixed);
				doMasonry();
			});
		}

		$(window).on('action:ajaxify.end', function(ev, data) {
			var url = data.url;

			if (url === "") {
				if(!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
					doMasonry();
					resize(fixed);
				}
			}
		});

		var div = $('

');
		div.css({
			position:'fixed',
			bottom: '20px',
			right: '20px'
		}).hide().appendTo(document.body);

		$(window).on('mousemove', function(ev) {
			if (ev.clientX > $(window).width() - 150 && ev.clientY > $(window).height() - 150) {
				div.fadeIn();
			} else {
				div.stop(true, true).fadeOut();
			}
		});

		div.on('click', function() {
			fixed = parseInt(fixed, 10) === 1 ? 0 : 1;
			resize(fixed);
		});
	});

	(function() {
		// loading animation
		var ajaxifyGo = ajaxify.go,
			loadData = ajaxify.loadData,
			refreshTitle = app.refreshTitle,
			loadingBar = $('.loading-bar');

		ajaxify.go = function(url, callback, quiet) {
			loadingBar.addClass('reset').css('width', '100%');
			return ajaxifyGo(url, callback, quiet);
		};

		ajaxify.loadData = function(callback, url, template) {
			setTimeout(function() {
				loadingBar.removeClass('reset').css('width', (Math.random() * 20) + 5 + '%');
			}, 10);

			return loadData(callback, url, template);
		};

		app.refreshTitle = function(url) {
			setTimeout(function() {
				loadingBar.css('width', '0%');
			}, 300);

			return refreshTitle(url);
		};
	}());
});<commit_msg>toggle fix<commit_after>$('document').ready(function() {
	requirejs([
		RELATIVE_PATH + '/css/assets/vendor/masonry.js',
		RELATIVE_PATH + '/css/assets/vendor/imagesLoaded.js',
	], function(Masonry, imagesLoaded) {
		var fixed = localStorage.getItem('fixed') || 0,
			masonry;

		function doMasonry() {
			if($('.home').length) {
				masonry = new Masonry('.row.home > div', {
					itemSelector: '.category-item',
					columnWidth: '.category-item'
				});

				$('.row.home > div p img').imagesLoaded(function() {
					masonry.layout();
				});
			}
		}

		function resize(fixed) {
			fixed = parseInt(fixed, 10);
			var container = $('.container').length ? $('.container') : $('.container-fluid');
			container.toggleClass('container-fluid', fixed !== 1).toggleClass('container', fixed === 1);

			container.bind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function() {
				localStorage.setItem('fixed', fixed);
				doMasonry();
			});
		}

		$(window).on('action:ajaxify.end', function(ev, data) {
			var url = data.url;

			if (url === "") {
				if(!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
					doMasonry();
					resize(fixed);
				}
			}
		});

		var div = $('

');
		div.css({
			position:'fixed',
			bottom: '20px',
			right: '20px'
		}).hide().appendTo(document.body);

		$(window).on('mousemove', function(ev) {
			if (ev.clientX > $(window).width() - 150 && ev.clientY > $(window).height() - 150) {
				div.fadeIn();
			} else {
				div.stop(true, true).fadeOut();
			}
		});

		div.on('click', function() {
			fixed = parseInt(fixed, 10) === 1 ? 0 : 1;
			resize(fixed);
		});
	});

	(function() {
		// loading animation
		var ajaxifyGo = ajaxify.go,
			loadData = ajaxify.loadData,
			refreshTitle = app.refreshTitle,
			loadingBar = $('.loading-bar');

		ajaxify.go = function(url, callback, quiet) {
			loadingBar.addClass('reset').css('width', '100%');
			return ajaxifyGo(url, callback, quiet);
		};

		ajaxify.loadData = function(callback, url, template) {
			setTimeout(function() {
				loadingBar.removeClass('reset').css('width', (Math.random() * 20) + 5 + '%');
			}, 10);

			return loadData(callback, url, template);
		};

		app.refreshTitle = function(url) {
			setTimeout(function() {
				loadingBar.css('width', '0%');
			}, 300);

			return refreshTitle(url);
		};
	}());
});<|endoftext|>


<commit_before>//__BEGIN_LICENSE__
//Copyright (C) 2008-2010 United States Government as represented by
//the Administrator of the National Aeronautics and Space Administration.
//All Rights Reserved.
//__END_LICENSE__

/*
 * Handlers for websocket that connects tornado server to client
 * for displaying rover images.
 */

xgds_video = {}; //namespace

$.extend(xgds_video, {
    haveNewData: false,
//  client side websocket event handlers
    onopen: function(zmq) {
        $('#socketStatus').html('connected');
//      there is a topic per camera source. I'm assuming that we'll know these sources beforehand.
        var topic1 = 'RapidImagesensorSampleHazCamLeft';
        var topic2 = 'RapidImagesensorSampleGroundCam';
        var topic3 = 'RapidImagesensorSampleNirvss';
        var handler = function() {
            return function(zmq, topic, obj) {
//              upon receiving the image, display it.
                var data = obj.data.split(':');
                var imgType = data[0];
                var imgContent = data[1];
                haveNewData = true;
                if (topic == topic1) {
                    $('#cameraImage1').attr('src', 'data:image/jpeg;base64,' + imgContent);
                } else if (topic == topic2) {
                    $('#cameraImage2').attr('src', 'data:image/jpeg;base64,' + imgContent);
                } else if (topic == topic3) {
                    $('#cameraImage3').attr('src', 'data:image/jpeg;base64,' + imgContent);
                }
            };
        }();
        zmq.subscribeJson(topic1, handler);
        zmq.subscribeJson(topic2, handler);
    },

    onclose: function(zmq) {
        $('#socketStatus').html('disconnected');
    },

    zmqInit: function() {
        var zmqUrl = zmqURL.replace('{{host}}', window.location.hostname);
        var zmq = new ZmqManager(zmqUrl, {onopen: xgds_video.onopen, onclose: xgds_video.onclose, autoReconnect: true});
        zmq.start();
    }
});
<commit_msg>masonry reloads<commit_after>//__BEGIN_LICENSE__
//Copyright (C) 2008-2010 United States Government as represented by
//the Administrator of the National Aeronautics and Space Administration.
//All Rights Reserved.
//__END_LICENSE__

/*
 * Handlers for websocket that connects tornado server to client
 * for displaying rover images.
 */

xgds_video = {}; //namespace

$.extend(xgds_video, {
    haveNewData: false,
//  client side websocket event handlers
    onopen: function(zmq) {
        $('#socketStatus').html('connected');
//      there is a topic per camera source. I'm assuming that we'll know these sources beforehand.
        var topic1 = 'RapidImagesensorSampleHazCamLeft';
        var topic2 = 'RapidImagesensorSampleGroundCam';
        var topic3 = 'RapidImagesensorSampleNirvss';
        var handler = function() {
            return function(zmq, topic, obj) {
//              upon receiving the image, display it.
                var data = obj.data.split(':');
                var imgType = data[0];
                var imgContent = data[1];
                haveNewData = true;
                if (topic == topic1) {
                    $('#cameraImage1').attr('src', 'data:image/jpeg;base64,' + imgContent);
                } else if (topic == topic2) {
                    $('#cameraImage2').attr('src', 'data:image/jpeg;base64,' + imgContent);
                } else if (topic == topic3) {
                    $('#cameraImage3').attr('src', 'data:image/jpeg;base64,' + imgContent);
                }
		$container.masonry();
            };
        }();
        zmq.subscribeJson(topic1, handler);
        zmq.subscribeJson(topic2, handler);
        zmq.subscribeJson(topic3, handler);
    },

    onclose: function(zmq) {
        $('#socketStatus').html('disconnected');
    },

    zmqInit: function() {
        var zmqUrl = zmqURL.replace('{{host}}', window.location.hostname);
        var zmq = new ZmqManager(zmqUrl, {onopen: xgds_video.onopen, onclose: xgds_video.onclose, autoReconnect: true});
        zmq.start();
    }
});
<|endoftext|>


<commit_before>/**
 * Project config file includes dev/prod and frontend/backend
 */
var path = require('path')
var _ = require('lodash')
{{#if_eq mock 'backend'}}
var backendBase = {
  // Root path of server
  root: path.normalize(__dirname),

  // Server port
  port: process.env.PORT || {{backendPort}},

  // Secret for session, you will want to change this and make it an environment variable
  secrets: {
    session: process.env.SECRET || '{{name}}-secret'
  },

  // List of user roles
  userRoles: ['admin', 'user'],

  // MongoDB connection options
  mongo: {
    options: {
      db: {
        safe: true
      }
    }
  }
}{{/if_eq}}

var development = {
  frontend: {
    port: {{frontendPort}},
    assetsRoot: path.resolve(__dirname, './{{#if_eq mock "backend"}}client/{{/if_eq}}src',
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: {
      '/api': { target: 'http://localhost:' + {{#if_eq mock 'backend'}}backendBase.port{{/if_eq}}{{#if_eq mock 'mock'}}{{mockPort}}{{/if_eq}}, changeOrigin: true, pathRewrite: { '^/api/': '' }},
      '/socket.io': { target: 'http://localhost:' + {{#if_eq mock 'backend'}}backendBase.port{{/if_eq}}{{#if_eq mock 'mock'}}{{mockPort}}{{/if_eq}}, changeOrigin: true, ws: true }
    },
    // CSS Sourcemaps off by default because relative paths are "buggy"
    // with this option, according to the CSS-Loader README
    // (https://github.com/webpack/css-loader#sourcemaps)
    // In our experience, they generally work as expected,
    // just be aware of this issue when enabling this option.
    cssSourceMap: false
  }{{#if_eq mock 'backend'}},
  backend: _.merge({}, backendBase, {
    mongo: {
      uri: {{#if mongoUri}}'{{mongoUri}}-dev'{{else}}'mongodb://localhost/{{name}}-dev'{{/if}}
    }
  }){{/if_eq}}{{#if_eq mock 'mock'}},
  mock: {
    port: {{mockPort}}
  }{{/if_eq}}
}
var production = {
  frontend: {
    index: path.resolve(__dirname, './{{#if_eq mock "backend"}}client/{{/if_eq}}dist/index.html'),
    assetsRoot: path.resolve(__dirname, './{{#if_eq mock "backend"}}client/{{/if_eq}}dist'),
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    cssSourceMap: true,
    // Gzip off by default as many popular static hosts such as
    // Surge or Netlify already gzip all static assets for you.
    // Before setting to `true`, make sure to:
    // npm install --save-dev compression-webpack-plugin
    productionGzip: false,
    productionGzipExtensions: ['js', 'css']
  }{{#if_eq mock 'backend'}},
  backend: _.merge({}, backendBase, {
    // whether backend servers the frontend, you can use nginx to server frontend and proxy to backend services
    // if set to true, you need no web services like nginx
    serverFrontend: true,
    // Server IP
    ip: process.env.APP_HOST || process.env.APP_IP || process.env.HOST || process.env.IP,
    // Server port
    port: process.env.APP_PORT || process.env.PORT,
    // MongoDB connection options
    mongo: {
      uri: process.env.MONGODB_URI || process.env.MONGOHQ_URI ||
           {{#if mongoUri}}'{{mongoUri}}'{{else}}'mongodb://localhost/{{name}}'{{/if}}
    },

    // frontend folder
    frontend: path.resolve(__dirname, './client/dist')
  }){{/if_eq}}{{#if_eq mock 'mock'}},
  mock: {
    port: {{mockPort}}
  }{{/if_eq}}
}

var config = process.env.NODE_ENV === 'production' ? production : development

module.exports = _.assign({}, config)
<commit_msg>update config.js template<commit_after>/**
 * Project config file includes dev/prod and frontend/backend
 */
var path = require('path')
var _ = require('lodash')
{{#if_eq mock 'backend'}}
var backendBase = {
  // Root path of server
  root: path.normalize(__dirname),

  // Server port
  port: process.env.PORT || {{backendPort}},

  // Secret for session, you will want to change this and make it an environment variable
  secrets: {
    session: process.env.SECRET || '{{name}}-secret'
  },

  // List of user roles
  userRoles: ['admin', 'user'],

  // MongoDB connection options
  mongo: {
    options: {
      db: {
        safe: true
      }
    }
  }
}{{/if_eq}}

var development = {
  frontend: {
    port: {{frontendPort}},
    assetsRoot: path.resolve(__dirname, './{{#if_eq mock "backend"}}client/{{/if_eq}}src'),
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: {
      '/api': { target: 'http://localhost:' + {{#if_eq mock 'backend'}}backendBase.port{{/if_eq}}{{#if_eq mock 'mock'}}{{mockPort}}{{/if_eq}}, changeOrigin: true, pathRewrite: { '^/api/': '' }},
      '/socket.io': { target: 'http://localhost:' + {{#if_eq mock 'backend'}}backendBase.port{{/if_eq}}{{#if_eq mock 'mock'}}{{mockPort}}{{/if_eq}}, changeOrigin: true, ws: true }
    },
    // CSS Sourcemaps off by default because relative paths are "buggy"
    // with this option, according to the CSS-Loader README
    // (https://github.com/webpack/css-loader#sourcemaps)
    // In our experience, they generally work as expected,
    // just be aware of this issue when enabling this option.
    cssSourceMap: false
  }{{#if_eq mock 'backend'}},
  backend: _.merge({}, backendBase, {
    mongo: {
      uri: {{#if mongoUri}}'{{mongoUri}}-dev'{{else}}'mongodb://localhost/{{name}}-dev'{{/if}}
    }
  }){{/if_eq}}{{#if_eq mock 'mock'}},
  mock: {
    port: {{mockPort}}
  }{{/if_eq}}
}
var production = {
  frontend: {
    index: path.resolve(__dirname, './{{#if_eq mock "backend"}}client/{{/if_eq}}dist/index.html'),
    assetsRoot: path.resolve(__dirname, './{{#if_eq mock "backend"}}client/{{/if_eq}}dist'),
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    cssSourceMap: true,
    // Gzip off by default as many popular static hosts such as
    // Surge or Netlify already gzip all static assets for you.
    // Before setting to `true`, make sure to:
    // npm install --save-dev compression-webpack-plugin
    productionGzip: false,
    productionGzipExtensions: ['js', 'css']
  }{{#if_eq mock 'backend'}},
  backend: _.merge({}, backendBase, {
    // whether backend servers the frontend, you can use nginx to server frontend and proxy to backend services
    // if set to true, you need no web services like nginx
    serverFrontend: true,
    // Server IP
    ip: process.env.APP_HOST || process.env.APP_IP || process.env.HOST || process.env.IP,
    // Server port
    port: process.env.APP_PORT || process.env.PORT,
    // MongoDB connection options
    mongo: {
      uri: process.env.MONGODB_URI || process.env.MONGOHQ_URI ||
           {{#if mongoUri}}'{{mongoUri}}'{{else}}'mongodb://localhost/{{name}}'{{/if}}
    },

    // frontend folder
    frontend: path.resolve(__dirname, './client/dist')
  }){{/if_eq}}{{#if_eq mock 'mock'}},
  mock: {
    port: {{mockPort}}
  }{{/if_eq}}
}

var config = process.env.NODE_ENV === 'production' ? production : development

module.exports = _.assign({}, config)
<|endoftext|>


<commit_before>'use strict'

const test = require('tap').test
const build = require('..')

test('ref internal - properties', (t) => {
  t.plan(2)

  const schema = {
    title: 'object with $ref',
    definitions: {
      def: {
        type: 'object',
        properties: {
          str: {
            type: 'string'
          }
        }
      }
    },
    type: 'object',
    properties: {
      obj: {
        $ref: '#/definitions/def'
      }
    }
  }

  const object = {
    obj: {
      str: 'test'
    }
  }

  const stringify = build(schema)
  const output = stringify(object)

  try {
    JSON.parse(output)
    t.pass()
  } catch (e) {
    t.fail()
  }

  t.equal('{"obj":{"str":"test"}}', output)
})

test('ref external - properties', (t) => {
  t.plan(2)

  const schema = {
    title: 'object with $ref',
    definitions: {
      def: {
        type: 'object',
        properties: {
          str: {
            type: 'string'
          }
        }
      }
    },
    type: 'object',
    properties: {
      obj: {
        $ref: __dirname + '/ref.json#/definitions/def' // eslint-disable-line
      }
    }
  }

  const object = {
    obj: {
      str: 'test'
    }
  }

  const stringify = build(schema)
  const output = stringify(object)

  try {
    JSON.parse(output)
    t.pass()
  } catch (e) {
    t.fail()
  }

  t.equal('{"obj":{"str":"test"}}', output)
})

test('ref internal - patternProperties', (t) => {
  t.plan(2)

  const schema = {
    title: 'object with $ref',
    definitions: {
      def: {
        type: 'object',
        properties: {
          str: {
            type: 'string'
          }
        }
      }
    },
    type: 'object',
    properties: {},
    patternProperties: {
      obj: {
        $ref: '#/definitions/def'
      }
    }
  }

  const object = {
    obj: {
      str: 'test'
    }
  }

  const stringify = build(schema)
  const output = stringify(object)

  try {
    JSON.parse(output)
    t.pass()
  } catch (e) {
    t.fail()
  }

  t.equal('{"obj":{"str":"test"}}', output)
})

test('ref internal - additionalProperties', (t) => {
  t.plan(2)

  const schema = {
    title: 'object with $ref',
    definitions: {
      def: {
        type: 'object',
        properties: {
          str: {
            type: 'string'
          }
        }
      }
    },
    type: 'object',
    properties: {},
    additionalProperties: {
      $ref: '#/definitions/def'
    }
  }

  const object = {
    obj: {
      str: 'test'
    }
  }

  const stringify = build(schema)
  const output = stringify(object)

  try {
    JSON.parse(output)
    t.pass()
  } catch (e) {
    t.fail()
  }

  t.equal('{"obj":{"str":"test"}}', output)
})

test('ref internal - pattern-additional Properties', (t) => {
  t.plan(2)

  const schema = {
    title: 'object with $ref',
    definitions: {
      def: {
        type: 'object',
        properties: {
          str: {
            type: 'string'
          }
        }
      }
    },
    type: 'object',
    properties: {},
    patternProperties: {
      reg: {
        $ref: '#/definitions/def'
      }
    },
    additionalProperties: {
      $ref: '#/definitions/def'
    }
  }

  const object = {
    reg: {
      str: 'test'
    },
    obj: {
      str: 'test'
    }
  }

  const stringify = build(schema)
  const output = stringify(object)

  try {
    JSON.parse(output)
    t.pass()
  } catch (e) {
    t.fail()
  }

  t.equal('{"reg":{"str":"test"},"obj":{"str":"test"}}', output)
})
<commit_msg>Updated test<commit_after>'use strict'

const test = require('tap').test
const build = require('..')

test('ref internal - properties', (t) => {
  t.plan(2)

  const schema = {
    title: 'object with $ref',
    definitions: {
      def: {
        type: 'object',
        properties: {
          str: {
            type: 'string'
          }
        }
      }
    },
    type: 'object',
    properties: {
      obj: {
        $ref: '#/definitions/def'
      }
    }
  }

  const object = {
    obj: {
      str: 'test'
    }
  }

  const stringify = build(schema)
  const output = stringify(object)

  try {
    JSON.parse(output)
    t.pass()
  } catch (e) {
    t.fail()
  }

  t.equal('{"obj":{"str":"test"}}', output)
})

test('ref external - properties', (t) => {
  t.plan(2)

  const externalSchema = {
    first: require('./ref.json'),
    second: {
      definitions: {
        num: {
          type: 'object',
          properties: {
            int: {
              type: 'integer'
            }
          }
        }
      }
    }
  }

  const schema = {
    title: 'object with $ref',
    type: 'object',
    properties: {
      obj: {
        $ref: 'first#/definitions/def'
      },
      num: {
        $ref: 'second#/definitions/num'
      }
    }
  }

  const object = {
    obj: {
      str: 'test'
    },
    num: {
      int: 42
    }
  }

  const stringify = build(schema, { schema: externalSchema })
  const output = stringify(object)

  try {
    JSON.parse(output)
    t.pass()
  } catch (e) {
    t.fail()
  }

  t.equal('{"obj":{"str":"test"},"num":{"int":42}}', output)
})

test('ref internal - patternProperties', (t) => {
  t.plan(2)

  const schema = {
    title: 'object with $ref',
    definitions: {
      def: {
        type: 'object',
        properties: {
          str: {
            type: 'string'
          }
        }
      }
    },
    type: 'object',
    properties: {},
    patternProperties: {
      obj: {
        $ref: '#/definitions/def'
      }
    }
  }

  const object = {
    obj: {
      str: 'test'
    }
  }

  const stringify = build(schema)
  const output = stringify(object)

  try {
    JSON.parse(output)
    t.pass()
  } catch (e) {
    t.fail()
  }

  t.equal('{"obj":{"str":"test"}}', output)
})

test('ref internal - additionalProperties', (t) => {
  t.plan(2)

  const schema = {
    title: 'object with $ref',
    definitions: {
      def: {
        type: 'object',
        properties: {
          str: {
            type: 'string'
          }
        }
      }
    },
    type: 'object',
    properties: {},
    additionalProperties: {
      $ref: '#/definitions/def'
    }
  }

  const object = {
    obj: {
      str: 'test'
    }
  }

  const stringify = build(schema)
  const output = stringify(object)

  try {
    JSON.parse(output)
    t.pass()
  } catch (e) {
    t.fail()
  }

  t.equal('{"obj":{"str":"test"}}', output)
})

test('ref internal - pattern-additional Properties', (t) => {
  t.plan(2)

  const schema = {
    title: 'object with $ref',
    definitions: {
      def: {
        type: 'object',
        properties: {
          str: {
            type: 'string'
          }
        }
      }
    },
    type: 'object',
    properties: {},
    patternProperties: {
      reg: {
        $ref: '#/definitions/def'
      }
    },
    additionalProperties: {
      $ref: '#/definitions/def'
    }
  }

  const object = {
    reg: {
      str: 'test'
    },
    obj: {
      str: 'test'
    }
  }

  const stringify = build(schema)
  const output = stringify(object)

  try {
    JSON.parse(output)
    t.pass()
  } catch (e) {
    t.fail()
  }

  t.equal('{"reg":{"str":"test"},"obj":{"str":"test"}}', output)
})

test('ref external - pattern-additional Properties', (t) => {
  t.plan(2)

  const externalSchema = {
    first: require('./ref.json'),
    second: {
      definitions: {
        num: {
          type: 'object',
          properties: {
            int: {
              type: 'integer'
            }
          }
        }
      }
    }
  }

  const schema = {
    title: 'object with $ref',
    type: 'object',
    properties: {},
    patternProperties: {
      reg: {
        $ref: 'first#/definitions/def'
      }
    },
    additionalProperties: {
      $ref: 'second#/definitions/num'
    }
  }

  const object = {
    reg: {
      str: 'test'
    },
    obj: {
      int: 42
    }
  }

  const stringify = build(schema, { schema: externalSchema })
  const output = stringify(object)

  try {
    JSON.parse(output)
    t.pass()
  } catch (e) {
    t.fail()
  }

  t.equal('{"reg":{"str":"test"},"obj":{"int":42}}', output)
})
<|endoftext|>


<commit_before>//Track data
/**
 * Created by ronfe on 15-5-5.
 */

/**
 * Created by libook on 15-1-22.
 */
'use strict';
/**
 * You can use this attribute like these:
 * <element post-point="clickSomething"></element>
 * <element post-point='{"eventKey":"clickSomething","moredata":"somedata"}'></element>
 * <element post-point='[{"eventKey":"clickSomething"},{"eventKey":"enterSomething"}]'></element>
 *
 * The eventKey may start with 'click' or 'enter'.
 * And this attribute can automatically bind event like that.
 *
 * If you need to record other kind of events, you can also use this function with javascript like this:
 * postPoint.buryPoint(element, pointData);
 * And the point will be sent immediately.
 */
var postPoint = {};
+function ($, window) {
    /**
     * Generate a Point object with all needed information.
     * @param pointData Some information from HTML attribute, after parsed to JSON.
     * @returns {{}} A point object.
     */
    var initPoint = function (pointData) {
        /**
         * Schema of point.
         */
        var point = {
            eventKey: '',
            eventValue: {},
            url: '',
            header: {}
        };

        /**
         * Insert data.
         */
        point.eventKey = pointData.eventKey;
        point.url = window.location.pathname + window.location.hash;
        // EventValue.
        point.eventValue.fromUrl = window.location.pathname + window.location.hash;
        // point.eventValue.preEventKey = simpleStorage.get('lastPoint.eventKey');
        // Header.
        +function () {
            var tempQudao = window.location.search;
            if (tempQudao !== '') {
                tempQudao = tempQudao.match(/(?:q\=).+/)[0].slice(2);
            }
            var q = tempQudao;
            if (q !== undefined || null) {
                if (point.header === undefined) {
                    point.header = {};
                }
                point.header.q = q;
            }
        }();

        /**
         * Traversal elements of the value of this directive.
         * If there is a same key in {point}, give the value into point.
         * Else put the key-value in the point.eventValue.
         */
        for (var i in pointData) {
            if (point[i] === undefined) {
                point.eventValue[i] = pointData[i];
            } else {
                point[i] = pointData[i];
            }
        }

        /**
         * Delete empty fields.
         */
        for (var i in point) {
            if (point[i] === '') {
                delete point[i];
            }
        }

        return point;
    };

    /**
     * Send point data with Ajax.
     * @param pointData
     */
    var sendPoint = function (pointData) {
        var point = initPoint(pointData);

        /**
         * Save this point as lastPoint in simpleStorage.
         */
            //simpleStorage.set('lastPoint.eventKey', point.eventKey);
            //simpleStorage.set('lastPoint.url', point.url);

        $.ajax({
            async: false,
            type: 'POST',
            url: 'http://localhost/point/' + window.location.search,
            crossDomain: true,
            dataType: 'json',
            data: {"point": point},
            error: function (XMLHttpRequest, textStatus, err) {
                //console.error(err);
                //console.error(point);
            }
        });
    };

    /**
     * Bind an event to this HTML element.
     * @param pointData
     */
    var buryPoint = function (element, pointData) {
        if (!pointData.eventKey) throw new Error('No EventKey Be Defined');

        /**
         * Automatically bind event on this element.
         */
        if (pointData.eventKey.indexOf('click') === 0) {
            // This is the click event.
            $(element).on('click', function () {
                sendPoint(pointData);
            });
        } else if (pointData.eventKey.indexOf('enter') === 0) {
            // This is the enter event.
            pointData.fromUrl = window.location.href;
            sendPoint(pointData);
        } else {
            // This is other event launched by javascript.
            sendPoint(pointData);
        }
    };
    var document = window.document;
    $(document).ready(function () {
        $('[post-point]').each(function (index, element) {
            var data = $(element).attr('post-point');

            /**
             * Check if the value is just a string, then use it as eventKey.
             */
            if (new RegExp(/[\{\[]/igm).test(data)) {
                try {
                    data = JSON.parse(data);
                } catch (err) {
                    console.error(err.stack);
                    console.error('The JSON string is:' + data);
                }
            } else {
                data = {"eventKey": data};
            }

            if ($.isArray(data)) {
                for (var i in data) {
                    buryPoint(element, data[i]);
                }
            } else {
                buryPoint(element, data);
            }
        });
    });
    postPoint.buryPoint = buryPoint;
}(jQuery, window);

//q for sharing platform
var createShareUrl = function (q) {
    var url = '';
    switch (q) {
        case 'qq':
            var p = {
                url: location.href,
                desc: '我在洋葱数学预习了' + document.title + '，轻松搞笑，知识讲解秒懂！不怕老师上课提问了～',
                title: '洋葱数学',
                summary: '洋葱数学：科学预习神器',
                pics: $('#video-thumbnail').attr('thumbnail')
            };
            var s = [];
            for (var i in p) {
                s.push(i + '=' + encodeURIComponent(p[i] || ''));
            }
            url = 'http://connect.qq.com/widget/shareqq/index.html?' + s.join('&');

            //url = 'http://connect.qq.com/widget/shareqq/index.html?url=' + window.location.href + '&title=洋葱数学';
            break;
        case 'qzone':
            var p = {
                url: location.href,
                showcount: '0',
                desc: '我在洋葱数学预习了' + document.title + '，轻松搞笑，知识讲解秒懂！不怕老师上课提问了～',
                summary: '洋葱数学：科学预习神器',
                title: '洋葱数学',
                pics: $('#video-thumbnail').attr('thumbnail')
            };
            var s = [];
            for (var i in p) {
                s.push(i + '=' + encodeURIComponent(p[i] || ''));
            }
            url = 'http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?' + s.join('&');
            //url = 'http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=' + window.location.href + '&shoucount=0&title=洋葱数学&summary=洋葱数学';
            break;
        case 'weibo':
            //url = 'http://service.weibo.com/share/share.php?url=' + window.location.href + '&type=button&language=zh_cn&appkey=1623791526&searchPic=false&style=simple';
            url = 'http://service.weibo.com/share/share.php?url=' + window.location.href + '&type=button&ralateUid=5341300586&language=zh_cn&appkey=1623791526&title=' + '我在洋葱数学预习了' + document.title + '，轻松搞笑，知识讲解秒懂！不怕老师上课提问了～' + '&pic=' + $('#video-thumbnail').attr('thumbnail') + '&searchPic=false&style=simple';
            break;
    }
    var win = window.open(url, '_blank');
    win.focus();
    //window.location.href= url + "?backurl="+ window.location.href;
}

if (bowser.android) {
    $('#mobileluodi').removeAttr('style');
    $('#pcluodi').remove();
    $('body').removeClass('pc');
    // $('body').addClass('mobile');
    $('#yangcong-logo').after('下载洋葱数学，看更多优质初中视频
');
    $('#footer-url').attr('href', 'http://m.yangcong345.com/api/apk/latest.apk');
    $('#yangcong-logo').attr('src', 'yangcong.png');
}
else if (bowser.ios) {
    $('#mobileluodi').removeAttr('style');
    $('#pcluodi').remove();
    $('body').removeClass('pc');
    // $('body').addClass('mobile');
    $('#yangcong-logo').after('更多优质视频，请通过电脑访问yangcong345.com
');
    $('#footer-url').attr('href', 'javascript: void(0)');
    $('#yangcong-logo').attr('src', 'yangcongIos.png');

}
else {
    $('#mobileluodi').remove();
}
<commit_msg>[ronfe] change the trackpoint url<commit_after>//Track data
/**
 * Created by ronfe on 15-5-5.
 */

/**
 * Created by libook on 15-1-22.
 */
'use strict';
/**
 * You can use this attribute like these:
 * <element post-point="clickSomething"></element>
 * <element post-point='{"eventKey":"clickSomething","moredata":"somedata"}'></element>
 * <element post-point='[{"eventKey":"clickSomething"},{"eventKey":"enterSomething"}]'></element>
 *
 * The eventKey may start with 'click' or 'enter'.
 * And this attribute can automatically bind event like that.
 *
 * If you need to record other kind of events, you can also use this function with javascript like this:
 * postPoint.buryPoint(element, pointData);
 * And the point will be sent immediately.
 */
var postPoint = {};
+function ($, window) {
    /**
     * Generate a Point object with all needed information.
     * @param pointData Some information from HTML attribute, after parsed to JSON.
     * @returns {{}} A point object.
     */
    var initPoint = function (pointData) {
        /**
         * Schema of point.
         */
        var point = {
            eventKey: '',
            eventValue: {},
            url: '',
            header: {}
        };

        /**
         * Insert data.
         */
        point.eventKey = pointData.eventKey;
        point.url = window.location.pathname + window.location.hash;
        // EventValue.
        point.eventValue.fromUrl = window.location.pathname + window.location.hash;
        // point.eventValue.preEventKey = simpleStorage.get('lastPoint.eventKey');
        // Header.
        +function () {
            var tempQudao = window.location.search;
            if (tempQudao !== '') {
                tempQudao = tempQudao.match(/(?:q\=).+/)[0].slice(2);
            }
            var q = tempQudao;
            if (q !== undefined || null) {
                if (point.header === undefined) {
                    point.header = {};
                }
                point.header.q = q;
            }
        }();

        /**
         * Traversal elements of the value of this directive.
         * If there is a same key in {point}, give the value into point.
         * Else put the key-value in the point.eventValue.
         */
        for (var i in pointData) {
            if (point[i] === undefined) {
                point.eventValue[i] = pointData[i];
            } else {
                point[i] = pointData[i];
            }
        }

        /**
         * Delete empty fields.
         */
        for (var i in point) {
            if (point[i] === '') {
                delete point[i];
            }
        }

        return point;
    };

    /**
     * Send point data with Ajax.
     * @param pointData
     */
    var sendPoint = function (pointData) {
        var point = initPoint(pointData);

        /**
         * Save this point as lastPoint in simpleStorage.
         */
            //simpleStorage.set('lastPoint.eventKey', point.eventKey);
            //simpleStorage.set('lastPoint.url', point.url);

        $.ajax({
            async: false,
            type: 'POST',
            url: 'http://yangcong345.com/point/' + window.location.search,
            crossDomain: true,
            dataType: 'json',
            data: {"point": point},
            error: function (XMLHttpRequest, textStatus, err) {
                //console.error(err);
                //console.error(point);
            }
        });
    };

    /**
     * Bind an event to this HTML element.
     * @param pointData
     */
    var buryPoint = function (element, pointData) {
        if (!pointData.eventKey) throw new Error('No EventKey Be Defined');

        /**
         * Automatically bind event on this element.
         */
        if (pointData.eventKey.indexOf('click') === 0) {
            // This is the click event.
            $(element).on('click', function () {
                sendPoint(pointData);
            });
        } else if (pointData.eventKey.indexOf('enter') === 0) {
            // This is the enter event.
            pointData.fromUrl = window.location.href;
            sendPoint(pointData);
        } else {
            // This is other event launched by javascript.
            sendPoint(pointData);
        }
    };
    var document = window.document;
    $(document).ready(function () {
        $('[post-point]').each(function (index, element) {
            var data = $(element).attr('post-point');

            /**
             * Check if the value is just a string, then use it as eventKey.
             */
            if (new RegExp(/[\{\[]/igm).test(data)) {
                try {
                    data = JSON.parse(data);
                } catch (err) {
                    console.error(err.stack);
                    console.error('The JSON string is:' + data);
                }
            } else {
                data = {"eventKey": data};
            }

            if ($.isArray(data)) {
                for (var i in data) {
                    buryPoint(element, data[i]);
                }
            } else {
                buryPoint(element, data);
            }
        });
    });
    postPoint.buryPoint = buryPoint;
}(jQuery, window);

//q for sharing platform
var createShareUrl = function (q) {
    var url = '';
    switch (q) {
        case 'qq':
            var p = {
                url: location.href,
                desc: '我在洋葱数学预习了' + document.title + '，轻松搞笑，知识讲解秒懂！不怕老师上课提问了～',
                title: '洋葱数学',
                summary: '洋葱数学：科学预习神器',
                pics: $('#video-thumbnail').attr('thumbnail')
            };
            var s = [];
            for (var i in p) {
                s.push(i + '=' + encodeURIComponent(p[i] || ''));
            }
            url = 'http://connect.qq.com/widget/shareqq/index.html?' + s.join('&');

            //url = 'http://connect.qq.com/widget/shareqq/index.html?url=' + window.location.href + '&title=洋葱数学';
            break;
        case 'qzone':
            var p = {
                url: location.href,
                showcount: '0',
                desc: '我在洋葱数学预习了' + document.title + '，轻松搞笑，知识讲解秒懂！不怕老师上课提问了～',
                summary: '洋葱数学：科学预习神器',
                title: '洋葱数学',
                pics: $('#video-thumbnail').attr('thumbnail')
            };
            var s = [];
            for (var i in p) {
                s.push(i + '=' + encodeURIComponent(p[i] || ''));
            }
            url = 'http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?' + s.join('&');
            //url = 'http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=' + window.location.href + '&shoucount=0&title=洋葱数学&summary=洋葱数学';
            break;
        case 'weibo':
            //url = 'http://service.weibo.com/share/share.php?url=' + window.location.href + '&type=button&language=zh_cn&appkey=1623791526&searchPic=false&style=simple';
            url = 'http://service.weibo.com/share/share.php?url=' + window.location.href + '&type=button&ralateUid=5341300586&language=zh_cn&appkey=1623791526&title=' + '我在洋葱数学预习了' + document.title + '，轻松搞笑，知识讲解秒懂！不怕老师上课提问了～' + '&pic=' + $('#video-thumbnail').attr('thumbnail') + '&searchPic=false&style=simple';
            break;
    }
    var win = window.open(url, '_blank');
    win.focus();
    //window.location.href= url + "?backurl="+ window.location.href;
}

if (bowser.android) {
    $('#mobileluodi').removeAttr('style');
    $('#pcluodi').remove();
    $('body').removeClass('pc');
    // $('body').addClass('mobile');
    $('#yangcong-logo').after('下载洋葱数学，看更多优质初中视频
');
    $('#footer-url').attr('href', 'http://m.yangcong345.com/api/apk/latest.apk');
    $('#yangcong-logo').attr('src', 'yangcong.png');
}
else if (bowser.ios) {
    $('#mobileluodi').removeAttr('style');
    $('#pcluodi').remove();
    $('body').removeClass('pc');
    // $('body').addClass('mobile');
    $('#yangcong-logo').after('更多优质视频，请通过电脑访问yangcong345.com
');
    $('#footer-url').attr('href', 'javascript: void(0)');
    $('#yangcong-logo').attr('src', 'yangcongIos.png');

}
else {
    $('#mobileluodi').remove();
}
<|endoftext|>


<commit_before>import $$observable from 'symbol-observable'

function observerPlugin(router) {
    let listeners = []

    function unsubscribe(listener) {
        if (listener) {
            listeners = listeners.filter(l => l !== listener)
        }
    }

    function subscribe(listener) {
        const finalListener =
            typeof listener === 'object' ? listener.next : listener

        listeners = listeners.concat(finalListener)

        return () => unsubscribe(finalListener)
    }

    function observable() {
        return {
            subscribe(observer) {
                if (typeof observer !== 'object' || observer === null) {
                    throw new TypeError(
                        'Expected the observer to be an object.'
                    )
                }

                function listener() {
                    if (observer.next) {
                        observer.next(router.getState())
                    }
                }

                listener()
                const unsubscribe = subscribe(listener)
                return { unsubscribe }
            },

            [$$observable]() {
                return this
            }
        }
    }

    router.subscribe = subscribe
    router[$$observable] = observable

    return {
        onTransitionSuccess: (toState, fromState) => {
            listeners.forEach(listener =>
                listener({
                    route: toState,
                    previousRoute: fromState
                })
            )
        }
    }
}

observerPlugin.pluginName = 'OBSERVABLE_PLUGIN'

export default function withObservablePlugin(router) {
    router.usePlugin(observerPlugin)
}
<commit_msg>refactor: improve observable interoperability<commit_after>import $$observable from 'symbol-observable'

function observerPlugin(router) {
    let listeners = []

    function unsubscribe(listener) {
        if (listener) {
            listeners = listeners.filter(l => l !== listener)
        }
    }

    function subscribe(listener) {
        const finalListener =
            typeof listener === 'object'
                ? listener.next.bind(listener)
                : listener

        listeners = listeners.concat(finalListener)

        return () => unsubscribe(finalListener)
    }

    function observable() {
        return {
            subscribe(observer) {
                if (typeof observer !== 'object' || observer === null) {
                    throw new TypeError(
                        'Expected the observer to be an object.'
                    )
                }
                const unsubscribe = subscribe(observer)

                return { unsubscribe }
            },

            [$$observable]() {
                return this
            }
        }
    }

    router.subscribe = subscribe
    router[$$observable] = observable

    return {
        onTransitionSuccess: (toState, fromState) => {
            listeners.forEach(listener =>
                listener({
                    route: toState,
                    previousRoute: fromState
                })
            )
        }
    }
}

observerPlugin.pluginName = 'OBSERVABLE_PLUGIN'

export default function withObservablePlugin(router) {
    router.usePlugin(observerPlugin)
}
<|endoftext|>


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

var crypto = require('crypto');

var keys = {};

test('reject unauthorized hosts', function (t) {
    t.plan(1);

    var server = seaport.createServer({
        authorized : [ keys.public ]
    });
    server.listen(0);

    server.on('register', function (service) {
        t.fail('registered when it should have been rejected');
    });

    var ports = seaport.connect(server.address().port);
    ports.on('reject', function (rejected) {
        t.equal(port, rejected);
    });

    var port = ports.register('http');

    t.on('end', function () {
        server.close();
        ports.close();
    });
});
<commit_msg>actually generate the keys in the failing rejected test<commit_after>var test = require('tap').test;
var seaport = require('../');

var crypto = require('crypto');

var keys = [
    (function () {
        // never use a value this low in real code
        // 256 just makes the test run faster
        var d = crypto.createDiffieHellman(256);
        d.generateKeys();
        return {
            public : d.getPublicKey('base64'),
            private : d.getPrivateKey('base64')
        };
    })()
];

test('reject unauthorized hosts', function (t) {
    t.plan(1);

    var server = seaport.createServer({ authorized : keys });
    server.listen(0);

    server.on('register', function (service) {
        t.fail('registered when it should have been rejected');
    });

    var ports = seaport.connect(server.address().port);
    ports.on('reject', function (rejected) {
        t.equal(port, rejected);
    });

    var port = ports.register('http');

    t.on('end', function () {
        server.close();
        ports.close();
    });
});
<|endoftext|>


<commit_before>require('../config/setDefault');

process.on('unhandledRejection', err => {
  console.error(err);
});

const express = require('express');
const next = require('next');
const { join } = require('path');
const { createRouter } = require('soya-next/server/router');
const config = require('config');
// @remove-on-eject-begin
const conf = require('../next.config');
// @remove-on-eject-end

const { appDir } = require('../config/paths');
const dev = typeof config.dev !== 'undefined' ? config.dev : process.env.NODE_ENV !== 'production';
const app = next({
  dev,
  // @remove-on-eject-begin
  conf,
  // @remove-on-eject-end
});
const buildSoya = require('./utils/build-soya');

app.prepare()
  .then(() => dev ? buildSoya({ dev }) : null)
  .then(() => require.resolve('soya'))
  .then(
    stats => stats ? require(join(appDir, 'build/server', 'index.js')).default : null,
    err => {
      if (err.code !== 'MODULE_NOT_FOUND') {
        throw err;
      }
    }
  )
  .then((soyaMiddleware = null) => {
    const server = express();
    if (config.basePath) {
      server.use((req, res, next) => {
        if (req.url.startsWith(config.basePath)) {
          req.url = req.url.replace(new RegExp(`^${config.basePath}/*`), "/");
        } else if (dev && ![
          '/_next/webpack-hmr',
          '/_next/on-demand-entries-ping',
        ].some(prefix => req.url.startsWith(prefix))) {
          return app.send404(res);
        }
        next();
      });
    }
    if (soyaMiddleware !== null) {
      server.use(soyaMiddleware);
    }
    server.use('/_soya/:path(*)', (req, res) => {
      const p = join(app.dir, app.dist, 'dist', 'static', req.params.path);
      app.serveStatic(req, res, p);
    });
    server.use(createRouter(app, {
      routes: config.routes,
      redirects: config.redirects,
      defaultLocale: config.defaultLocale,
      siteLocales: config.siteLocales,
      compression: config.server.compression,
      whoami: config.whoami,
    }));
    server.listen(config.server.port, config.server.host, err => {
      if (err) {
        throw err;
      }

      if (typeof process.send === 'function') {
        process.send('ready');
      }

      // eslint-disable-next-line no-console
      console.log(`> Ready on ${config.server.host}:${config.server.port}`);
    });
  })
  .catch(ex => {
    // eslint-disable-next-line no-console
    console.error(ex.stack);
    process.exit(1);
  });
<commit_msg>Exclude soya to not use basePath<commit_after>require('../config/setDefault');

process.on('unhandledRejection', err => {
  console.error(err);
});

const express = require('express');
const next = require('next');
const { join } = require('path');
const { createRouter } = require('soya-next/server/router');
const config = require('config');
// @remove-on-eject-begin
const conf = require('../next.config');
// @remove-on-eject-end

const { appDir } = require('../config/paths');
const dev = typeof config.dev !== 'undefined' ? config.dev : process.env.NODE_ENV !== 'production';
const app = next({
  dev,
  // @remove-on-eject-begin
  conf,
  // @remove-on-eject-end
});
const buildSoya = require('./utils/build-soya');

app.prepare()
  .then(() => dev ? buildSoya({ dev }) : null)
  .then(() => require.resolve('soya'))
  .then(
    stats => stats ? require(join(appDir, 'build/server', 'index.js')).default : null,
    err => {
      if (err.code !== 'MODULE_NOT_FOUND') {
        throw err;
      }
    }
  )
  .then((soyaMiddleware = null) => {
    const server = express();
    if (soyaMiddleware !== null) {
      server.use(soyaMiddleware);
    }
    if (config.basePath) {
      server.use((req, res, next) => {
        if (req.url.startsWith(config.basePath)) {
          req.url = req.url.replace(new RegExp(`^${config.basePath}/*`), "/");
        } else if (dev && ![
          '/_next/webpack-hmr',
          '/_next/on-demand-entries-ping',
        ].some(prefix => req.url.startsWith(prefix))) {
          return app.send404(res);
        }
        next();
      });
    }
    server.use('/_soya/:path(*)', (req, res) => {
      const p = join(app.dir, app.dist, 'dist', 'static', req.params.path);
      app.serveStatic(req, res, p);
    });
    server.use(createRouter(app, {
      routes: config.routes,
      redirects: config.redirects,
      defaultLocale: config.defaultLocale,
      siteLocales: config.siteLocales,
      compression: config.server.compression,
      whoami: config.whoami,
    }));
    server.listen(config.server.port, config.server.host, err => {
      if (err) {
        throw err;
      }

      if (typeof process.send === 'function') {
        process.send('ready');
      }

      // eslint-disable-next-line no-console
      console.log(`> Ready on ${config.server.host}:${config.server.port}`);
    });
  })
  .catch(ex => {
    // eslint-disable-next-line no-console
    console.error(ex.stack);
    process.exit(1);
  });
<|endoftext|>


<commit_before>const faker = require("faker");
const addContext = require("mochawesome/addContext");
const commands = require("../utils/commands");

const Blueprint = require("../components/Blueprint.component");
const blueprintsPage = require("../pages/blueprints.page");
const ViewBlueprintPage = require("../pages/ViewBlueprint.page");

describe("View Blueprint Page", function() {
  const name = faker.lorem.slug();
  const description = faker.lorem.sentence();
  const blueprintComponent = new Blueprint(name);
  const viewBlueprintPage = new ViewBlueprintPage(name, description);

  before(function() {
    commands.login();
    commands.startLoraxIfItDoesNotStart();
  });

  after(function() {
    commands.deleteBlueprint(name);
    blueprintsPage.loading();
  });

  describe("Run test on a new blueprint", function() {
    before(function() {
      addContext(this, `create new blueprint with name, ${name}, and description, ${description}`);
      commands.newBlueprint(name, description);
      blueprintComponent.blueprintNameLink.click();
      viewBlueprintPage.loading();
    });

    after(function() {
      viewBlueprintPage.backToBlueprintsLink.click();
      blueprintsPage.loading();
    });

    describe("Page element checking", function() {
      it(`blueprint name in navigation bar should be "${name}"`, function() {
        expect(viewBlueprintPage.navigationBlueprintNameLabel.getText()).to.equal(name);
      });

      it(`blueprint name in header should be "${name}"`, function() {
        expect(viewBlueprintPage.headerBlueprintNameLabel.getText()).to.equal(name);
      });

      it(`blueprint description in header should be "${description}"`, function() {
        expect(viewBlueprintPage.headerBlueprintDescriptionLabel.getText()).to.equal(description);
      });

      it('"Details" tab should be active by default', function() {
        expect(viewBlueprintPage.detailsTab.getAttribute("aria-selected")).to.equal("true");
      });
    });

    describe('"Details" tab', function() {
      it(`blueprint description under "Details" tab should be "${description}"`, function() {
        expect(viewBlueprintPage.detailsTabBlueprintDescriptionLabel.getText()).to.equal(description);
      });

      it("click X button => blueprint description not updated", function() {
        viewBlueprintPage.editBlueprintDescriptionButton.click();
        viewBlueprintPage.descriptionInputBox.setValue(faker.lorem.sentence());
        viewBlueprintPage.cancelButton.click();
        expect(viewBlueprintPage.detailsTabBlueprintDescriptionLabel.getText()).to.equal(description);
      });

      it("blueprint description should be updated", function() {
        const updatedDescription = faker.lorem.sentence();
        viewBlueprintPage.editBlueprintDescriptionButton.click();
        viewBlueprintPage.descriptionInputBox.setValue(updatedDescription);
        viewBlueprintPage.okButton.click();
        expect(viewBlueprintPage.updatedBlueprintDescriptionLabel(updatedDescription).getText()).to.equal(
          updatedDescription
        );
      });

      it("hostname should be added", function() {
        const hostname = faker.lorem.slug();
        viewBlueprintPage.editHostnameButton.click();
        viewBlueprintPage.hostnameInputBox.setValue(hostname);
        viewBlueprintPage.okHostnameButton.click();
        // UI should get updated
        expect(viewBlueprintPage.detailsTabHostnameLabel(hostname).getText()).to.equal(hostname);

        // get dependencies from API
        const endpoint = `/api/v0/blueprints/info/${name}`;
        const result = commands.apiFetchTest(endpoint).value;
        // result looks like:
        // https://github.com/weldr/lorax/blob/b57de934681056aa4f9bd480a34136cf340f510a/src/pylorax/api/v0.py#L66
        const result_hostname = JSON.parse(result.data).blueprints[0].customizations.hostname;
        // new hostname should be stored
        expect(result_hostname).to.equal(hostname);
      });

      it("hostname should be updated", function() {
        const hostname = faker.lorem.slug();
        viewBlueprintPage.editHostnameButton.click();
        viewBlueprintPage.hostnameInputBox.setValue(hostname);
        viewBlueprintPage.okHostnameButton.click();
        // UI should get updated
        expect(viewBlueprintPage.detailsTabHostnameLabel(hostname).getText()).to.equal(hostname);

        // get dependencies from API
        const endpoint = `/api/v0/blueprints/info/${name}`;
        const result = commands.apiFetchTest(endpoint).value;
        // result looks like:
        // https://github.com/weldr/lorax/blob/b57de934681056aa4f9bd480a34136cf340f510a/src/pylorax/api/v0.py#L66
        const result_hostname = JSON.parse(result.data).blueprints[0].customizations.hostname;
        // new hostname should be stored
        expect(result_hostname).to.equal(hostname);
      });

      it("hostname should not get updated by clicking X button", function() {
        // set a new hostname in this test
        const hostname = faker.lorem.slug();
        viewBlueprintPage.editHostnameButton.click();
        viewBlueprintPage.hostnameInputBox.setValue(hostname);
        viewBlueprintPage.okHostnameButton.click();
        // update hostname and click X button
        viewBlueprintPage.editHostnameButton.click();
        viewBlueprintPage.hostnameInputBox.setValue(faker.lorem.slug());
        viewBlueprintPage.cancelHostnameButton.click();
        // UI should get updated
        expect(viewBlueprintPage.detailsTabHostnameLabel(hostname).getText()).to.equal(hostname);
      });

      it("disable OK button and show error input box if hostname has invalid character", function() {
        viewBlueprintPage.editHostnameButton.click();
        // input ?, invalid hostname character
        viewBlueprintPage.hostnameInputBox.setValue("?");
        // OK button should be disabled
        expect(viewBlueprintPage.okHostnameButton.getAttribute("type")).to.equal("button");
        expect(viewBlueprintPage.okHostnameButton.getAttribute("disabled")).to.equal("true");
        // input box should be an error box
        expect(browser.getAttribute('[data-form="hostname"]', "class")).to.include("has-error");
        // cancel edit to clear environment
        viewBlueprintPage.cancelHostnameButton.click();
      });
    });

    describe("Edit Blueprint", function() {
      const EditBlueprintPage = require("../pages/EditBlueprint.page");
      const editBlueprintPage = new EditBlueprintPage(name);

      before(function() {
        viewBlueprintPage.editBlueprintButton.click();
        editBlueprintPage.loading();
      });

      after(function() {
        editBlueprintPage.blueprintNameLink.click();
        viewBlueprintPage.loading();
      });

      it("should go to Edit Blueprint page by clicking Edit Blueprint button", function() {
        expect(editBlueprintPage.blueprintNameLabel.getText()).to.equal(name);
      });
    });

    describe("Export Blueprint", function() {
      const ExportPage = require("../pages/Export.page");
      const exportPage = new ExportPage(name);
      it("should copy correct blueprint manifest", function() {
        viewBlueprintPage.moreButton.click();
        browser.keys("ArrowDown");
        browser.keys("Enter");
        exportPage.loading();
        // getText() does not work here on Edge, but works on Firefox and Chrome
        // the copied content should replace '\n' with space because
        // the text in blueprint description box does not include '\n', but space
        const blueprintManifest = exportPage.contentsTextarea.getValue().replace(/\n/g, " ");
        exportPage.copyButton.click();
        exportPage.closeButton.click();
        browser.waitForExist(exportPage.containerSelector, timeout, true);
        // back to view blueprint page for pasting
        viewBlueprintPage.selectedComponentsTab.click();
        // paste blueprint manifest here to test copy function
        viewBlueprintPage.selectedComponentFilter.click();
        viewBlueprintPage.selectedComponentFilter.setValue(["Control", "v"]);
        viewBlueprintPage.selectedComponentFilter.waitForValue(timeout);
        expect(viewBlueprintPage.selectedComponentFilter.getValue()).to.equal(blueprintManifest);
      });
    });
  });
});
<commit_msg>test: skip copied content checking on Edge<commit_after>const faker = require("faker");
const addContext = require("mochawesome/addContext");
const commands = require("../utils/commands");
const wdioConfig = require("../wdio.conf.js");

const Blueprint = require("../components/Blueprint.component");
const blueprintsPage = require("../pages/blueprints.page");
const ViewBlueprintPage = require("../pages/ViewBlueprint.page");

describe("View Blueprint Page", function() {
  const name = faker.lorem.slug();
  const description = faker.lorem.sentence();
  const blueprintComponent = new Blueprint(name);
  const viewBlueprintPage = new ViewBlueprintPage(name, description);

  before(function() {
    commands.login();
    commands.startLoraxIfItDoesNotStart();
  });

  after(function() {
    commands.deleteBlueprint(name);
    blueprintsPage.loading();
  });

  describe("Run test on a new blueprint", function() {
    before(function() {
      addContext(this, `create new blueprint with name, ${name}, and description, ${description}`);
      commands.newBlueprint(name, description);
      blueprintComponent.blueprintNameLink.click();
      viewBlueprintPage.loading();
    });

    after(function() {
      viewBlueprintPage.backToBlueprintsLink.click();
      blueprintsPage.loading();
    });

    describe("Page element checking", function() {
      it(`blueprint name in navigation bar should be "${name}"`, function() {
        expect(viewBlueprintPage.navigationBlueprintNameLabel.getText()).to.equal(name);
      });

      it(`blueprint name in header should be "${name}"`, function() {
        expect(viewBlueprintPage.headerBlueprintNameLabel.getText()).to.equal(name);
      });

      it(`blueprint description in header should be "${description}"`, function() {
        expect(viewBlueprintPage.headerBlueprintDescriptionLabel.getText()).to.equal(description);
      });

      it('"Details" tab should be active by default', function() {
        expect(viewBlueprintPage.detailsTab.getAttribute("aria-selected")).to.equal("true");
      });
    });

    describe('"Details" tab', function() {
      it(`blueprint description under "Details" tab should be "${description}"`, function() {
        expect(viewBlueprintPage.detailsTabBlueprintDescriptionLabel.getText()).to.equal(description);
      });

      it("click X button => blueprint description not updated", function() {
        viewBlueprintPage.editBlueprintDescriptionButton.click();
        viewBlueprintPage.descriptionInputBox.setValue(faker.lorem.sentence());
        viewBlueprintPage.cancelButton.click();
        expect(viewBlueprintPage.detailsTabBlueprintDescriptionLabel.getText()).to.equal(description);
      });

      it("blueprint description should be updated", function() {
        const updatedDescription = faker.lorem.sentence();
        viewBlueprintPage.editBlueprintDescriptionButton.click();
        viewBlueprintPage.descriptionInputBox.setValue(updatedDescription);
        viewBlueprintPage.okButton.click();
        expect(viewBlueprintPage.updatedBlueprintDescriptionLabel(updatedDescription).getText()).to.equal(
          updatedDescription
        );
      });

      it("hostname should be added", function() {
        const hostname = faker.lorem.slug();
        viewBlueprintPage.editHostnameButton.click();
        viewBlueprintPage.hostnameInputBox.setValue(hostname);
        viewBlueprintPage.okHostnameButton.click();
        // UI should get updated
        expect(viewBlueprintPage.detailsTabHostnameLabel(hostname).getText()).to.equal(hostname);

        // get dependencies from API
        const endpoint = `/api/v0/blueprints/info/${name}`;
        const result = commands.apiFetchTest(endpoint).value;
        // result looks like:
        // https://github.com/weldr/lorax/blob/b57de934681056aa4f9bd480a34136cf340f510a/src/pylorax/api/v0.py#L66
        const result_hostname = JSON.parse(result.data).blueprints[0].customizations.hostname;
        // new hostname should be stored
        expect(result_hostname).to.equal(hostname);
      });

      it("hostname should be updated", function() {
        const hostname = faker.lorem.slug();
        viewBlueprintPage.editHostnameButton.click();
        viewBlueprintPage.hostnameInputBox.setValue(hostname);
        viewBlueprintPage.okHostnameButton.click();
        // UI should get updated
        expect(viewBlueprintPage.detailsTabHostnameLabel(hostname).getText()).to.equal(hostname);

        // get dependencies from API
        const endpoint = `/api/v0/blueprints/info/${name}`;
        const result = commands.apiFetchTest(endpoint).value;
        // result looks like:
        // https://github.com/weldr/lorax/blob/b57de934681056aa4f9bd480a34136cf340f510a/src/pylorax/api/v0.py#L66
        const result_hostname = JSON.parse(result.data).blueprints[0].customizations.hostname;
        // new hostname should be stored
        expect(result_hostname).to.equal(hostname);
      });

      it("hostname should not get updated by clicking X button", function() {
        // set a new hostname in this test
        const hostname = faker.lorem.slug();
        viewBlueprintPage.editHostnameButton.click();
        viewBlueprintPage.hostnameInputBox.setValue(hostname);
        viewBlueprintPage.okHostnameButton.click();
        // update hostname and click X button
        viewBlueprintPage.editHostnameButton.click();
        viewBlueprintPage.hostnameInputBox.setValue(faker.lorem.slug());
        viewBlueprintPage.cancelHostnameButton.click();
        // UI should get updated
        expect(viewBlueprintPage.detailsTabHostnameLabel(hostname).getText()).to.equal(hostname);
      });

      it("disable OK button and show error input box if hostname has invalid character", function() {
        viewBlueprintPage.editHostnameButton.click();
        // input ?, invalid hostname character
        viewBlueprintPage.hostnameInputBox.setValue("?");
        // OK button should be disabled
        expect(viewBlueprintPage.okHostnameButton.getAttribute("type")).to.equal("button");
        expect(viewBlueprintPage.okHostnameButton.getAttribute("disabled")).to.equal("true");
        // input box should be an error box
        expect(browser.getAttribute('[data-form="hostname"]', "class")).to.include("has-error");
        // cancel edit to clear environment
        viewBlueprintPage.cancelHostnameButton.click();
      });
    });

    describe("Edit Blueprint", function() {
      const EditBlueprintPage = require("../pages/EditBlueprint.page");
      const editBlueprintPage = new EditBlueprintPage(name);

      before(function() {
        viewBlueprintPage.editBlueprintButton.click();
        editBlueprintPage.loading();
      });

      after(function() {
        editBlueprintPage.blueprintNameLink.click();
        viewBlueprintPage.loading();
      });

      it("should go to Edit Blueprint page by clicking Edit Blueprint button", function() {
        expect(editBlueprintPage.blueprintNameLabel.getText()).to.equal(name);
      });
    });

    describe("Export Blueprint", function() {
      const ExportPage = require("../pages/Export.page");
      const exportPage = new ExportPage(name);
      it("should copy correct blueprint manifest", function() {
        viewBlueprintPage.moreButton.click();
        browser.keys("ArrowDown");
        browser.keys("Enter");
        exportPage.loading();
        // getText() does not work here on Edge, but works on Firefox and Chrome
        // the copied content should replace '\n' with space because
        // the text in blueprint description box does not include '\n', but space
        const blueprintManifest = exportPage.contentsTextarea.getValue().replace(/\n/g, " ");
        exportPage.copyButton.click();
        exportPage.closeButton.click();
        browser.waitForExist(exportPage.containerSelector, timeout, true);
        if (wdioConfig.config.capabilities[0].browserName !== "MicrosoftEdge") {
          // back to view blueprint page for pasting
          viewBlueprintPage.selectedComponentsTab.click();
          // paste blueprint manifest here to test copy function
          viewBlueprintPage.selectedComponentFilter.click();
          viewBlueprintPage.selectedComponentFilter.setValue(["Control", "v"]);
          viewBlueprintPage.selectedComponentFilter.waitForValue(timeout);
          expect(viewBlueprintPage.selectedComponentFilter.getValue()).to.equal(blueprintManifest);
        }
      });
    });
  });
});
<|endoftext|>