<commit_before>/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.EffectComposer = function ( renderer, renderTarget ) {

	this.renderer = renderer;

	if ( renderTarget === undefined ) {

		var width = window.innerWidth || 1;
		var height = window.innerHeight || 1;
		var parameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false };

		renderTarget = new THREE.WebGLRenderTarget( width, height, parameters );

	}

	this.renderTarget1 = renderTarget;
	this.renderTarget2 = renderTarget.clone();

	this.writeBuffer = this.renderTarget1;
	this.readBuffer = this.renderTarget2;

	this.passes = [];

	if ( THREE.CopyShader === undefined )
		console.error( "THREE.EffectComposer relies on THREE.CopyShader" );

	this.copyPass = new THREE.ShaderPass( THREE.CopyShader );

};

THREE.EffectComposer.prototype = {

	swapBuffers: function() {

		var tmp = this.readBuffer;
		this.readBuffer = this.writeBuffer;
		this.writeBuffer = tmp;

	},

	addPass: function ( pass ) {

		this.passes.push( pass );

	},

	insertPass: function ( pass, index ) {

		this.passes.splice( index, 0, pass );

	},

	render: function ( delta ) {

		this.writeBuffer = this.renderTarget1;
		this.readBuffer = this.renderTarget2;

		var maskActive = false;

		var pass, i, il = this.passes.length;

		for ( i = 0; i < il; i ++ ) {

			pass = this.passes[ i ];

			if ( !pass.enabled ) continue;

			pass.render( this.renderer, this.writeBuffer, this.readBuffer, delta, maskActive );

			if ( pass.needsSwap ) {

				if ( maskActive ) {

					var context = this.renderer.context;

					context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff );

					this.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer, delta );

					context.stencilFunc( context.EQUAL, 1, 0xffffffff );

				}

				this.swapBuffers();

			}

			if ( pass instanceof THREE.MaskPass ) {

				maskActive = true;

			} else if ( pass instanceof THREE.ClearMaskPass ) {

				maskActive = false;

			}

		}

	},

	reset: function ( renderTarget ) {

		if ( renderTarget === undefined ) {

			renderTarget = this.renderTarget1.clone();

			renderTarget.width = window.innerWidth;
			renderTarget.height = window.innerHeight;

		}

		this.renderTarget1 = renderTarget;
		this.renderTarget2 = renderTarget.clone();

		this.writeBuffer = this.renderTarget1;
		this.readBuffer = this.renderTarget2;

	},

	setSize: function ( width, height ) {

		var renderTarget = this.renderTarget1.clone();

		renderTarget.width = width;
		renderTarget.height = height;

		this.reset( renderTarget );

	}

};

// shared ortho camera

THREE.EffectComposer.camera = new THREE.OrthographicCamera( -1, 1, 1, -1, 0, 1 );

THREE.EffectComposer.quad = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), null );

THREE.EffectComposer.scene = new THREE.Scene();
THREE.EffectComposer.scene.add( THREE.EffectComposer.quad );
<commit_msg>Keep track of active framebuffer for easy read-back<commit_after>/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.EffectComposer = function ( renderer, renderTarget ) {

	this.renderer = renderer;

	if ( renderTarget === undefined ) {

		var width = window.innerWidth || 1;
		var height = window.innerHeight || 1;
		var parameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false };

		renderTarget = new THREE.WebGLRenderTarget( width, height, parameters );

	}

	this.renderTarget1 = renderTarget;
	this.renderTarget2 = renderTarget.clone();

	// Keep track if which one is "active" and store it as our primary
	this.output = this.renderTarget1;

	this.writeBuffer = this.renderTarget1;
	this.readBuffer = this.renderTarget2;
	this.output = this.readBuffer;

	this.passes = [];

	if ( THREE.CopyShader === undefined )
		console.error( "THREE.EffectComposer relies on THREE.CopyShader" );

	this.copyPass = new THREE.ShaderPass( THREE.CopyShader );

};

THREE.EffectComposer.prototype = {

	swapBuffers: function() {

		var tmp = this.readBuffer;
		this.readBuffer = this.writeBuffer;
		this.writeBuffer = tmp;

	},

	addPass: function ( pass ) {

		this.passes.push( pass );

	},

	insertPass: function ( pass, index ) {

		this.passes.splice( index, 0, pass );

	},

	render: function ( delta ) {

		this.writeBuffer = this.renderTarget1;
		this.readBuffer = this.renderTarget2;

		this.output = this.readBuffer;

		var maskActive = false;

		var pass, i, il = this.passes.length;

		for ( i = 0; i < il; i ++ ) {

			pass = this.passes[ i ];

			if ( !pass.enabled ) continue;

			pass.render( this.renderer, this.writeBuffer, this.readBuffer, delta, maskActive );

			if ( pass.needsSwap ) {

				if ( maskActive ) {

					var context = this.renderer.context;

					context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff );

					this.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer, delta );

					context.stencilFunc( context.EQUAL, 1, 0xffffffff );

				}

				this.swapBuffers();

			}

			if ( pass instanceof THREE.MaskPass ) {

				maskActive = true;

			} else if ( pass instanceof THREE.ClearMaskPass ) {

				maskActive = false;

			}

		}

	},

	reset: function ( renderTarget ) {

		if ( renderTarget === undefined ) {

			renderTarget = this.renderTarget1.clone();

			renderTarget.width = window.innerWidth;
			renderTarget.height = window.innerHeight;

		}

		this.renderTarget1 = renderTarget;
		this.renderTarget2 = renderTarget.clone();

		this.writeBuffer = this.renderTarget1;
		this.readBuffer = this.renderTarget2;

	},

	setSize: function ( width, height ) {

		var renderTarget = this.renderTarget1.clone();

		renderTarget.width = width;
		renderTarget.height = height;

		this.reset( renderTarget );

	}

};

// shared ortho camera

THREE.EffectComposer.camera = new THREE.OrthographicCamera( -1, 1, 1, -1, 0, 1 );

THREE.EffectComposer.quad = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), null );

THREE.EffectComposer.scene = new THREE.Scene();
THREE.EffectComposer.scene.add( THREE.EffectComposer.quad );
<|endoftext|>


<commit_before>const assert = require("assert");
const fs = require("fs");
const request = require("request-promise");
const sinon = require("sinon");
const { VersionRange } = require("../../../compilerSupplier/loadingStrategies");
const instance = new VersionRange();
let fileName;
const compilerFileNames = [
  "soljson-v0.4.22+commit.124ca40d.js",
  "soljson-v0.4.23+commit.1534a40d.js",
  "soljson-v0.4.11+commit.124234rd.js"
];

const allVersions = {
  builds: [
    {
      path: "soljson-v0.1.1+commit.6ff4cd6.js",
      version: "0.1.1",
      build: "commit.6ff4cd6",
      longVersion: "0.1.1+commit.6ff4cd6",
      keccak256:
        "0xd8b8c64f4e9de41e6604e6ac30274eff5b80f831f8534f0ad85ec0aff466bb25",
      urls: [
        "bzzr://8f3c028825a1b72645f46920b67dca9432a87fc37a8940a2b2ce1dd6ddc2e29b"
      ]
    },
    {
      path: "soljson-v0.1.2+commit.d0d36e3.js",
      version: "0.1.2",
      build: "commit.d0d36e3",
      longVersion: "0.1.2+commit.d0d36e3",
      keccak256:
        "0xa70b3d4acf77a303efa93c3ddcadd55b8762c7be109fd8f259ec7d6be654f03e",
      urls: [
        "bzzr://e662d71e9b8e1b0311c129b962e678e5dd63487ad9b020ee539d7f74cd7392c9"
      ]
    }
  ],
  releases: {
    "0.5.4": "soljson-v0.5.4+commit.9549d8ff.js",
    "0.5.3": "soljson-v0.5.3+commit.10d17f24.js",
    "0.5.2": "soljson-v0.5.2+commit.1df8f40c.js",
    "0.5.1": "soljson-v0.5.1+commit.c8a2cb62.js",
    "0.5.0": "soljson-v0.5.0+commit.1d4f565a.js",
    "0.4.25": "soljson-v0.4.25+commit.59dbf8f1.js",
    "0.4.24": "soljson-v0.4.24+commit.e67f0147.js",
    "0.4.23": "soljson-v0.4.23+commit.124ca40d.js",
    "0.4.22": "soljson-v0.4.22+commit.4cb486ee.js"
  },
  latestRelease: "0.5.4"
};

