text:
"use strict";

const ms = require("ms");
const jwt = require("jsonwebtoken");
const Bluebird = require("bluebird");
const should = require("should");
const sinon = require("sinon");
const mockrequire = require("mock-require");

const {
  BadRequestError,
  InternalError: KuzzleInternalError,
  UnauthorizedError,
} = require("../../../index");
const KuzzleMock = require("../../mocks/kuzzle.mock");
const MutexMock = require("../../mocks/mutex.mock");

const { Token } = require("../../../lib/model/security/token");
const { User } = require("../../../lib/model/security/user");
const Repository = require("../../../lib/core/shared/repository");
const ApiKey = require("../../../lib/model/storage/apiKey");

describe("Test: security/tokenRepository", () => {
  let kuzzle;
  let TokenRepository;
  let tokenRepository;

  beforeEach(() => {
    kuzzle = new KuzzleMock();
    kuzzle.secret = "test-secret";

    mockrequire("../../../lib/util/mutex", { Mutex: MutexMock });
    TokenRepository = mockrequire.reRequire(
      "../../../lib/core/security/tokenRepository"
    );

    tokenRepository = new TokenRepository();
    sinon.stub(tokenRepository, "_loadApiKeys");
    sinon.stub(ApiKey, "batchExecute");

    return tokenRepository.init();
  });

  afterEach(() => {
    ApiKey.batchExecute.restore();
    mockrequire.stopAll();
  });

  describe("#constructor", () => {
    it("should take into account the options given", () => {
      const repository = new TokenRepository({ ttl: 1000 });

      should(repository.ttl).be.exactly(1000);
    });

    it("should define a valid anonymous token", () => {
      assertIsAnonymous(tokenRepository.anonymousToken);
    });
  });

  describe("#hydrate", () => {
    it("should return the given token if the given data is not a valid object", () => {
      const t = new Token();

      return Bluebird.all([
        tokenRepository.hydrate(t, null),
        tokenRepository.hydrate(t),
        tokenRepository.hydrate(t, "a scalar"),
      ]).then((results) =>
        results.forEach((token) => should(token).be.exactly(t))
      );
    });

    it("should return the anonymous token if no _id is set", (done) => {
      const token = new Token();

      tokenRepository
        .hydrate(token, {})
        .then((result) => {
          assertIsAnonymous(result);
          done();
        })
        .catch((err) => {
          done(err);
        });
    });
  });

  describe("#verify", () => {
    beforeEach(() => {
      kuzzle.ask.withArgs("core:cache:internal:get").resolves(null);
    });

    it('should register a "verify" event', async () => {
      sinon.stub(tokenRepository, "verifyToken");

      kuzzle.ask.restore();
      await kuzzle.ask("core:security:token:verify", "hash");

      should(tokenRepository.verifyToken).calledWith("hash");
    });

    it("should reject the promise if the jwt is invalid", () => {
      return should(
        tokenRepository.verifyToken("invalidToken")
      ).be.rejectedWith(UnauthorizedError, {
        id: "security.token.invalid",
      });
    });

    it("should reject the token if the uuid is not known", () => {
      const token = jwt.sign({ _id: -99999 }, kuzzle.secret, {
        algorithm: kuzzle.config.security.jwt.algorithm,
      });

      return should(tokenRepository.verifyToken(token)).be.rejectedWith(
        UnauthorizedError,
        {
          id: "security.token.invalid",
        }
      );
    });

    it("should reject if the jwt is expired", () => {
      const token = jwt.sign({ _id: -1 }, kuzzle.secret, {
        algorithm: kuzzle.config.security.jwt.algorithm,
        expiresIn: 0,
      });

      return should(tokenRepository.verifyToken(token)).be.rejectedWith(
        UnauthorizedError,
        {
          id: "security.token.expired",
        }
      );
    });

    it("should reject if an error occurred while fetching the user from the cache", () => {
      const token = jwt.sign({ _id: "auser" }, kuzzle.secret, {
        algorithm: kuzzle.config.security.jwt.algorithm,
      });

      sinon
        .stub(tokenRepository, "loadFromCache")
        .rejects(new KuzzleInternalError("Error"));

      return should(tokenRepository.verifyToken(token)).be.rejectedWith(
        KuzzleInternalError,
        {
          id: "security.token.verification_error",
        }
      );
    });

    it("should load the anonymous user if the token is null", async () => {
      const userToken = await tokenRepository.verifyToken(null);

      assertIsAnonymous(userToken);
    });

    it("should reject the token if it does not contain the user id", () => {
      const token = jwt.sign({ forged: "token" }, kuzzle.secret, {
        algorithm: kuzzle.config.security.jwt.algorithm,
      });

      return should(tokenRepository.verifyToken(token)).be.rejectedWith(
        UnauthorizedError,
        {
          id: "security.token.invalid",
        }
      );
    });

    it("should return the token loaded from cache", async () => {
      const _id = "auser";
      const token = jwt.sign({ _id }, kuzzle.secret, {
        algorithm: kuzzle.config.security.jwt.algorithm,
      });
      const cacheObj = JSON.stringify({ _id, jwt: token });

      kuzzle.ask
        .withArgs(
          "core:cache:internal:get",
          tokenRepository.getCacheKey(`${_id}#${token}`)
        )
        .resolves(cacheObj);

      const loaded = await tokenRepository.verifyToken(token);

      should(loaded).be.instanceOf(Token).and.match(JSON.parse(cacheObj));

      // the cache entry must not be refreshed
      should(kuzzle.ask).not.be.calledWith("core:cache:internal:expire");
    });
  });

  describe("#create", () => {
    it('should register a "create" event', async () => {
      sinon.stub(tokenRepository, "generateToken");

      kuzzle.ask.restore();
      await kuzzle.ask("core:security:token:create", "user", "opts");

      should(tokenRepository.generateToken).calledWith("user", "opts");
    });

    it("should reject the promise if the username is null", () => {
      return should(tokenRepository.generateToken(null)).be.rejectedWith(
        KuzzleInternalError,
        {
          id: "security.token.unknown_user",
        }
      );
    });

    it("should resolve to a token signed with the provided username", async () => {
      const user = new User();
      const rawToken = jwt.sign({ _id: "userInCache" }, kuzzle.secret, {
        algorithm: kuzzle.config.security.jwt.algorithm,
        expiresIn: ms(kuzzle.config.security.jwt.expiresIn) / 1000,
      });
      const checkToken = Token.AUTH_PREFIX + rawToken;

      user._id = "userInCache";

      sinon.spy(tokenRepository, "persistForUser");

      const token = await tokenRepository.generateToken(user);

      should(token).be.an.instanceOf(Token);
      should(token.jwt).be.exactly(checkToken);
      should(token._id).be.exactly(`${user._id}#${checkToken}`);
      should(tokenRepository.persistForUser).be.calledWith(
        checkToken,
        user._id,
        3600000
      );
    });

    it("should return an internal error if an error occurs when generating token", async () => {
      const user = new User();

      user._id = "userInCache";

      mockrequire("jsonwebtoken", {
        sign: () => {
          throw new Error("oh noes");
        },
      });

      const MockedTokenRepository = mockrequire.reRequire(
        "../../../lib/core/security/tokenRepository"
      );

      tokenRepository = new MockedTokenRepository();

      try {
        await should(tokenRepository.generateToken(user)).be.rejectedWith(
          KuzzleInternalError,
          {
            id: "security.token.generation_failed",
          }
        );
      } finally {
        mockrequire.stopAll();
      }
    });

    it("should allow a big ttl if no maxTTL is set for jwt", async () => {
      const user = new User();
      user._id = "id";

      const token = await tokenRepository.generateToken(user, {
        expiresIn: "1000y",
      });

      should(token).be.an.instanceOf(Token);
    });

    it("should allow a big ttl if no maxTTL is set for apiKey", async () => {
      const user = new User();
      user._id = "id";

      const token = await tokenRepository.generateToken(user, {
        expiresIn: "1000y",
        type: "apiKey",
      });

      should(token).be.an.instanceOf(Token);
    });

    it("should prefix the token", async () => {
      const user = new User();
      user._id = "id";
      const tokenAuth = await tokenRepository.generateToken(user);
      const tokenApiKey = await tokenRepository.generateToken(user, {
        type: "apiKey",
      });

      should(tokenAuth.jwt).be.startWith("kauth-");
      should(tokenApiKey.jwt).be.startWith("kapikey-");
    });

    it("should allow a ttl lower than the maxTTL for jwt", async () => {
      const user = new User();
      user._id = "id";

      kuzzle.config.security.jwt.maxTTL = 42000;

      const token = await tokenRepository.generateToken(user, {
        expiresIn: "30s",
      });

      should(token).be.an.instanceOf(Token);
    });

    it("should allow a ttl lower than the maxTTL for apiKey", async () => {
      const user = new User();
      user._id = "id";

      kuzzle.config.security.apiKey.maxTTL = 42000;

      const token = await tokenRepository.generateToken(user, {
        expiresIn: "30s",
        type: "apiKey",
      });

      should(token).be.an.instanceOf(Token);
    });

    it("should reject if the ttl exceeds the maxTTL for jwt", () => {
      const user = new User();
      user._id = "id";

      kuzzle.config.security.jwt.maxTTL = 42000;

      return should(
        tokenRepository.generateToken(user, { expiresIn: "1m" })
      ).be.rejectedWith(BadRequestError, { id: "security.token.ttl_exceeded" });
    });

    it("should reject if the ttl exceeds the maxTTL for apiKey", () => {
      const user = new User();
      user._id = "id";

      kuzzle.config.security.apiKey.maxTTL = 42000;

      return should(
        tokenRepository.generateToken(user, { expiresIn: "1m", type: "apiKey" })
      ).be.rejectedWith(BadRequestError, { id: "security.token.ttl_exceeded" });
    });

    it("should reject if the ttl is infinite and the maxTTL is finite for jwt", () => {
      const user = new User();
      user._id = "id";

      kuzzle.config.security.jwt.maxTTL = 42000;

      return should(
        tokenRepository.generateToken(user, { expiresIn: -1 })
      ).be.rejectedWith(BadRequestError, { id: "security.token.ttl_exceeded" });
    });

    it("should reject if the ttl is infinite and the maxTTL is finite for apiKey", () => {
      const user = new User();
      user._id = "id";

      kuzzle.config.security.apiKey.maxTTL = 42000;

      return should(
        tokenRepository.generateToken(user, { expiresIn: -1, type: "apiKey" })
      ).be.rejectedWith(BadRequestError, { id: "security.token.ttl_exceeded" });
    });

    it("should reject if the ttl is not ms-compatible or not a number", () => {
      const user = new User();
      user._id = "id";

      return should(
        tokenRepository.generateToken(user, { expiresIn: "ehh" })
      ).be.rejectedWith(BadRequestError, {
        id: "api.assert.invalid_argument",
      });
    });

    it("should pass the correct expiration delay to jwt.sign", async () => {
      // jwt.sign does not accept double values for its expiresIn option
      // in previous versions of Kuzzle, we simply divided the number of
      // milliseconds received by 1000 without precaution, making jwt.sign
      // throw an error when generating the token
      const user = new User();
      const rawToken = jwt.sign({ _id: "userInCache" }, kuzzle.secret, {
        algorithm: kuzzle.config.security.jwt.algorithm,
        expiresIn: 123,
      });
      const checkToken = Token.AUTH_PREFIX + rawToken;

      user._id = "userInCache";

      sinon.spy(tokenRepository, "persistForUser");

      const token = await tokenRepository.generateToken(user, {
        expiresIn: 123456,
      });

      should(token).be.an.instanceOf(Token);
      should(token.jwt).be.exactly(checkToken);
      should(token._id).be.exactly(`${user._id}#${checkToken}`);
      should(tokenRepository.persistForUser).be.calledWith(
        checkToken,
        user._id,
        123456
      );
    });
  });

  describe("#assign", () => {
    it('should register an "assign" event', async () => {
      sinon.stub(tokenRepository, "persistForUser");

      kuzzle.ask.restore();
      await kuzzle.ask("core:security:token:assign", "hash", "user", "ttl");

      should(tokenRepository.persistForUser).calledWith("hash", "user", "ttl");
    });

    it("should persist a token with TTL into Redis", async () => {
      const token = await tokenRepository.persistForUser(
        "encoded-token",
        "user-id",
        42000
      );

      should(kuzzle.ask).be.calledWith(
        "core:cache:internal:store",
        "repos/kuzzle/token/user-id#encoded-token",
        JSON.stringify(token),
        { ttl: 42000 }
      );
      should(token._id).be.eql("user-id#encoded-token");
      should(token.ttl).be.eql(42000);
      should(token.expiresAt).be.approximately(Date.now() + 42000, 20);
    });

    it("should persist a token without TTL into Redis", async () => {
      const token = await tokenRepository.persistForUser(
        "encoded-token",
        "user-id",
        -1
      );

      should(kuzzle.ask).be.calledWith(
        "core:cache:internal:store",
        "repos/kuzzle/token/user-id#encoded-token",
        JSON.stringify(token)
      );
    });
  });

  describe("#serializeToCache", () => {
    it("should return a valid plain object", () => {
      const token = new Token({ userId: "foo" });
      const result = tokenRepository.serializeToCache(token);

      should(result).not.be.an.instanceOf(Token);
      should(result).be.an.Object();
      should(result._id).be.exactly(null);
      should(result.userId).be.exactly("foo");
    });
  });

  describe("#delete", () => {
    it('should register a "delete" event', async () => {
      sinon.stub(tokenRepository, "expire");

      kuzzle.ask.restore();
      await kuzzle.ask("core:security:token:delete", "token");

      should(tokenRepository.expire).calledWith("token");
    });

    it("should be able to expires a token", async () => {
      const user = new User();
      user._id = "userInCache";

      const token = await tokenRepository.generateToken(user, "connectionId");

      sinon.stub(Repository.prototype, "expireFromCache");

      try {
        await tokenRepository.expire(token);

        should(kuzzle.tokenManager.expire).be.calledOnce().be.calledWith(token);
      } finally {
        Repository.prototype.expireFromCache.restore();
      }
    });
  });

  describe("#deleteByKuid", () => {
    it('should register a "deleteByKuid" event', async () => {
      sinon.stub(tokenRepository, "deleteByKuid");

      kuzzle.ask.restore();
      await kuzzle.ask("core:security:token:deleteByKuid", "kuid");

      should(tokenRepository.deleteByKuid).calledWith("kuid");
    });

    it("should delete the tokens associated to a user identifier", async () => {
      sinon.stub(tokenRepository, "refreshCacheTTL");
      kuzzle.ask
        .withArgs("core:cache:internal:searchKeys")
        .resolves([
          "repos/kuzzle/token/foo#foo",
          "repos/kuzzle/token/foo#bar",
          `repos/kuzzle/token/foo#${Token.APIKEY_PREFIX}baz`,
        ]);

      kuzzle.ask
        .withArgs("core:cache:internal:get")
        .onFirstCall()
        .resolves(
          JSON.stringify({
            userId: "foo",
            _id: "foo",
            expiresAt: 1,
            jwt: "foo",
          })
        );

      kuzzle.ask
        .withArgs("core:cache:internal:get")
        .onSecondCall()
        .resolves(
          JSON.stringify({
            userId: "foo",
            _id: "bar",
            expiresAt: 2,
            jwt: "bar",
          })
        );

      kuzzle.ask
        .withArgs("core:cache:internal:get")
        .onThirdCall()
        .resolves(
          JSON.stringify({
            userId: "foo",
            _id: `${Token.APIKEY_PREFIX}baz`,
            expiresAt: 3,
            jwt: `${Token.APIKEY_PREFIX}baz`,
          })
        );

      await tokenRepository.deleteByKuid("foo", { keepApiKeys: false });

      should(kuzzle.ask)
        .calledWith("core:cache:internal:expire", "repos/kuzzle/token/foo", -1)
        .calledWith("core:cache:internal:expire", "repos/kuzzle/token/bar", -1)
        .calledWith(
          "core:cache:internal:expire",
          `repos/kuzzle/token/${Token.APIKEY_PREFIX}baz`,
          -1
        );

      should(kuzzle.tokenManager.expire)
        .calledWithMatch({ userId: "foo", _id: "foo", expiresAt: 1 })
        .calledWithMatch({ userId: "foo", _id: "bar", expiresAt: 2 })
        .calledWithMatch({
          userId: "foo",
          _id: `${Token.APIKEY_PREFIX}baz`,
          expiresAt: 3,
        });
    });

    it("should delete the tokens associated to a user identifier except the ones that are API Keys", async () => {
      sinon.stub(tokenRepository, "refreshCacheTTL");
      kuzzle.ask
        .withArgs("core:cache:internal:searchKeys")
        .resolves([
          "repos/kuzzle/token/foo#foo",
          "repos/kuzzle/token/foo#bar",
          `repos/kuzzle/token/foo#${Token.APIKEY_PREFIX}baz`,
        ]);

      kuzzle.ask
        .withArgs("core:cache:internal:get")
        .onFirstCall()
        .resolves(
          JSON.stringify({
            userId: "foo",
            _id: "foo",
            expiresAt: 1,
            jwt: "foo",
          })
        );

      kuzzle.ask
        .withArgs("core:cache:internal:get")
        .onSecondCall()
        .resolves(
          JSON.stringify({
            userId: "foo",
            _id: "bar",
            expiresAt: 2,
            jwt: "bar",
          })
        );

      kuzzle.ask
        .withArgs("core:cache:internal:get")
        .onThirdCall()
        .resolves(
          JSON.stringify({
            userId: "foo",
            _id: `${Token.APIKEY_PREFIX}baz`,
            expiresAt: 3,
            jwt: `${Token.APIKEY_PREFIX}baz`,
          })
        );
      await tokenRepository.deleteByKuid("foo", { keepApiKeys: true });

      should(kuzzle.ask)
        .calledWith("core:cache:internal:expire", "repos/kuzzle/token/foo", -1)
        .calledWith("core:cache:internal:expire", "repos/kuzzle/token/bar", -1)
        .not.calledWith(
          "core:cache:internal:expire",
          `repos/kuzzle/token/${Token.APIKEY_PREFIX}baz`,
          -1
        );

      should(kuzzle.tokenManager.expire)
        .calledWithMatch({ userId: "foo", _id: "foo", expiresAt: 1 })
        .calledWithMatch({ userId: "foo", _id: "bar", expiresAt: 2 })
        .not.calledWithMatch({
          userId: "foo",
          _id: `${Token.APIKEY_PREFIX}baz`,
          expiresAt: 3,
        });
    });

    it("should not delete tokens if the internal cache return a false positive", async () => {
      sinon.stub(tokenRepository, "refreshCacheTTL");
      kuzzle.ask
        .withArgs("core:cache:internal:searchKeys")
        .resolves([
          "repos/kuzzle/token/foo#foo",
          "repos/kuzzle/token/foo#bar#bar",
          "repos/kuzzle/token/foo#baz",
        ]);

      const cacheGetStub = kuzzle.ask.withArgs("core:cache:internal:get");

      cacheGetStub
        .onFirstCall()
        .resolves(JSON.stringify({ userId: "foo", _id: "foo", expiresAt: 1 }));

      cacheGetStub
        .onSecondCall()
        .resolves(JSON.stringify({ userId: "foo", _id: "baz", expiresAt: 2 }));

      await tokenRepository.deleteByKuid("foo");

      should(cacheGetStub.callCount).be.eql(2);

      const expireStub = kuzzle.ask.withArgs("core:cache:internal:expire");

      should(expireStub.callCount).be.eql(2);
      should(expireStub)
        .calledWith("core:cache:internal:expire", "repos/kuzzle/token/foo", -1)
        .calledWith("core:cache:internal:expire", "repos/kuzzle/token/baz", -1);

      should(kuzzle.tokenManager.expire.callCount).be.eql(2);
      should(kuzzle.tokenManager.expire)
        .calledWithMatch({ userId: "foo", _id: "foo", expiresAt: 1 })
        .calledWithMatch({ userId: "foo", _id: "baz", expiresAt: 2 });
    });
  });

  describe("#get", () => {
    it('should register a "get" event', async () => {
      sinon.stub(tokenRepository, "loadForUser");

      kuzzle.ask.restore();
      await kuzzle.ask("core:security:token:get", "user", "hash");

      should(tokenRepository.loadForUser).calledWith("user", "hash");
    });

    it("should retrieve the right token", async () => {
      sinon.stub(Repository.prototype, "load").resolves("foo");

      try {
        const ret = await tokenRepository.loadForUser("user", "hash");

        should(ret).eql("foo");

        should(Repository.prototype.load).calledWith("user#hash");
      } finally {
        Repository.prototype.load.restore();
      }
    });
  });

  describe("#refresh", () => {
    let fakeToken;

    beforeEach(() => {
      fakeToken = new Token();

      sinon.stub(tokenRepository, "generateToken").resolves(fakeToken);
      sinon.stub(tokenRepository, "persistToCache").resolves();
    });

    it('should register a "refresh" event', async () => {
      sinon.stub(tokenRepository, "refresh");

      kuzzle.ask.restore();
      await kuzzle.ask("core:security:token:refresh", "user", "token", "ttl");

      should(tokenRepository.refresh).calledWith("user", "token", "ttl");
    });

    it("should create a new token and expire the old one", async () => {
      const oldToken = new Token();

      const token = await tokenRepository.refresh("user", oldToken, "10m");

      should(token).eql(fakeToken);
      should(oldToken.refreshed).be.true();
      should(tokenRepository.generateToken).calledWithMatch("user", {
        expiresIn: "10m",
      });
      should(tokenRepository.persistToCache).calledWithMatch(oldToken, {
        ttl: kuzzle.config.security.jwt.gracePeriod,
      });
      should(kuzzle.tokenManager.refresh).calledWith(oldToken, fakeToken);
    });

    it("should leave the current token intact if a new one cannot be created", async () => {
      const oldToken = new Token();

      tokenRepository.generateToken.rejects(new Error("foo"));

      await should(
        tokenRepository.refresh("user", oldToken, "10m")
      ).rejectedWith("foo");

      should(oldToken.refreshed).be.false();
      should(tokenRepository.persistToCache).not.called();
    });

    it("should refuse to refresh an already refreshed token", async () => {
      const oldToken = new Token();
      oldToken.refreshed = true;

      await should(
        tokenRepository.refresh("user", oldToken, "10m")
      ).rejectedWith(UnauthorizedError, { id: "security.token.invalid" });

      should(tokenRepository.generateToken).not.called();
      should(tokenRepository.persistToCache).not.called();
    });

    it("should refuse to refresh an API Key", async () => {
      const oldToken = new Token();
      oldToken.jwt = "kapikey-jwt";

      await should(
        tokenRepository.refresh("user", oldToken, "10m")
      ).rejectedWith(UnauthorizedError, {
        id: "security.token.refresh_forbidden",
      });

      should(tokenRepository.generateToken).not.called();
      should(tokenRepository.persistToCache).not.called();
    });

    it("should refuse to refresh a token with an infinite TTL", async () => {
      const oldToken = new Token();
      oldToken.ttl = -1;

      await should(
        tokenRepository.refresh("user", oldToken, "10m")
      ).rejectedWith(UnauthorizedError, {
        id: "security.token.refresh_forbidden",
      });

      should(tokenRepository.generateToken).not.called();
      should(tokenRepository.persistToCache).not.called();
    });
  });

  describe("#_loadApiKeys", () => {
    beforeEach(() => {
      tokenRepository._loadApiKeys.restore();
      sinon.stub(tokenRepository, "persistForUser");

      kuzzle.ask.withArgs("core:cache:internal:get").returns(null);

      ApiKey.batchExecute.callsArgWith(1, [
        { _source: { token: "encoded-token-1", userId: "user-id-1", ttl: 42 } },
        { _source: { token: "encoded-token-2", userId: "user-id-2", ttl: -1 } },
      ]);
    });

    it("should load API key tokens to Redis cache", async () => {
      await tokenRepository._loadApiKeys();

      should(ApiKey.batchExecute).be.calledWith({ match_all: {} });

      should(tokenRepository.persistForUser)
        .be.calledWith("encoded-token-1", "user-id-1", 42)
        .be.calledWith("encoded-token-2", "user-id-2", -1);

      should(kuzzle.ask).be.calledWith(
        "core:cache:internal:get",
        "token/bootstrap"
      );

      should(kuzzle.ask).be.calledWith(
        "core:cache:internal:store",
        "token/bootstrap",
        1
      );
    });

    it("should not load API keys if the bootstrap key exists", async () => {
      kuzzle.ask.withArgs("core:cache:internal:get").returns("1");
      await tokenRepository._loadApiKeys();

      should(ApiKey.batchExecute).not.called();

      should(kuzzle.ask).be.calledWith(
        "core:cache:internal:get",
        "token/bootstrap"
      );

      should(kuzzle.ask.withArgs("core:cache:internal:store")).not.called();
    });
  });
});

