<commit_before>import Unsplash from "../src/unsplash.js";
import expect, { spyOn, restoreSpies } from "expect";

describe("Unsplash", () => {
  describe("constructor", () => {
    const applicationId = "applicationId";
    const secret = "secret";

    let unsplash = new Unsplash({
      applicationId: applicationId,
      secret: secret
    });

    it("should successfully construct an Unsplash instance", () => {
      expect(unsplash).toBeAn(Unsplash);
    });

    it("should set an apiUrl on the Unsplash instance", () => {
      expect(unsplash.apiUrl).toBe("https://api.unsplash.com");
    });

    it("should set the applicationId argument on the Unsplash instance", () => {
      expect(unsplash.applicationId).toBe(applicationId);
    });

    it("should set the secret argument on the Unsplash instance", () => {
      expect(unsplash.secret).toBe(secret);
    });

    it("should have a currentUser method", () => {
      expect(unsplash.currentUser).toExist();
    });

    it("should have a users method", () => {
      expect(unsplash.users).toExist();
    });

    it("should have a photos method", () => {
      expect(unsplash.photos).toExist();
    });

    it("should have a categories method", () => {
      expect(unsplash.categories).toExist();
    });

    it("should have a curatedBatches method", () => {
      expect(unsplash.curatedBatches).toExist();
    });

    it("should have a stats method", () => {
      expect(unsplash.stats).toExist();
    });
  });

  describe("auth", () => {
    const applicationId = "foo";
    const secret = "bar";

    let unsplash = new Unsplash({
      applicationId: applicationId,
      secret: secret
    });

    describe("getAuthenticationUrl", () => {
      expect(unsplash.auth.getAuthenticationUrl("http://foo.com", ["public", "read_user"]))
        .toBe(`https://unsplash.com/oauth/authorize?client_id=${applicationId}&redirect_uri=http://foo.com&response_type=code&scope=public+read_user`);
    });

    describe("userAuthentication", () => {
      let spy = spyOn(unsplash, "request");
      unsplash.auth.userAuthentication("http://foo.com", "oauth_code");

      expect(spy.calls.length).toEqual(1);
      expect(spy.calls[0].arguments).toEqual([{
        url: "https://unsplash.com/oauth/token",
        method: "POST",
        body: {
          client_id: "foo",
          client_secret: "bar",
          redirect_uri: "http://foo.com",
          code: "oauth_code",
          grant_type: "authorization_code"
        },
        oauth: true
      }]);

      restoreSpies();
    });
  });

  describe("currentUser", () => {
    let unsplash = new Unsplash({
      applicationId: "foo",
      secret: "bar"
    });

    it("should make a GET request to /me", () => {
      let spy = spyOn(unsplash, "request");
      unsplash.currentUser();

      expect(spy.calls.length).toEqual(1);
      expect(spy.calls[0].arguments).toEqual([{
        method: "GET",
        url: "/me"
      }]);
    });
  });

  describe("users", () => {
    afterEach(function () {
      restoreSpies();
    });

    let unsplash = new Unsplash({
      applicationId: "foo",
      secret: "bar"
    });

    describe("profile", () => {
      it("should make a GET request to /users/{username}", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.users.profile("naoufal");

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          method: "GET",
          url: "/users/naoufal"
        }]);
      });
    });

    describe("photos", () => {
      it("should make a GET request to /users/{username}/photos", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.users.photos("naoufal");

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          method: "GET",
          url: "/users/naoufal/photos"
        }]);
      });
    });

    describe("likes", () => {
      it("should make a GET request to /users/{username}/likes", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.users.likes("naoufal");

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          method: "GET",
          url: "/users/naoufal/likes",
          query: {
            page: undefined,
            per_page: undefined
          }
        }]);
      });
    });
  });
});
<commit_msg>Add a bunch of tests<commit_after>import Unsplash from "../src/unsplash.js";
import expect, { spyOn, restoreSpies } from "expect";

const applicationId = "applicationId";
const secret = "secret";
const callbackUrl = "http://foo.com"