describe("VersionRange loading strategy", () => {
  describe("async load(versionRange)", () => {
    beforeEach(() => {
      sinon.stub(instance, "getCachedSolcByVersionRange");
      sinon.stub(instance, "getSolcFromCacheOrUrl");
      sinon.stub(instance, "versionIsCached").returns(true);
      sinon.stub(request, "get").returns("response");
    });
    afterEach(() => {
      instance.getCachedSolcByVersionRange.restore();
      instance.getSolcFromCacheOrUrl.restore();
      instance.versionIsCached.restore();
      request.get.restore();
    });

    it("calls getCachedSolcByVersionRange when single solc is specified", async () => {
      await instance.load("0.5.0");
      assert(instance.getCachedSolcByVersionRange.called);
    });
    it("calls getSolcFromCacheOrUrl when a larger range is specified", async () => {
      await instance.load("^0.5.0");
      assert(instance.getSolcFromCacheOrUrl.called);
    });
  });

  describe("getSolcFromCacheOrUrl(version)", () => {
    beforeEach(() => {
      sinon.stub(instance, "getSolcVersions").returns(allVersions);
      sinon.stub(instance, "getCachedSolcByFileName");
    });
    afterEach(() => {
      instance.getSolcVersions.restore();
      instance.getCachedSolcByFileName.restore();
    });

    describe("when a version constraint is specified", () => {
      beforeEach(() => {
        sinon.stub(instance, "getSolcByUrlAndCache");
      });
      afterEach(() => {
        instance.getSolcByUrlAndCache.restore();
      });

      it("calls findNewstValidVersion to determine which version to fetch", async () => {
        await instance.getSolcFromCacheOrUrl("^0.5.0");
        assert(
          instance.getSolcByUrlAndCache.calledWith(
            "soljson-v0.5.4+commit.9549d8ff.js"
          ),
          "getSolcByUrlAndCache not called with the compiler file name"
        );
      });
    });

    describe("when the version is cached", () => {
      beforeEach(() => {
        sinon.stub(instance, "fileIsCached").returns(true);
      });
      afterEach(() => {
        instance.fileIsCached.restore();
      });

      it("calls getCachedSolcByFileName", async () => {
        await instance.getSolcFromCacheOrUrl("0.5.0");
        assert(
          instance.getCachedSolcByFileName.calledWith(
            "soljson-v0.5.0+commit.1d4f565a.js"
          )
        );
      });
    });

    describe("when the version is not cached", () => {
      beforeEach(() => {
        sinon.stub(instance, "fileIsCached").returns(false);
        sinon.stub(instance, "compilerFromString").returns("compiler");
        sinon.stub(instance, "addFileToCache");
      });
      afterEach(() => {
        instance.fileIsCached.restore();
        instance.compilerFromString.restore();
        instance.addFileToCache.restore();
      });

      it("eventually calls addFileToCache and compilerFromString", async () => {
        await instance.getSolcFromCacheOrUrl("0.5.1");
        assert(instance.addFileToCache.called);
        assert(instance.compilerFromString.called);
      });
    });
  });

  describe("async getSolcByCommit(commit)", () => {
    describe("when the file is cached", () => {
      beforeEach(() => {
        sinon
          .stub(instance, "getCachedSolcFileName")
          .withArgs("commit.porkBelly")
          .returns("someFile.js");
        sinon.stub(instance, "getCachedSolcByFileName");
      });
      afterEach(() => {
        instance.getCachedSolcFileName.restore();
        instance.getCachedSolcByFileName.restore();
      });

      it("calls getCachedSolcByFileName with the file name", async () => {
        await instance.getSolcByCommit("commit.porkBelly");
        assert(instance.getCachedSolcByFileName.calledWith("someFile.js"));
      });
    });

    describe("when the file is not cached", () => {
      beforeEach(() => {
        // commit string for v 0.5.1
        commitString = "commit.c8a2cb62";
        sinon
          .stub(instance, "getCachedSolcFileName")
          .withArgs(commitString)
          .returns(undefined);
        sinon.stub(request, "get").returns("requestResponse");
        sinon.stub(instance, "addFileToCache");
        sinon.stub(instance, "compilerFromString");
        expectedUrl =
          instance.config.compilerRoots[0] +
          "soljson-v0.5.1+commit.c8a2cb62.js";
      });
      afterEach(() => {
        instance.getCachedSolcFileName.restore();
        request.get.restore();
        instance.addFileToCache.restore();
        instance.compilerFromString.restore();
      });

      it("eventually calls compilerFromString with request reponse", async () => {
        await instance.getSolcByCommit(commitString);
        assert(instance.compilerFromString.calledWith("requestResponse"));
      });
      it("throws an error when it can't find a match", async () => {
        try {
          await instance.getSolcByCommit("some garbage that will not match");
          assert(false);
        } catch (error) {
          assert(error.message === "No matching version found");
        }
      });
    });
  });

  describe(".getSolcByUrlAndCache(fileName)", () => {
    beforeEach(() => {
      fileName = "someSolcFile";
      sinon
        .stub(request, "get")
        .withArgs(`${instance.config.compilerRoots[0]}${fileName}`)
        .returns("requestReturn");
      sinon.stub(instance, "addFileToCache").withArgs("requestReturn");
      sinon
        .stub(instance, "compilerFromString")
        .withArgs("requestReturn")
        .returns("success");
    });
    afterEach(() => {
      request.get.restore();
      instance.addFileToCache.restore();
      instance.compilerFromString.restore();
    });

    it("calls addFileToCache with the response and the file name", async () => {
      result = await instance.getSolcByUrlAndCache(fileName, 0);
      assert(
        instance.addFileToCache.calledWith("requestReturn", "someSolcFile")
      );
      assert(result === "success");
    });
  });

  describe(".findNewestValidVersion(version, allVersions)", () => {
    it("returns the version name of the newest valid version", () => {
      expectedResult = "0.5.4";
      assert(
        instance.findNewestValidVersion("^0.5.0", allVersions) ===
          expectedResult
      );
    });
    it("returns null when the version is invalid", () => {
      assert(instance.findNewestValidVersion("garbageInput") === null);
    });
    it("returns null when there are no valid versions", () => {
      assert(instance.findNewestValidVersion("^0.8.0", allVersions) === null);
    });
  });

  describe("versionIsCached(version)", () => {
    beforeEach(() => {
      sinon.stub(fs, "readdirSync").returns(compilerFileNames);
    });
    afterEach(() => {
      fs.readdirSync.restore();
    });

    describe("when a cached version of the compiler is present", () => {
      beforeEach(() => {
        expectedResult = "v0.4.11+commit.124234rd.js";
      });

      it("returns the file name with the prefix removed", () => {
        assert.equal(instance.versionIsCached("0.4.11"), expectedResult);
      });
    });

    describe("when a cached version of the compiler is not present", () => {
      beforeEach(() => {
        expectedResult = undefined;
      });

      it("returns undefined", () => {
        assert.equal(instance.versionIsCached("0.4.29"), expectedResult);
      });
    });
  });

  describe("getCachedSolcByVersionRange(version)", () => {
    beforeEach(() => {
      expectedResult = "soljson-v0.4.23+commit.1534a40d.js";
      sinon.stub(fs, "readdirSync").returns(compilerFileNames);
      sinon.stub(instance, "getCachedSolcByFileName");
    });
    afterEach(() => {
      fs.readdirSync.restore();
      instance.getCachedSolcByFileName.restore();
    });

    it("returns the compiler when a single version is specified", () => {
      instance.getCachedSolcByVersionRange("0.4.23");
      assert(instance.getCachedSolcByFileName.calledWith(expectedResult));
    });
    it("returns the newest compiler when there are multiple valid ones", () => {
      instance.getCachedSolcByVersionRange("^0.4.1");
      assert(instance.getCachedSolcByFileName.calledWith(expectedResult));
    });
  });
});
<commit_msg>stub file is cached<commit_after>const assert = require("assert");
const fs = require("fs");
const request = require("request-promise");
const sinon = require("sinon");
const { VersionRange } = require("../../../compilerSupplier/loadingStrategies");
const instance = new VersionRange();
let fileName;
const compilerFileNames = [
  "soljson-v0.4.22+commit.124ca40d.js",
  "soljson-v0.4.23+commit.1534a40d.js",
  "soljson-v0.4.11+commit.124234rd.js"
];

const allVersions = {
  builds: [
    {
      path: "soljson-v0.1.1+commit.6ff4cd6.js",
      version: "0.1.1",
      build: "commit.6ff4cd6",
      longVersion: "0.1.1+commit.6ff4cd6",
      keccak256:
        "0xd8b8c64f4e9de41e6604e6ac30274eff5b80f831f8534f0ad85ec0aff466bb25",
      urls: [
        "bzzr://8f3c028825a1b72645f46920b67dca9432a87fc37a8940a2b2ce1dd6ddc2e29b"
      ]
    },
    {
      path: "soljson-v0.1.2+commit.d0d36e3.js",
      version: "0.1.2",
      build: "commit.d0d36e3",
      longVersion: "0.1.2+commit.d0d36e3",
      keccak256:
        "0xa70b3d4acf77a303efa93c3ddcadd55b8762c7be109fd8f259ec7d6be654f03e",
      urls: [
        "bzzr://e662d71e9b8e1b0311c129b962e678e5dd63487ad9b020ee539d7f74cd7392c9"
      ]
    }
  ],
  releases: {
    "0.5.4": "soljson-v0.5.4+commit.9549d8ff.js",
    "0.5.3": "soljson-v0.5.3+commit.10d17f24.js",
    "0.5.2": "soljson-v0.5.2+commit.1df8f40c.js",
    "0.5.1": "soljson-v0.5.1+commit.c8a2cb62.js",
    "0.5.0": "soljson-v0.5.0+commit.1d4f565a.js",
    "0.4.25": "soljson-v0.4.25+commit.59dbf8f1.js",
    "0.4.24": "soljson-v0.4.24+commit.e67f0147.js",
    "0.4.23": "soljson-v0.4.23+commit.124ca40d.js",
    "0.4.22": "soljson-v0.4.22+commit.4cb486ee.js"
  },
  latestRelease: "0.5.4"
};