function assertIsAnonymous(token) {
  should(token._id).be.null();
  should(token.userId).be.exactly("-1");
}


text:
package com.google.cloud.spanner;

import static com.google.common.testing.SerializableTester.reserializeAndAssert;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;

import com.google.cloud.Timestamp;
import com.google.cloud.spanner.TimestampBound.Mode;
import com.google.common.testing.EqualsTester;
import com.google.spanner.v1.TransactionOptions;
import java.util.concurrent.TimeUnit;
import org.hamcrest.MatcherAssert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Unit tests for {@link com.google.cloud.spanner.TimestampBound}. */
@RunWith(JUnit4.class)
public class TimestampBoundTest {
  private static final long TEST_TIME_SECONDS = 1444662894L;
  private static final String TEST_TIME_ISO = "2015-10-12T15:14:54Z";

  @Test
  public void serialization() {
    reserializeAndAssert(TimestampBound.strong());
    reserializeAndAssert(TimestampBound.ofExactStaleness(10, TimeUnit.NANOSECONDS));
    reserializeAndAssert(TimestampBound.ofMaxStaleness(100, TimeUnit.DAYS));
    reserializeAndAssert(TimestampBound.ofMinReadTimestamp(Timestamp.now()));
    reserializeAndAssert(TimestampBound.ofReadTimestamp(Timestamp.now()));
  }