describe("Unsplash", () => {
  describe("constructor", () => {
    let unsplash = new Unsplash({
      applicationId,
      secret,
      callbackUrl
    });

    it("should successfully construct an Unsplash instance", () => {
      expect(unsplash).toBeAn(Unsplash);
    });

    it("should set an apiUrl on the Unsplash instance", () => {
      expect(unsplash._apiUrl).toBe("https://api.unsplash.com");
    });

    it("should set the applicationId argument on the Unsplash instance", () => {
      expect(unsplash._applicationId).toBe(applicationId);
    });

    it("should set the secret argument on the Unsplash instance", () => {
      expect(unsplash._secret).toBe(secret);
    });

    it("should set the callbackUrl argument on the Unsplash instance", () => {
      expect(unsplash._callbackUrl).toBe(callbackUrl);
    });

    it("should have an auth method", () => {
      expect(unsplash.auth).toExist();
    });

    it("should have a currentUser method", () => {
      expect(unsplash.currentUser).toExist();
    });

    it("should have a users method", () => {
      expect(unsplash.users).toExist();
    });

    it("should have a photos method", () => {
      expect(unsplash.photos).toExist();
    });

    it("should have a categories method", () => {
      expect(unsplash.categories).toExist();
    });

    it("should have a curatedBatches method", () => {
      expect(unsplash.curatedBatches).toExist();
    });

    it("should have a stats method", () => {
      expect(unsplash.stats).toExist();
    });

    it("should have a setBearerToken method", () => {
      expect(unsplash.setBearerToken).toExist();
    });
  });

  describe("auth", () => {
    let unsplash = new Unsplash({
      applicationId,
      secret,
      callbackUrl
    });

    describe("getAuthenticationUrl", () => {
      it("should return an authentication url", () => {
        expect(unsplash.auth.getAuthenticationUrl(
          ["public", "read_user"]
        ))
        .toBe([
          "https://unsplash.com/oauth/authorize",
          `?client_id=${applicationId}`,
          "&redirect_uri=http://foo.com",
          "&response_type=code",
          "&scope=public+read_user"
        ].join(""));
      });
    });

    describe("userAuthentication", () => {
      it("should make a POST request to /oauth/token", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.auth.userAuthentication("oauth_code");

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          url: "https://unsplash.com/oauth/token",
          method: "POST",
          body: {
            client_id: "applicationId",
            client_secret: "secret",
            redirect_uri: "http://foo.com",
            code: "oauth_code",
            grant_type: "authorization_code"
          },
          oauth: true
        }]);

        restoreSpies();
      });
    });
  });

  describe("currentUser", () => {
    let unsplash = new Unsplash({
      applicationId,
      secret,
      callbackUrl
    });

    it("should make a GET request to /me", () => {
      let spy = spyOn(unsplash, "request");
      unsplash.currentUser();

      expect(spy.calls.length).toEqual(1);
      expect(spy.calls[0].arguments).toEqual([{
        method: "GET",
        url: "/me"
      }]);
    });
  });

  describe("users", () => {
    afterEach(function () {
      restoreSpies();
    });

    let unsplash = new Unsplash({
      applicationId,
      secret,
      callbackUrl
    });

    describe("profile", () => {
      it("should make a GET request to /users/{username}", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.users.profile("naoufal");

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          method: "GET",
          url: "/users/naoufal"
        }]);
      });
    });

    describe("photos", () => {
      it("should make a GET request to /users/{username}/photos", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.users.photos("naoufal");

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          method: "GET",
          url: "/users/naoufal/photos"
        }]);
      });
    });

    describe("likes", () => {
      it("should make a GET request to /users/{username}/likes", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.users.likes("naoufal");

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          method: "GET",
          url: "/users/naoufal/likes",
          query: {
            page: undefined,
            per_page: undefined
          }
        }]);
      });
    });
  });

  describe("photos", () => {
    let unsplash = new Unsplash({
      applicationId,
      secret,
      callbackUrl
    });

    afterEach(function () {
      restoreSpies();
    });

    describe("listPhotos", () => {
      it("should make a GET request to /photos", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.photos.listPhotos(2, 15);

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          method: "GET",
          url: "/photos",
          query: {
            page: 2,
            per_page: 15
          }
        }]);
      });
    });

    describe("searchPhotos", () => {
      it("should make a GET request to /photos/search", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.photos.searchPhotos("cats", [11, 4, 88], 2, 15);

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          method: "GET",
          url: "/photos/search",
          query: {
            query: "cats",
            category: "11,4,88",
            page: 2,
            per_page: 15
          }
        }]);
      });
    });

    describe("getPhoto", () => {
      it("should make a GET request to /photos/{id}", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.photos.getPhoto(88, 1920, 1080);

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          method: "GET",
          url: "/photos/88",
          query: {
            w: 1920,
            h: 1080,
            rect: undefined
          }
        }]);
      });
    });

    describe("getRandomPhoto", () => {
      it("should make a GET request to /photos/random", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.photos.getRandomPhoto();

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          method: "GET",
          url: "/photos/random",
          query: {
            category: undefined,
            featured: undefined,
            username: undefined,
            query: undefined,
            w: undefined,
            h: undefined
          }
        }]);
      });
    });

    describe("uploadPhoto", () => {
      let unsplash = new Unsplash({
        applicationId,
        secret,
        callbackUrl
      });

      it("should throw is bearerToken when not set", () => {
        expect(unsplash.photos.uploadPhoto.bind(null, "photo"))
          .toThrow(/Requires a bearerToken to be set./);
      });

      it("should make a POST request to /photos", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.setBearerToken("foo");
        unsplash.photos.uploadPhoto("photo.jpg");

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          method: "POST",
          url: "/photos",
          body: {
            photo: "photo.jpg"
          }
        }]);
      });
    });

    describe("likePhoto", () => {
      let unsplash = new Unsplash({
        applicationId,
        secret,
        callbackUrl
      });

      it("should throw is bearerToken when not set", () => {
        expect(unsplash.photos.likePhoto.bind(null, 88))
          .toThrow(/Requires a bearerToken to be set./);
      });

      it("should make a POST request to /photos/{id}/like", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.setBearerToken("foo");
        unsplash.photos.likePhoto(88);

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          method: "POST",
          url: "/photos/88/like"
        }]);
      });
    });

    describe("unlikePhoto", () => {
      let unsplash = new Unsplash({
        applicationId,
        secret,
        callbackUrl
      });

      it("should throw is bearerToken when not set", () => {
        expect(unsplash.photos.unlikePhoto.bind(null, 88))
          .toThrow(/Requires a bearerToken to be set./);
      });

      it("should make a DELETE request to /photos/{id}/like", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.setBearerToken("foo");
        unsplash.photos.unlikePhoto(88);

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          method: "DELETE",
          url: "/photos/88/like"
        }]);
      });
    });
  });

  describe("categories", () => {
    let unsplash = new Unsplash({
      applicationId,
      secret,
      callbackUrl
    });

    afterEach(function () {
      restoreSpies();
    });

    describe("listCategories", () => {
      it("should make a GET request to /categories", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.categories.listCategories();

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          method: "GET",
          url: "/categories"
        }]);
      });
    });

    describe("category", () => {
      it("should make a GET request to /categories/{id}", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.categories.category(88);

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          method: "GET",
          url: "/categories/88"
        }]);
      });
    });

    describe("categoryPhotos", () => {
      it("should make a GET request to /categories/{id}/photos", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.categories.categoryPhotos(88, 2, 15);

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          method: "GET",
          url: "/categories/88/photos",
          query: {
            page: 2,
            per_page: 15
          }
        }]);
      });
    });
  });

  describe("curatedBatches", () => {
    let unsplash = new Unsplash({
      applicationId,
      secret,
      callbackUrl
    });

    afterEach(function () {
      restoreSpies();
    });

    describe("listCuratedBatches", () => {
      it("should make a GET request to /curated_batches", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.curatedBatches.listCuratedBatches(2, 15);

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          method: "GET",
          url: "/curated_batches",
          query: {
            page: 2,
            per_page: 15
          }
        }]);
      });
    });

    describe("curatedBatch", () => {
      it("should make a GET request to /curated_batches/{id}", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.curatedBatches.curatedBatch(88);

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          method: "GET",
          url: "/curated_batches/88",
        }]);
      });
    });

    describe("curatedBatchPhotos", () => {
      it("should make a GET request to /curated_batches/{id}/photos", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.curatedBatches.curatedBatchPhotos(88);

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          method: "GET",
          url: "/curated_batches/88/photos",
        }]);
      });
    });
  });

  describe("stats", () => {
    let unsplash = new Unsplash({
      applicationId,
      secret,
      callbackUrl
    });

    describe("total", () => {
      it("should make a GET request to /stats", () => {
        let spy = spyOn(unsplash, "request");
        unsplash.stats.total();

        expect(spy.calls.length).toEqual(1);
        expect(spy.calls[0].arguments).toEqual([{
          method: "GET",
          url: "/stats",
        }]);
      });
    });
  });

  describe("setBearerToken", () => {
    let unsplash = new Unsplash({
      applicationId,
      secret,
      callbackUrl
    });

    it("should set _bearerToken", () => {
      unsplash.setBearerToken("bar");
      expect(unsplash._bearerToken).toBe("bar");
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

var urlHash = require('../index')
  , url     = require('url')
  , crypto  = require('crypto')
  , expect  = require('expect.js');

describe('url-hash module', function(){

  var baseUrl = 'http://www.domain.com/page/';
  var queryString = '?id=4';

  describe('urlHash.config', function(){

    it('should allow salt to be changed', function(){

      urlHash.config({salt: 'newSalt'});

      expect(urlHash._salt).to.equal('newSalt');

    });

    it('should allow hash parameter key to be changed', function(){

      urlHash.config({hashKey: 'myHash'});

      expect(urlHash._hashKey).to.equal('myHash');

    });

    it('should be possible to set link expiry', function(){

      var expiryTime = 60000;

      urlHash.config({expire: expiryTime});

      expect(urlHash._expire).to.equal(expiryTime);

    });

  });

  describe('resetExpiry', function(){

    it('should set _expire to 0', function(){

      urlHash.resetExpiry();

      expect(urlHash._expire).to.be(0);

    });

  });

  describe('urlHash.create', function(){

    it('should be a function', function(){

      expect(urlHash.create).to.be.a('function');

    });

    it('should not change base url', function(){

      var result = urlHash.create(baseUrl + queryString).indexOf(baseUrl);

      expect(result).to.equal(0);

    });

    it('should return a url with parameter: hash', function(){

      var hashedUrl = urlHash.create(baseUrl + queryString);

      var urlObject = url.parse(hashedUrl, true);

      var result = urlObject.query.hasOwnProperty(urlHash._hashKey);

      expect(result).to.be(true);

    });

    it('hash parameter should be an sha256 hash of the url', function(){

      var expectedHash = crypto
                          .createHash('sha256')
                          .update(baseUrl + queryString + urlHash._salt)
                          .digest('hex');

      var hashedUrl = urlHash.create(baseUrl + queryString);

      var urlObject = url.parse(hashedUrl, true);

      var result = urlObject.query[urlHash._hashKey];

      expect(result).to.equal(expectedHash);

    });

    it('should add expire parameter if _expire has been set', function(){

      urlHash.config({expire: 60000});

      var testUrl = urlHash.create(baseUrl + queryString);

      var result = testUrl.indexOf('&expire=60000');

      expect(result).to.be.above(0);

    });

    it('should not add expire parameter if _expire is 0', function(){

      urlHash.resetExpiry();

      var testUrl = urlHash.create(baseUrl + queryString);

      var result = testUrl.indexOf('&expire=');

      expect(result).to.be(-1);

    });

  });

  describe('urlHash.check', function(){

    it('should return true if the url is unchanged', function(){

      var urlToCheck = urlHash.create(baseUrl + queryString);

      var result = urlHash.check(urlToCheck);

      expect(result).to.be(true);

    });

    it('should return false if the url has been changed', function(){

      var urlToCheck = urlHash.create(baseUrl + queryString);

      urlToCheck = urlToCheck.replace('id=4', 'id=5');

      var result = urlHash.check(urlToCheck);

      expect(result).to.be(false);

    });

    it('should return false if link has expired', function(){

      //  set expiry time to 1/4 second after creation
      urlHash.config({expire: 250});

      var urlToCheck = urlHash.create(baseUrl + queryString);

      // wait to let url expire
      this.timeout(300);

      var result = urlHash.check(urlToCheck);

      expect(result).to.be(false);

    });

  });

});
<commit_msg>update check expiry test to use negative expiry instead of timeout<commit_after>'use strict';

var urlHash = require('../index')
  , url     = require('url')
  , crypto  = require('crypto')
  , expect  = require('expect.js');

describe('url-hash module', function(){

  var baseUrl = 'http://www.domain.com/page/';
  var queryString = '?id=4';

  describe('urlHash.config', function(){

    it('should allow salt to be changed', function(){

      urlHash.config({salt: 'newSalt'});

      expect(urlHash._salt).to.equal('newSalt');

    });

    it('should allow hash parameter key to be changed', function(){

      urlHash.config({hashKey: 'myHash'});

      expect(urlHash._hashKey).to.equal('myHash');

    });

    it('should be possible to set link expiry', function(){

      var expiryTime = 60000;

      urlHash.config({expire: expiryTime});

      expect(urlHash._expire).to.equal(expiryTime);

    });

  });

  describe('resetExpiry', function(){

    it('should set _expire to 0', function(){

      urlHash.resetExpiry();

      expect(urlHash._expire).to.be(0);

    });

  });

  describe('urlHash.create', function(){

    it('should be a function', function(){

      expect(urlHash.create).to.be.a('function');

    });

    it('should not change base url', function(){

      var result = urlHash.create(baseUrl + queryString).indexOf(baseUrl);

      expect(result).to.equal(0);

    });

    it('should return a url with parameter: hash', function(){

      var hashedUrl = urlHash.create(baseUrl + queryString);

      var urlObject = url.parse(hashedUrl, true);

      var result = urlObject.query.hasOwnProperty(urlHash._hashKey);

      expect(result).to.be(true);

    });

    it('hash parameter should be an sha256 hash of the url', function(){

      var expectedHash = crypto
                          .createHash('sha256')
                          .update(baseUrl + queryString + urlHash._salt)
                          .digest('hex');

      var hashedUrl = urlHash.create(baseUrl + queryString);

      var urlObject = url.parse(hashedUrl, true);

      var result = urlObject.query[urlHash._hashKey];

      expect(result).to.equal(expectedHash);

    });

    it('should add expire parameter if _expire has been set', function(){

      urlHash.config({expire: 60000});

      var testUrl = urlHash.create(baseUrl + queryString);

      var result = testUrl.indexOf('&expire=');

      expect(result).to.be.above(0);

    });

    it('should not add expire parameter if _expire is 0', function(){

      urlHash.resetExpiry();

      var testUrl = urlHash.create(baseUrl + queryString);

      var result = testUrl.indexOf('&expire=');

      expect(result).to.be(-1);

    });

  });

  describe('urlHash.check', function(){

    it('should return true if the url is unchanged', function(){

      var urlToCheck = urlHash.create(baseUrl + queryString);

      var result = urlHash.check(urlToCheck);

      expect(result).to.be(true);

    });

    it('should return false if the url has been changed', function(){

      var urlToCheck = urlHash.create(baseUrl + queryString);

      urlToCheck = urlToCheck.replace('id=4', 'id=5');

      var result = urlHash.check(urlToCheck);

      expect(result).to.be(false);

    });

    it('should return false if link has expired', function(){

      //  set expiry time to 1/4 second before creation
      urlHash.config({expire: -250});

      var urlToCheck = urlHash.create(baseUrl + queryString);

      var result = urlHash.check(urlToCheck);

      expect(result).to.be(false);

    });

  });

});
<|endoftext|>


<commit_before>'use strict';

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

goog.provide('tachyfont.Reporter');

goog.require('goog.userAgent');

/**
 * Singleton reporter.
 *
 * @param {string} url The base URL to send reports to.
 * @constructor
 */
tachyfont.Reporter = function(url) {

  /** @private {string} */
  this.url_ = url + tachyfont.Reporter.URL_PATH;

  /** @private {!Object<string, (number|string)>} */
  this.items_ = {};
};

/**
 * The gen_204 path.
 * @type {string}
 */
tachyfont.Reporter.URL_PATH = '/gen_204?id=tf&';

/**
 * Enum for report params.
 * @enum {string}
 */
tachyfont.Reporter.Param = {
  ERROR_ID: 'ei',
  ERROR_TYPE: 'er',
  LOG_TYPE: 'lg',
  MOBILE: 'm',
  REPORT_TYPE: 'rt',
  END: ''
};

/**
 * The TachyFont start time.
 * This is as close to the user start time as possible. This is useful for
 * reporting how long after start time activities happened.
 *
 * @private {number} The milliseconds since midnight, January 1, 1970
 */
tachyfont.Reporter.startTime_ = goog.now();

/**
 * The TachyFont Reporter singleton object.
 * @private {?tachyfont.Reporter}
 */
tachyfont.Reporter.instance_ = null;

/**
 * Gets the reporter instance.
 * @return {?tachyfont.Reporter}
 */
tachyfont.Reporter.getInstance = function() {
  return tachyfont.Reporter.instance_;
};

/**
 * Sets the reporter instance.
 * @param {?tachyfont.Reporter} instance The reporter instance
 */
tachyfont.Reporter.setInstance = function(instance) {
  tachyfont.Reporter.instance_ = instance;
};

/**
 * Initializes the reporter singleton.
 * @param {string} url The base URL to send reports to.
 */
tachyfont.Reporter.initReporter = function(url) {
  if (tachyfont.Reporter.instance_ == null) {
    tachyfont.Reporter.instance_ = new tachyfont.Reporter(url);
  }
};

/**
 * Resets the reporter singleton.
 */
tachyfont.Reporter.reset = function() {
  tachyfont.Reporter.instance_ = null;
};

/**
 * Adds the time an item happened.
 * @param {string} name The name of the item.
 */
tachyfont.Reporter.addItemTime = function(name) {
  var deltaTime = goog.now() - tachyfont.Reporter.startTime_;
  tachyfont.Reporter.addItem(name, deltaTime);
};

/**
 * Adds an item to report.
 * @param {string} name The name of the item.
 * @param {string|number} value The value of the item.
 */
tachyfont.Reporter.addItem = function(name, value) {
  if (typeof value == 'number') {
    value = Math.round(value);
  }
  tachyfont.Reporter.instance_.items_[name] = value;
};

/**
 * Sends an error report.
 * @param {string} errorId The error id.
 * @param {string} fontId Font identifying information.
 * @param {*} errInfo The error information.
 */
tachyfont.Reporter.reportError = function(errorId, fontId, errInfo) {
  if (tachyfont.Reporter.instance_ == null) {
    return;
  }
  var params = [];
  params.push(
      tachyfont.Reporter.Param.REPORT_TYPE + '=' +
      tachyfont.Reporter.Param.ERROR_TYPE);
  params.push(tachyfont.Reporter.Param.ERROR_ID + '=' + errorId);
  params.push(
      tachyfont.Reporter.Param.MOBILE + '=' +
      (goog.userAgent.MOBILE ? '1' : '0'));
  var name = errorId + '.' + fontId;
  var msg = '';

  // Get the error message out of the error object.
  if (typeof errInfo == 'string') {
    msg += errInfo;
  } else if (typeof errInfo == 'object') {
    if (errInfo['message']) {
      msg += errInfo['message'];
    }
    if (errInfo['name']) {
      if (msg) {
        msg += ', ';
      }
      msg += errInfo['name'] + ', ';
    }
    if (errInfo['url']) {
      if (msg) {
        msg += ', ';
      }
      msg += errInfo['url'] + ', ';
    }
    if (errInfo['lineNumber']) {
      if (msg) {
        msg += ', ';
      }
      msg += errInfo['lineNumber'] + ', ';
    }
    // e.target.error.name
    if (errInfo['target']) {
      var target = errInfo['target'];
      if (target['error']) {
        var error = target['error'];
        if (error['name']) {
          if (msg) {
            msg += ', ';
          }
          msg += error['name'] + ', ';
        }
      }
      if (target['source']) {
        var source = target['source'];
        if (source['name']) {
          if (msg) {
            msg += ', ';
          }
          msg += source['name'] + ', ';
        }
      }
    }
  }
  params.push(name + '=' + msg);
  tachyfont.Reporter.sendGen204_(params);
};

/**
 * Sends a log report.
 */
tachyfont.Reporter.sendReport = function() {
  var keys = Object.keys(tachyfont.Reporter.instance_.items_);
  keys.sort();
  if (keys.length == 0) {
    return;
  }

  var length = tachyfont.Reporter.instance_.url_.length;
  var items = [];
  var item = tachyfont.Reporter.Param.REPORT_TYPE + '=' +
      tachyfont.Reporter.Param.LOG_TYPE;
  length += item.length;
  items.push(item);

  item = tachyfont.Reporter.Param.MOBILE + '=' +
      (goog.userAgent.MOBILE ? '1' : '0');
  length += item.length;
  items.push(item);
  for (var i = 0; i < keys.length; i++) {
    var name = keys[i];
    var value = encodeURIComponent(
        (tachyfont.Reporter.instance_.items_[name]).toString());
    delete tachyfont.Reporter.instance_.items_[name];
    item = encodeURIComponent(name) + '=' + value;
    if (length + item.length > 2000) {
      tachyfont.Reporter.sendGen204_(items);
      length = tachyfont.Reporter.instance_.url_.length;
      items = [];
    }
    length += item.length;
    items.push(item);
  }
  tachyfont.Reporter.sendGen204_(items);
};

/**
 * Sends the gen_204.
 * @param {!Array<string>} params The URL parameters.
 * @private
 */
tachyfont.Reporter.sendGen204_ = function(params) {
  var reportUrl =
      tachyfont.Reporter.instance_.url_ + params.join('&');
  var image = new Image();
  image.onload = image.onerror = tachyfont.Reporter.cleanUpFunc_(image);
  image.src = reportUrl;
};

/**
 * Clears references off the Image so it can be garbage collected.
 * @param {!Image} image The image to clean up.
 * @return {!function()} Function that cleans up the image.
 * @private
 */
tachyfont.Reporter.cleanUpFunc_ = function(image) {
  return function() {
    image.onload = image.onerror = null;
  };
};
<commit_msg>Report the font id as a separate url parameter.<commit_after>'use strict';

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

goog.provide('tachyfont.Reporter');

goog.require('goog.userAgent');

/**
 * Singleton reporter.
 *
 * @param {string} url The base URL to send reports to.
 * @constructor
 */
tachyfont.Reporter = function(url) {

  /** @private {string} */
  this.url_ = url + tachyfont.Reporter.URL_PATH;

  /** @private {!Object<string, (number|string)>} */
  this.items_ = {};
};

/**
 * The gen_204 path.
 * @type {string}
 */
tachyfont.Reporter.URL_PATH = '/gen_204?id=tf&';

/**
 * Enum for report params.
 * @enum {string}
 */
tachyfont.Reporter.Param = {
  ERROR_ID: 'ei',
  ERROR_TYPE: 'er',
  FONT_ID: 'fi',
  LOG_TYPE: 'lg',
  MOBILE: 'm',
  REPORT_TYPE: 'rt',
  END: ''
};

/**
 * The TachyFont start time.
 * This is as close to the user start time as possible. This is useful for
 * reporting how long after start time activities happened.
 *
 * @private {number} The milliseconds since midnight, January 1, 1970
 */
tachyfont.Reporter.startTime_ = goog.now();

/**
 * The TachyFont Reporter singleton object.
 * @private {?tachyfont.Reporter}
 */
tachyfont.Reporter.instance_ = null;

/**
 * Gets the reporter instance.
 * @return {?tachyfont.Reporter}
 */
tachyfont.Reporter.getInstance = function() {
  return tachyfont.Reporter.instance_;
};

/**
 * Sets the reporter instance.
 * @param {?tachyfont.Reporter} instance The reporter instance
 */
tachyfont.Reporter.setInstance = function(instance) {
  tachyfont.Reporter.instance_ = instance;
};

/**
 * Initializes the reporter singleton.
 * @param {string} url The base URL to send reports to.
 */
tachyfont.Reporter.initReporter = function(url) {
  if (tachyfont.Reporter.instance_ == null) {
    tachyfont.Reporter.instance_ = new tachyfont.Reporter(url);
  }
};

/**
 * Resets the reporter singleton.
 */
tachyfont.Reporter.reset = function() {
  tachyfont.Reporter.instance_ = null;
};

/**
 * Adds the time an item happened.
 * @param {string} name The name of the item.
 */
tachyfont.Reporter.addItemTime = function(name) {
  var deltaTime = goog.now() - tachyfont.Reporter.startTime_;
  tachyfont.Reporter.addItem(name, deltaTime);
};

/**
 * Adds an item to report.
 * @param {string} name The name of the item.
 * @param {string|number} value The value of the item.
 */
tachyfont.Reporter.addItem = function(name, value) {
  if (typeof value == 'number') {
    value = Math.round(value);
  }
  tachyfont.Reporter.instance_.items_[name] = value;
};

/**
 * Sends an error report.
 * @param {string} errorId The error id.
 * @param {string} fontId Font identifying information.
 * @param {*} errInfo The error information.
 */
tachyfont.Reporter.reportError = function(errorId, fontId, errInfo) {
  if (tachyfont.Reporter.instance_ == null) {
    return;
  }
  var params = [];
  params.push(
      tachyfont.Reporter.Param.REPORT_TYPE + '=' +
      tachyfont.Reporter.Param.ERROR_TYPE);
  params.push(tachyfont.Reporter.Param.ERROR_ID + '=' + errorId);
  params.push(tachyfont.Reporter.Param.FONT_ID + '=' + fontId);
  params.push(
      tachyfont.Reporter.Param.MOBILE + '=' +
      (goog.userAgent.MOBILE ? '1' : '0'));
  var name = errorId + '.' + fontId;
  var msg = '';

  // Get the error message out of the error object.
  if (typeof errInfo == 'string') {
    msg += errInfo;
  } else if (typeof errInfo == 'object') {
    if (errInfo['message']) {
      msg += errInfo['message'];
    }
    if (errInfo['name']) {
      if (msg) {
        msg += ', ';
      }
      msg += errInfo['name'] + ', ';
    }
    if (errInfo['url']) {
      if (msg) {
        msg += ', ';
      }
      msg += errInfo['url'] + ', ';
    }
    if (errInfo['lineNumber']) {
      if (msg) {
        msg += ', ';
      }
      msg += errInfo['lineNumber'] + ', ';
    }
    // e.target.error.name
    if (errInfo['target']) {
      var target = errInfo['target'];
      if (target['error']) {
        var error = target['error'];
        if (error['name']) {
          if (msg) {
            msg += ', ';
          }
          msg += error['name'] + ', ';
        }
      }
      if (target['source']) {
        var source = target['source'];
        if (source['name']) {
          if (msg) {
            msg += ', ';
          }
          msg += source['name'] + ', ';
        }
      }
    }
  }
  params.push(name + '=' + msg);
  tachyfont.Reporter.sendGen204_(params);
};

/**
 * Sends a log report.
 */
tachyfont.Reporter.sendReport = function() {
  var keys = Object.keys(tachyfont.Reporter.instance_.items_);
  keys.sort();
  if (keys.length == 0) {
    return;
  }

  var length = tachyfont.Reporter.instance_.url_.length;
  var items = [];
  var item = tachyfont.Reporter.Param.REPORT_TYPE + '=' +
      tachyfont.Reporter.Param.LOG_TYPE;
  length += item.length;
  items.push(item);

  item = tachyfont.Reporter.Param.MOBILE + '=' +
      (goog.userAgent.MOBILE ? '1' : '0');
  length += item.length;
  items.push(item);
  for (var i = 0; i < keys.length; i++) {
    var name = keys[i];
    var value = encodeURIComponent(
        (tachyfont.Reporter.instance_.items_[name]).toString());
    delete tachyfont.Reporter.instance_.items_[name];
    item = encodeURIComponent(name) + '=' + value;
    if (length + item.length > 2000) {
      tachyfont.Reporter.sendGen204_(items);
      length = tachyfont.Reporter.instance_.url_.length;
      items = [];
    }
    length += item.length;
    items.push(item);
  }
  tachyfont.Reporter.sendGen204_(items);
};

/**
 * Sends the gen_204.
 * @param {!Array<string>} params The URL parameters.
 * @private
 */
tachyfont.Reporter.sendGen204_ = function(params) {
  var reportUrl =
      tachyfont.Reporter.instance_.url_ + params.join('&');
  var image = new Image();
  image.onload = image.onerror = tachyfont.Reporter.cleanUpFunc_(image);
  image.src = reportUrl;
};

/**
 * Clears references off the Image so it can be garbage collected.
 * @param {!Image} image The image to clean up.
 * @return {!function()} Function that cleans up the image.
 * @private
 */
tachyfont.Reporter.cleanUpFunc_ = function(image) {
  return function() {
    image.onload = image.onerror = null;
  };
};
<|endoftext|>


<commit_before>'use strict';

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

goog.provide('tachyfont.Reporter');

goog.require('goog.log');

/**
 * Singleton reporter.
 *
 * @param {string} url The base URL to send reports to.
 * @constructor
 */
tachyfont.Reporter = function(url) {

  /** @private {string} */
  this.url_ = url;

  /** @private {!Object.<string, string>} */
  this.items_ = {};

  /**
   * The duplicate items count;
   *
   * Useful when keeping duplicates separately.
   *
   * @private {!Object.<string, number>}
   */
  this.dupCnts_ = {};
};

/**
 * TachyFont start time.
 *
 * This is as close to the user start time as possible. This is useful for
 * reporting how long after start time activities happened.
 *
 * @private {number} The milliseconds since midnight, January 1, 1970
 */
tachyfont.Reporter.startTime_ = goog.now();

/**
 * TachyFont singleton object.
 *
 * @private {!tachyfont.Reporter}
 */
tachyfont.Reporter.object_;

/**
 * Get the reporter singleton.
 *
 * @param {string} url The base URL to send reports to.
 * @return {!tachyfont.Reporter} The reporter singleton.
 */
tachyfont.Reporter.getReporter = function(url) {
  if (goog.DEBUG) {
    if (tachyfont.Reporter.object_ && tachyfont.Reporter.object_.url_ != url) {
      debugger;
    }
  }
  if (!tachyfont.Reporter.object_) {
    tachyfont.Reporter.object_ = new tachyfont.Reporter(url);
  }
  return tachyfont.Reporter.object_;
};

/**
 * Add the time an item happened.
 *
 * @param {string} name The name of the item.
 * @param {boolean=} opt_recordDups If true record duplicates separately.
 */
tachyfont.Reporter.prototype.addItemTime = function(name, opt_recordDups) {
  var deltaTime = goog.now() - tachyfont.Reporter.startTime_;
  this.addItem(name, '' + deltaTime, opt_recordDups);
};

/**
 * Add an item to report.
 *
 * @param {string} name The name of the item.
 * @param {string} value The value of the item.
 * @param {boolean=} opt_recordDups If true record duplicates separately.
 */
tachyfont.Reporter.prototype.addItem = function(name, value, opt_recordDups) {
  if (opt_recordDups) {
    if (name in this.dupCnts_) {
      var dupCnt = this.dupCnts_[name] + 1;
      this.dupCnts_[name] = dupCnt;
      name += '.' + dupCnt;
    } else {
      this.dupCnts_[name] = 0;
    }
  }
  this.items_[name] = value;
};

/**
 * Send the report.
 *
 * @param {boolean=} opt_okIfNoItems Do not complain if not items.
 */
tachyfont.Reporter.prototype.sendReport = function(opt_okIfNoItems) {
  var names = Object.keys(this.items_);
  names.sort();
  if (names.length == 0) {
    if (goog.DEBUG) {
      if (!opt_okIfNoItems) {
        goog.log.warning(tachyfont.logger, 'sendReport: no items');
        debugger;
      }
    }
    return;
  }
  if (goog.DEBUG) {
    if (!this.url_) {
      goog.log.error(tachyfont.logger, 'sendReport: URL not set');
      debugger;
      return;
    }
  }

  var items = [];
  if (goog.DEBUG) {
    goog.log.info(tachyfont.logger, 'report items:');
  }
  for (var i = 0; i < names.length; i++) {
    var name = names[i];
    var item = name + '=' + this.items_[name];
    items.push(item);
    if (goog.DEBUG) {
      goog.log.info(tachyfont.logger, '    ' + item);
    }
  }
  var reportUrl = this.url_ + '/gen_204?id=tf&' + items.join('&');
  var image = new Image();
  image.onload = image.onerror = tachyfont.Reporter.cleanUpFunc_(image);
  image.src = reportUrl;

  // Clean out the old items.
  this.items_ = {};
};

/**
 * Clear references off the Image so it can be garbage collected.
 * @private
 * @param {!Image} image The image to clean up.
 * @return {!function()} Function that cleans up the image.
 */
tachyfont.Reporter.cleanUpFunc_ = function(image) {
  return function() {
    image.onload = image.onerror = null;
  };
};

<commit_msg>Add an error reporting function.<commit_after>'use strict';

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

goog.provide('tachyfont.Reporter');

goog.require('goog.log');

/**
 * Singleton reporter.
 *
 * @param {string} url The base URL to send reports to.
 * @constructor
 */
tachyfont.Reporter = function(url) {

  /** @private {string} */
  this.url_ = url;

  /** @private {!Object.<string, string>} */
  this.items_ = {};

  /**
   * The duplicate items count;
   *
   * Useful when keeping duplicates separately.
   *
   * @private {!Object.<string, number>}
   */
  this.dupCnts_ = {};
};

/**
 * TachyFont start time.
 *
 * This is as close to the user start time as possible. This is useful for
 * reporting how long after start time activities happened.
 *
 * @private {number} The milliseconds since midnight, January 1, 1970
 */
tachyfont.Reporter.startTime_ = goog.now();

/**
 * TachyFont singleton object.
 *
 * @private {!tachyfont.Reporter}
 */
tachyfont.Reporter.object_;

/**
 * Get the reporter singleton.
 *
 * @param {string} url The base URL to send reports to.
 * @return {!tachyfont.Reporter} The reporter singleton.
 */
tachyfont.Reporter.getReporter = function(url) {
  if (goog.DEBUG) {
    if (tachyfont.Reporter.object_ && tachyfont.Reporter.object_.url_ != url) {
      debugger;
    }
  }
  if (!tachyfont.Reporter.object_) {
    tachyfont.Reporter.object_ = new tachyfont.Reporter(url);
  }
  return tachyfont.Reporter.object_;
};

/**
 * Add the time an item happened.
 *
 * @param {string} name The name of the item.
 * @param {boolean=} opt_recordDups If true record duplicates separately.
 */
tachyfont.Reporter.prototype.addItemTime = function(name, opt_recordDups) {
  var deltaTime = goog.now() - tachyfont.Reporter.startTime_;
  this.addItem(name, '' + deltaTime, opt_recordDups);
};

/**
 * Add an item to report.
 *
 * @param {string} name The name of the item.
 * @param {string} value The value of the item.
 * @param {boolean=} opt_recordDups If true record duplicates separately.
 */
tachyfont.Reporter.prototype.addItem = function(name, value, opt_recordDups) {
  if (opt_recordDups) {
    if (name in this.dupCnts_) {
      var dupCnt = this.dupCnts_[name] + 1;
      this.dupCnts_[name] = dupCnt;
      name += '.' + dupCnt;
    } else {
      this.dupCnts_[name] = 0;
    }
  }
  this.items_[name] = value;
};

/**
 * Send the report.
 *
 * @param {string} name The error name.
 * @param {Object} errObj The error object.
 */
tachyfont.Reporter.prototype.reportError = function(name, errObj) {
  // Move any pre-existing items aside.
  var preexistingItems = this.items_;
  this.items_ = {};
  name = 'e.' + name;
  this.addItem(name, '', true);

  // Get the error message out of the error object.
  var value = '';
  if (errObj) {
    if (errObj['stack']) {
      value = errObj['stack'];
      this.addItem(name + '.' + 'stack', value, true);
    } else if (errObj['message']) {
      value = errObj['message'];
      this.addItem(name + '.' + 'message', value, true);
    } else if (errObj['name']) {
      value = errObj['name'];
      this.addItem(name + '.' + 'name', value, true);
    }
    if (errObj['url']) {
      value = errObj['url'];
      this.addItem(name + '.' + 'url', value, true);
    }
    if (errObj['lineNumber']) {
      value = errObj['lineNumber'];
      this.addItem(name + '.' + 'lineNumber', value, true);
    }
    if (errObj['column']) {
      value = errObj['column'];
      this.addItem(name + '.' + 'column', value, true);
    }
  }
  this.sendReport();

  // Restore any pre-existing items.
  this.items_ = preexistingItems;

};

/**
 * Send the report.
 *
 * @param {boolean=} opt_okIfNoItems Do not complain if not items.
 */
tachyfont.Reporter.prototype.sendReport = function(opt_okIfNoItems) {
  var names = Object.keys(this.items_);
  names.sort();
  if (names.length == 0) {
    if (goog.DEBUG) {
      if (!opt_okIfNoItems) {
        goog.log.warning(tachyfont.logger, 'sendReport: no items');
        debugger;
      }
    }
    return;
  }
  if (goog.DEBUG) {
    if (!this.url_) {
      goog.log.error(tachyfont.logger, 'sendReport: URL not set');
      debugger;
      return;
    }
  }

  var baseUrl = this.url_ + '/gen_204?id=tf&';
  var length = baseUrl.length;
  var items = [];
  if (goog.DEBUG) {
    goog.log.info(tachyfont.logger, 'report items:');
  }
  for (var i = 0; i < names.length; i++) {
    var name = names[i];
    var value = encodeURIComponent(this.items_[name]);
    var item = name + '=' + value;
    if (length + item.length > 2000) {
      items.push('truncated=true');
      break;
    }
    length += item.length;
    items.push(item);
    if (goog.DEBUG) {
      goog.log.info(tachyfont.logger, '    ' + item);
    }
  }
  var reportUrl = + items.join('&');
  var image = new Image();
  image.onload = image.onerror = tachyfont.Reporter.cleanUpFunc_(image);
  image.src = reportUrl;

  // Clean out the old items.
  this.items_ = {};
};

/**
 * Clear references off the Image so it can be garbage collected.
 * @private
 * @param {!Image} image The image to clean up.
 * @return {!function()} Function that cleans up the image.
 */
tachyfont.Reporter.cleanUpFunc_ = function(image) {
  return function() {
    image.onload = image.onerror = null;
  };
};

<|endoftext|>


<commit_before>define(['typeServices/dispatch'], function(dispatch) {

  'use strict';

  function Volume() {
    this.files = {};
  }
  Volume.prototype = {
    charset: 'utf-8',
    pathSeparator: '/',
    joinPath: function(parts) {
      return parts.join(this.pathSeparator);
    },
    splitPath: function(path) {
      return path.split(this.pathSeparator);
    },
    load: function(segment) {
      switch (segment.typeName) {
        case 'application/zip': return this.loadZip(segment);
        default: return Promise.reject('Cannot load volume from ' + segment.typeName);
      }
    },
    loadZip: function(zip) {
      var promises = [];
      var self = this;
      return zip.split(
        function(entry) {
          if (entry.getTypeParameter('type') !== 'local') return;
          promises.push(entry.getStruct().then(function(record) {
            var ext = record.path.match(/[^\.]*$/)[0].toLowerCase();
            var type = dispatch.byExtension[ext] || 'application/octet-stream';
            if (entry.compressionMethod !== 'none') {
              var compressedType;
              switch (entry.compressionMethod) {
                case 'shrunk': type = 'application/x-lzw; variant=shrink'; break;
                case 'factor1': type = 'application/x-reduced; factor=1'; break;
                case 'factor2': type = 'application/x-reduced; factor=2'; break;
                case 'factor3': type = 'application/x-reduced; factor=3'; break;
                case 'factor4': type = 'application/x-reduced; factor=4'; break;
                case 'imploded': type = 'application/x-ibm-terse; variant=old'; break;
                case 'deflated': type = 'application/x-deflated'; break;
                case 'enhancedDeflated': type = 'application/x-deflated; variant=deflate64'; break;
                case 'dclImploded': type = 'application/x-imploded; variant=dcl'; break;
                case 'bzip2': type = 'application/x-bzip2'; break;
                case 'lzma': type = 'application/x-lzma'; break;
                case 'terse': type = 'application/x-ibm-terse; variant=new'; break;
                case 'lz77': type = 'application/x-lz77'; break;
                case 'jpeg': type = 'image/jpeg'; break;
                case 'wavpack': type = 'audio/x-wavpack'; break;
                case 'ppmd': type = 'application/x-ppmd; version=i; rev=1'; break;
                case 'aes': type = 'application/x-aes'; break;
                default: return Promise.reject('unknown compression: ' + entry.compressionMethod);
              }
              compressedType += '; type='+type;
              var full = record.uncompressedByteLength32; // TODO: zip64
              compressedType += '; full='+full;
              type = compressedType;
            }
            self.addFile(entry.path, entry.getSegment(type, entry.byteLength));
          }));
        },
        function() {
          return Promise.all(promises);
        });
    },
    addFile: function(path, segment) {
      this.files[path] = segment;
      this.onfile(path, segment);
    },
    onfile: function(){},
  };

  return Volume;

});
<commit_msg>Fix segment accesses that should be on the struct<commit_after>define(['typeServices/dispatch'], function(dispatch) {

  'use strict';

  function Volume() {
    this.files = {};
  }
  Volume.prototype = {
    charset: 'utf-8',
    pathSeparator: '/',
    joinPath: function(parts) {
      return parts.join(this.pathSeparator);
    },
    splitPath: function(path) {
      return path.split(this.pathSeparator);
    },
    load: function(segment) {
      switch (segment.typeName) {
        case 'application/zip': return this.loadZip(segment);
        default: return Promise.reject('Cannot load volume from ' + segment.typeName);
      }
    },
    loadZip: function(zip) {
      var promises = [];
      var self = this;
      return zip.split(
        function(entry) {
          if (entry.getTypeParameter('type') !== 'local') return;
          promises.push(entry.getStruct().then(function(record) {
            var ext = record.path.match(/[^\.]*$/)[0].toLowerCase();
            var type = dispatch.byExtension[ext] || 'application/octet-stream';
            if (record.compressionMethod !== 'none') {
              var compressedType;
              switch (record.compressionMethod) {
                case 'shrunk': type = 'application/x-lzw; variant=shrink'; break;
                case 'factor1': type = 'application/x-reduced; factor=1'; break;
                case 'factor2': type = 'application/x-reduced; factor=2'; break;
                case 'factor3': type = 'application/x-reduced; factor=3'; break;
                case 'factor4': type = 'application/x-reduced; factor=4'; break;
                case 'imploded': type = 'application/x-ibm-terse; variant=old'; break;
                case 'deflated': type = 'application/x-deflated'; break;
                case 'enhancedDeflated': type = 'application/x-deflated; variant=deflate64'; break;
                case 'dclImploded': type = 'application/x-imploded; variant=dcl'; break;
                case 'bzip2': type = 'application/x-bzip2'; break;
                case 'lzma': type = 'application/x-lzma'; break;
                case 'terse': type = 'application/x-ibm-terse; variant=new'; break;
                case 'lz77': type = 'application/x-lz77'; break;
                case 'jpeg': type = 'image/jpeg'; break;
                case 'wavpack': type = 'audio/x-wavpack'; break;
                case 'ppmd': type = 'application/x-ppmd; version=i; rev=1'; break;
                case 'aes': type = 'application/x-aes'; break;
                default: return Promise.reject('unknown compression: ' + record.compressionMethod);
              }
              compressedType += '; type='+type;
              var full = record.uncompressedByteLength32; // TODO: zip64
              compressedType += '; full='+full;
              type = compressedType;
            }
            self.addFile(entry.path, entry.getSegment(type, entry.byteLength));
          }));
        },
        function() {
          return Promise.all(promises);
        });
    },
    addFile: function(path, segment) {
      this.files[path] = segment;
      this.onfile(path, segment);
    },
    onfile: function(){},
  };

  return Volume;

});
<|endoftext|>


<commit_before>suite('Valid Schema Tests', () => {
  let assert = require('assert');
  let validator = require('../');
  let debug = require('debug')('test');
  let _ = require('lodash');

  let validate = null;

  suiteSetup(async () => {
    validate = await validator({
      folder: 'test/schemas',
      baseUrl: 'http://localhost:1203/',
      constants: {'my-constant': 42},
    });
  });

  test('load json', () => {
    let error = validate(
      {value: 42},
      'http://localhost:1203/test-schema.json#');
    assert.equal(error, null);
  });

  test('load yml', () => {
    let error = validate(
      {value: 42},
      'http://localhost:1203/yml-test-schema#');
    assert.equal(error, null);
  });

  test('load yaml', () => {
    let error = validate(
      {value: 42},
      'http://localhost:1203/yaml-test-schema#');
    assert.equal(error, null);
  });

  test('$ref', () => {
    let error = validate({
      reference: {value: 42},
      tid: new Date().toJSON(),
    }, 'http://localhost:1203/ref-test-schema#');
    assert.equal(error, null);
  });

  test('default values are inserted', () => {
    let json = {value: 42};
    let error = validate(
      json,
      'http://localhost:1203/default-schema');
    assert.equal(error, null);
    assert.equal(json.value, 42);
    assert.equal(json.optionalValue, 'my-default-value');
  });

  test('default values aren\'t overridden', () => {
    let json = {value: 42, optionalValue: 'already-here'};
    let error = validate(
      json,
      'http://localhost:1203/default-schema');
    assert.equal(error, null);
    assert.equal(json.value, 42);
    assert.equal(json.optionalValue, 'already-here');
  });

  test('default values with array and objects', () => {
    let json = {};
    let error = validate(
      json,
      'http://localhost:1203/default-array-obj-schema');
    assert.equal(error, null);
    assert.equal(json.optObj.hello, 'world');
    assert.equal(json.optArray.length, 1);
    assert.equal(json.optArray[0], 'my-default-value');
    assert.equal(json.optEmpty.length, 0);
  });

  test('no opts', async () => validator());

  test('using constants.yml', async () => {
    try {
      let v = await validator({
        folder: 'test/schemas',
        constants: 'test/schemas/constants.yml',
        baseUrl: 'http://localhost:1203/',
      });
      let error = v(
        {value: 43},
        'http://localhost:1203/yml-test-schema#');
      return assert.equal(error, null);
    } catch (err) {
      return err;
    }
  });

  test('rejects poorly formed object', () => {
    let error = validate(
      {value: 43},
      'http://localhost:1203/test-schema#');
    debug(error);
    assert.notEqual(error, null);
  });

  test('messages for large schema are nice', () => {
    let error = validate(
      {},
      'http://localhost:1203/big-schema#');
    debug(error);
    assert.notEqual(error, null);
  });

  test('automatic id', () => {
    let error = validate(
      {value: 42},
      'http://localhost:1203/auto-named-schema#');
    assert.equal(error, null);
  });

  test('schemas available', () => {
    let schemas = validate.schemas;
    assert.equal(_.keys(schemas).length, 9);
    assert(_.includes(_.keys(schemas), 'default-schema.json'));
  });

  test('message specifies unwanted additional property', () => {
    let error = validate(
      {value: 42, unwanted_value: 1729},
      'http://localhost:1203/default-schema');
    debug(error);
    assert.notEqual(error, null);
    assert(error.includes('data should NOT have additional properties:"unwanted_value"'));
  });
});
<commit_msg>fix test<commit_after>suite('Valid Schema Tests', () => {
  let assert = require('assert');
  let validator = require('../');
  let debug = require('debug')('test');
  let _ = require('lodash');

  let validate = null;

  suiteSetup(async () => {
    validate = await validator({
      folder: 'test/schemas',
      baseUrl: 'http://localhost:1203/',
      constants: {'my-constant': 42},
    });
  });

  test('load json', () => {
    let error = validate(
      {value: 42},
      'http://localhost:1203/test-schema.json#');
    assert.equal(error, null);
  });

  test('load yml', () => {
    let error = validate(
      {value: 42},
      'http://localhost:1203/yml-test-schema#');
    assert.equal(error, null);
  });

  test('load yaml', () => {
    let error = validate(
      {value: 42},
      'http://localhost:1203/yaml-test-schema#');
    assert.equal(error, null);
  });

  test('$ref', () => {
    let error = validate({
      reference: {value: 42},
      tid: new Date().toJSON(),
    }, 'http://localhost:1203/ref-test-schema#');
    assert.equal(error, null);
  });

  test('default values are inserted', () => {
    let json = {value: 42};
    let error = validate(
      json,
      'http://localhost:1203/default-schema');
    assert.equal(error, null);
    assert.equal(json.value, 42);
    assert.equal(json.optionalValue, 'my-default-value');
  });

  test('default values aren\'t overridden', () => {
    let json = {value: 42, optionalValue: 'already-here'};
    let error = validate(
      json,
      'http://localhost:1203/default-schema');
    assert.equal(error, null);
    assert.equal(json.value, 42);
    assert.equal(json.optionalValue, 'already-here');
  });

  test('default values with array and objects', () => {
    let json = {};
    let error = validate(
      json,
      'http://localhost:1203/default-array-obj-schema');
    assert.equal(error, null);
    assert.equal(json.optObj.hello, 'world');
    assert.equal(json.optArray.length, 1);
    assert.equal(json.optArray[0], 'my-default-value');
    assert.equal(json.optEmpty.length, 0);
  });

  test('no opts', async () => validator());

  test('using constants.yml', async () => {
    try {
      let v = await validator({
        folder: 'test/schemas',
        constants: 'test/schemas/constants.yml',
        baseUrl: 'http://localhost:1203/',
      });
      let error = v(
        {value: 43},
        'http://localhost:1203/yml-test-schema#');
      return assert.equal(error, null);
    } catch (err) {
      return err;
    }
  });

  test('rejects poorly formed object', () => {
    let error = validate(
      {value: 43},
      'http://localhost:1203/test-schema#');
    debug(error);
    assert.notEqual(error, null);
  });

  test('messages for large schema are nice', () => {
    let error = validate(
      {},
      'http://localhost:1203/big-schema#');
    debug(error);
    assert.notEqual(error, null);
  });

  test('automatic id', () => {
    let error = validate(
      {value: 42},
      'http://localhost:1203/auto-named-schema#');
    assert.equal(error, null);
  });

  test('schemas available', () => {
    let schemas = validate.schemas;
    assert.equal(_.keys(schemas).length, 9);
    assert(_.includes(_.keys(schemas), 'default-schema.json'));
  });

  test('message specifies unwanted additional property', () => {
    let error = validate(
      {value: 42, unwanted_value: 1729},
      'http://localhost:1203/default-schema');
    debug(error);
    assert.notEqual(error, null);
    assert(error.includes('data should NOT have additional properties: "unwanted_value"'));
  });
});
<|endoftext|>


<commit_before>var nock = require('nock')

const mockResponse = {
  invalidSecret: {
    response: {
      result: 'error',
      reason: 'Invalid application secret.',
      trace_id: 'Xcm545545198200907134i',
      code: 21301,
      description: '认证失败'
    }
  },
  getInvalidRegIds: {
    response: {
      result: 'ok',
      description: '成功',
      data: { list: ['regid1', 'regid2', 'regid3'] },
      code: 0
    }
  },
  sendToRegid: {
    method: 'post',
    response: {
      result: 'ok',
      trace_id: 'Xdm011145198187915406b',
      code: 0,
      data: {
        id: 'scm51336519827468580b1'
      },
      description: '成功',
      info: 'Received push messages for 1 REGID'
    }
  },
  getStats: {
    response: {
      result: 'ok',
      description: '成功',
      data: {
        data: [
          {
            date: '20140428',
            single_recipients: 0,
            broadcast_recipients: 7689,
            received: 7026,
            click: 1703
          },
          {
            date: '20140429',
            single_recipients: 0,
            broadcast_recipients: 5129,
            received: 4642,
            click: 1256
          }
        ]
      },
      code: 0
    }
  },
  getAliasesOf: {
    response: {
      result: 'ok',
      code: 0,
      data: { list: ['XXXXXX', 'YYYYY'] },
      description: '成功'
    }
  },
  getMessageStatus: {
    response: {
      result: 'ok',
      trace_id: 'Xcm521145198274755965y',
      code: 0,
      data: {
        data: {
          create_time: '2018-02-28 22:17:48',
          invalid_target: 0,
          raw_counter: 0,
          click_rate: '0%',
          delivered: 0,
          click: 0,
          bar_closed: 0,
          device_condition_unmatch: 0,
          create_timestamp: 1519827468580,
          time_to_live: '1209600s',
          msg_type: 'Common',
          delivery_rate: '0%',
          id: 'scm51336519827468580b1',
          resolved: 0,
          app_not_register: 0
        }
      },
      description: '成功'
    }
  },
  getMessagesStatus: {
    response: {
      result: 'ok',
      trace_id: 'Xcm53586519827658479gh',
      code: 0,
      data: {
        data: []
      }
    }
  },
  getMessageGroupStatus: {
    response: {
      result: 'ok',
      trace_id: 'Xcm53586519827658479gh',
      code: 0,
      data: {
        data: []
      }
    }
  },
  subscribeTopic: {
    method: 'post',
    response: {
      result: 'ok',
      reason: 'Success',
      trace_id: 'Xdm00671519828734517Bt',
      code: 0,
      description: '成功'
    }
  }
}

module.exports = function (apiName) {
  const mockConfig = mockResponse[apiName]
  if (!mockConfig) {
    throw new Error(apiName + ' not supported')
  }
  const method = mockConfig.method || 'get'
  const response = mockConfig.response
  nock(/.*/)
    [method](/.*/)
    .reply(200, response)
}
<commit_msg>fix lint vs prettier<commit_after>var nock = require('nock')

const mockResponse = {
  invalidSecret: {
    response: {
      result: 'error',
      reason: 'Invalid application secret.',
      trace_id: 'Xcm545545198200907134i',
      code: 21301,
      description: '认证失败'
    }
  },
  getInvalidRegIds: {
    response: {
      result: 'ok',
      description: '成功',
      data: { list: ['regid1', 'regid2', 'regid3'] },
      code: 0
    }
  },
  sendToRegid: {
    method: 'post',
    response: {
      result: 'ok',
      trace_id: 'Xdm011145198187915406b',
      code: 0,
      data: {
        id: 'scm51336519827468580b1'
      },
      description: '成功',
      info: 'Received push messages for 1 REGID'
    }
  },
  getStats: {
    response: {
      result: 'ok',
      description: '成功',
      data: {
        data: [
          {
            date: '20140428',
            single_recipients: 0,
            broadcast_recipients: 7689,
            received: 7026,
            click: 1703
          },
          {
            date: '20140429',
            single_recipients: 0,
            broadcast_recipients: 5129,
            received: 4642,
            click: 1256
          }
        ]
      },
      code: 0
    }
  },
  getAliasesOf: {
    response: {
      result: 'ok',
      code: 0,
      data: { list: ['XXXXXX', 'YYYYY'] },
      description: '成功'
    }
  },
  getMessageStatus: {
    response: {
      result: 'ok',
      trace_id: 'Xcm521145198274755965y',
      code: 0,
      data: {
        data: {
          create_time: '2018-02-28 22:17:48',
          invalid_target: 0,
          raw_counter: 0,
          click_rate: '0%',
          delivered: 0,
          click: 0,
          bar_closed: 0,
          device_condition_unmatch: 0,
          create_timestamp: 1519827468580,
          time_to_live: '1209600s',
          msg_type: 'Common',
          delivery_rate: '0%',
          id: 'scm51336519827468580b1',
          resolved: 0,
          app_not_register: 0
        }
      },
      description: '成功'
    }
  },
  getMessagesStatus: {
    response: {
      result: 'ok',
      trace_id: 'Xcm53586519827658479gh',
      code: 0,
      data: {
        data: []
      }
    }
  },
  getMessageGroupStatus: {
    response: {
      result: 'ok',
      trace_id: 'Xcm53586519827658479gh',
      code: 0,
      data: {
        data: []
      }
    }
  },
  subscribeTopic: {
    method: 'post',
    response: {
      result: 'ok',
      reason: 'Success',
      trace_id: 'Xdm00671519828734517Bt',
      code: 0,
      description: '成功'
    }
  }
}

module.exports = function (apiName) {
  const mockConfig = mockResponse[apiName]
  if (!mockConfig) {
    throw new Error(apiName + ' not supported')
  }
  const method = mockConfig.method || 'get'
  const response = mockConfig.response

  const scope = nock(/.*/)
  scope[method](/.*/).reply(200, response)
}
<|endoftext|>


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

/**
 * This application demonstrates how to perform basic operations on alerting
 * policies with the Google Stackdriver Monitoring API.
 *
 * For more information, see https://cloud.google.com/monitoring/docs/.
 */

'use strict';

async function backupPolicies(projectId) {
  // [START monitoring_alert_backup_policies]
  const fs = require('fs');

  // Imports the Google Cloud client library
  const monitoring = require('@google-cloud/monitoring');

  // Creates a client
  const client = new monitoring.AlertPolicyServiceClient();

  /**
   * TODO(developer): Uncomment the following lines before running the sample.
   */
  // const projectId = 'YOUR_PROJECT_ID';

  const listAlertPoliciesRequest = {
    name: client.projectPath(projectId),
  };

  let [policies] = await client.listAlertPolicies(listAlertPoliciesRequest);

  // filter out any policies created by tests for this sample
  policies = policies.filter(policy => {
    return !policy.displayName.startsWith('gcloud-tests-');
  });

  fs.writeFileSync(
    './policies_backup.json',
    JSON.stringify(policies, null, 2),
    'utf-8'
  );

  console.log('Saved policies to ./policies_backup.json');
  // [END monitoring_alert_backup_policies]
}

async function restorePolicies(projectId) {
  // Note: The policies are restored one at a time because I get 'service
  //       unavailable' when I try to create multiple alerts simultaneously.
  // [START monitoring_alert_restore_policies]
  // [START monitoring_alert_create_policy]
  const fs = require('fs');

  // Imports the Google Cloud client library
  const monitoring = require('@google-cloud/monitoring');

  // Creates a client
  const client = new monitoring.AlertPolicyServiceClient();

  /**
   * TODO(developer): Uncomment the following lines before running the sample.
   */
  // const projectId = 'YOUR_PROJECT_ID';

  console.log('Loading policies from ./policies_backup.json');
  const fileContent = fs.readFileSync('./policies_backup.json', 'utf-8');
  const policies = JSON.parse(fileContent);

  for (const index in policies) {
    // Restore each policy one at a time
    let policy = policies[index];
    if (await doesAlertPolicyExist(policy.name)) {
      policy = await client.updateAlertPolicy({alertPolicy: policy});
    } else {
      // Clear away output-only fields
      delete policy.name;
      delete policy.creationRecord;
      delete policy.mutationRecord;
      policy.conditions.forEach(condition => delete condition.name);

      policy = await client.createAlertPolicy({
        name: client.projectPath(projectId),
        alertPolicy: policy,
      });
    }

    console.log(`Restored ${policy[0].name}.`);
  }
  async function doesAlertPolicyExist(name) {
    try {
      const [policy] = await client.getAlertPolicy({name});
      return policy ? true : false;
    } catch (err) {
      if (err && err.code === 5) {
        // Error code 5 comes from the google.rpc.code.NOT_FOUND protobuf
        return false;
      }
      throw err;
    }
  }
  // [END monitoring_alert_create_policy]
  // [END monitoring_alert_restore_policies]
}

async function deleteChannels(projectId, filter) {
  // [START monitoring_alert_delete_channel]
  // [START monitoring_alert_list_channel]

  // Imports the Google Cloud client library
  const monitoring = require('@google-cloud/monitoring');

  // Creates a client
  const client = new monitoring.NotificationChannelServiceClient();

  /**
   * TODO(developer): Uncomment the following lines before running the sample.
   */
  // const projectId = 'YOUR_PROJECT_ID';
  // const filter = 'A filter for selecting policies, e.g. description:"cloud"';

  const request = {name: client.projectPath(projectId), filter};
  const channels = await client.listNotificationChannels(request);
  console.log(channels);
  for (const channel of channels[0]) {
    console.log(`Deleting channel ${channel.displayName}`);
    try {
      await client.deleteNotificationChannel({
        name: channel.name,
      });
    } catch (err) {
      // ignore error
    }
  }
  // [END monitoring_alert_create_policy]
  // [END monitoring_alert_restore_policies]
}

async function replaceChannels(projectId, alertPolicyId, channelIds) {
  // [START monitoring_alert_replace_channels]
  // [START monitoring_alert_enable_channel]
  // [START monitoring_alert_update_channel]
  // [START monitoring_alert_create_channel]

  // Imports the Google Cloud client library
  const monitoring = require('@google-cloud/monitoring');

  // Creates clients
  const alertClient = new monitoring.AlertPolicyServiceClient();
  const notificationClient = new monitoring.NotificationChannelServiceClient();

  /**
   * TODO(developer): Uncomment the following lines before running the sample.
   */
  // const projectId = 'YOUR_PROJECT_ID';
  // const alertPolicyId = '123456789012314';
  // const channelIds = [
  //   'channel-1',
  //   'channel-2',
  //   'channel-3',
  // ];

  const notificationChannels = channelIds.map(id =>
    notificationClient.notificationChannelPath(projectId, id)
  );

  for (const channel of notificationChannels) {
    const updateChannelRequest = {
      updateMask: {paths: ['enabled']},
      notificationChannel: {
        name: channel,
        enabled: {value: true},
      },
    };
    try {
      await notificationClient.updateNotificationChannel(updateChannelRequest);
    } catch (err) {
      const createChannelRequest = {
        notificationChannel: {
          name: channel,
          notificationChannel: {type: 'email'},
        },
      };
      const newChannel = await notificationClient.createNotificationChannel(
        createChannelRequest
      );
      notificationChannels.push(newChannel);
    }
  }

  const updateAlertPolicyRequest = {
    updateMask: {paths: ['notification_channels']},
    alertPolicy: {
      name: alertClient.alertPolicyPath(projectId, alertPolicyId),
      notificationChannels: notificationChannels,
    },
  };
  const [alertPolicy] = await alertClient.updateAlertPolicy(
    updateAlertPolicyRequest
  );
  console.log(`Updated ${alertPolicy.name}.`);
  // [END monitoring_alert_replace_channels]
}

async function enablePolicies(projectId, enabled, filter) {
  // [START monitoring_alert_enable_policies]
  // Imports the Google Cloud client library
  const monitoring = require('@google-cloud/monitoring');

  // Creates a client
  const client = new monitoring.AlertPolicyServiceClient();

  /**
   * TODO(developer): Uncomment the following lines before running the sample.
   */
  // const projectId = 'YOUR_PROJECT_ID';
  // const enabled = true;
  // const filter = 'A filter for selecting policies, e.g. description:"cloud"';

  const listAlertPoliciesRequest = {
    name: client.projectPath(projectId),
    // See https://cloud.google.com/monitoring/alerting/docs/sorting-and-filtering
    filter: filter,
  };

  const [policies] = await client.listAlertPolicies(listAlertPoliciesRequest);
  const tasks = await Promise.all(
    policies
      .map(policy => {
        return {
          updateMask: {paths: ['disabled']},
          alertPolicy: {
            name: policy.name,
            disabled: enabled ? false : true,
          },
        };
      })
      .map(updateAlertPolicyRequest =>
        client.updateAlertPolicy(updateAlertPolicyRequest)
      )
  );
  tasks.forEach(response => {
    const alertPolicy = response[0];
    console.log(`${enabled ? 'Enabled' : 'Disabled'} ${alertPolicy.name}.`);
  });
  // [END monitoring_alert_enable_policies]
}

async function listPolicies(projectId) {
  // [START monitoring_alert_list_policies]
  // Imports the Google Cloud client library
  const monitoring = require('@google-cloud/monitoring');

  // Creates a client
  const client = new monitoring.AlertPolicyServiceClient();

  /**
   * TODO(developer): Uncomment the following lines before running the sample.
   */
  // const projectId = 'YOUR_PROJECT_ID';

  const listAlertPoliciesRequest = {
    name: client.projectPath(projectId),
  };
  const [policies] = await client.listAlertPolicies(listAlertPoliciesRequest);
  console.log('Policies:');
  policies.forEach(policy => {
    console.log(`  Display name: ${policy.displayName}`);
    if (policy.documentation && policy.documentation.content) {
      console.log(`     Documentation: ${policy.documentation.content}`);
    }
  });

  // [END monitoring_alert_list_policies]
}

require(`yargs`)
  .demand(1)
  .command(
    `backup <projectId>`,
    `Save alert policies to a ./policies_backup.json file.`,
    {},
    opts => backupPolicies(opts.projectId, opts.filter || '')
  )
  .command(
    `restore <projectId>`,
    `Restore alert policies from a ./policies_backup.json file.`,
    {},
    opts => restorePolicies(opts.projectId, opts.filter || '')
  )
  .command(
    `replace <alertPolicyName> <channelNames..>`,
    `Replace the notification channels of the specified alert policy.`,
    {},
    opts => {
      const parts = opts.alertPolicyName.split('/');
      const channelIds = opts.channelNames.map(name => name.split('/')[3]);
      replaceChannels(parts[1], parts[3], channelIds);
    }
  )
  .command(
    `disable <projectId> [filter]`,
    `Disables policies that match the given filter.`,
    {},
    opts => enablePolicies(opts.projectId, false, opts.filter || ``)
  )
  .command(
    `enable <projectId> [filter]`,
    `Enables policies that match the given filter.`,
    {},
    opts => enablePolicies(opts.projectId, true, opts.filter || ``)
  )
  .command(
    `list <projectId>`,
    `Lists alert policies in the specified project.`,
    {},
    opts => listPolicies(opts.projectId)
  )
  .command(
    `deleteChannels <projectId> [filter]`,
    `Lists and deletes all channels in the specified project.`,
    {},
    opts => deleteChannels(opts.projectId, opts.filter || ``)
  )
  .options({
    alertPolicyName: {
      type: 'string',
      requiresArg: true,
    },
  })
  .example(`node $0 backup my-project-id`, `Backup policies.`)
  .example(`node $0 restore my-project-id`, `Restore policies.`)
  .example(
    `node $0 replace projects/my-project-id/alertPolicies/12345 channel-1 channel-2 channel-3`,
    `Replace the notification channels of the specified alert policy.`
  )
  .example(
    `node $0 disable my-project-id "(NOT display_name.empty OR NOT description.empty) AND user_labels='active'"`,
    `Disables policies that match the given filter.`
  )
  .example(
    `node $0 disable my-project-id "description:'cloud'"`,
    `Disables policies that match the given filter.`
  )
  .example(
    `node $0 disable my-project-id "display_name=monitoring.regex.full_match('Temp \\d{4}')"`,
    `Disables policies that match the given filter.`
  )
  .example(
    `node $0 enable my-project-id "(NOT display_name.empty OR NOT description.empty) AND user_labels='active'"`,
    `Enables policies that match the given filter.`
  )
  .example(
    `node $0 enable my-project-id "description:'cloud'"`,
    `Enables policies that match the given filter.`
  )
  .example(
    `node $0 enable my-project-id "display_name=monitoring.regex.full_match('Temp \\d{4}')"`,
    `Enables policies that match the given filter.`
  )
  .wrap(120)
  .recommendCommands()
  .epilogue(
    `For more information, see https://cloud.google.com/monitoring/docs/`
  )
  .help()
  .strict().argv;
<commit_msg>chore: fix region tags (#187)<commit_after>/**
 * Copyright 2018, Google, Inc.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * This application demonstrates how to perform basic operations on alerting
 * policies with the Google Stackdriver Monitoring API.
 *
 * For more information, see https://cloud.google.com/monitoring/docs/.
 */

'use strict';

async function backupPolicies(projectId) {
  // [START monitoring_alert_backup_policies]
  const fs = require('fs');

  // Imports the Google Cloud client library
  const monitoring = require('@google-cloud/monitoring');

  // Creates a client
  const client = new monitoring.AlertPolicyServiceClient();

  /**
   * TODO(developer): Uncomment the following lines before running the sample.
   */
  // const projectId = 'YOUR_PROJECT_ID';

  const listAlertPoliciesRequest = {
    name: client.projectPath(projectId),
  };

  let [policies] = await client.listAlertPolicies(listAlertPoliciesRequest);

  // filter out any policies created by tests for this sample
  policies = policies.filter(policy => {
    return !policy.displayName.startsWith('gcloud-tests-');
  });

  fs.writeFileSync(
    './policies_backup.json',
    JSON.stringify(policies, null, 2),
    'utf-8'
  );

  console.log('Saved policies to ./policies_backup.json');
  // [END monitoring_alert_backup_policies]
}

async function restorePolicies(projectId) {
  // Note: The policies are restored one at a time because I get 'service
  //       unavailable' when I try to create multiple alerts simultaneously.
  // [START monitoring_alert_restore_policies]
  // [START monitoring_alert_create_policy]
  const fs = require('fs');

  // Imports the Google Cloud client library
  const monitoring = require('@google-cloud/monitoring');

  // Creates a client
  const client = new monitoring.AlertPolicyServiceClient();

  /**
   * TODO(developer): Uncomment the following lines before running the sample.
   */
  // const projectId = 'YOUR_PROJECT_ID';

  console.log('Loading policies from ./policies_backup.json');
  const fileContent = fs.readFileSync('./policies_backup.json', 'utf-8');
  const policies = JSON.parse(fileContent);

  for (const index in policies) {
    // Restore each policy one at a time
    let policy = policies[index];
    if (await doesAlertPolicyExist(policy.name)) {
      policy = await client.updateAlertPolicy({alertPolicy: policy});
    } else {
      // Clear away output-only fields
      delete policy.name;
      delete policy.creationRecord;
      delete policy.mutationRecord;
      policy.conditions.forEach(condition => delete condition.name);

      policy = await client.createAlertPolicy({
        name: client.projectPath(projectId),
        alertPolicy: policy,
      });
    }

    console.log(`Restored ${policy[0].name}.`);
  }
  async function doesAlertPolicyExist(name) {
    try {
      const [policy] = await client.getAlertPolicy({name});
      return policy ? true : false;
    } catch (err) {
      if (err && err.code === 5) {
        // Error code 5 comes from the google.rpc.code.NOT_FOUND protobuf
        return false;
      }
      throw err;
    }
  }
  // [END monitoring_alert_create_policy]
  // [END monitoring_alert_restore_policies]
}

async function deleteChannels(projectId, filter) {
  // [START monitoring_alert_delete_channel]
  // [START monitoring_alert_list_channel]

  // Imports the Google Cloud client library
  const monitoring = require('@google-cloud/monitoring');

  // Creates a client
  const client = new monitoring.NotificationChannelServiceClient();

  /**
   * TODO(developer): Uncomment the following lines before running the sample.
   */
  // const projectId = 'YOUR_PROJECT_ID';
  // const filter = 'A filter for selecting policies, e.g. description:"cloud"';

  const request = {name: client.projectPath(projectId), filter};
  const channels = await client.listNotificationChannels(request);
  console.log(channels);
  for (const channel of channels[0]) {
    console.log(`Deleting channel ${channel.displayName}`);
    try {
      await client.deleteNotificationChannel({
        name: channel.name,
      });
    } catch (err) {
      // ignore error
    }
  }
  // [END monitoring_alert_delete_channel]
  // [END monitoring_alert_list_channel]
}

async function replaceChannels(projectId, alertPolicyId, channelIds) {
  // [START monitoring_alert_replace_channels]
  // [START monitoring_alert_enable_channel]
  // [START monitoring_alert_update_channel]
  // [START monitoring_alert_create_channel]

  // Imports the Google Cloud client library
  const monitoring = require('@google-cloud/monitoring');

  // Creates clients
  const alertClient = new monitoring.AlertPolicyServiceClient();
  const notificationClient = new monitoring.NotificationChannelServiceClient();

  /**
   * TODO(developer): Uncomment the following lines before running the sample.
   */
  // const projectId = 'YOUR_PROJECT_ID';
  // const alertPolicyId = '123456789012314';
  // const channelIds = [
  //   'channel-1',
  //   'channel-2',
  //   'channel-3',
  // ];

  const notificationChannels = channelIds.map(id =>
    notificationClient.notificationChannelPath(projectId, id)
  );

  for (const channel of notificationChannels) {
    const updateChannelRequest = {
      updateMask: {paths: ['enabled']},
      notificationChannel: {
        name: channel,
        enabled: {value: true},
      },
    };
    try {
      await notificationClient.updateNotificationChannel(updateChannelRequest);
    } catch (err) {
      const createChannelRequest = {
        notificationChannel: {
          name: channel,
          notificationChannel: {type: 'email'},
        },
      };
      const newChannel = await notificationClient.createNotificationChannel(
        createChannelRequest
      );
      notificationChannels.push(newChannel);
    }
  }

  const updateAlertPolicyRequest = {
    updateMask: {paths: ['notification_channels']},
    alertPolicy: {
      name: alertClient.alertPolicyPath(projectId, alertPolicyId),
      notificationChannels: notificationChannels,
    },
  };
  const [alertPolicy] = await alertClient.updateAlertPolicy(
    updateAlertPolicyRequest
  );
  console.log(`Updated ${alertPolicy.name}.`);
  // [END monitoring_alert_replace_channels]
  // [END monitoring_alert_enable_channel]
  // [END monitoring_alert_update_channel]
  // [END monitoring_alert_create_channel]
}

async function enablePolicies(projectId, enabled, filter) {
  // [START monitoring_alert_enable_policies]
  // Imports the Google Cloud client library
  const monitoring = require('@google-cloud/monitoring');

  // Creates a client
  const client = new monitoring.AlertPolicyServiceClient();

  /**
   * TODO(developer): Uncomment the following lines before running the sample.
   */
  // const projectId = 'YOUR_PROJECT_ID';
  // const enabled = true;
  // const filter = 'A filter for selecting policies, e.g. description:"cloud"';

  const listAlertPoliciesRequest = {
    name: client.projectPath(projectId),
    // See https://cloud.google.com/monitoring/alerting/docs/sorting-and-filtering
    filter: filter,
  };

  const [policies] = await client.listAlertPolicies(listAlertPoliciesRequest);
  const tasks = await Promise.all(
    policies
      .map(policy => {
        return {
          updateMask: {paths: ['disabled']},
          alertPolicy: {
            name: policy.name,
            disabled: enabled ? false : true,
          },
        };
      })
      .map(updateAlertPolicyRequest =>
        client.updateAlertPolicy(updateAlertPolicyRequest)
      )
  );
  tasks.forEach(response => {
    const alertPolicy = response[0];
    console.log(`${enabled ? 'Enabled' : 'Disabled'} ${alertPolicy.name}.`);
  });
  // [END monitoring_alert_enable_policies]
}

async function listPolicies(projectId) {
  // [START monitoring_alert_list_policies]
  // Imports the Google Cloud client library
  const monitoring = require('@google-cloud/monitoring');

  // Creates a client
  const client = new monitoring.AlertPolicyServiceClient();

  /**
   * TODO(developer): Uncomment the following lines before running the sample.
   */
  // const projectId = 'YOUR_PROJECT_ID';

  const listAlertPoliciesRequest = {
    name: client.projectPath(projectId),
  };
  const [policies] = await client.listAlertPolicies(listAlertPoliciesRequest);
  console.log('Policies:');
  policies.forEach(policy => {
    console.log(`  Display name: ${policy.displayName}`);
    if (policy.documentation && policy.documentation.content) {
      console.log(`     Documentation: ${policy.documentation.content}`);
    }
  });

  // [END monitoring_alert_list_policies]
}

require(`yargs`)
  .demand(1)
  .command(
    `backup <projectId>`,
    `Save alert policies to a ./policies_backup.json file.`,
    {},
    opts => backupPolicies(opts.projectId, opts.filter || '')
  )
  .command(
    `restore <projectId>`,
    `Restore alert policies from a ./policies_backup.json file.`,
    {},
    opts => restorePolicies(opts.projectId, opts.filter || '')
  )
  .command(
    `replace <alertPolicyName> <channelNames..>`,
    `Replace the notification channels of the specified alert policy.`,
    {},
    opts => {
      const parts = opts.alertPolicyName.split('/');
      const channelIds = opts.channelNames.map(name => name.split('/')[3]);
      replaceChannels(parts[1], parts[3], channelIds);
    }
  )
  .command(
    `disable <projectId> [filter]`,
    `Disables policies that match the given filter.`,
    {},
    opts => enablePolicies(opts.projectId, false, opts.filter || ``)
  )
  .command(
    `enable <projectId> [filter]`,
    `Enables policies that match the given filter.`,
    {},
    opts => enablePolicies(opts.projectId, true, opts.filter || ``)
  )
  .command(
    `list <projectId>`,
    `Lists alert policies in the specified project.`,
    {},
    opts => listPolicies(opts.projectId)
  )
  .command(
    `deleteChannels <projectId> [filter]`,
    `Lists and deletes all channels in the specified project.`,
    {},
    opts => deleteChannels(opts.projectId, opts.filter || ``)
  )
  .options({
    alertPolicyName: {
      type: 'string',
      requiresArg: true,
    },
  })
  .example(`node $0 backup my-project-id`, `Backup policies.`)
  .example(`node $0 restore my-project-id`, `Restore policies.`)
  .example(
    `node $0 replace projects/my-project-id/alertPolicies/12345 channel-1 channel-2 channel-3`,
    `Replace the notification channels of the specified alert policy.`
  )
  .example(
    `node $0 disable my-project-id "(NOT display_name.empty OR NOT description.empty) AND user_labels='active'"`,
    `Disables policies that match the given filter.`
  )
  .example(
    `node $0 disable my-project-id "description:'cloud'"`,
    `Disables policies that match the given filter.`
  )
  .example(
    `node $0 disable my-project-id "display_name=monitoring.regex.full_match('Temp \\d{4}')"`,
    `Disables policies that match the given filter.`
  )
  .example(
    `node $0 enable my-project-id "(NOT display_name.empty OR NOT description.empty) AND user_labels='active'"`,
    `Enables policies that match the given filter.`
  )
  .example(
    `node $0 enable my-project-id "description:'cloud'"`,
    `Enables policies that match the given filter.`
  )
  .example(
    `node $0 enable my-project-id "display_name=monitoring.regex.full_match('Temp \\d{4}')"`,
    `Enables policies that match the given filter.`
  )
  .wrap(120)
  .recommendCommands()
  .epilogue(
    `For more information, see https://cloud.google.com/monitoring/docs/`
  )
  .help()
  .strict().argv;
<|endoftext|>