describe("VersionRange loading strategy", () => {
  describe("async load(versionRange)", () => {
    beforeEach(() => {
      sinon.stub(instance, "getCachedSolcByVersionRange");
      sinon.stub(instance, "getSolcFromCacheOrUrl");
      sinon.stub(instance, "versionIsCached").returns(true);
      sinon.stub(request, "get").returns("response");
    });
    afterEach(() => {
      instance.getCachedSolcByVersionRange.restore();
      instance.getSolcFromCacheOrUrl.restore();
      instance.versionIsCached.restore();
      request.get.restore();
    });

    it("calls getCachedSolcByVersionRange when single solc is specified", async () => {
      await instance.load("0.5.0");
      assert(instance.getCachedSolcByVersionRange.called);
    });
    it("calls getSolcFromCacheOrUrl when a larger range is specified", async () => {
      await instance.load("^0.5.0");
      assert(instance.getSolcFromCacheOrUrl.called);
    });
  });

  describe("getSolcFromCacheOrUrl(version)", () => {
    beforeEach(() => {
      sinon.stub(instance, "getSolcVersions").returns(allVersions);
      sinon.stub(instance, "getCachedSolcByFileName");
    });
    afterEach(() => {
      instance.getSolcVersions.restore();
      instance.getCachedSolcByFileName.restore();
    });

    describe("when a version constraint is specified", () => {
      beforeEach(() => {
        sinon.stub(instance, "getSolcByUrlAndCache");
        sinon.stub(instance, "fileIsCached").returns(false);
      });
      afterEach(() => {
        instance.getSolcByUrlAndCache.restore();
        instance.fileIsCached.restore();
      });

      it("calls findNewstValidVersion to determine which version to fetch", async () => {
        await instance.getSolcFromCacheOrUrl("^0.5.0");
        assert(
          instance.getSolcByUrlAndCache.calledWith(
            "soljson-v0.5.4+commit.9549d8ff.js"
          ),
          "getSolcByUrlAndCache not called with the compiler file name"
        );
      });
    });

    describe("when the version is cached", () => {
      beforeEach(() => {
        sinon.stub(instance, "fileIsCached").returns(true);
      });
      afterEach(() => {
        instance.fileIsCached.restore();
      });

      it("calls getCachedSolcByFileName", async () => {
        await instance.getSolcFromCacheOrUrl("0.5.0");
        assert(
          instance.getCachedSolcByFileName.calledWith(
            "soljson-v0.5.0+commit.1d4f565a.js"
          )
        );
      });
    });

    describe("when the version is not cached", () => {
      beforeEach(() => {
        sinon.stub(instance, "fileIsCached").returns(false);
        sinon.stub(instance, "compilerFromString").returns("compiler");
        sinon.stub(instance, "addFileToCache");
      });
      afterEach(() => {
        instance.fileIsCached.restore();
        instance.compilerFromString.restore();
        instance.addFileToCache.restore();
      });

      it("eventually calls addFileToCache and compilerFromString", async () => {
        await instance.getSolcFromCacheOrUrl("0.5.1");
        assert(instance.addFileToCache.called);
        assert(instance.compilerFromString.called);
      });
    });
  });

  describe("async getSolcByCommit(commit)", () => {
    describe("when the file is cached", () => {
      beforeEach(() => {
        sinon
          .stub(instance, "getCachedSolcFileName")
          .withArgs("commit.porkBelly")
          .returns("someFile.js");
        sinon.stub(instance, "getCachedSolcByFileName");
      });
      afterEach(() => {
        instance.getCachedSolcFileName.restore();
        instance.getCachedSolcByFileName.restore();
      });

      it("calls getCachedSolcByFileName with the file name", async () => {
        await instance.getSolcByCommit("commit.porkBelly");
        assert(instance.getCachedSolcByFileName.calledWith("someFile.js"));
      });
    });

    describe("when the file is not cached", () => {
      beforeEach(() => {
        // commit string for v 0.5.1
        commitString = "commit.c8a2cb62";
        sinon
          .stub(instance, "getCachedSolcFileName")
          .withArgs(commitString)
          .returns(undefined);
        sinon.stub(request, "get").returns("requestResponse");
        sinon.stub(instance, "addFileToCache");
        sinon.stub(instance, "compilerFromString");
        expectedUrl =
          instance.config.compilerRoots[0] +
          "soljson-v0.5.1+commit.c8a2cb62.js";
      });
      afterEach(() => {
        instance.getCachedSolcFileName.restore();
        request.get.restore();
        instance.addFileToCache.restore();
        instance.compilerFromString.restore();
      });

      it("eventually calls compilerFromString with request reponse", async () => {
        await instance.getSolcByCommit(commitString);
        assert(instance.compilerFromString.calledWith("requestResponse"));
      });
      it("throws an error when it can't find a match", async () => {
        try {
          await instance.getSolcByCommit("some garbage that will not match");
          assert(false);
        } catch (error) {
          assert(error.message === "No matching version found");
        }
      });
    });
  });

  describe(".getSolcByUrlAndCache(fileName)", () => {
    beforeEach(() => {
      fileName = "someSolcFile";
      sinon
        .stub(request, "get")
        .withArgs(`${instance.config.compilerRoots[0]}${fileName}`)
        .returns("requestReturn");
      sinon.stub(instance, "addFileToCache").withArgs("requestReturn");
      sinon
        .stub(instance, "compilerFromString")
        .withArgs("requestReturn")
        .returns("success");
    });
    afterEach(() => {
      request.get.restore();
      instance.addFileToCache.restore();
      instance.compilerFromString.restore();
    });

    it("calls addFileToCache with the response and the file name", async () => {
      result = await instance.getSolcByUrlAndCache(fileName, 0);
      assert(
        instance.addFileToCache.calledWith("requestReturn", "someSolcFile")
      );
      assert(result === "success");
    });
  });

  describe(".findNewestValidVersion(version, allVersions)", () => {
    it("returns the version name of the newest valid version", () => {
      expectedResult = "0.5.4";
      assert(
        instance.findNewestValidVersion("^0.5.0", allVersions) ===
          expectedResult
      );
    });
    it("returns null when the version is invalid", () => {
      assert(instance.findNewestValidVersion("garbageInput") === null);
    });
    it("returns null when there are no valid versions", () => {
      assert(instance.findNewestValidVersion("^0.8.0", allVersions) === null);
    });
  });

  describe("versionIsCached(version)", () => {
    beforeEach(() => {
      sinon.stub(fs, "readdirSync").returns(compilerFileNames);
    });
    afterEach(() => {
      fs.readdirSync.restore();
    });

    describe("when a cached version of the compiler is present", () => {
      beforeEach(() => {
        expectedResult = "v0.4.11+commit.124234rd.js";
      });

      it("returns the file name with the prefix removed", () => {
        assert.equal(instance.versionIsCached("0.4.11"), expectedResult);
      });
    });

    describe("when a cached version of the compiler is not present", () => {
      beforeEach(() => {
        expectedResult = undefined;
      });

      it("returns undefined", () => {
        assert.equal(instance.versionIsCached("0.4.29"), expectedResult);
      });
    });
  });

  describe("getCachedSolcByVersionRange(version)", () => {
    beforeEach(() => {
      expectedResult = "soljson-v0.4.23+commit.1534a40d.js";
      sinon.stub(fs, "readdirSync").returns(compilerFileNames);
      sinon.stub(instance, "getCachedSolcByFileName");
    });
    afterEach(() => {
      fs.readdirSync.restore();
      instance.getCachedSolcByFileName.restore();
    });

    it("returns the compiler when a single version is specified", () => {
      instance.getCachedSolcByVersionRange("0.4.23");
      assert(instance.getCachedSolcByFileName.calledWith(expectedResult));
    });
    it("returns the newest compiler when there are multiple valid ones", () => {
      instance.getCachedSolcByVersionRange("^0.4.1");
      assert(instance.getCachedSolcByFileName.calledWith(expectedResult));
    });
  });
});
<|endoftext|>


<commit_before>
var accounts = db.collection_steps.aggregate({$match: {"returned_value.success": {$ne: true}, trigger_date: {$lt: ISODate()}}}, {$group: {_id: "$extra_params.aid", count: {$sum: 1}}}, {$match: {count: {$gte: 1}}});
var accounts_per_day = 1000000; //'UNLIMITED';
var multiplier = 1;
var acc_arr =[];
var acc_array_per_day =[];

accounts.forEach(function (acc) {
acc_arr.push(acc);
});

var acc_sum = acc_arr.length;

function calcDaysOfOperation(acc_sum){
    var sum =0;
   for (var i = 1; i <=acc_sum; i=i+((accounts_per_day)*(multiplier))) {
       print("whata " +i);
        sum++;
    }
    return sum;
}

function arrCreator(num_days,mul,acc_per_day){
    total = mul*acc_per_day;
    acc_amounts = acc_sum;
    for (var i = 0; i < num_days; i++) {
        for (var j = 0; i < total; i++) {
            if(total>acc_amounts){
            acc_array_per_day.push(acc_amounts);
        }else{
            acc_array_per_day.push(total);
            acc_amounts = acc_amounts - total;
        }
    }
}}

var num_of_days = calcDaysOfOperation(acc_sum);

arrCreator(num_of_days,multiplier,accounts_per_day);

function setAlert(stepId, cur_date, type, stepcode) {

    var data = new Date(cur_date.getTime() + type * 24 * 60 * 60000);
    print("set step " + stepcode + " to " + data);

    db.collection_steps.update({"_id": stepId}, {$set: {"trigger_date": data}});

}
function DaysToSkip(type) {

    switch (type) {
        case "HTTP step 1":
            return 1;
            break;
        case "HTTP step 2":
            return 5;
            break;
        case "HTTP step 3":
            return 10;
            break;
        case "HTTP step 4":
            return 20;
            break;
        case "HTTP step 5":
            return 30;
            break;
        case "HTTP step 6":
            return 50;
            break;
    }
}

var pivot = 0;

for (var cur_day = 0; cur_day < num_of_days; cur_day++) {

    var day_delay = (cur_day+1);

     //
     print("sdsdssdsdsd"+acc_array_per_day[cur_day]);

    for (cur_acc=0; cur_acc < ((acc_array_per_day[cur_day])); cur_acc++) {
        if(pivot<acc_sum){
        operateOnacc(acc_arr[pivot]._id,day_delay);
        pivot++;}
    }
}

function operateOnacc(account,day_delay){

    print ("setting steps for account: " +account);
    var first = true;

    var currnet_acc = db.collection_steps.find({"returned_value.success": {$ne: true}, "extra_params.aid": account}).sort({step_code: 1});

        currnet_acc.forEach(function (step) {

        newDate = ISODate();
        var prevDate = new Date(newDate.getTime() + day_delay * 24 * 60 * 60000);
        var nextSkip;
        var stepcode = step["step_code"];
        var id = step["_id"];
        if (first === true) {
            nextSkip = 0;
            first = false;
        } else {
            nextSkip = DaysToSkip(stepcode);
        }
        setAlert(id, prevDate, nextSkip, stepcode);
    });
}

print("number of accounts " + acc_sum);
print("process is divided to "+num_of_days +" days");

<commit_msg>set date to current<commit_after>
var accounts = db.collection_steps.aggregate({$match: {"returned_value.success": {$ne: true}, trigger_date: {$lt: ISODate()}}}, {$group: {_id: "$extra_params.aid", count: {$sum: 1}}}, {$match: {count: {$gte: 1}}});
var accounts_per_day = 1000000; //'UNLIMITED';
var multiplier = 1;
var acc_arr =[];
var acc_array_per_day =[];

accounts.forEach(function (acc) {
acc_arr.push(acc);
});

var acc_sum = acc_arr.length;

function calcDaysOfOperation(acc_sum){
    var sum =0;
   for (var i = 1; i <=acc_sum; i=i+((accounts_per_day)*(multiplier))) {
        sum++;
    }
    return sum;
}

function arrCreator(num_days,mul,acc_per_day){
    total = mul*acc_per_day;
    acc_amounts = acc_sum;
    for (var i = 0; i < num_days; i++) {
        for (var j = 0; i < total; i++) {
            if(total>acc_amounts){
            acc_array_per_day.push(acc_amounts);
        }else{
            acc_array_per_day.push(total);
            acc_amounts = acc_amounts - total;
        }
    }
}}

var num_of_days = calcDaysOfOperation(acc_sum);

arrCreator(num_of_days,multiplier,accounts_per_day);