  @Test
  public void strong() {
    TimestampBound bound = TimestampBound.strong();
    assertThat(bound.getMode()).isEqualTo(Mode.STRONG);
    assertThat(bound.toString()).isEqualTo("strong");
    assertProto(bound, "strong: true");
  }

  @Test
  public void readTimestamp() {
    Timestamp ts = Timestamp.ofTimeSecondsAndNanos(TEST_TIME_SECONDS, 0);
    TimestampBound bound = TimestampBound.ofReadTimestamp(ts);
    assertThat(bound.getMode()).isEqualTo(Mode.READ_TIMESTAMP);
    assertThat(bound.getReadTimestamp()).isEqualTo(ts);
    assertThat(bound.toString()).isEqualTo("exact_timestamp: " + TEST_TIME_ISO);
    assertProto(bound, "read_timestamp { seconds: " + TEST_TIME_SECONDS + " }");
  }

  @Test
  public void minReadTimestamp() {
    Timestamp ts = Timestamp.ofTimeSecondsAndNanos(TEST_TIME_SECONDS, 0);
    TimestampBound bound = TimestampBound.ofMinReadTimestamp(ts);
    assertThat(bound.getMode()).isEqualTo(Mode.MIN_READ_TIMESTAMP);
    assertThat(bound.getMinReadTimestamp()).isEqualTo(ts);
    assertThat(bound.toString()).isEqualTo("min_read_timestamp: " + TEST_TIME_ISO);
    assertProto(bound, "min_read_timestamp { seconds: " + TEST_TIME_SECONDS + " }");
  }

  @Test
  public void exactStaleness() {
    TimestampBound bound = TimestampBound.ofExactStaleness(3140, TimeUnit.MILLISECONDS);
    assertThat(bound.getMode()).isEqualTo(Mode.EXACT_STALENESS);
    assertThat(bound.getExactStaleness(TimeUnit.SECONDS)).isEqualTo(3);
    assertThat(bound.getExactStaleness(TimeUnit.MILLISECONDS)).isEqualTo(3140);
    assertThat(bound.getExactStaleness(TimeUnit.MICROSECONDS)).isEqualTo(3140000);
    assertThat(bound.getExactStaleness(TimeUnit.NANOSECONDS)).isEqualTo(3140000000L);
    assertThat(bound.toString()).isEqualTo("exact_staleness: 3.140s");
    assertProto(bound, "exact_staleness { seconds: 3 nanos: 140000000 }");
  }

  @Test
  public void exactStalenessNegative() {
    IllegalArgumentException e =
        assertThrows(
            IllegalArgumentException.class,
            () -> TimestampBound.ofExactStaleness(-1, TimeUnit.SECONDS));
    assertNotNull(e.getMessage());
  }

  @Test
  public void maxStaleness() {
    TimestampBound bound = TimestampBound.ofMaxStaleness(3140, TimeUnit.MILLISECONDS);
    assertThat(bound.getMode()).isEqualTo(Mode.MAX_STALENESS);
    assertThat(bound.getMaxStaleness(TimeUnit.SECONDS)).isEqualTo(3);
    assertThat(bound.getMaxStaleness(TimeUnit.MILLISECONDS)).isEqualTo(3140);
    assertThat(bound.getMaxStaleness(TimeUnit.MICROSECONDS)).isEqualTo(3140000);
    assertThat(bound.getMaxStaleness(TimeUnit.NANOSECONDS)).isEqualTo(3140000000L);
    assertThat(bound.toString()).isEqualTo("max_staleness: 3.140s");
    assertProto(bound, "max_staleness { seconds: 3 nanos: 140000000 }");
  }

  @Test
  public void stalenessSourceUnits() {
    long num = 7;
    for (TimeUnit units : TimeUnit.values()) {
      TimestampBound bound = TimestampBound.ofExactStaleness(num, units);
      assertWithMessage(units.toString())
          .that(bound.getExactStaleness(TimeUnit.NANOSECONDS))
          .isEqualTo(units.toNanos(num));
    }
  }

  @Test
  public void maxStalenessNegative() {
    IllegalArgumentException e =
        assertThrows(
            IllegalArgumentException.class,
            () -> TimestampBound.ofMaxStaleness(-1, TimeUnit.SECONDS));
    assertNotNull(e.getMessage());
  }

  @Test
  public void equalsAndHashCode() {
    Timestamp ts = Timestamp.ofTimeSecondsAndNanos(1444662894L, 0);
    Timestamp ts2 = Timestamp.ofTimeSecondsAndNanos(1444662895L, 0);
    int staleness = 5;
    EqualsTester tester = new EqualsTester();
    tester.addEqualityGroup(TimestampBound.strong(), TimestampBound.strong());
    tester.addEqualityGroup(TimestampBound.ofReadTimestamp(ts), TimestampBound.ofReadTimestamp(ts));
    tester.addEqualityGroup(TimestampBound.ofReadTimestamp(ts2));
    tester.addEqualityGroup(
        TimestampBound.ofMinReadTimestamp(ts), TimestampBound.ofMinReadTimestamp(ts));
    tester.addEqualityGroup(TimestampBound.ofMinReadTimestamp(ts2));
    tester.addEqualityGroup(
        TimestampBound.ofExactStaleness(staleness, TimeUnit.SECONDS),
        TimestampBound.ofExactStaleness(staleness, TimeUnit.SECONDS));
    tester.addEqualityGroup(TimestampBound.ofExactStaleness(staleness, TimeUnit.MILLISECONDS));
    tester.addEqualityGroup(
        TimestampBound.ofMaxStaleness(staleness, TimeUnit.SECONDS),
        TimestampBound.ofMaxStaleness(staleness, TimeUnit.SECONDS));
    tester.addEqualityGroup(TimestampBound.ofMaxStaleness(staleness, TimeUnit.MILLISECONDS));
    tester.testEquals();
  }

  private static void assertProto(TimestampBound bound, String expectedProtoTextFormat) {
    MatcherAssert.assertThat(
        bound.toProto(),
        SpannerMatchers.matchesProto(TransactionOptions.ReadOnly.class, expectedProtoTextFormat));
  }
}

redpajama_set_name: RedPajamaGithub


text:
package city.test1;

/**
 * Generic interface for comparing edges in a graph.
 *
 * @author chris
 *
 * @param <T>
 *            Vertex
 * @param <E>
 *            Edge
 */
public interface Comparator<T, E extends IEdge<T>> {
	/**
	 * Value used for Infinite in Dijkstra's algorithm
	 */
	public final double INF = -1.0;

	public int compare(E edge1, double currentCost, double newCost);
}


text:
class MemberSessionsController < UserSessionsController
  skip_authorization_check

  def new
    @redirect_to = params[:redirect_to]
    @member_login_id = params[:member_login_id]
  end

  def create
    member = Member.authenticate(params[:member_login_id], params[:member_password])

    if member.nil?
      flash.now[:error] = t('sessions.login_error')

      @member_login_id = params[:member_login_id]
      @redirect_to = params[:redirect_to]
      render :new
    else
      login_member member
      redirect_after_login root_path
    end
  end