function setAlert(stepId, cur_date, type, stepcode) {

    var data = new Date(cur_date.getTime() + type * 24 * 60 * 60000);
    print("set step " + stepcode + " to " + data);

    db.collection_steps.update({"_id": stepId}, {$set: {"trigger_date": data}});

}
function DaysToSkip(type) {

    switch (type) {
        case "HTTP step 1":
            return 1;
            break;
        case "HTTP step 2":
            return 5;
            break;
        case "HTTP step 3":
            return 10;
            break;
        case "HTTP step 4":
            return 20;
            break;
        case "HTTP step 5":
            return 30;
            break;
        case "HTTP step 6":
            return 50;
            break;
    }
}

var pivot = 0;

for (var cur_day = 0; cur_day < num_of_days; cur_day++) {

    //var day_delay = (cur_day+1);
    var day_delay = (cur_day);

    for (cur_acc=0; cur_acc < ((acc_array_per_day[cur_day])); cur_acc++) {
        if(pivot<acc_sum){
        operateOnacc(acc_arr[pivot]._id,day_delay);
        pivot++;}
    }
}

function operateOnacc(account,day_delay){

    print ("setting steps for account: " +account);
    var first = true;

    var currnet_acc = db.collection_steps.find({"returned_value.success": {$ne: true}, "extra_params.aid": account}).sort({step_code: 1});

        currnet_acc.forEach(function (step) {

        newDate = ISODate();
        var prevDate = new Date(newDate.getTime() + day_delay * 24 * 60 * 60000);
        var nextSkip;
        var stepcode = step["step_code"];
        var id = step["_id"];
        if (first === true) {
            nextSkip = 0;
            first = false;
        } else {
            nextSkip = DaysToSkip(stepcode);
        }
        setAlert(id, prevDate, nextSkip, stepcode);
    });
}

print("number of accounts " + acc_sum);
print("process is divided to "+num_of_days +" days");

<|endoftext|>


<commit_before>import _ from "underscore";

import { createAction } from "redux-actions";
import { AngularResourceProxy, createThunkAction } from "metabase/lib/redux";
import { normalize, Schema, arrayOf } from "normalizr";

import moment from "moment";
import { augmentDatabase } from "metabase/lib/table";

import MetabaseAnalytics from "metabase/lib/analytics";
import { getPositionForNewDashCard } from "metabase/lib/dashboard_grid";

const DATASET_TIMEOUT = 60;

// normalizr schemas
const dashcard = new Schema('dashcard');
const card = new Schema('card');
const dashboard = new Schema('dashboard');
dashboard.define({
  ordered_cards: arrayOf(dashcard)
});

// action constants
export const SELECT_DASHBOARD = 'SELECT_DASHBOARD';
export const SET_EDITING_DASHBOARD = 'SET_EDITING';

export const FETCH_CARDS = 'FETCH_CARDS';
export const DELETE_CARD = 'DELETE_CARD';

export const FETCH_DASHBOARD = 'FETCH_DASHBOARD';
export const SET_DASHBOARD_ATTRIBUTES = 'SET_DASHBOARD_ATTRIBUTES';
export const SET_DASHCARD_VISUALIZATION_SETTING = 'SET_DASHCARD_VISUALIZATION_SETTING';
export const SAVE_DASHBOARD = 'SAVE_DASHBOARD';
export const DELETE_DASHBOARD = 'DELETE_DASHBOARD';

export const ADD_CARD_TO_DASH = 'ADD_CARD_TO_DASH';
export const REMOVE_CARD_FROM_DASH = 'REMOVE_CARD_FROM_DASH';
export const SET_DASHCARD_ATTRIBUTES = 'SET_DASHCARD_ATTRIBUTES';
export const SAVE_DASHCARD = 'SAVE_DASHCARD';

export const FETCH_CARD_DATA = 'FETCH_CARD_DATA';
export const FETCH_REVISIONS = 'FETCH_REVISIONS';
export const REVERT_TO_REVISION = 'REVERT_TO_REVISION';

export const MARK_NEW_CARD_SEEN = 'MARK_NEW_CARD_SEEN';

export const FETCH_DATABASE_METADATA = 'FETCH_DATABASE_METADATA';

// resource wrappers
const DashboardApi = new AngularResourceProxy("Dashboard", ["get", "update", "delete", "reposition_cards", "addcard", "removecard"]);
const MetabaseApi = new AngularResourceProxy("Metabase", ["dataset", "db_metadata"]);
const CardApi = new AngularResourceProxy("Card", ["list", "update", "delete"]);
const RevisionApi = new AngularResourceProxy("Revision", ["list", "revert"]);

// FIXME: REMOVE SCALING ONCE WE ADD A DB MIGRATION TO SCALE DASHCARD SIZES
const FIXME_DASHCARD_X_SCALE = 2;
const FIXME_DASHCARD_Y_SCALE = 2;

// action creators

export const setEditingDashboard = createAction(SET_EDITING_DASHBOARD);

export const markNewCardSeen = createAction(MARK_NEW_CARD_SEEN);

// these operations don't get saved to server immediately
export const setDashboardAttributes = createAction(SET_DASHBOARD_ATTRIBUTES);
export const setDashCardAttributes = createAction(SET_DASHCARD_ATTRIBUTES);

export const fetchCards = createThunkAction(FETCH_CARDS, function(filterMode = "all") {
    return async function(dispatch, getState) {
        let cards = await CardApi.list({ filterMode });
        for (var c of cards) {
            c.updated_at = moment(c.updated_at);
        }
        return normalize(cards, arrayOf(card));
    };
});

export const deleteCard = createThunkAction(DELETE_CARD, function(cardId) {
    return async function(dispatch, getState) {
        await CardApi.delete({ cardId });
        return cardId;
    };
});

export const addCardToDashboard = function({ dashId, cardId }) {
    return function(dispatch, getState) {
        var state = getState();
        var existingCards = state.dashboards[dashId].ordered_cards.map(id => state.dashcards[id]).filter(dc => !dc.isRemoved);
        let id = Math.random(); // temporary id
        dispatch(createAction(ADD_CARD_TO_DASH)({
            id: id,
            dashboard_id: dashId,
            card_id: cardId,
            card: state.cards[cardId],
            ...getPositionForNewDashCard(existingCards)
        }));
    };
}

export const removeCardFromDashboard = createAction(REMOVE_CARD_FROM_DASH);

export const fetchCardData = createThunkAction(FETCH_CARD_DATA, function(card) {
    return async function(dispatch, getState) {
        let result = await timeout(MetabaseApi.dataset(card.dataset_query), DATASET_TIMEOUT * 1000, "Card took longer than " + DATASET_TIMEOUT + " seconds to load.");
        return { id: card.id, result };
    };
});

export const fetchDashboard = createThunkAction(FETCH_DASHBOARD, function(id) {
    return async function(dispatch, getState) {
        let result = await DashboardApi.get({ dashId: id });
        // FIXME: REMOVE SCALING ONCE WE ADD A DB MIGRATION TO SCALE DASHCARD SIZES
        result = {
            ...result,
            ordered_cards: result.ordered_cards.map((dc) => ({
                ...dc,
                row: dc.row * FIXME_DASHCARD_Y_SCALE,
                col: dc.col * FIXME_DASHCARD_X_SCALE,
                sizeX: dc.sizeX * FIXME_DASHCARD_X_SCALE,
                sizeY: dc.sizeY * FIXME_DASHCARD_Y_SCALE
            }))
        };
        return normalize(result, dashboard);
    };
});

export const saveDashboard = createThunkAction(SAVE_DASHBOARD, function(dashId) {
    return async function(dispatch, getState) {
        let { dashboards, dashcards } = getState();
        let dashboard = {
            ...dashboards[dashId],
            ordered_cards: dashboards[dashId].ordered_cards.map(dashcardId => dashcards[dashcardId])
        };

        // remove isRemoved dashboards
        await Promise.all(dashboard.ordered_cards
            .filter(dc => dc.isRemoved && !dc.isAdded)
            .map(dc => DashboardApi.removecard({ dashId: dashboard.id, dashcardId: dc.id })));

        // add isAdded dashboards
        let updatedDashcards = await Promise.all(dashboard.ordered_cards
            .filter(dc => !dc.isRemoved)
            .map(async dc => {
                if (dc.isAdded) {
                    let result = await DashboardApi.addcard({ dashId, cardId: dc.card_id })
                    // mark isAdded because addcard doesn't record the position
                    return { ...result, col: dc.col, row: dc.row, sizeX: dc.sizeX, sizeY: dc.sizeY, series: dc.series, isAdded: true }
                } else {
                    return dc;
                }
            }));

        // update modified cards
        await Promise.all(dashboard.ordered_cards
            .filter(dc => dc.card.isDirty)
            .map(async dc => CardApi.update(dc.card)));

        // update the dashboard itself
        if (dashboard.isDirty) {
            let { id, name, description, public_perms } = dashboard;
            dashboard = await DashboardApi.update({ id, name, description, public_perms });
        }

        // reposition the cards
        if (_.some(updatedDashcards, (dc) => dc.isDirty || dc.isAdded)) {
            let cards = updatedDashcards.map(({ id, row, col, sizeX, sizeY, series }) => ({
                id,
                // FIXME: REMOVE SCALING ONCE WE ADD A DB MIGRATION TO SCALE DASHCARD SIZES
                row: Math.floor(row / FIXME_DASHCARD_Y_SCALE),
                col: Math.floor(col / FIXME_DASHCARD_X_SCALE),
                sizeX: Math.floor(sizeX / FIXME_DASHCARD_X_SCALE),
                sizeY: Math.floor(sizeY / FIXME_DASHCARD_Y_SCALE),
                series
            }));
            var result = await DashboardApi.reposition_cards({ dashId, cards });
            if (result.status !== "ok") {
                throw new Error(result.status);
            }
        }

        // make sure that we've fully cleared out any dirty state from editing (this is overkill, but simple)
        dispatch(fetchDashboard(dashId));

        MetabaseAnalytics.trackEvent("Dashboard", "Update");

        return dashboard;
    };
});

export const deleteDashboard = createThunkAction(DELETE_DASHBOARD, function(dashId) {
    return async function(dispatch, getState) {
        await DashboardApi.delete({ dashId });
        MetabaseAnalytics.trackEvent("Dashboard", "Delete");
        return dashId;
    };
});

export const fetchRevisions = createThunkAction(FETCH_REVISIONS, function({ entity, id }) {
    return async function(dispatch, getState) {
        let revisions = await RevisionApi.list({ entity, id });
        return { entity, id, revisions };
    };
});

export const revertToRevision = createThunkAction(REVERT_TO_REVISION, function({ entity, id, revision_id }) {
    return async function(dispatch, getState) {
        await RevisionApi.revert({ entity, id, revision_id });
    };
});