private

  def login_member(member)
    session[:applicant_id] = nil
    session[:member_id] = member.id
    cookies[:signed_in] = 1
    flash[:success] = t('sessions.login_success', name: CGI.escapeHTML(member.full_name))
  end
end


text:
require 'houst/utils'

module Houst
  class Core
    include Utils
    attr_accessor :hosts

    def initialize
      @commands = [
        { name: "list", description: "lists all hosts" },
        { name: "add",  description: "adds a new host" },
        { name: "rm",   description: "removes an host" },
        { name: "help", description: "displays this dialog" }
      ]
      @hosts = {}
    end

    #
    # Shows the command banner usage.
    #
    def help
      base = ["Usage: houst [action] [optional parameter]"]

      @commands.each do |command|
        base << "\t#{command[:name]}: \t#{command[:description]}"
      end

      base << "\nAdditional help can be obtained by using\n\thoust help [command]\n"

      base.join "\n"
    end

    #
    # Shows a list of the hosts
    #
    def list
      unless hosts.empty?
        format hosts
      else
        "No custom hosts found.\nYou can add some using:\n\thoust add [alias] [address]\n"
      end
    end

    #
    # Adds an host alias to /etc/hosts.
    #
    def add(params)
      from, to = params[:from], params[:to]
      hosts[from] = to
    end

    #
    # Deletes an host alias from /etc/hosts.
    #
    def rm(hostname)
      hosts.delete hostname
    end
  end
end


text:
<?php

namespace Ddeboer\DataImport\Reader;

/**
 * Reads Excel files with the help of PHPExcel
 *
 * PHPExcel must be installed.
 *
 * @author David de Boer <david@ddeboer.nl>
 * @link   http://phpexcel.codeplex.com/
 * @link   https://github.com/logiQ/PHPExcel
 */
class ExcelReader implements CountableReaderInterface, \SeekableIterator
{
    protected $worksheet;
    protected $headerRowNumber;
    protected $pointer = 0;
    protected $columnHeaders;

    /**
     * Total number of rows
     *
     * @var int
     */
    protected $count;

    /**
     * Construct CSV reader
     *
     * @param \SplFileObject $file            Excel file
     * @param int            $headerRowNumber Optional number of header row
     * @param int            $activeSheet     Index of active sheet to read from
     */
    public function __construct(\SplFileObject $file, $headerRowNumber = null, $activeSheet = null)
    {
        $reader = \PHPExcel_IOFactory::createReaderForFile($file->getPathName());
        $reader->setReadDataOnly(true);
        /** @var \PHPExcel $excel */
        $excel = $reader->load($file->getPathname());

        if (null !== $activeSheet) {
            $excel->setActiveSheetIndex($activeSheet);
        }

        $this->worksheet = $excel->getActiveSheet()->toArray();

        if (null !== $headerRowNumber) {
            $this->setHeaderRowNumber($headerRowNumber);
        }
    }

    /**
     * Return the current row as an array
     *
     * If a header row has been set, an associative array will be returned
     *
     * @return array
     */
    public function current()
    {
        $row = $this->worksheet[$this->pointer];

        // If the CSV has column headers, use them to construct an associative
        // array for the columns in this line
        if (!empty($this->columnHeaders)) {
            // Count the number of elements in both: they must be equal.
            // If not, ignore the row
            if (count($this->columnHeaders) == count($row)) {
                return array_combine(array_values($this->columnHeaders), $row);
            }
        } else {
            // Else just return the column values
            return $row;
        }
    }

    /**
     * Get column headers
     *
     * @return array
     */
    public function getColumnHeaders()
    {
        return $this->columnHeaders;
    }

    /**
     * Set column headers
     *
     * @param array $columnHeaders
     *
     * @return $this
     */
    public function setColumnHeaders(array $columnHeaders)
    {
        $this->columnHeaders = $columnHeaders;

        return $this;
    }

    /**
     * Rewind the file pointer
     *
     * If a header row has been set, the pointer is set just below the header
     * row. That way, when you iterate over the rows, that header row is
     * skipped.
     *
     */
    public function rewind()
    {
        if (null === $this->headerRowNumber) {
            $this->pointer = 0;
        } else {
            $this->pointer = $this->headerRowNumber + 1;
        }
    }

    /**
     * Set header row number
     *
     * @param int $rowNumber Number of the row that contains column header names
     *
     * @return $this
     */
    public function setHeaderRowNumber($rowNumber)
    {
        $this->headerRowNumber = $rowNumber;
        $this->columnHeaders = $this->worksheet[$rowNumber];

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function next()
    {
        $this->pointer++;
    }

    /**
     * {@inheritdoc}
     */
    public function valid()
    {
         return isset($this->worksheet[$this->pointer]);
    }

    /**
     * {@inheritdoc}
     */
    public function key()
    {
        return $this->pointer;
    }

    /**
     * {@inheritdoc}
     */
    public function seek($pointer)
    {
        $this->pointer = $pointer;
    }

    /**
     * {@inheritdoc}
     */
    public function count()
    {
        $count = count($this->worksheet);
        if (null !== $this->headerRowNumber) {
            $count--;
        }

        return $count;
    }

    /**
     * {@inheritdoc}
     */
    public function getFields()
    {
        return $this->columnHeaders;
    }

    /**
     * Get a row
     *
     * @param int $number Row number
     *
     * @return array
     */
    public function getRow($number)
    {
        $this->seek($number);

        return $this->current();
    }
}


text:
<?php

namespace NetSuite\Classes;

class VendorSubsidiaryRelationship extends Record {
    public $baseCurrency;
    public $creditLimit;
    public $entity;
    public $isPrimarySub;
    public $primaryCurrency;
    public $subsidiary;
    public $taxItem;
    public $customFieldList;
    public $internalId;
    public $externalId;
    static $paramtypesmap = array(
        "baseCurrency" => "RecordRef",
        "creditLimit" => "float",
        "entity" => "RecordRef",
        "isPrimarySub" => "boolean",
        "primaryCurrency" => "RecordRef",
        "subsidiary" => "RecordRef",
        "taxItem" => "RecordRef",
        "customFieldList" => "CustomFieldList",
        "internalId" => "string",
        "externalId" => "string",
    );
}


text:
using InfluxData.Net.InfluxDb.Constants;
using InfluxData.Net.InfluxDb.Enums;
using System;

namespace InfluxData.Net.InfluxDb.QueryBuilders
{
    public class UserQueryBuilder : IUserQueryBuilder
    {
        public virtual string GetUsers()
        {
            return QueryStatements.GetUsers;
        }

        public virtual string CreateUser(string username, string password, bool isAdmin = false)
        {
            return String.Format(QueryStatements.CreateUser, username, password, isAdmin ? QueryStatements.WithAllPrivileges : null);
        }

        public virtual string DropUser(string username)
        {
            return String.Format(QueryStatements.DropUser, username);
        }

        public virtual string SetPassword(string username, string password)
        {
            return String.Format(QueryStatements.SetPassword, username, password);
        }

        public virtual string GetPrivileges(string username)
        {
            return String.Format(QueryStatements.GetGrants, username);
        }

        public virtual string GrantAdministator(string username)
        {
            return String.Format(QueryStatements.GrantAdministrator, username);
        }

        public virtual string RevokeAdministrator(string username)
        {
            return String.Format(QueryStatements.RevokeAdministrator, username);
        }

        public virtual string GrantPrivilege(string username, Privileges privilege, string dbName)
        {
            return String.Format(QueryStatements.GrantPrivilege, privilege.ToString().ToUpper(), dbName, username);
        }