export const fetchDatabaseMetadata = createThunkAction(FETCH_DATABASE_METADATA, function(dbId) {
    return async function(dispatch, getState) {
        let databaseMetadata = await MetabaseApi.db_metadata({ dbId });
        augmentDatabase(databaseMetadata);
        return databaseMetadata;
    };
});

export const setDashCardVisualizationSetting = createAction(SET_DASHCARD_VISUALIZATION_SETTING);

// promise helpers

// if a promise doesn't resolve/reject within a given duration it will reject
function timeout(promise, duration, error) {
    return new Promise((resolve, reject) => {
        promise.then(resolve, reject);
        setTimeout(() => reject(error || new Error("Operation timed out")), duration);
    });
}

// returns a promise that resolves after a given duration
// function delay(duration) {
//     return new Promise((resolve, reject) => setTimeout(resolve, duration));
// }
<commit_msg>Change legacy dashboard vertical scaling factor from 2 to 3<commit_after>import _ from "underscore";

import { createAction } from "redux-actions";
import { AngularResourceProxy, createThunkAction } from "metabase/lib/redux";
import { normalize, Schema, arrayOf } from "normalizr";

import moment from "moment";
import { augmentDatabase } from "metabase/lib/table";

import MetabaseAnalytics from "metabase/lib/analytics";
import { getPositionForNewDashCard } from "metabase/lib/dashboard_grid";

const DATASET_TIMEOUT = 60;

// normalizr schemas
const dashcard = new Schema('dashcard');
const card = new Schema('card');
const dashboard = new Schema('dashboard');
dashboard.define({
  ordered_cards: arrayOf(dashcard)
});

// action constants
export const SELECT_DASHBOARD = 'SELECT_DASHBOARD';
export const SET_EDITING_DASHBOARD = 'SET_EDITING';

export const FETCH_CARDS = 'FETCH_CARDS';
export const DELETE_CARD = 'DELETE_CARD';

export const FETCH_DASHBOARD = 'FETCH_DASHBOARD';
export const SET_DASHBOARD_ATTRIBUTES = 'SET_DASHBOARD_ATTRIBUTES';
export const SET_DASHCARD_VISUALIZATION_SETTING = 'SET_DASHCARD_VISUALIZATION_SETTING';
export const SAVE_DASHBOARD = 'SAVE_DASHBOARD';
export const DELETE_DASHBOARD = 'DELETE_DASHBOARD';

export const ADD_CARD_TO_DASH = 'ADD_CARD_TO_DASH';
export const REMOVE_CARD_FROM_DASH = 'REMOVE_CARD_FROM_DASH';
export const SET_DASHCARD_ATTRIBUTES = 'SET_DASHCARD_ATTRIBUTES';
export const SAVE_DASHCARD = 'SAVE_DASHCARD';

export const FETCH_CARD_DATA = 'FETCH_CARD_DATA';
export const FETCH_REVISIONS = 'FETCH_REVISIONS';
export const REVERT_TO_REVISION = 'REVERT_TO_REVISION';

export const MARK_NEW_CARD_SEEN = 'MARK_NEW_CARD_SEEN';

export const FETCH_DATABASE_METADATA = 'FETCH_DATABASE_METADATA';

// resource wrappers
const DashboardApi = new AngularResourceProxy("Dashboard", ["get", "update", "delete", "reposition_cards", "addcard", "removecard"]);
const MetabaseApi = new AngularResourceProxy("Metabase", ["dataset", "db_metadata"]);
const CardApi = new AngularResourceProxy("Card", ["list", "update", "delete"]);
const RevisionApi = new AngularResourceProxy("Revision", ["list", "revert"]);

// FIXME: REMOVE SCALING ONCE WE ADD A DB MIGRATION TO SCALE DASHCARD SIZES
const FIXME_DASHCARD_X_SCALE = 2;
const FIXME_DASHCARD_Y_SCALE = 3;

// action creators

export const setEditingDashboard = createAction(SET_EDITING_DASHBOARD);

export const markNewCardSeen = createAction(MARK_NEW_CARD_SEEN);

// these operations don't get saved to server immediately
export const setDashboardAttributes = createAction(SET_DASHBOARD_ATTRIBUTES);
export const setDashCardAttributes = createAction(SET_DASHCARD_ATTRIBUTES);

export const fetchCards = createThunkAction(FETCH_CARDS, function(filterMode = "all") {
    return async function(dispatch, getState) {
        let cards = await CardApi.list({ filterMode });
        for (var c of cards) {
            c.updated_at = moment(c.updated_at);
        }
        return normalize(cards, arrayOf(card));
    };
});

export const deleteCard = createThunkAction(DELETE_CARD, function(cardId) {
    return async function(dispatch, getState) {
        await CardApi.delete({ cardId });
        return cardId;
    };
});

export const addCardToDashboard = function({ dashId, cardId }) {
    return function(dispatch, getState) {
        var state = getState();
        var existingCards = state.dashboards[dashId].ordered_cards.map(id => state.dashcards[id]).filter(dc => !dc.isRemoved);
        let id = Math.random(); // temporary id
        dispatch(createAction(ADD_CARD_TO_DASH)({
            id: id,
            dashboard_id: dashId,
            card_id: cardId,
            card: state.cards[cardId],
            ...getPositionForNewDashCard(existingCards)
        }));
    };
}

export const removeCardFromDashboard = createAction(REMOVE_CARD_FROM_DASH);

export const fetchCardData = createThunkAction(FETCH_CARD_DATA, function(card) {
    return async function(dispatch, getState) {
        let result = await timeout(MetabaseApi.dataset(card.dataset_query), DATASET_TIMEOUT * 1000, "Card took longer than " + DATASET_TIMEOUT + " seconds to load.");
        return { id: card.id, result };
    };
});

export const fetchDashboard = createThunkAction(FETCH_DASHBOARD, function(id) {
    return async function(dispatch, getState) {
        let result = await DashboardApi.get({ dashId: id });
        // FIXME: REMOVE SCALING ONCE WE ADD A DB MIGRATION TO SCALE DASHCARD SIZES
        result = {
            ...result,
            ordered_cards: result.ordered_cards.map((dc) => ({
                ...dc,
                row: dc.row * FIXME_DASHCARD_Y_SCALE,
                col: dc.col * FIXME_DASHCARD_X_SCALE,
                sizeX: dc.sizeX * FIXME_DASHCARD_X_SCALE,
                sizeY: dc.sizeY * FIXME_DASHCARD_Y_SCALE
            }))
        };
        return normalize(result, dashboard);
    };
});

export const saveDashboard = createThunkAction(SAVE_DASHBOARD, function(dashId) {
    return async function(dispatch, getState) {
        let { dashboards, dashcards } = getState();
        let dashboard = {
            ...dashboards[dashId],
            ordered_cards: dashboards[dashId].ordered_cards.map(dashcardId => dashcards[dashcardId])
        };

        // remove isRemoved dashboards
        await Promise.all(dashboard.ordered_cards
            .filter(dc => dc.isRemoved && !dc.isAdded)
            .map(dc => DashboardApi.removecard({ dashId: dashboard.id, dashcardId: dc.id })));

        // add isAdded dashboards
        let updatedDashcards = await Promise.all(dashboard.ordered_cards
            .filter(dc => !dc.isRemoved)
            .map(async dc => {
                if (dc.isAdded) {
                    let result = await DashboardApi.addcard({ dashId, cardId: dc.card_id })
                    // mark isAdded because addcard doesn't record the position
                    return { ...result, col: dc.col, row: dc.row, sizeX: dc.sizeX, sizeY: dc.sizeY, series: dc.series, isAdded: true }
                } else {
                    return dc;
                }
            }));

        // update modified cards
        await Promise.all(dashboard.ordered_cards
            .filter(dc => dc.card.isDirty)
            .map(async dc => CardApi.update(dc.card)));

        // update the dashboard itself
        if (dashboard.isDirty) {
            let { id, name, description, public_perms } = dashboard;
            dashboard = await DashboardApi.update({ id, name, description, public_perms });
        }

        // reposition the cards
        if (_.some(updatedDashcards, (dc) => dc.isDirty || dc.isAdded)) {
            let cards = updatedDashcards.map(({ id, row, col, sizeX, sizeY, series }) => ({
                id,
                // FIXME: REMOVE SCALING ONCE WE ADD A DB MIGRATION TO SCALE DASHCARD SIZES
                row: Math.floor(row / FIXME_DASHCARD_Y_SCALE),
                col: Math.floor(col / FIXME_DASHCARD_X_SCALE),
                sizeX: Math.floor(sizeX / FIXME_DASHCARD_X_SCALE),
                sizeY: Math.floor(sizeY / FIXME_DASHCARD_Y_SCALE),
                series
            }));
            var result = await DashboardApi.reposition_cards({ dashId, cards });
            if (result.status !== "ok") {
                throw new Error(result.status);
            }
        }

        // make sure that we've fully cleared out any dirty state from editing (this is overkill, but simple)
        dispatch(fetchDashboard(dashId));

        MetabaseAnalytics.trackEvent("Dashboard", "Update");

        return dashboard;
    };
});

export const deleteDashboard = createThunkAction(DELETE_DASHBOARD, function(dashId) {
    return async function(dispatch, getState) {
        await DashboardApi.delete({ dashId });
        MetabaseAnalytics.trackEvent("Dashboard", "Delete");
        return dashId;
    };
});

export const fetchRevisions = createThunkAction(FETCH_REVISIONS, function({ entity, id }) {
    return async function(dispatch, getState) {
        let revisions = await RevisionApi.list({ entity, id });
        return { entity, id, revisions };
    };
});

export const revertToRevision = createThunkAction(REVERT_TO_REVISION, function({ entity, id, revision_id }) {
    return async function(dispatch, getState) {
        await RevisionApi.revert({ entity, id, revision_id });
    };
});

export const fetchDatabaseMetadata = createThunkAction(FETCH_DATABASE_METADATA, function(dbId) {
    return async function(dispatch, getState) {
        let databaseMetadata = await MetabaseApi.db_metadata({ dbId });
        augmentDatabase(databaseMetadata);
        return databaseMetadata;
    };
});

export const setDashCardVisualizationSetting = createAction(SET_DASHCARD_VISUALIZATION_SETTING);

// promise helpers

// if a promise doesn't resolve/reject within a given duration it will reject
function timeout(promise, duration, error) {
    return new Promise((resolve, reject) => {
        promise.then(resolve, reject);
        setTimeout(() => reject(error || new Error("Operation timed out")), duration);
    });
}

// returns a promise that resolves after a given duration
// function delay(duration) {
//     return new Promise((resolve, reject) => setTimeout(resolve, duration));
// }
<|endoftext|>


<commit_before>//this file will upload data to database
var path = require('path')
var async = require('async')
var app = require('../../../../web-api/server/server')
var entities = require(path.resolve(rootPath, 'lib', 'anp-stations', 'entities'))

module.getCityState = function(cityId, states) {
	var state = states.filter(function(st) {
		return st.cities.some(function(c) {
			return c.id = cityId
		})
	})

	if (state.length) {
		return state[0]
	} else {
		return null
	}
}

module.exports.load = function(entitiesPath, callback) {
	app.datasources.mongodb.on('connected', function() {
		var states = require(path.resolve(entitiesPath, 'states'))
		var cities = require(path.resolve(entitiesPath, 'cities'))
		var fuelTypes = require(path.resolve(entitiesPath, 'fuelTypes'))
		var stations = require(path.resolve(entitiesPath, 'stations'))
		var stationsProcessed = require(path.resolve(entitiesPath, 'ppStations'))

		var putFuelTypes = function(fuelTypes) {
			async.each(fuelTypes, function(f, cb) {
				app.models.fuelType.findOrCreate({
					anpId: f.id
				}, {
					name: f.name,
					anpId: f.id
				}, cb)
			}, function(err) {
				if (err) callback(err)

				app.models.fuelType.find({}, function(err, dbFuelTypes) {
					if (err) callback('error processing fuel types')

					putStates(states, dbFuelTypes)
				})
			})
		}

		var putStates = function(states, dbFuelTypes) {
			async.each(states, function(s, cb) {
				app.models.state.findOrCreate({
					fu: s.fu
				}, {
					name: s.name,
					fu: s.id
				}, cb)
			}, function(err) {
				if (err) throw err

				app.models.state.find({}, function(err, dbStates) {
					if (err) callback('error processing states')

					putCities(cities, dbStates, dbFuelTypes)
				})
			})
		}

		var putCities = function(cities, dbStates, dbFuelTypes) {
			async.each(cities, function(c, cb) {
				var state = module.getCityState(c.id, states)
				var dbState = dbStates.filter(function(ds) {
					return ds.fu === state.id
				})
				if (!dbState.length) {
					callback('it wasn\'t possible find the city\'s state ' + c.name)
				}
				dbState = dbState[0]
				app.models.city.findOrCreate({
					anpId: c.id
				}, {
					name: c.name,
					anpId: c.id,
					stateId: dbState.id //fu
				}, cb)
			}, function(err) {
				if(err) callback('error processing cities')

				app.models.city.find({}, function(err, dbCities) {
					if (err) callback(err)

					putStations(stations, dbCities, dbFuelTypes)
				})
			})
		}

		var putStations = function(stations, dbCities, dbFuelTypes) {
			var i = 0
			var stationsUnique = stations.filter(function(s) {
				return s.invoiceOk
			}).reduce(function(prev, curr) {
				console.log('station reduce working: ', i++, '/', stations.length)
				if (!Array.isArray(prev)) {
					if (prev.razaoSocial.toLowerCase() === curr.razaoSocial.toLowerCase()) {
						return [prev]
					} else {
						return [prev, curr]
					}
				} else {
					var exists = prev.some(function(p) {
						return p.razaoSocial.toLowerCase() === curr.razaoSocial.toLowerCase()
					})

					if (!exists) {
						prev.push(curr)
					}
					return prev
				}
			})
			console.log('### station reduce completed ### ')

			async.each(stationsUnique, function(s, cb) {
				var dbCity = dbCities.filter(function(dc) {
					return dc.anpId === s.cityId
				})
				if (!dbCity.length) {
					callback('It wasn\'t possible to retrieve the city of gas station ' + s.razaoSocial)
				}
				dbCity = dbCity[0]

				//for first load to database
				var stationProcessed = stationsProcessed.filter(function(sp) {
					return sp.razaoSocial.toLowerCase() === s.razaoSocial.toLowerCase()
				})
				if (stationProcessed.length) {
					stationProcessed = stationsProcessed[0]
				}

				app.models.gasStation.findOrCreate({
					companyName: s.razaoSocial
				}, {
					companyName: s.razaoSocial,
					flag: notHiphen(s.bandeira),
					geolocation: stationProcessed.geolocation,
					distributor: notHiphen(s.distribuidora),
					invoiceOk: s.invoiceOk,
					address: s.endereco,
					neighborhood: s.bairro,
					cityId: dbCity.id,
					stateId: dbCity.stateId
				}, cb)
			}, function(err) {
				if (err) callback('error processing gas stations')

				app.models.gasStation.find({ fields: { id: true, companyName: true } }, function(err, dbGasStations) {
					putFuelPrices(stations, dbFuelTypes, dbGasStations)
				})
			})
		}

		var putFuelPrices = function(stations, dbFuelTypes, dbGasStations) {
			stations = stations.filter(function(s) {
				return s.invoiceOk
			})

			async.each(stations, function(s, cb) {
				var dataColeta = brDateToDate(s.dataColeta)

				console.log('fuel price ', stations.indexOf(s), '/', stations.length)

				var dbFuelType = dbFuelTypes.filter(function(f) {
					return f.anpId === s.fuelTypeId
				})
				if (!dbFuelType.length) {
					callback('It wasn\'t possible to retrieve the fuel type of gas station ' + s.razaoSocial)
				}
				dbFuelType = dbFuelType[0]

				var dbGasStation = dbGasStations.filter(function(gs) {
					return gs.companyName.toLowerCase() === s.razaoSocial.toLowerCase()
				})
				if (!dbGasStation.length) {
					callback('It wasn\'t possible to retrieve the gas station of fuel price ' + s.razaoSocial)
				}
				dbGasStation = dbGasStation[0]

				app.models.fuelPrice.findOrCreate({
					and: [{
						date: dataColeta
					}, {
						fuelTypeId: dbFuelType.id
					}]
				}, {
					sale: Number(notHiphen(s.precoVenda.replace(',', '.'))),
					purchase: Number(notHiphen(s.precoCompra.replace(',', '.'))),
					supplierWhiteFlag: notHiphen(s.fornecedorBBranca),
					purchaseMode: notHiphen(s.modalidadecompra),
					date: dataColeta,
					unit: notHiphen(s.unit),
					fuelTypeId: dbFuelType.id,
					gasStationId: dbGasStation.id
				}, cb)
			}, function(err) {
				if (err) callback('error processing fuel prices')

				callback('load to database success')
			})
		}

		var notHiphen = function (word) {
			return word === '-' ? null : word
		}

		var brDateToDate = function(dt) {
			dt = dt.split('/')
			for (var i = 0; i < dt.length; i++) {
				dt[i] = Number(dt[i])
			}
			return new Date(dt[2], (dt[1] - 1), dt[0])
		}

		putFuelTypes(fuelTypes)
	})
}
<commit_msg>implemented errors<commit_after>//this file will upload data to database
var path = require('path')
var async = require('async')
var app = require('../../../../web-api/server/server')
var entities = require(path.resolve(rootPath, 'lib', 'anp-stations', 'entities'))

module.getCityState = function(cityId, states) {
	var state = states.filter(function(st) {
		return st.cities.some(function(c) {
			return c.id = cityId
		})
	})

	if (state.length) {
		return state[0]
	} else {
		return null
	}
}