        public virtual string RevokePrivilege(string username, Privileges privilege, string dbName)
        {
            return String.Format(QueryStatements.RevokePrivilege, privilege.ToString().ToUpper(), dbName, username);
        }
    }
}


text:
import fs from 'fs';
import { createFilter } from 'rollup-pluginutils';
import postcss from 'postcss';
import CssModules from 'css-modules-loader-core';
import { join, dirname, relative } from 'path';
import { /*writeFile,*/ readFile } from 'fs';
import glob from 'glob';
function pathJoin(file) {
  return join(process.cwd(), file);
}
var cssfile = [];
const cached = {};
var trace = 0;
const cssModules = new CssModules();
export default function (options = {}) {
  const filter = createFilter(options.include, options.exclude);
  /*const outputFile = typeof options.output === 'string';
  const outputFunction = typeof options.output === 'function';*/
  return {
    transform(source, id) {
      if (!filter(id)) {
        return null;
      }
      const opts = {
        from: options.from ? pathJoin(options.from) : id,
        to: options.to ? pathJoin(options.to) : id,
        map: {
          inline: false,
          annotation: false
        }
      };
      const relativePath = relative(process.cwd(), id);
      //console.log('relativePath', relativePath);
      trace++;
      var cache = (res) => {
        cached[relativePath] = res;
        cssfile.push(res.injectableSource);
        return res;
      };
      return postcss(options.plugins || [])
        .process(source, opts)
        .then(({ css, map }) => cssModules
          .load(css, relativePath, trace, pathFetcher)
          .then(cache)
          .then(({ exportTokens }) => ({
              code: getExports(exportTokens),
              map: options.sourceMap && map ? JSON.parse(map) : {mappings: ''}
            }))
          //.then(res => {console.log(res);return res;})
        )
        /*.then(r => {
                  if (outputFile) {
                    fs.writeFile(options.output, cssfile.join(''));
                  } else if (outputFunction) {
                    options.output(cssfile.join('\n'));
                  }
                  return r;
                })*/
      ;
    },
    transformBundle() {
      console.log('writing css to:', options.output);
      fs.writeFile(options.output, cssfile.join(''));
    }
  };
}

function getExports(exportTokens) {
  return Object.keys(exportTokens)
    .map(t => `var ${t}="${exportTokens[t]}"`)
    .concat([
      `export { ${Object.keys(exportTokens).join(',')} }`,
      `export default ${JSON.stringify(exportTokens)}`
    ])
    .join(';\n');
}

function pathFetcher(file, relativeTo, depTrace) {
  var sourcePath;
  file = file.replace(/^["']|["']$/g, '');
  if (file.startsWith('.')) {
    return Promise.reject('implement relative path bleat!');
    let dir = dirname(relativeTo);
    let sourcePath = glob.sync(join(dir, file))[0];
    console.log('sourcePath', sourcePath);
    if (!sourcePath) {
      console.error('no sourcePath', dir, file);
      /*this._options.paths.some(dir => {
        return sourcePath = glob.sync(join(dir, file))[0]
      })*/
    }
    /*if (!sourcePath) {
      return new Promise((resolve, reject) => {
        let errorMsg = `Not Found : ${file}  from ${dir}`;
        if (this._options.paths.length) {
          errorMsg += " and " + this._options.paths.join(" ")
        }
        reject(errorMsg)
      })
    }*/
  } else {
    sourcePath = `node_modules/${file}`;
    if (!file.endsWith('.css')) {
      sourcePath += '.css';
    }
    console.log('pathFetcher', sourcePath);
  }
  return new Promise((resolve, reject) => {
    let _cached = cached[sourcePath];
    if (_cached) {
      return resolve(_cached.exportTokens);
    }
    readFile(sourcePath, 'utf-8', (error, sourceString) => {
      if (error) {
        return reject(error);
      }
      cssModules
        .load(sourceString, sourcePath, ++trace, pathFetcher)
        .then(result => {
          cached[sourcePath] = result;
          resolve(result.exportTokens);
        })
        .catch(reject);
    });
  });
}


text:
//// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
//// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
//// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//// PARTICULAR PURPOSE.
////
//// Copyright (c) Microsoft Corporation. All rights reserved

(function () {
    "use strict";
    var page = WinJS.UI.Pages.define("/html/image.html", {
        ready: function (element, options) {
            document.getElementById("scenario2Copy").addEventListener("click", scenario2Copy_Click, false);
            document.getElementById("scenario2CopyDelayedRendering").addEventListener("click", scenario2CopyDelayedRendering_Click, false);
            document.getElementById("scenario2Paste").addEventListener("click", scenario2Paste, false);
        }
    });

    function displayStatus(statusString) {
        return WinJS.log && WinJS.log(statusString, "sample", "status");
    }

    function displayError(errorString) {
        return WinJS.log && WinJS.log(errorString, "sample", "error");
    }

    var imageFile = null;

    function scenario2ClearOutput() {
        displayError("");
        displayStatus("");
        document.getElementById("scenario2ImageHolder").style.visibility = "hidden";
        document.getElementById("scenario2ImageHolder").src = "/images/placeholder-sdk.png";
    }

    function scenario2Copy_Click() {
        scenario2Copy(false);
    }

    function scenario2CopyDelayedRendering_Click() {
        scenario2Copy(true);
    }

    function scenario2Copy(isDelayRendered) {
        scenario2ClearOutput();

        imageFile = null;
        var picker = new Windows.Storage.Pickers.FileOpenPicker();
        picker.viewMode = Windows.Storage.Pickers.PickerViewMode.thumbnail;
        picker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.picturesLibrary;
        picker.fileTypeFilter.replaceAll([".jpg", ".jpeg", ".png", ".bmp"]);
        picker.pickSingleFileAsync().done(function (file) {
            if (file) {
                var dataPackage = new Windows.ApplicationModel.DataTransfer.DataPackage();
                var statusText;

                if (isDelayRendered) {
                    // Delay providing the data until delegate is called
                    imageFile = file;
                    dataPackage.setDataProvider(Windows.ApplicationModel.DataTransfer.StandardDataFormats.bitmap, onDeferredImageRequestedHandler);

                    statusText = "Image copied to Clipboard using delayed rendering";
                } else {
                    // Add the selected image to the DataPackage
                    dataPackage.setBitmap(Windows.Storage.Streams.RandomAccessStreamReference.createFromFile(file));

                    statusText = "Image copied to Clipboard";
                }

                try {
                    // copy the content to Clipboard
                    Windows.ApplicationModel.DataTransfer.Clipboard.setContent(dataPackage);

                    displayStatus(statusText);
                } catch (e) {
                    // Copying data to Clipboard can potentially fail - for example, if another application is holding Clipboard open
                    displayError("Error copying content to Clipboard: " + e + ". Try again.");
                }
            } else {
                displayStatus("No image selected");
            }
        });
    }

    function onDeferredImageRequestedHandler(request) {
        if (imageFile) {
            // Since this method is calling an async method prior to setting the data in DataPackage,
            // deferral object must be used
            var deferral = request.getDeferral();

            var imageStream,
                imageDecoder,
                inMemoryStream;
            imageFile.openAsync(Windows.Storage.FileAccessMode.Read).then(function (stream) {
                imageStream = stream;
                // Decode the image
                return Windows.Graphics.Imaging.BitmapDecoder.createAsync(imageStream);
            }).then(function (decoder) {
                imageDecoder = decoder;
                // Re-encode the image at 50% width and height
                inMemoryStream = new Windows.Storage.Streams.InMemoryRandomAccessStream();
                return Windows.Graphics.Imaging.BitmapEncoder.createForTranscodingAsync(inMemoryStream, imageDecoder);
            }).then(function (imageEncoder) {
                imageEncoder.bitmapTransform.scaledWidth = imageDecoder.orientedPixelWidth / 2;
                imageEncoder.bitmapTransform.scaledHeight = imageDecoder.orientedPixelHeight / 2;
                return imageEncoder.flushAsync();
            }).done(function () {
                request.setData(Windows.Storage.Streams.RandomAccessStreamReference.createFromStream(inMemoryStream));

                // Data has been set, now we need to signal completion of the operation
                deferral.complete();
                imageStream.close();
            }, function () {
                // Didn't succeed, but we still need to release deferral, to avoid a hang in the target app
                deferral.complete();
                imageStream && imageStream.close();
            });
        }
    }

    function scenario2Paste() {
        scenario2ClearOutput();

        // Get the content from clipboard
        var dataPackageView = Windows.ApplicationModel.DataTransfer.Clipboard.getContent();

        if (dataPackageView.contains(Windows.ApplicationModel.DataTransfer.StandardDataFormats.bitmap)) {
            dataPackageView.getBitmapAsync().then(function (streamRef) {
                return streamRef.openReadAsync();
            }).done(function (bitmapStream) {
                document.getElementById("scenario2ImageHolder").src = window.URL.createObjectURL(bitmapStream, { oneTimeOnly: true });
                document.getElementById("scenario2ImageHolder").style.visibility = "visible";
                displayStatus("Image pasted from Clipboard");
            }, function (e) {
                displayError("Error retrieving image stream:  " + e);
            });
        } else {
            displayStatus("Bitmap format is not available in clipboard");
        }
    }
})();


text:
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Web.Script.Serialization;
using XenAdmin.Model;
using XenAPI;
using System.Linq;

namespace XenAdmin.Actions
{
    public class GetHealthCheckAnalysisResultAction: AsyncAction
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        private const string DIAG_RESULT_URL = "/diag_sdk/diag_results/";
        private const string ANALYSIS_PROGRESS_URL = "/diag_sdk/analysis_progress/";
        private readonly string diagnosticDomainName = "https://cis.citrix.com";

        public GetHealthCheckAnalysisResultAction(Pool pool, bool suppressHistory)
            : base(pool.Connection, Messages.ACTION_GET_HEALTH_CHECK_RESULT, Messages.ACTION_GET_HEALTH_CHECK_RESULT_PROGRESS, suppressHistory)
        {
            #region RBAC Dependencies
            ApiMethodsToRoleCheck.Add("secret.get_by_uuid");
            ApiMethodsToRoleCheck.Add("secret.get_value");
            ApiMethodsToRoleCheck.Add("pool.set_health_check_config");
            #endregion
        }

        public GetHealthCheckAnalysisResultAction(Pool pool, string diagnosticDomainName, bool suppressHistory)
            : this(pool, suppressHistory)
        {
            if (!string.IsNullOrEmpty(diagnosticDomainName))
                this.diagnosticDomainName = diagnosticDomainName;
        }

        protected override void Run()
        {
            try
            {
                var healthCheckSettings = Pool.HealthCheckSettings();

                var diagnosticToken = healthCheckSettings.GetSecretyInfo(Session, HealthCheckSettings.DIAGNOSTIC_TOKEN_SECRET);
                if (string.IsNullOrEmpty(diagnosticToken))
                {
                    log.DebugFormat("Cannot get the diagnostic result for {0}, because couldn't retrieve the diagnostic token", Pool.Name());
                    Description = Messages.ACTION_GET_HEALTH_CHECK_RESULT_FAILED;
                    return;
                }
                if (!healthCheckSettings.HasUpload)
                {
                    log.DebugFormat("Cannot get the diagnostic result for {0}, because the there is no upload completed yet", Pool.Name());
                    Description = Messages.ACTION_GET_HEALTH_CHECK_RESULT_FAILED;
                    return;
                }

                var analysisProgress = GetAnalysisProgress(diagnosticToken, healthCheckSettings.UploadUuid);

                if (analysisProgress >= 0 && analysisProgress < 100) // check if the progress is a valid value less than 100
                {
                    log.DebugFormat("Analysis for {0} not completed yet", Pool.Name());
                    Description = Messages.COMPLETED;
                    return;
                }

                var analysisResult = GetAnalysisResult(diagnosticToken, healthCheckSettings.UploadUuid);

                if (analysisResult.Count == 0 && analysisProgress == -1 && DateTime.Compare(healthCheckSettings.LastSuccessfulUploadTime.AddMinutes(10), DateTime.UtcNow) > 0)
                {
                    log.DebugFormat("Diagnostic result for {0} is empty. Maybe analysis result is not yet available", Pool.Name());
                    Description = Messages.COMPLETED;
                    return;
                }

                log.Debug("Saving analysis result");
                Dictionary<string, string> newConfig = Pool.health_check_config;
                newConfig[HealthCheckSettings.REPORT_ANALYSIS_SEVERITY] = GetMaxSeverity(analysisResult).ToString();
                newConfig[HealthCheckSettings.REPORT_ANALYSIS_ISSUES_DETECTED] = GetDistinctIssueCount(analysisResult).ToString();
                newConfig[HealthCheckSettings.REPORT_ANALYSIS_UPLOAD_UUID] = healthCheckSettings.UploadUuid;
                newConfig[HealthCheckSettings.REPORT_ANALYSIS_UPLOAD_TIME] = healthCheckSettings.LastSuccessfulUpload;
                Pool.set_health_check_config(Session, Pool.opaque_ref, newConfig);
            }
            catch (Exception e)
            {
                log.ErrorFormat("Exception while getting diagnostic result from {0}. Exception Message: {1} ", diagnosticDomainName, e.Message);
                Description = Messages.ACTION_GET_HEALTH_CHECK_RESULT_FAILED;
                throw;
            }

            Description = Messages.COMPLETED;
        }

        private DiagnosticAlertSeverity GetMaxSeverity(List<AnalysisResult> diagnosticAlerts)
        {
            var maxSeverity = DiagnosticAlertSeverity.Info;
            foreach (var diagnosticAlert in diagnosticAlerts)
            {
                var severity = HealthCheckSettings.StringToDiagnosticAlertSeverity(diagnosticAlert.severity);
                if (severity > maxSeverity)
                    maxSeverity = severity;
            }
            return maxSeverity;
        }

        private int GetDistinctIssueCount(List<AnalysisResult> issues)
        {
            // get the number of distinct issues (by name)
            return issues.Select(issue => issue.name).Distinct().Count();
        }

        /// <summary>
        /// Tries to retrieve the analysis progress for a particulat upload
        /// </summary>
        /// <param name="diagnosticToken"></param>
        /// <param name="uploadUuid"></param>
        /// <returns>the analysis progress as pecentage, or -1 if the progress cannot be retrieved</returns>
        private double GetAnalysisProgress(string diagnosticToken, string uploadUuid)
        {
            try
            {
                var urlString = string.Format("{0}{1}?upload_id={2}", diagnosticDomainName, ANALYSIS_PROGRESS_URL, uploadUuid);
                var authorizationHeader = "BT " + diagnosticToken;
                var httpWebRequest = (HttpWebRequest)WebRequest.Create(urlString);
                httpWebRequest.Headers.Add("Authorization", authorizationHeader);
                httpWebRequest.Method = "GET";
                httpWebRequest.Proxy = XenAdminConfigManager.Provider.GetProxyFromSettings(null, false);

                string result;
                var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
                using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
                {
                    result = streamReader.ReadToEnd();
                }

                return ParseAnalysisProgress(result, uploadUuid);
            }
            catch (Exception e)
            {
                log.DebugFormat("Exception while getting analysis progress result from {0}. Exception Message: {1} ", diagnosticDomainName, e.Message);
                return -1;
            }
        }

        /// <summary>
        /// Deserialize the analysis progress from a JSON object that has "upload_id" as key and a number (percentage from 0 to 100) as a value
        /// </summary>
        /// <param name="jsonString"></param>
        /// <param name="uploadUuid"></param>
        /// <returns>the analysis progress as pecentage, or -1 if the JSON object is invalid</returns>
        public static double ParseAnalysisProgress(string jsonString, string uploadUuid)
        {
            if (string.IsNullOrEmpty(jsonString))
                return -1;
            try
            {
                var serializer = new JavaScriptSerializer();
                Dictionary<string, object> result = serializer.DeserializeObject(jsonString) as Dictionary<string, object>;
                var progress = result != null && result.ContainsKey(uploadUuid) ? Convert.ToDouble(result[uploadUuid]) : -1;
                return progress >= 0 && progress <= 100 ? progress : -1;
            }
            catch (Exception e)
            {
                log.DebugFormat("Exception while deserializing json: {0}. Exception Message: {1} ", jsonString, e.Message);
                return -1;
            }
        }

        private List<AnalysisResult> GetAnalysisResult(string diagnosticToken, string uploadUuid)
        {
            var urlString = string.Format("{0}{1}?upload_uuid={2}", diagnosticDomainName, DIAG_RESULT_URL, uploadUuid);
            var authorizationHeader = "BT " + diagnosticToken;
            var httpWebRequest = (HttpWebRequest)WebRequest.Create(urlString);
            httpWebRequest.Headers.Add("Authorization", authorizationHeader);
            httpWebRequest.Method = "GET";
            httpWebRequest.Proxy = XenAdminConfigManager.Provider.GetProxyFromSettings(null, false);

            string result;
            var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
            using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
            {
                result = streamReader.ReadToEnd();
            }
            TemplateResponse response = new JavaScriptSerializer().Deserialize<TemplateResponse>(result);
            return response.results;
        }

        private class TemplateResponse
        {
            public List<AnalysisResult> results { get; set; }
        }

        private class AnalysisResult
        {
            public string severity { get; set; }
            public string extra_information { get; set; }
            public string owner { get; set; }
            public string crm_id { get; set; }
            public string id { get; set; }
            public List<string> category { get; set; }
            public string analysis_id { get; set; }
            public string priority { get; set; }
            public string product { get; set; }
            public string description { get; set; }
            public DateTime analysis_completion_time { get; set; }
            public string component { get; set; }
            public string name { get; set; }
            public string upload_description { get; set; }
            public string upload_id { get; set; }
            public string recommendations { get; set; }
            public string env_identifier { get; set; }
        }
    }
}


text:
<resources>
  <string name="app_name">PopupMenu</string>
</resources>


text:
layout:     post
title:      "Résultats du coffre de clan du 30 Octobre 2017"
subtitle:   "Les posts reviennent, plus forts que jamais"
date:       2017-10-30 08:00:00
author:     "Zoru"
header-img: "img/clash-royale/clash-royale-chest.jpg"
category: clash-royale
---

Salutations à tous !

Après 2 semaines sans post à cause d'un bug du site de stats que j'utilise (qui n'est d'ailleurs toujours pas résolu), c'est l'heure du bilan de notre 11ème coffre de clan. Enfin un peu plus en théorie mais je ne compte pas les semaines sans post pour simplifier. Allons directement analyser nos performances !

[![Stats du 30/10/2017]({{ site.url }}/img/clash-royale/statsDu30102017.png)]({{ site.url }}/img/clash-royale/statsDu30102017.png)
Ouvrir l'image dans un nouvel onglet ou cliquer pour zoomer

Si tu veux plus de détails sur la façon dont est calculé le score, je te conseille le premier post récapitulatif qui contient les explications. Pour cette semaine, le palier de promotion est resté à 15 000 et le palier de kick est resté à 700.

Comme chaque semaine désormais, on débute avec une comparaison de nos moyennes avec celles de la semaine précédente.

Format : semaine précédente / semaine actuelle

Niveau moyen : 9 / 10

Nombre de trophées moyen : 2706 / 2882

Dons moyens : 322 / 295

Couronnes moyennes : 32 (maximum du coffre 10)

Score moyen : 7047 / 6696

Présence moyenne (en semaines) : 6 / 6

Infos additionnelles

Pour le calcul du nombre de semaines, je n'ai pas pu prendre en compte les semaines où il n'y a pas eu de post. Le calcul est automatisé et je ne peux pas prendre le temps de vérifier un par un qui était là chaque semaine pour le rajouter à la main ensuite. Il est donc normal que le chiffre soit légèrement inférieur à ce qu'il devrait être pour certains, j'en suis désolé mais je ne peux pas faire autrement !

Les satisfactions

Le groupe est de nouveau au complet ! Et dès qu'une place se libère, elle est très vite prise de nouveau tout en respectant nos conditions d'entrée. On va donc pouvoir reprendre le principe de promotions et kicks.

Niveau statistiques, le niveau moyen augmente et les trophées ont progressé de 6,5% en moyenne. Le groupe est globalement assez stable et continue d'échanger régulièrement. Pour cette semaine, la meilleure performance fut celle de MaxBalet qui a à la fois fortement contribué au coffre de clan ainsi qu'aux dons. Il obtient donc une promotion bien méritée ! Je tiens aussi à chaudement féliciter myzho et Monkey.D.Livaï qui viennent de nous rejoindre et qui passent à rien d'obtenir un score suffisant pour la promotion. Elle n'est de toute façon pas accessible aux membres ayant moins de deux semaines de présence parmi nous mais il faut noter ces deux superbes entrées en espérant que le rythme soit maintenu par la suite !

Les moins satisfactions

Les dons baissent en moyenne mais on reste sur un score assez élevé et c'est donc une très légère déception. Le score moyen chute aussi en conséquence mais encore une fois, rien de bien inquiétant. Le plus décevant cette semaine sera surement le départ de Kalajen qui est avec nous depuis quasiment le début mais qui est totalement inactif depuis près d'un mois. J'avais accordé un peu de temps supplémentaire pour voir s'il revenait mais il semblerait que non et il faut donc renouveler l'effectif.

Conclusion

Une assez belle semaine pour le clan ! On félicite donc MaxBalet pour sa promotion, ainsi que Leootaku qui obtient une promotion exceptionnelle ! Je lui accorde car il est présent quasiment depuis le début, participe toujours régulièrement à la fois en dons, en couronnes et dans le chat. Il a toujours été un membre exemplaire et a frôlé plusieurs fois cette récompense. Je suis donc ravi de lui donner aujourd'hui pour tous ces efforts. On dit par contre au-revoir à Kalajen, trytex et yoyman en espérant que cela nous permettra de recruter des membres plus déterminés. Il aurait aussi fallu exclure Riklaunim en théorie mais c'est quelqu'un de présent depuis longtemps et qui jusque là participait assez activement au clan. Je lui laisse donc une semaine ou deux supplémentaires.

Merci pour votre participation et à la semaine prochaine pour un nouveau bilan !

Zoru


text:
using Microsoft.EntityFrameworkCore.TestUtilities;

namespace Microsoft.EntityFrameworkCore
{
    public class MigrationsMySqlFixture : MigrationsFixtureBase
    {
        protected override ITestStoreFactory TestStoreFactory => MySqlTestStoreFactory.Instance;

        public MigrationsMySqlFixture()
        {
            ((MySqlTestStore)TestStore).ExecuteNonQuery(
                @"USE master
IF EXISTS(select * from sys.databases where name='TransactionSuppressed')
DROP DATABASE TransactionSuppressed");
        }

        public override MigrationsContext CreateContext()
        {
            var options = AddOptions(
                    new DbContextOptionsBuilder()
                        .UseMySql(TestStore.ConnectionString, b => b.ApplyConfiguration().CommandTimeout(MySqlTestStore.CommandTimeout)))
                .UseInternalServiceProvider(ServiceProvider)
                .Options;
            return new MigrationsContext(options);
        }
    }
}


text:
package org.hisp.dhis.android.core.arch.db.adapters.custom.internal;

import android.content.ContentValues;
import android.database.Cursor;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.gabrielittner.auto.value.cursor.ColumnTypeAdapter;

import java.io.IOException;
import java.util.Collections;
import java.util.List;

@SuppressWarnings({"PMD.PreserveStackTrace"})
public class IntegerArrayColumnAdapter implements ColumnTypeAdapter<List<Integer>> {

    @Override
    public List<Integer> fromCursor(Cursor cursor, String columnName) {
        int columnIndex = cursor.getColumnIndex(columnName);
        String sourceValue = cursor.getString(columnIndex);

        if (sourceValue == null || sourceValue.equals("")) {
            return Collections.emptyList();
        } else {
            ObjectMapper objectMapper  = new ObjectMapper();
            TypeFactory typeFactory = objectMapper.getTypeFactory();
            try {
                return objectMapper.readValue(sourceValue,
                        typeFactory.constructCollectionType(List.class, Integer.class));
            } catch (IOException e) {
                throw new RuntimeException("Couldn't deserialize integer array");
            }
        }
    }

    @Override
    public void toContentValues(ContentValues values, String columnName, List<Integer> value) {
        values.put(columnName, serialize(value));
    }

    public static String serialize(List<Integer> value) {
        try {
            return new ObjectMapper().writeValueAsString(value);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("Couldn't serialize integer array");
        }
    }
}


text:
namespace AngleSharp.Dom.Io
{
    using AngleSharp.Attributes;
    using System;
    using System.IO;

    /// <summary>
    /// Represents a binary large object.
    /// http://dev.w3.org/2006/webapi/FileAPI/#dfn-Blob
    /// </summary>
    [DomName("Blob")]
    public interface IBlob : IDisposable
    {
        /// <summary>
        /// Gets the length of the blob.
        /// </summary>
        [DomName("size")]
        Int32 Length { get; }

        /// <summary>
        /// Gets the mime-type of the blob.
        /// </summary>
        [DomName("type")]
        String Type { get; }

        /// <summary>
        /// Gets if the stream to the blob is closed.
        /// </summary>
        [DomName("isClosed")]
        Boolean IsClosed { get; }

        /// <summary>
        /// Gets the stream to the file.
        /// </summary>
        Stream Body { get; }

        /// <summary>
        /// Slices a subset of the blob into a another blob.
        /// </summary>
        /// <param name="start">The start of the slicing in bytes.</param>
        /// <param name="end">The end of the slicing in bytes.</param>
        /// <param name="contentType">The mime-type of the new blob.</param>
        /// <returns>A new blob with this blob's subset.</returns>
        [DomName("slice")]
        IBlob Slice(Int32 start = 0, Int32 end = Int32.MaxValue, String contentType = null);

        /// <summary>
        /// Closes the stream to the blob.
        /// </summary>
        [DomName("close")]
        void Close();
    }
}