module.exports.load = function(entitiesPath, callback) {
	app.datasources.mongodb.on('connected', function() {
		var states = require(path.resolve(entitiesPath, 'states'))
		var cities = require(path.resolve(entitiesPath, 'cities'))
		var fuelTypes = require(path.resolve(entitiesPath, 'fuelTypes'))
		var stations = require(path.resolve(entitiesPath, 'stations'))
		var stationsProcessed = require(path.resolve(entitiesPath, 'ppStations'))

		var putFuelTypes = function(fuelTypes) {
			async.each(fuelTypes, function(f, cb) {
				app.models.fuelType.findOrCreate({
					anpId: f.id
				}, {
					name: f.name,
					anpId: f.id
				}, cb)
			}, function(err) {
				if (err) callback('error processing fuel types', err)

				app.models.fuelType.find({}, function(err, dbFuelTypes) {
					if (err) callback('error processing fuel types 2', err)

					putStates(states, dbFuelTypes)
				})
			})
		}

		var putStates = function(states, dbFuelTypes) {
			async.each(states, function(s, cb) {
				app.models.state.findOrCreate({
					fu: s.fu
				}, {
					name: s.name,
					fu: s.id
				}, cb)
			}, function(err) {
				if (err) callback('error processing states', err)

				app.models.state.find({}, function(err, dbStates) {
					if (err) callback('error processing states 2', err)

					putCities(cities, dbStates, dbFuelTypes)
				})
			})
		}

		var putCities = function(cities, dbStates, dbFuelTypes) {
			async.each(cities, function(c, cb) {
				var state = module.getCityState(c.id, states)
				var dbState = dbStates.filter(function(ds) {
					return ds.fu === state.id
				})
				if (!dbState.length) {
					callback('it wasn\'t possible find the city\'s state ' + c.name)
				}
				dbState = dbState[0]
				app.models.city.findOrCreate({
					anpId: c.id
				}, {
					name: c.name,
					anpId: c.id,
					stateId: dbState.id //fu
				}, cb)
			}, function(err) {
				if(err) callback('error processing cities', err)

				app.models.city.find({}, function(err, dbCities) {
					if (err) callback('error processing cities 2', err)

					putStations(stations, dbCities, dbFuelTypes)
				})
			})
		}

		var putStations = function(stations, dbCities, dbFuelTypes) {
			var i = 0
			var stationsUnique = stations.filter(function(s) {
				return s.invoiceOk
			}).reduce(function(prev, curr) {
				console.log('station reduce working: ', i++, '/', stations.length)
				if (!Array.isArray(prev)) {
					if (prev.razaoSocial.toLowerCase() === curr.razaoSocial.toLowerCase()) {
						return [prev]
					} else {
						return [prev, curr]
					}
				} else {
					var exists = prev.some(function(p) {
						return p.razaoSocial.toLowerCase() === curr.razaoSocial.toLowerCase()
					})

					if (!exists) {
						prev.push(curr)
					}
					return prev
				}
			})
			console.log('### station reduce completed ### ')

			async.each(stationsUnique, function(s, cb) {
				var dbCity = dbCities.filter(function(dc) {
					return dc.anpId === s.cityId
				})
				if (!dbCity.length) {
					callback('It wasn\'t possible to retrieve the city of gas station ' + s.razaoSocial)
				}
				dbCity = dbCity[0]

				//for first load to database
				var stationProcessed = stationsProcessed.filter(function(sp) {
					return sp.razaoSocial.toLowerCase() === s.razaoSocial.toLowerCase()
				})
				if (stationProcessed.length) {
					stationProcessed = stationsProcessed[0]
				}

				app.models.gasStation.findOrCreate({
					companyName: s.razaoSocial
				}, {
					companyName: s.razaoSocial,
					flag: notHiphen(s.bandeira),
					geolocation: stationProcessed.geolocation,
					distributor: notHiphen(s.distribuidora),
					invoiceOk: s.invoiceOk,
					address: s.endereco,
					neighborhood: s.bairro,
					cityId: dbCity.id,
					stateId: dbCity.stateId
				}, cb)
			}, function(err) {
				if (err) callback('error processing gas stations', err)

				app.models.gasStation.find({ fields: { id: true, companyName: true } }, function(err, dbGasStations) {
					if (err) callback('error processing gas stations 2', err)

					putFuelPrices(stations, dbFuelTypes, dbGasStations)
				})
			})
		}

		var putFuelPrices = function(stations, dbFuelTypes, dbGasStations) {
			stations = stations.filter(function(s) {
				return s.invoiceOk
			})

			async.each(stations, function(s, cb) {
				var dataColeta = brDateToDate(s.dataColeta)

				console.log('fuel price ', stations.indexOf(s), '/', stations.length)

				var dbFuelType = dbFuelTypes.filter(function(f) {
					return f.anpId === s.fuelTypeId
				})
				if (!dbFuelType.length) {
					callback('It wasn\'t possible to retrieve the fuel type of gas station ' + s.razaoSocial)
				}
				dbFuelType = dbFuelType[0]

				var dbGasStation = dbGasStations.filter(function(gs) {
					return gs.companyName.toLowerCase() === s.razaoSocial.toLowerCase()
				})
				if (!dbGasStation.length) {
					callback('It wasn\'t possible to retrieve the gas station of fuel price ' + s.razaoSocial)
				}
				dbGasStation = dbGasStation[0]

				app.models.fuelPrice.findOrCreate({
					and: [{
						date: dataColeta
					}, {
						fuelTypeId: dbFuelType.id
					}]
				}, {
					sale: Number(notHiphen(s.precoVenda.replace(',', '.'))),
					purchase: Number(notHiphen(s.precoCompra.replace(',', '.'))),
					supplierWhiteFlag: notHiphen(s.fornecedorBBranca),
					purchaseMode: notHiphen(s.modalidadecompra),
					date: dataColeta,
					unit: notHiphen(s.unit),
					fuelTypeId: dbFuelType.id,
					gasStationId: dbGasStation.id
				}, cb)
			}, function(err) {
				if (err) callback('error processing fuel prices', err)

				callback('load to database success')
			})
		}

		var notHiphen = function (word) {
			return word === '-' ? null : word
		}

		var brDateToDate = function(dt) {
			dt = dt.split('/')
			for (var i = 0; i < dt.length; i++) {
				dt[i] = Number(dt[i])
			}
			return new Date(dt[2], (dt[1] - 1), dt[0])
		}

		putFuelTypes(fuelTypes)
	})
}
<|endoftext|>


<commit_before>import React from 'react';
import { subscribe } from 'horizon-react';
import { Row, Col, Form, FormGroup, Button } from 'react-bootstrap';
import { updateRsvpQuery, updateRsvpResult } from '../../../actions/actionCreators';
import PageHeader from '../../_partials/page-header';
import InviteNotFound from '../rsvp/not-found';
import SubmitBtn from '../../shared/submit-btn';
import glob from 'styles/app';
import effects from 'styles/effects';

/**
  *
  * RSVP Search Page
  *
  * Includes ..
  *
  * @param ..
  *
  * @return {ReactComponent}
  */

const emailInInvitation = (invitation, props, cb) => {
  let found = false;
  invitation.guests.forEach(
    guest => {
      if (guest.email && guest.email === props.rsvpSearch.query) {
        found = true;
      }
    }
  );
  cb(found);
};

const mapDataToProps = {
  invitations: (hz, props) => {
    hz('invitations').fetch().subscribe(
      invitations => {
        if (invitations) {
          invitations.forEach(
            invitation => {
              emailInInvitation(invitation, props, (found) => {
                if (found) {
                  props.dispatch(updateRsvpResult(invitation));
                }
              });
            }
          );
        }
      }
    );
    return hz('invitations');
  }
};

const mapStateToProps = (state) => ({
  rsvpSearch: state.rsvpSearch
});

class Rsvp extends React.Component {
  constructor(props) {
    super(props);
    this.state = { submitted: false };
  }

  render() {
    const query = this.props.rsvpSearch.query;

    let inviteFoundJsx = <InviteNotFound />;

    if (!this.state.submitted) {
      inviteFoundJsx = <SubmitBtn displayText="Find" />;
    } else if (this.props.rsvpSearch.result) {
      // added check for when invite found, and then input changes
      emailInInvitation(this.props.rsvpSearch.result, this.props, (found) => {
        if (found) {
          const shortName = this.props.rsvpSearch.result.shortName;
          inviteFoundJsx = (
            <div className={`${effects.fade}`}>

RSVP Found

              <Button bsSize="large" className={`${glob.button}`} href={`/rsvp/${shortName}`}>
                Go to RSVP
              </Button>

          );
        }
      });
    }

    const inputJsx = (

        Email
        <input
          className={`${glob.matInput}`}
          type="email"
          id="rsvp-query"
          value={query}
          onBlur={this._handleBlur.bind(this)}
          onChange={this._handleChange.bind(this)}
          onFocus={this._handleFocus.bind(this)}
        />

    );

    let formGroupClasses = `${glob.matGroup}`;
    if (this.state && this.state.active || query) {
      formGroupClasses = `${glob.matGroup} ${glob.isActive} ${glob.isCompleted}`;
    }

    const formGroupJsx = (
      <FormGroup className={formGroupClasses} style={{ textAlign: 'center' }}>
        {inputJsx}
      </FormGroup>
    );

    return (

        <PageHeader page="Find RSVP" />

          <Row>
            <Col xs={10} xsOffset={1} sm={6} smOffset={3}>
              <Form
                onSubmit={this._handleSubmit.bind(this)}
                style={{ textAlign: 'center' }}
              >

                  <Row>
                    <Col xs={12}>
                      {formGroupJsx}
                    </Col>
                  </Row>

                <Row style={{ marginTop: '30px' }}>
                  <Col xs={12} style={{ textAlign: 'center' }}>
                    {inviteFoundJsx}
                  </Col>
                </Row>
              </Form>
            </Col>
          </Row>

    );
  }

  _handleSubmit(e) {
    e.preventDefault();
    this.setState({ submitted: true });
  }

  _handleBlur() {
    if (this.props.rsvpSearch.query === '') {
      this.setState({ active: false });
    }
  }

  _handleFocus() {
    this.setState({ active: true });
  }

  _handleChange(event) {
    if (event.target.value === '') {
      this.setState({ active: false });
    }
    this.props.dispatch(updateRsvpQuery(event.target.value));
  }
}

export default subscribe({
  mapDataToProps,
  mapStateToProps
})(Rsvp);
<commit_msg>undid change<commit_after>import React from 'react';
import { subscribe } from 'horizon-react';
import { Row, Col, Form, FormGroup, Button } from 'react-bootstrap';
import { updateRsvpQuery, updateRsvpResult } from '../../../actions/actionCreators';
import PageHeader from '../../_partials/page-header';
import InviteNotFound from '../rsvp/not-found';
import SubmitBtn from '../../shared/submit-btn';
import glob from 'styles/app';
import effects from 'styles/effects';

/**
  *
  * RSVP Search Page
  *
  * Includes ..
  *
  * @param ..
  *
  * @return {ReactComponent}
  */

const emailInInvitation = (invitation, props, cb) => {
  let found = false;
  invitation.guests.forEach(
    guest => {
      if (guest.email && guest.email === props.rsvpSearch.query) {
        found = true;
      }
    }
  );
  cb(found);
};

const mapDataToProps = {
  invitations: (hz, props) => {
    hz('invitations').fetch().subscribe(
      invitations => {
        invitations.forEach(
          invitation => {
            emailInInvitation(invitation, props, (found) => {
              if (found) {
                props.dispatch(updateRsvpResult(invitation));
              }
            });
          }
        );
      }
    );
    return hz('invitations');
  }
};

const mapStateToProps = (state) => ({
  rsvpSearch: state.rsvpSearch
});

class Rsvp extends React.Component {
  constructor(props) {
    super(props);
    this.state = { submitted: false };
  }

  render() {
    const query = this.props.rsvpSearch.query;

    let inviteFoundJsx = <InviteNotFound />;

    if (!this.state.submitted) {
      inviteFoundJsx = <SubmitBtn displayText="Find" />;
    } else if (this.props.rsvpSearch.result) {
      // added check for when invite found, and then input changes
      emailInInvitation(this.props.rsvpSearch.result, this.props, (found) => {
        if (found) {
          const shortName = this.props.rsvpSearch.result.shortName;
          inviteFoundJsx = (
            <div className={`${effects.fade}`}>

RSVP Found

              <Button bsSize="large" className={`${glob.button}`} href={`/rsvp/${shortName}`}>
                Go to RSVP
              </Button>

          );
        }
      });
    }

    const inputJsx = (

        Email
        <input
          className={`${glob.matInput}`}
          type="email"
          id="rsvp-query"
          value={query}
          onBlur={this._handleBlur.bind(this)}
          onChange={this._handleChange.bind(this)}
          onFocus={this._handleFocus.bind(this)}
        />

    );

    let formGroupClasses = `${glob.matGroup}`;
    if (this.state && this.state.active || query) {
      formGroupClasses = `${glob.matGroup} ${glob.isActive} ${glob.isCompleted}`;
    }

    const formGroupJsx = (
      <FormGroup className={formGroupClasses} style={{ textAlign: 'center' }}>
        {inputJsx}
      </FormGroup>
    );

    return (

        <PageHeader page="Find RSVP" />

          <Row>
            <Col xs={10} xsOffset={1} sm={6} smOffset={3}>
              <Form
                onSubmit={this._handleSubmit.bind(this)}
                style={{ textAlign: 'center' }}
              >

                  <Row>
                    <Col xs={12}>
                      {formGroupJsx}
                    </Col>
                  </Row>

                <Row style={{ marginTop: '30px' }}>
                  <Col xs={12} style={{ textAlign: 'center' }}>
                    {inviteFoundJsx}
                  </Col>
                </Row>
              </Form>
            </Col>
          </Row>

    );
  }

  _handleSubmit(e) {
    e.preventDefault();
    this.setState({ submitted: true });
  }

  _handleBlur() {
    if (this.props.rsvpSearch.query === '') {
      this.setState({ active: false });
    }
  }

  _handleFocus() {
    this.setState({ active: true });
  }

  _handleChange(event) {
    if (event.target.value === '') {
      this.setState({ active: false });
    }
    this.props.dispatch(updateRsvpQuery(event.target.value));
  }
}

export default subscribe({
  mapDataToProps,
  mapStateToProps
})(Rsvp);
<|endoftext|>


<commit_before>'use strict';

var EventEmitter = require('eventemitter3');

/**
 * A Shared Worker Engine for the tabdancer.
 *
 * @constructor
 * @param {Dancer} dancer The dancer which uses this engine.
 * @param {Object} options Configuration.
 * @api public
 */
function Shared(dancer, options) {
  this.blob = false;                // Check if we support the Blob interface.
  this.worker = 0;                  // Reference to our Worker instance.
  this.url = 0;                     // URL Blob.
}

Shared.prototype = new EventEmitter();
Shared.prototype.constructor = Shared;
Shared.prototype.emits = require('./emits');

/**
 * The piece of code that needs to be loaded in the Shared Worker so we can
 * broadcast all our information.
 *
 * @type {String}
 * @private
 */
Shared.prototype.echo = [
  'var connections = [];',

  'self.addEventListener("connect", function onconnect(e) {',
    'var port = e.ports[0]; connections.push(port);',

    'port.addEventListener("message", function message(e) {',
      'for (var i = 0, l = connections.length; i < l; i++) {',
        'connections[i].postMessage(e.data);',
      '}',
    '}, false);',

    'port.start();',
    'port.postMessaage({ type: "tabdancer", connections: connections.length });',
  '}, false);'
].join('\n');

/**
 * Start listening for incoming data and or events.
 *
 * @param {Function} fn Receives boolean indication for master indication.
 * @api private
 */
Shared.prototype.listen = function listen(fn) {
  var waiting = true
    , selfie = this
    , blob, worker;

  //
  // Detect ancient blob interfaces to figure out how we can compile our code
  // to something useful. This detection is already done in the .supported
  // method which sets the .blob to true when it's supported.
  //
  if (!this.blob) {
    blob = new BlobBuilder();
    blob.append(this.echo);
    blob = blob.getBlob();
  } else {
    blob = new Blob([this.echo], { type: 'text/javascript' });
  }

  this.url = URL.createObjectURL(blob);

  worker = this.worker = new SharedWorker(this.url, this.dancer.prefix);
  worker.port.addEventListener('error', this.emits('error'), false);
  worker.port.addEventListener('message', this.emits('data', function parser(e) {
    var data = e.data;

    //
    // This is the first message that we receive from the worker which tells us
    // how many connections there are. If there are 0, it's save to assume that
    // we're the first to start this worker and are there for the master
    // process.
    //
    if (waiting && 'object' === typeof data && data.type === "tabdancer") {
      waiting = false;
      fn(undefined, selfie, data.connections === 0);
      return selfie.emits; // Return it self as indication to prevent execution
    }

    return data;
  }), false);

  //
  // The worker.port is only needed when assigning event listeners to the
  // worker. Which is something that we're doing.
  //
  worker.port.start();
};

/**
 * Write a message to all the things.
 *
 * @param {String} data Message to be broadcast.
 * @api public
 */
Shared.prototype.write = function write(data) {
  return this.worker.port.postMessage(data);
};

/**
 * End the Shared Worker and clean up all references to all the things.
 *
 * @api public
 */
Shared.prototype.end = function end() {
  if (this.url) URL.revokeObjectURL(this.url);
  if (this.worker) this.worker.terminate();
};

/**
 * Check to see if this engine is supported for tab dancing. It needs to check
 * if:
 *
 * - Blob URL's are working.
 * - Shared workers exist.
 * - Shared workers can communicate.
 *
 * @param {Function} fn Completion callback.
 * @api private
 */
Shared.prototype.supported = function supported(fn) {
  var passed = false
    , selfie = this
    , echo = this.echo
    , url, worker, timer, blob
    , message = this.dancer.prefix +':supported';

  /**
   * Cleanup all the crap that we've created while testing if this Shared Worker
   * thing is supported.
   *
   * @api private
   */
  function cleanup() {
    selfie.destroy();
    if (timer) clearTimeout(timer);

    fn(passed);
  }

  try {
    try { blob = new Blob([echo], { type: 'text/javascript' }); this.blob = true; }
    catch (e) { blob = new BlobBuilder(); blob.append(echo); blob = blob.getBlob(); }

    this.url = URL.createObjectURL(blob);
    this.worker = new SharedWorker(url);

    worker.port.addEventListener('error', cleanup);
    timer = setTimeout(cleanup, 200);

    worker.port.addEventListener('message', function message(e) {
      passed = e.data === message;
      cleanup();
    }, false);

    worker.port.start();
    worker.port.postMessage(message);
  } catch (e) {
    cleanup();
  }
};

//
// Expose the engine.
//
module.exports = Shared;
<commit_msg>[fix] Added missing dancer reference. [fix] Correctly close the worker using `.port.close()` [fix] Call `.end` instead of `.destroy`<commit_after>'use strict';

var EventEmitter = require('eventemitter3');

/**
 * A Shared Worker Engine for the tabdancer.
 *
 * @constructor
 * @param {Dancer} dancer The dancer which uses this engine.
 * @param {Object} options Configuration.
 * @api public
 */
function Shared(dancer, options) {
  if (!(this instanceof Shared)) return new Shared(dancer, options);

  this.dancer = dancer;             // Reference to our dancer instance.
  this.blob = false;                // Check if we support the Blob interface.
  this.worker = 0;                  // Reference to our Worker instance.
  this.url = 0;                     // URL Blob.
}

Shared.prototype = new EventEmitter();
Shared.prototype.constructor = Shared;
Shared.prototype.emits = require('./emits');

/**
 * The piece of code that needs to be loaded in the Shared Worker so we can
 * broadcast all our information.
 *
 * @type {String}
 * @private
 */
Shared.prototype.echo = [
  'var connections = [];',

  'self.addEventListener("connect", function onconnect(e) {',
    'var port = e.ports[0]; connections.push(port);',

    'port.addEventListener("message", function message(e) {',
      'for (var i = 0, l = connections.length; i < l; i++) {',
        'connections[i].postMessage(e.data);',
      '}',
    '}, false);',

    'port.start();',
    'port.postMessaage({ type: "tabdancer", connections: connections.length });',
  '}, false);'
].join('\n');

/**
 * Start listening for incoming data and or events.
 *
 * @param {Function} fn Receives boolean indication for master indication.
 * @api private
 */
Shared.prototype.listen = function listen(fn) {
  var waiting = true
    , selfie = this
    , blob, worker;

  //
  // Detect ancient blob interfaces to figure out how we can compile our code
  // to something useful. This detection is already done in the .supported
  // method which sets the .blob to true when it's supported.
  //
  if (!this.blob) {
    blob = new BlobBuilder();
    blob.append(this.echo);
    blob = blob.getBlob();
  } else {
    blob = new Blob([this.echo], { type: 'text/javascript' });
  }

  this.url = URL.createObjectURL(blob);

  worker = this.worker = new SharedWorker(this.url, this.dancer.prefix);
  worker.port.addEventListener('error', this.emits('error'), false);
  worker.port.addEventListener('message', this.emits('data', function parser(e) {
    var data = e.data;

    //
    // This is the first message that we receive from the worker which tells us
    // how many connections there are. If there are 0, it's save to assume that
    // we're the first to start this worker and are there for the master
    // process.
    //
    if (waiting && 'object' === typeof data && data.type === "tabdancer") {
      waiting = false;
      fn(undefined, selfie, data.connections === 0);
      return selfie.emits; // Return it self as indication to prevent execution
    }

    return data;
  }), false);

  //
  // The worker.port is only needed when assigning event listeners to the
  // worker. Which is something that we're doing.
  //
  worker.port.start();
};

/**
 * Write a message to all the things.
 *
 * @param {String} data Message to be broadcast.
 * @api public
 */
Shared.prototype.write = function write(data) {
  return this.worker.port.postMessage(data);
};

/**
 * End the Shared Worker and clean up all references to all the things.
 *
 * @api public
 */
Shared.prototype.end = function end() {
  if (this.url) URL.revokeObjectURL(this.url);
  if (this.worker) this.worker.port.close();
};

/**
 * Check to see if this engine is supported for tab dancing. It needs to check
 * if:
 *
 * - Blob URL's are working.
 * - Shared workers exist.
 * - Shared workers can communicate.
 *
 * @param {Function} fn Completion callback.
 * @api private
 */
Shared.prototype.supported = function supported(fn) {
  var passed = false
    , selfie = this
    , echo = this.echo
    , url, worker, timer, blob
    , message = this.dancer.prefix +':supported';

  /**
   * Cleanup all the crap that we've created while testing if this Shared Worker
   * thing is supported.
   *
   * @api private
   */
  function cleanup() {
    selfie.end();
    if (timer) clearTimeout(timer);

    fn(passed);
  }

  try {
    try { blob = new Blob([echo], { type: 'text/javascript' }); this.blob = true; }
    catch (e) { blob = new BlobBuilder(); blob.append(echo); blob = blob.getBlob(); }

    this.url = URL.createObjectURL(blob);
    this.worker = new SharedWorker(url);

    worker.port.addEventListener('error', cleanup);
    timer = setTimeout(cleanup, 200);

    worker.port.addEventListener('message', function message(e) {
      passed = e.data === message;
      cleanup();
    }, false);

    worker.port.start();
    worker.port.postMessage(message);
  } catch (e) {
    cleanup();
  }
};

//
// Expose the engine.
//
module.exports = Shared;
<|endoftext|>