<commit_before>/*

Copyright 2013 tadruj

Project home: https://github.com/tadruj/s3upload-coffee-javascript

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.

*/

define([], function() {

  window.S3Upload = (function() {

    S3Upload.prototype.s3_object_name = 'default_name';

    S3Upload.prototype.s3_sign_put_url = '/signS3put';

    S3Upload.prototype.file_dom_selector = 'file_upload';

    S3Upload.prototype.onFinishS3Put = function(public_url) {
      return console.log('base.onFinishS3Put()', public_url);
    };

    S3Upload.prototype.onProgress = function(percent, status) {
      return console.log('base.onProgress()', percent, status);
    };

    S3Upload.prototype.onError = function(status) {
      return console.log('base.onError()', status);
    };

    function S3Upload(options) {
      if (options == null) options = {};
      for (option in options) {
        this[option] = options[option];
      }
      this.handleFileSelect(document.getElementById(this.file_dom_selector));
    }

    S3Upload.prototype.handleFileSelect = function(file_element) {
      var f, files, output, _i, _len, _results;
      this.onProgress(0, 'Upload started.');
      files = file_element.files;
      output = [];
      _results = [];
      for (_i = 0, _len = files.length; _i < _len; _i++) {
        f = files[_i];
        _results.push(this.uploadFile(f));
      }
      return _results;
    };

    S3Upload.prototype.createCORSRequest = function(method, url) {
      var xhr;
      xhr = new XMLHttpRequest();
      if (xhr.withCredentials != null) {
        xhr.open(method, url, true);
      } else if (typeof XDomainRequest !== "undefined") {
        xhr = new XDomainRequest();
        xhr.open(method, url);
      } else {
        xhr = null;
      }
      return xhr;
    };

    S3Upload.prototype.executeOnSignedUrl = function(file, callback) {
      var this_s3upload, xhr;
      this_s3upload = this;
      xhr = new XMLHttpRequest();
      xhr.open('GET', this.s3_sign_put_url + '?s3_object_type=' + file.type + '&s3_object_name=' + this.s3_object_name, true);
      xhr.overrideMimeType('text/plain; charset=x-user-defined');
      xhr.onreadystatechange = function(e) {
        var result;
        if (this.readyState === 4 && this.status === 200) {
          try {
            result = JSON.parse(this.responseText);
          } catch (error) {
            this_s3upload.onError('Signing server returned some ugly/empty JSON: "' + this.responseText + '"');
            return false;
          }
          return callback(decodeURIComponent(result.signed_request), result.url);
        } else if (this.readyState === 4 && this.status !== 200) {
          return this_s3upload.onError('Could not contact request signing server. Status = ' + this.status);
        }
      };
      return xhr.send();
    };

    S3Upload.prototype.uploadToS3 = function(file, url, public_url) {
      var this_s3upload, xhr;
      this_s3upload = this;
      xhr = this.createCORSRequest('PUT', url);
      if (!xhr) {
        this.onError('CORS not supported');
      } else {
        xhr.onload = function() {
          if (xhr.status === 200) {
            this_s3upload.onProgress(100, 'Upload completed.');
            return this_s3upload.onFinishS3Put(public_url);
          } else {
            return this_s3upload.onError('Upload error: ' + xhr.status);
          }
        };
        xhr.onerror = function() {
          return this_s3upload.onError('XHR error.');
        };
        xhr.upload.onprogress = function(e) {
          var percentLoaded;
          if (e.lengthComputable) {
            percentLoaded = Math.round((e.loaded / e.total) * 100);
            return this_s3upload.onProgress(percentLoaded, percentLoaded === 100 ? 'Finalizing.' : 'Uploading.');
          }
        };
      }
      xhr.setRequestHeader('Content-Type', file.type);
      xhr.setRequestHeader('x-amz-acl', 'public-read');
      return xhr.send(file);
    };

    S3Upload.prototype.uploadFile = function(file) {
      var this_s3upload;
      this_s3upload = this;
      return this.executeOnSignedUrl(file, function(signedURL, publicURL) {
        return this_s3upload.uploadToS3(file, signedURL, publicURL);
      });
    };

  })();
  return S3Upload;

})<commit_msg>help uploader<commit_after>/*

Copyright 2013 tadruj

Project home: https://github.com/tadruj/s3upload-coffee-javascript

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.

*/

define([], function() {

  window.S3Upload = (function() {

    S3Upload.prototype.s3_object_name = 'default_name';

    S3Upload.prototype.s3_sign_put_url = '/signS3put';

    S3Upload.prototype.file_dom_selector = 'file_upload';

    S3Upload.prototype.onFinishS3Put = function(public_url) {
      return console.log('base.onFinishS3Put()', public_url);
    };

    S3Upload.prototype.onProgress = function(percent, status) {
      return console.log('base.onProgress()', percent, status);
    };

    S3Upload.prototype.onError = function(status) {
      return console.log('base.onError()', status);
    };

    function S3Upload(options) {
      if (options == null) options = {};
      for (option in options) {
        this[option] = options[option];
      }
      this.handleFileSelect(document.getElementById(this.file_dom_selector));
    }

    S3Upload.prototype.handleFileSelect = function(file_element) {
      var f, files, output, _i, _len, _results;
      this.onProgress(0, 'Upload started.');
      files = file_element.files;
      output = [];
      _results = [];
      for (_i = 0, _len = files.length; _i < _len; _i++) {
        f = files[_i];
        _results.push(this.uploadFile(f));
      }
      return _results;
    };

    S3Upload.prototype.createCORSRequest = function(method, url) {
      var xhr;
      xhr = new XMLHttpRequest();
      if (xhr.withCredentials != null) {
        xhr.open(method, url, true);
      } else if (typeof XDomainRequest !== "undefined") {
        xhr = new XDomainRequest();
        xhr.open(method, url);
      } else {
        xhr = null;
      }
      return xhr;
    };

    S3Upload.prototype.executeOnSignedUrl = function(file, callback) {
      var this_s3upload, xhr;
      this_s3upload = this;
      xhr = new XMLHttpRequest();
      xhr.open('GET', this.s3_sign_put_url + '?s3_object_type=' + file.type + '&s3_object_name=' + this.s3_object_name, true);
      xhr.overrideMimeType('text/plain; charset=x-user-defined');
      xhr.onreadystatechange = function(e) {
        var result;
        if (this.readyState === 4 && this.status === 200) {
          try {
            result = JSON.parse(this.responseText);
          } catch (error) {
            this_s3upload.onError('Signing server returned some ugly/empty JSON: "' + this.responseText + '"');
            return false;
          }
          return callback(decodeURIComponent(result.signed_request), result.url);
        } else if (this.readyState === 4 && this.status !== 200) {
          return this_s3upload.onError('Could not contact request signing server. Status = ' + this.status);
        }
      };
      return xhr.send();
    };

    S3Upload.prototype.uploadToS3 = function(file, url, public_url) {
      var this_s3upload, xhr;
      this_s3upload = this;
      xhr = this.createCORSRequest('PUT', url);
      if (!xhr) {
        this.onError('CORS not supported');
      } else {
        xhr.onload = function() {
          if (xhr.status === 200) {
            this_s3upload.onProgress(100, 'Upload completed.');
            return this_s3upload.onFinishS3Put(public_url);
          } else {
            return this_s3upload.onError('Upload error: ' + xhr.status);
          }
        };
        xhr.onerror = function() {
          return this_s3upload.onError('XHR error.');
        };
        xhr.upload.onprogress = function(e) {
          var percentLoaded;
          if (e.lengthComputable) {
            percentLoaded = Math.round((e.loaded / e.total) * 100);
            return this_s3upload.onProgress(percentLoaded, percentLoaded === 100 ? 'Finalizing.' : 'Uploading.');
          }
        };
      }
      xhr.setRequestHeader('Content-Type', file.type);
      xhr.setRequestHeader('x-amz-acl', 'public-read');
      return xhr.send(file);
    };

    S3Upload.prototype.uploadFile = function(file) {
      var this_s3upload;
      this_s3upload = this;
      return this.executeOnSignedUrl(file, function(signedURL, publicURL) {
        return this_s3upload.uploadToS3(file, signedURL, publicURL);
      });
    };
  });
  return S3Upload;

})<|endoftext|>


<commit_before>// POST /db/{db}/groups/create
// Groups / Create a group
//
// Alpha @ 0.1.37
//
// `202 Accepted`,
// [Delayed](/docs/#/concept/delayed.md).
// sometimes [Idempotent](/docs/#/concept/idempotent.md).
//
// Creates a new group. Initially empty.
//
// ### Request format
//     { "id" : <customid> | null,
//       "label" : <label> | null }
//  - `id` is an optional [custom identifier](/docs/#/types/custom-id.js).
//  - `label` is an optional [human-readable name](/docs/#/types/label.js).
//
// ### Response format
//     { "id" : <id>,
//       "at" : <clock> }

TEST("The response has valid return code and content type.", function(next) {

    var example = { "label" : "Board members" };

    var db = Query.mkdb();
    var token = Query.auth(db);
    var response = Test.query("POST",["db/",db,"/groups/create"],example,token).response();

    [
	Assert.areEqual(202, response.map('status')),
	Assert.isTrue(response.map('responseJSON'), "Response type is JSON")
    ].then(next);

});

//
// The behaviour of the request depends on whether an identifier was provided:
// **force-id** mode or **generate-id** mode.
//
// # Force-id mode
//
// RunOrg will attempt to create a group with that identifier, and do nothing if
// the group already exists ([idempotent](/docs/#/concept/idempotent.md)
// request).
//
// ### Example request
//     POST /db/0SNQc00211H/groups/create
//     Content-Type: application/json
//
//     { "id": "board",
//       "label": "Board members" }
//
// ### Example request
//     202 Accepted
//     Content-Type: application/json
//
//     { "id" : "board",
//       "at" : [[2,218]] }

TEST("Group with forced id appears.", function(next) {

    var id = "board";
    var example = { "id" : id, "label" : "Board members" };

    var db = Query.mkdb();
    var token = Query.auth(db);

    Test.query("POST",["db/",db,"/groups/create"],example,token).response().then(function(){

	var get = Test.query("GET",["db/",db,"/groups/",id,"/info"],token).result();

	[
	    Assert.areEqual({"id":id,"label":"Board members",count:0}, get)
	].then(next);

    });

});

TEST("New group with forced id created after deletion.", function(next) {

    var id = "board";
    var example = { "id" : id, "label" : "Broad members" };

    var db = Query.mkdb();
    var token = Query.auth(db);

    Test.query("POST",["db/",db,"/groups/create"],example,token).response().then(function(){

	Test.query("DELETE",["db/",db,"/groups/",id],token).response().then(function(){

	    example.label = "Board members";

	    Test.query("POST",["db/",db,"/groups/create"],example,token).response().then(function(){

		var get = Test.query("GET",["db/",db,"/groups/",id,"/info"],token).result();

		[
		    Assert.areEqual({"id":id,"label":"Board members",count:0}, get)
		].then(next);
	    });
	});
    });
});

// # Generate-id mode
//
// RunOrg will create brand new group, with a brand new identifier. Running the
// request twice will create two groups.
//
// ### Example request
//     POST /db/0SNQc00211H/groups/create
//     Content-Type: application/json
//
//     { "label": "Members imported on Nov 1, 2013" }
//
// ### Example request
//     202 Accepted
//     Content-Type: application/json
//
//     { "id" : "0SNQe0032JZ",
//       "at" : [[2,219]] }

TEST("Multiple creations create multiple groups.", function(next) {

    var example = { "label" : "Sample group" };

    var db = Query.mkdb();
    var token = Query.auth(db);

    var id1 = Test.query("POST",["db/",db,"/groups/create"],example,token).result("id");
    var id2 = Test.query("POST",["db/",db,"/groups/create"],example,token).result("id");

    var get1 = Test.query("GET",["db/",db,"/groups/",id1,"/info"],token).result();
    var get2 = Test.query("GET",["db/",db,"/groups/",id2,"/info"],token).result();

    [
	Assert.notEqual(id1, id2),
	Assert.areEqual({"id":id1,"label":"Sample group",count:0}, get1),
	Assert.areEqual({"id":id2,"label":"Sample group",count:0}, get2)
    ].then(next);

});

// # Errors
//
// ## Returns `400 Bad Request`
// - ... if the provided identifier is not a valid [custom
//   identifier](/docs/#/types/custom-id.js)

TEST("Returns 400 when custom id is invalid.", function(next) {

    var ex1 = { "id": "a-b", "label" : "Invalid character" };
    var ex2 = { "id": "0123456789a", "label" : "Too long" };

    var db = Query.mkdb();
    var token = Query.auth(db);
    var r1 = Test.query("POST",["db/",db,"/groups/create"],ex1,token).response();
    var r2 = Test.query("POST",["db/",db,"/groups/create"],ex2,token).response();

    [
	Assert.areEqual(400, r1.map('status')),
	Assert.areEqual(400, r2.map('status'))
    ].then(next);

});

// ## Returns `404 Not Found`
// - ... if database `{db}` does not exist

TEST("Returns 404 when database does not exist.", function(next) {
    var response = Test.query("POST",["db/01234567890/groups/create"],{},"00000000000").response();
    Assert.areEqual(404, response.map('status')).then(next);
});

// ## Returns `400 Conflict`
// - ... if a group already exists with the provided identifier.

TEST("Returns 409 when the group exists.", function(next) {

    var id = "board";
    var example = { "id" : id, "label" : "Board members" };

    var db = Query.mkdb();
    var token = Query.auth(db);

    Test.query("POST",["db/",db,"/groups/create"],example,token).response().then(function(){
	var response = Test.query("POST",["db/",db,"/groups/create"],example,token).response();
	Assert.areEqual(409, response.map('status')).then(next);
    });
});

TEST("Returns 409 when re-creating the admin group.", function(next) {

    var id = "admin";
    var example = { "id" : id, "label" : "Board members" };

    var db = Query.mkdb();
    var token = Query.auth(db);

    var response = Test.query("POST",["db/",db,"/groups/create"],example,token).response();
    Assert.areEqual(409, response.map('status')).then(next);
});

// ## Returns `401 Unauthorized`
// - ... if the provided token does not allow group creation,
//   or no token was provided

TEST("Returns 401 when token is not valid.", function(next) {
    Assert.fail();
});

// # Access restrictions
//
// Currently, anyone can create a group with a token for the corresponding database.
// This is subject to change in future versions.
<commit_msg>Token testing<commit_after>// POST /db/{db}/groups/create
// Groups / Create a group
//
// Alpha @ 0.1.37
//
// `202 Accepted`,
// [Delayed](/docs/#/concept/delayed.md).
// sometimes [Idempotent](/docs/#/concept/idempotent.md).
//
// Creates a new group. Initially empty.
//
// ### Request format
//     { "id" : <customid> | null,
//       "label" : <label> | null }
//  - `id` is an optional [custom identifier](/docs/#/types/custom-id.js).
//  - `label` is an optional [human-readable name](/docs/#/types/label.js).
//
// ### Response format
//     { "id" : <id>,
//       "at" : <clock> }

TEST("The response has valid return code and content type.", function(next) {

    var example = { "label" : "Board members" };

    var db = Query.mkdb();
    var token = Query.auth(db);
    var response = Test.query("POST",["db/",db,"/groups/create"],example,token).response();

    [
	Assert.areEqual(202, response.map('status')),
	Assert.isTrue(response.map('responseJSON'), "Response type is JSON")
    ].then(next);

});

//
// The behaviour of the request depends on whether an identifier was provided:
// **force-id** mode or **generate-id** mode.
//
// # Force-id mode
//
// RunOrg will attempt to create a group with that identifier, and do nothing if
// the group already exists ([idempotent](/docs/#/concept/idempotent.md)
// request).
//
// ### Example request
//     POST /db/0SNQc00211H/groups/create
//     Content-Type: application/json
//
//     { "id": "board",
//       "label": "Board members" }
//
// ### Example request
//     202 Accepted
//     Content-Type: application/json
//
//     { "id" : "board",
//       "at" : [[2,218]] }

TEST("Group with forced id appears.", function(next) {

    var id = "board";
    var example = { "id" : id, "label" : "Board members" };

    var db = Query.mkdb();
    var token = Query.auth(db);

    Test.query("POST",["db/",db,"/groups/create"],example,token).response().then(function(){

	var get = Test.query("GET",["db/",db,"/groups/",id,"/info"],token).result();

	[
	    Assert.areEqual({"id":id,"label":"Board members",count:0}, get)
	].then(next);

    });

});

TEST("New group with forced id created after deletion.", function(next) {

    var id = "board";
    var example = { "id" : id, "label" : "Broad members" };

    var db = Query.mkdb();
    var token = Query.auth(db);

    Test.query("POST",["db/",db,"/groups/create"],example,token).response().then(function(){

	Test.query("DELETE",["db/",db,"/groups/",id],token).response().then(function(){

	    example.label = "Board members";

	    Test.query("POST",["db/",db,"/groups/create"],example,token).response().then(function(){

		var get = Test.query("GET",["db/",db,"/groups/",id,"/info"],token).result();

		[
		    Assert.areEqual({"id":id,"label":"Board members",count:0}, get)
		].then(next);
	    });
	});
    });
});

// # Generate-id mode
//
// RunOrg will create brand new group, with a brand new identifier. Running the
// request twice will create two groups.
//
// ### Example request
//     POST /db/0SNQc00211H/groups/create
//     Content-Type: application/json
//
//     { "label": "Members imported on Nov 1, 2013" }
//
// ### Example request
//     202 Accepted
//     Content-Type: application/json
//
//     { "id" : "0SNQe0032JZ",
//       "at" : [[2,219]] }

TEST("Multiple creations create multiple groups.", function(next) {

    var example = { "label" : "Sample group" };

    var db = Query.mkdb();
    var token = Query.auth(db);

    var id1 = Test.query("POST",["db/",db,"/groups/create"],example,token).result("id");
    var id2 = Test.query("POST",["db/",db,"/groups/create"],example,token).result("id");

    var get1 = Test.query("GET",["db/",db,"/groups/",id1,"/info"],token).result();
    var get2 = Test.query("GET",["db/",db,"/groups/",id2,"/info"],token).result();

    [
	Assert.notEqual(id1, id2),
	Assert.areEqual({"id":id1,"label":"Sample group",count:0}, get1),
	Assert.areEqual({"id":id2,"label":"Sample group",count:0}, get2)
    ].then(next);

});

// # Errors
//
// ## Returns `400 Bad Request`
// - ... if the provided identifier is not a valid [custom
//   identifier](/docs/#/types/custom-id.js)

TEST("Returns 400 when custom id is invalid.", function(next) {

    var ex1 = { "id": "a-b", "label" : "Invalid character" };
    var ex2 = { "id": "0123456789a", "label" : "Too long" };

    var db = Query.mkdb();
    var token = Query.auth(db);
    var r1 = Test.query("POST",["db/",db,"/groups/create"],ex1,token).response();
    var r2 = Test.query("POST",["db/",db,"/groups/create"],ex2,token).response();

    [
	Assert.areEqual(400, r1.map('status')),
	Assert.areEqual(400, r2.map('status'))
    ].then(next);

});

// ## Returns `404 Not Found`
// - ... if database `{db}` does not exist

TEST("Returns 404 when database does not exist.", function(next) {
    var response = Test.query("POST",["db/01234567890/groups/create"],{},"00000000000").response();
    Assert.areEqual(404, response.map('status')).then(next);
});

// ## Returns `400 Conflict`
// - ... if a group already exists with the provided identifier.

TEST("Returns 409 when the group exists.", function(next) {

    var id = "board";
    var example = { "id" : id, "label" : "Board members" };

    var db = Query.mkdb();
    var token = Query.auth(db);

    Test.query("POST",["db/",db,"/groups/create"],example,token).response().then(function(){
	var response = Test.query("POST",["db/",db,"/groups/create"],example,token).response();
	Assert.areEqual(409, response.map('status')).then(next);
    });
});

TEST("Returns 409 when re-creating the admin group.", function(next) {

    var id = "admin";
    var example = { "id" : id, "label" : "Board members" };

    var db = Query.mkdb();
    var token = Query.auth(db);

    var response = Test.query("POST",["db/",db,"/groups/create"],example,token).response();
    Assert.areEqual(409, response.map('status')).then(next);
});

// ## Returns `401 Unauthorized`
// - ... if the provided token does not allow group creation,
//   or no token was provided

TEST("Returns 401 when token is not valid.", function(next) {
    var db = Query.mkdb();
    Test.query("POST",["db/",db,"/groups/create"],{}).error(401).then(function() {
	Test.query("POST",["db/",db,"/groups/create"],{},"0123456789a").error(401).then(next);
    });
});

// # Access restrictions
//
// Currently, anyone can create a group with a token for the corresponding database.
// This is subject to change in future versions.
<|endoftext|>


<commit_before>const selectors = require('../../../../selectors')

describe('Collection', () => {
  describe('company', () => {
    before(() => {
      cy.visit('/companies')
    })

    it('should return the results summary for a company collection', () => {
      verifyCollection()
    })
  })

  describe('contact', () => {
    before(() => {
      cy.visit('/contacts')
    })

    it('should return the results summary for a contact collection', () => {
      verifyCollection()
    })
  })

  context('investment', () => {
    describe('projects', () => {
      before(() => {
        cy.visit('/investments/projects')
      })

      it('should return the results summary for a contact collection', () => {
        verifyCollection()
      })
    })

    describe('interaction', () => {
      before(() => {
        cy.visit('/investments/projects/ba1f0b14-5fe4-4c36-bf6a-ddf115272977/interactions')
      })

      it('should return the results summary for a contact collection', () => {
        verifyCollection()
      })
    })

    describe('proposition', () => {
      before(() => {
        cy.visit('/investments/projects/ba1f0b14-5fe4-4c36-bf6a-ddf115272977/propositions')
      })

      it('should return the results summary for a contact collection', () => {
        verifyCollection()
      })
    })

    describe('proposition', () => {
      before(() => {
        cy.visit('/investments/projects/ba1f0b14-5fe4-4c36-bf6a-ddf115272977/team')
      })

      it('should return the results summary for a contact collection', () => {
        cy.get(selectors.companyInvestmentProjects.investmentTeamGrid)
          .should('contain', 'Client Relationship Manager')
          .and('contain', 'Marketing - Marketing Team')
          .and('contain', 'Paula Churing')
      })
    })
  })
})

const verifyCollection = () => {
  cy.get(selectors.collection.headerCount).invoke('text').then((headerCount) => {
    cy.get(selectors.collection.items).should((collectionItems) => {
      expect(headerCount).to.eq(collectionItems.length.toString())
    })
  })
}
<commit_msg>Fix PR comment<commit_after>const selectors = require('../../../../selectors')

const verifyCollection = () => {
  cy.get(selectors.collection.headerCount).invoke('text').then((headerCount) => {
    cy.get(selectors.collection.items).should((collectionItems) => {
      expect(headerCount).to.eq(collectionItems.length.toString())
    })
  })
}

describe('Collection', () => {
  describe('company', () => {
    before(() => {
      cy.visit('/companies')
    })

    it('should return the results summary for a company collection', () => {
      verifyCollection()
    })
  })

  describe('contact', () => {
    before(() => {
      cy.visit('/contacts')
    })

    it('should return the results summary for a contact collection', () => {
      verifyCollection()
    })
  })

  context('investment', () => {
    describe('projects', () => {
      before(() => {
        cy.visit('/investments/projects')
      })

      it('should return the results summary for a contact collection', () => {
        verifyCollection()
      })
    })

    describe('interaction', () => {
      before(() => {
        cy.visit('/investments/projects/ba1f0b14-5fe4-4c36-bf6a-ddf115272977/interactions')
      })

      it('should return the results summary for a contact collection', () => {
        verifyCollection()
      })
    })

    describe('proposition', () => {
      before(() => {
        cy.visit('/investments/projects/ba1f0b14-5fe4-4c36-bf6a-ddf115272977/propositions')
      })

      it('should return the results summary for a contact collection', () => {
        verifyCollection()
      })
    })

    describe('proposition', () => {
      before(() => {
        cy.visit('/investments/projects/ba1f0b14-5fe4-4c36-bf6a-ddf115272977/team')
      })

      it('should return the results summary for a contact collection', () => {
        cy.get(selectors.companyInvestmentProjects.investmentTeamGrid)
          .should('contain', 'Client Relationship Manager')
          .and('contain', 'Marketing - Marketing Team')
          .and('contain', 'Paula Churing')
      })
    })
  })
})
<|endoftext|>


<commit_before>import React from 'react'
import MemberFields from '../../../shared/dumb_components/member_fields.js'
import { reduxForm } from 'redux-form'
import { validate, fieldStructure, required, removed, read_only_user }
  from '../../../shared/form_fields/member.js'
import buttons from '../my_details/buttons.js'

import { reject, contains, concat, __ } from 'ramda'

export default ({ toggle_member_mode, mode, update_member_user, active_tab, ...props }) =>
  <ViewMember
    {...props}
    fields={filter_fields(removed)(field_mapper[active_tab])}
    Buttons={buttons}
    button_props={
      { edit_member_click: toggle_member_mode
      , cancel_member_click: toggle_member_mode
      , mode
      }
    }
    mode={mode}
    onSubmit={update_member_user}
    required={required}
    read_only={read_only_user}
  />

const ViewMember = reduxForm(
  { form: 'user'
  , validate
  , fields: []
  }
  )(MemberFields)

const filter_fields = to_be_removed => reject(contains(__, to_be_removed))

const field_mapper =
  { contact_details: concat(fieldStructure.address, fieldStructure.personal)
  , membership_details: concat(['id'], fieldStructure.membership)
  , account_details: concat(['id'], fieldStructure.edit)
  }
<commit_msg>Delete unuse account_details.js<commit_after><|endoftext|>


<commit_before>/**
 * Grab-bag of utility functions.
 * @flow
 */
'use strict';

import type {InflatedBlock} from './types';
import type * as Q from 'q';

var pako = require('pako');

// Compare two tuples of equal length. Is t1 <= t2?
// TODO: make this tupleLessOrEqual<T> -- it works with strings or booleans, too.
function tupleLessOrEqual(t1: Array<number>, t2: Array<number>): boolean {
  if (t1.length != t2.length) throw new Error('Comparing non-equal length tuples');
  for (var i = 0; i < t1.length; i++) {
    if (t1[i] > t2[i]) {
      return false;
    } else if (t1[i] < t2[i]) {
      return true;
    }
  }
  return true;
}

// Do two ranges of tuples overlap?
// TODO: make this tupleRangeOverlaps<T> -- it works with strings or booleans, too.
function tupleRangeOverlaps(tupleRange1: Array<Array<number>>,
                            tupleRange2: Array<Array<number>>): boolean {
  return (
     // Are the ranges overlapping?
     tupleLessOrEqual(tupleRange1[0], tupleRange2[1]) &&
     tupleLessOrEqual(tupleRange2[0], tupleRange1[1]) &&
     // ... and non-empty?
     tupleLessOrEqual(tupleRange1[0], tupleRange1[1]) &&
     tupleLessOrEqual(tupleRange2[0], tupleRange2[1]));
}

// Return a new ArrayBuffer by concatenating an array of ArrayBuffers.
function concatArrayBuffers(buffers: ArrayBuffer[]): ArrayBuffer {
  var totalBytes = buffers.map(b => b.byteLength).reduce((a, b) => a + b, 0);
  var output = new Uint8Array(totalBytes);
  var position = 0;
  buffers.forEach(buf => {
    output.set(new Uint8Array(buf), position);
    position += buf.byteLength;
  });
  return output.buffer;
}

type InflateCacheKey = {
  filename: string;
  initialOffset: number;
}

type PakoResult = {
  err: number;
  msg: string;
  buffer: ?ArrayBuffer;
  total_in: number;
}
var inflationCache: {[key: string]: PakoResult} = {};

// extracted for caching
function _inflateOne(buffer, position): PakoResult {
  var inflator = new pako.Inflate();
  inflator.push(buffer.slice(position));
  return {
    err: inflator.err,
    msg: inflator.msg,
    buffer: inflator.result ? inflator.result.buffer : null,
    total_in: inflator.strm.total_in
  };
}

function cachedInflateOne(buffer, position, cache?: InflateCacheKey) {
  if (!cache) {
    return _inflateOne(buffer, position);
  }
  var cacheKey = cache.filename + ':' + (cache.initialOffset + position);
  var v = inflationCache[cacheKey];
  if (v && (position + v.total_in > buffer.byteLength)) {
    // It should fail.
    return _inflateOne(buffer, position);
  }

  if (!v) {
    v = _inflateOne(buffer, position);
  }
  if (!v.err && v.buffer) {
    inflationCache[cacheKey] = v;
  }
  return v;
}

/**
 * BAM files are written in "BGZF" format, which consists of many concatenated
 * gzip blocks. gunzip concatenates all the inflated blocks, but pako only
 * inflates one block at a time. This wrapper makes pako behave like gunzip.
 * If specified, lastBlockStart will stop inflation before all the blocks
 * have been processed.
 */
function inflateConcatenatedGzip(buffer: ArrayBuffer,
                                 lastBlockStart?: number,
                                 cache?: InflateCacheKey): InflatedBlock[] {
  var position = 0,
      blocks = [];
  if (lastBlockStart === undefined) {
    lastBlockStart = buffer.byteLength;
  }
  do {
    var result = cachedInflateOne(buffer, position, cache);

    if (result.err) {
      throw 'Gzip error: ' + result.msg;
    }
    if (result.buffer) {
      blocks.push({
        offset: position,
        compressedLength: result.total_in,
        buffer: result.buffer
      });
    }
    position += result.total_in;
  } while (position <= lastBlockStart && position < buffer.byteLength);
  return blocks;
}

/**
 * Inflate one or more gzip blocks in the buffer.
 * Returns the concatenation of all inflated blocks.
 * This mirrors the behavior of gzip(1).
 */
function inflateGzip(buffer: ArrayBuffer): ArrayBuffer {
  return concatArrayBuffers(inflateConcatenatedGzip(buffer).map(x => x.buffer));
}

/**
 * Generate a space-separated css class name for a base pair.
 */
function basePairClass(basePair: ?string): string {
  if (!basePair) return 'basepair';
  return 'basepair ' + basePair;
}

// Given 'chr9', return '9'. Given '9', return 'chr9'.
function altContigName(contig: string): string {
  if (contig.slice(0, 3) == 'chr') {
    return contig.slice(3);
  } else {
    return 'chr' + contig;
  }
}

/**
 * Pipe all promise events through a deferred object.
 * This is similar to deferred.resolve(promise), except that it allows progress
 * notifications from the promise to bubble through.
 */
function pipePromise<T>(deferred: Q.Deferred<T>, promise: Q.Promise<T>) {
  promise.then(function(o) {
    deferred.resolve(o);
  }, function(e) {
    deferred.reject(e);
  }, function(e) {
    deferred.notify(e);
  });
}

module.exports = {
  tupleLessOrEqual,
  tupleRangeOverlaps,
  concatArrayBuffers,
  inflateConcatenatedGzip,
  inflateGzip,
  basePairClass,
  altContigName,
  pipePromise
};
<commit_msg>simplify logic<commit_after>/**
 * Grab-bag of utility functions.
 * @flow
 */
'use strict';

import type {InflatedBlock} from './types';
import type * as Q from 'q';

var pako = require('pako');

// Compare two tuples of equal length. Is t1 <= t2?
// TODO: make this tupleLessOrEqual<T> -- it works with strings or booleans, too.
function tupleLessOrEqual(t1: Array<number>, t2: Array<number>): boolean {
  if (t1.length != t2.length) throw new Error('Comparing non-equal length tuples');
  for (var i = 0; i < t1.length; i++) {
    if (t1[i] > t2[i]) {
      return false;
    } else if (t1[i] < t2[i]) {
      return true;
    }
  }
  return true;
}

// Do two ranges of tuples overlap?
// TODO: make this tupleRangeOverlaps<T> -- it works with strings or booleans, too.
function tupleRangeOverlaps(tupleRange1: Array<Array<number>>,
                            tupleRange2: Array<Array<number>>): boolean {
  return (
     // Are the ranges overlapping?
     tupleLessOrEqual(tupleRange1[0], tupleRange2[1]) &&
     tupleLessOrEqual(tupleRange2[0], tupleRange1[1]) &&
     // ... and non-empty?
     tupleLessOrEqual(tupleRange1[0], tupleRange1[1]) &&
     tupleLessOrEqual(tupleRange2[0], tupleRange2[1]));
}

// Return a new ArrayBuffer by concatenating an array of ArrayBuffers.
function concatArrayBuffers(buffers: ArrayBuffer[]): ArrayBuffer {
  var totalBytes = buffers.map(b => b.byteLength).reduce((a, b) => a + b, 0);
  var output = new Uint8Array(totalBytes);
  var position = 0;
  buffers.forEach(buf => {
    output.set(new Uint8Array(buf), position);
    position += buf.byteLength;
  });
  return output.buffer;
}

type InflateCacheKey = {
  filename: string;
  initialOffset: number;
}

type PakoResult = {
  err: number;
  msg: string;
  buffer: ?ArrayBuffer;
  total_in: number;
}
var inflationCache: {[key: string]: PakoResult} = {};

// extracted for caching
function _inflateOne(buffer, position): PakoResult {
  var inflator = new pako.Inflate();
  inflator.push(buffer.slice(position));
  return {
    err: inflator.err,
    msg: inflator.msg,
    buffer: inflator.result ? inflator.result.buffer : null,
    total_in: inflator.strm.total_in
  };
}

function cachedInflateOne(buffer, position, cache?: InflateCacheKey) {
  if (!cache) {
    return _inflateOne(buffer, position);
  }
  var cacheKey = cache.filename + ':' + (cache.initialOffset + position);
  var v = inflationCache[cacheKey];
  if (v && (position + v.total_in > buffer.byteLength)) {
    // It should fail.
    return _inflateOne(buffer, position);
  }

  if (!v) {
    v = _inflateOne(buffer, position);
  }
  if (!v.err && v.buffer) {
    inflationCache[cacheKey] = v;
  }
  return v;
}

/**
 * BAM files are written in "BGZF" format, which consists of many concatenated
 * gzip blocks. gunzip concatenates all the inflated blocks, but pako only
 * inflates one block at a time. This wrapper makes pako behave like gunzip.
 * If specified, lastBlockStart will stop inflation before all the blocks
 * have been processed.
 */
function inflateConcatenatedGzip(buffer: ArrayBuffer,
                                 lastBlockStart?: number,
                                 cache?: InflateCacheKey): InflatedBlock[] {
  var position = 0,
      blocks = [];
  if (lastBlockStart === undefined) {
    lastBlockStart = buffer.byteLength;
  }
  do {
    var result = cachedInflateOne(buffer, position, cache);

    if (result.err) {
      throw 'Gzip error: ' + result.msg;
    }
    if (result.buffer) {
      blocks.push({
        offset: position,
        compressedLength: result.total_in,
        buffer: result.buffer
      });
    }
    position += result.total_in;
  } while (position <= lastBlockStart && position < buffer.byteLength);
  return blocks;
}

/**
 * Inflate one or more gzip blocks in the buffer.
 * Returns the concatenation of all inflated blocks.
 * This mirrors the behavior of gzip(1).
 */
function inflateGzip(buffer: ArrayBuffer): ArrayBuffer {
  return concatArrayBuffers(inflateConcatenatedGzip(buffer).map(x => x.buffer));
}

/**
 * Generate a space-separated css class name for a base pair.
 */
function basePairClass(basePair: ?string): string {
  if (!basePair) return 'basepair';
  return 'basepair ' + basePair;
}

// Given 'chr9', return '9'. Given '9', return 'chr9'.
function altContigName(contig: string): string {
  if (contig.slice(0, 3) == 'chr') {
    return contig.slice(3);
  } else {
    return 'chr' + contig;
  }
}

/**
 * Pipe all promise events through a deferred object.
 * This is similar to deferred.resolve(promise), except that it allows progress
 * notifications from the promise to bubble through.
 */
function pipePromise<T>(deferred: Q.Deferred<T>, promise: Q.Promise<T>) {
  promise.then(deferred.resolve, deferred.reject, deferred.notify);
}

module.exports = {
  tupleLessOrEqual,
  tupleRangeOverlaps,
  concatArrayBuffers,
  inflateConcatenatedGzip,
  inflateGzip,
  basePairClass,
  altContigName,
  pipePromise
};
<|endoftext|>


<commit_before>import { expect } from 'chai';
import { Given, When, Then } from 'cucumber';

import * as libpayments from '../../../../server/lib/payments';
import * as libtransactions from '../../../../server/lib/transactions';
import * as store from '../stores';
import * as utils from '../../../utils';

/** Helper for interpreting fee description
 *
 * The fee can be expressed as an absolute value, like "50" which
 * means $50.00 (the value will be multiplied by 100 to account for
 * the cents).
 *
 * The fee can also be expressed as a percentage of the value. In that
 * case it looks like "5%". That's why this helper takes the amount
 * parameter so the absolute value of the fee can be calculated.
 *
 * @param {Number} amount is the total amount of the expense. Used to
 *  calculate the absolute value of fees expressed as percentages.
 * @param {String} feeStr is the data read from the `.features` test
 *  file. That can be expressed as an absolute value or as a
 *  percentage.
 */
const readFee = (amount, feeStr) => {
  if (!feeStr) {
    return 0;
  } else if (feeStr.endsWith('%')) {
    const asFloat = parseFloat(feeStr.replace('%', ''));
    return asFloat > 0 ? libpayments.calcFee(amount, asFloat) : asFloat;
  } else {
    /* The `* 100` is for converting from cents */
    return parseFloat(feeStr) * 100;
  }
};

Given('a User {string}', async function (name) {
  const { user, userCollective } = await store.newUser(name);
  this.addValue(name, userCollective);
  this.addValue(`${name}-user`, user);
});

Given('a Host {string} in {string} and charges {string} of fee', async function (name, currency, fee) {
  const { hostCollective, hostAdmin } = await store.newHost(name, currency, fee);
  this.addValue(name, hostCollective);
  this.addValue(`${name}-admin`, hostAdmin);
});

Given('a Collective {string} in {string} hosted by {string}', async function (name, currency, hostName) {
  const hostCollective = this.getValue(hostName);
  const hostAdmin = this.getValue(`${hostName}-admin`);
  const { collective } = await store.newCollectiveInHost(name, currency, hostCollective);
  this.addValue(name, collective);
  this.addValue(`${name}-host-collective`, hostCollective);
  this.addValue(`${name}-host-admin`, hostAdmin);
});

When('{string} expenses {string} for {string} to {string} via {string}', async function (userName, value, description, collectiveName, payoutMethod) {
  const [ amount, currency ] = value.split(' ');
  const user = this.getValue(`${userName}-user`);
  const collective = this.getValue(collectiveName);
  const expense = {
    amount,
    currency,
    description,
    payoutMethod: payoutMethod.toLowerCase(),
    collective: { id: collective.id },
  };
  const query =
    `mutation createExpense($expense: ExpenseInputType!) {
      createExpense(expense: $expense) { id, status } }`;
  const result = await utils.graphqlQuery(
    query, { expense }, user);
  expect(result.errors).to.not.exist;
  this.addValue(`expense-${description}`, result.data.createExpense);
});

When('expense for {string} is approved by {string}', async function(description, collectiveName) {
  const hostAdmin = this.getValue(`${collectiveName}-host-admin`);
  const expense = this.getValue(`expense-${description}`);
  const query = `mutation approveExpense($id: Int!) { approveExpense(id: $id) { id } }`;
  const result = await utils.graphqlQuery(query, expense, hostAdmin);
  expect(result.errors).to.not.exist;
});

When('expense for {string} is paid by {string} with {string} fee', async function(description, collectiveName, fee) {
  const hostAdmin = this.getValue(`${collectiveName}-host-admin`);
  const query = `mutation payExpense($id: Int!, $fee: Int!) { payExpense(id: $id, fee: $fee) { id } }`;
  const expense = this.getValue(`expense-${description}`);
  const parameters = { id: expense.id, fee: readFee(expense.totalAmount, fee) };
  const result = await utils.graphqlQuery(query, parameters, hostAdmin);
  result.errors && console.log(result.errors);
  expect(result.errors).to.not.exist;
});

Then('{string} should have contributed {string} to {string}', async function(userName, value, collectiveName) {
  const [ amount, currency ] = value.split(' ');
  const userCollective = this.getValue(userName);
  const collective = this.getValue(collectiveName);
  /* Doesn't ever sum up different currencies */
  const userToCollectiveAmount = await libtransactions.sum({
    FromCollectiveId: userCollective.id,
    CollectiveId: collective.id,
    currency,
    type: 'CREDIT',
  });
  expect(userToCollectiveAmount).to.equal(parseInt(amount));
});

Then('{string} should have {string} in their balance', async function(collectiveName, value) {
  const [ amount, currency ] = value.split(' ');
  const collective = this.getValue(collectiveName);
  /* Doesn't ever sum up different currencies */
  const userToCollectiveAmount = await libtransactions.sum({
    FromCollectiveId: collective.id,
    CollectiveId: collective.id,
    currency,
  });
  expect(userToCollectiveAmount).to.equal(parseInt(amount));
});
<commit_msg>chore(tests): Add new BDD steps for connected account & orders<commit_after>import { expect } from 'chai';
import { Given, When, Then } from 'cucumber';

import * as libpayments from '../../../../server/lib/payments';
import * as libtransactions from '../../../../server/lib/transactions';
import * as store from '../stores';
import * as utils from '../../../utils';

/** Helper for interpreting fee description
 *
 * The fee can be expressed as an absolute value, like "50" which
 * means $50.00 (the value will be multiplied by 100 to account for
 * the cents).
 *
 * The fee can also be expressed as a percentage of the value. In that
 * case it looks like "5%". That's why this helper takes the amount
 * parameter so the absolute value of the fee can be calculated.
 *
 * @param {Number} amount is the total amount of the expense. Used to
 *  calculate the absolute value of fees expressed as percentages.
 * @param {String} feeStr is the data read from the `.features` test
 *  file. That can be expressed as an absolute value or as a
 *  percentage.
 */
const readFee = (amount, feeStr) => {
  if (!feeStr) {
    return 0;
  } else if (feeStr.endsWith('%')) {
    const asFloat = parseFloat(feeStr.replace('%', ''));
    return asFloat > 0 ? libpayments.calcFee(amount, asFloat) : asFloat;
  } else {
    /* The `* 100` is for converting from cents */
    return parseFloat(feeStr) * 100;
  }
};

Given('a User {string}', async function (name) {
  const { user, userCollective } = await store.newUser(name);
  this.addValue(name, userCollective);
  this.addValue(`${name}-user`, user);
});

Given('a Host {string} in {string} and charges {string} of fee', async function (name, currency, fee) {
  const { hostCollective, hostAdmin } = await store.newHost(name, currency, fee);
  this.addValue(name, hostCollective);
  this.addValue(`${name}-admin`, hostAdmin);
});

Given('a Collective {string} in {string} hosted by {string}', async function (name, currency, hostName) {
  const hostCollective = this.getValue(hostName);
  const hostAdmin = this.getValue(`${hostName}-admin`);
  const { collective } = await store.newCollectiveInHost(name, currency, hostCollective);
  this.addValue(name, collective);
  this.addValue(`${name}-host-collective`, hostCollective);
  this.addValue(`${name}-host-admin`, hostAdmin);
});

Given('{string} connects a {string} account', async function (hostName, connectedAccountName) {
  const host = this.getValue(hostName);
  const hostAdmin = this.getValue(`${hostName}-admin`);
  const method = {
    stripe: store.stripeConnectedAccount,
  }[connectedAccountName.toLowerCase()];
  await method(host.id, hostAdmin.id);
});

Given('{string} payment processor fee is {string}', async function (ppName, feeStr) {
  this.addValue(`${ppName.toLowerCase()}-payment-provider-fee`, feeStr);
});

Given('platform fee is {string}', async function (feeStr) {
  this.addValue(`platform-fee`, feeStr);
});

When('{string} donates {string} to {string} via {string}', async function (fromName, value, toName, paymentMethod) {
  const [ amountStr, currency ] = value.split(' ');
  const amount = parseInt(amountStr);
  const userCollective = this.getValue(fromName);
  const collective = this.getValue(toName);
  /* Retrieve fees that may or may not have been set */
  const paymentMethodName = paymentMethod.toLowerCase();
  const ppFee = readFee(amount, this.getValue(`${paymentMethodName}-payment-provider-fee`));
  const appFee = readFee(amount, this.getValue('platform-fee'));
  /* We currently only have these available payment methods */
  const method = {
    stripe: store.stripeOneTimeDonation,
  }[paymentMethodName]
  await method({ userCollective, collective, currency, amount, appFee, ppFee });
});

When('{string} expenses {string} for {string} to {string} via {string}', async function (userName, value, description, collectiveName, payoutMethod) {
  const [ amount, currency ] = value.split(' ');
  const user = this.getValue(`${userName}-user`);
  const collective = this.getValue(collectiveName);
  const expense = {
    amount,
    currency,
    description,
    payoutMethod: payoutMethod.toLowerCase(),
    collective: { id: collective.id },
  };
  const query =
    `mutation createExpense($expense: ExpenseInputType!) {
      createExpense(expense: $expense) { id, status } }`;
  const result = await utils.graphqlQuery(
    query, { expense }, user);
  expect(result.errors).to.not.exist;
  this.addValue(`expense-${description}`, result.data.createExpense);
});

When('expense for {string} is approved by {string}', async function(description, collectiveName) {
  const hostAdmin = this.getValue(`${collectiveName}-host-admin`);
  const expense = this.getValue(`expense-${description}`);
  const query = `mutation approveExpense($id: Int!) { approveExpense(id: $id) { id } }`;
  const result = await utils.graphqlQuery(query, expense, hostAdmin);
  expect(result.errors).to.not.exist;
});

When('expense for {string} is paid by {string} with {string} fee', async function(description, collectiveName, fee) {
  const hostAdmin = this.getValue(`${collectiveName}-host-admin`);
  const query = `mutation payExpense($id: Int!, $fee: Int!) { payExpense(id: $id, fee: $fee) { id } }`;
  const expense = this.getValue(`expense-${description}`);
  const parameters = { id: expense.id, fee: readFee(expense.totalAmount, fee) };
  const result = await utils.graphqlQuery(query, parameters, hostAdmin);
  result.errors && console.log(result.errors);
  expect(result.errors).to.not.exist;
});

Then('{string} should have contributed {string} to {string}', async function(userName, value, collectiveName) {
  const [ amount, currency ] = value.split(' ');
  const userCollective = this.getValue(userName);
  const collective = this.getValue(collectiveName);
  /* Doesn't ever sum up different currencies */
  const userToCollectiveAmount = await libtransactions.sum({
    FromCollectiveId: userCollective.id,
    CollectiveId: collective.id,
    currency,
    type: 'CREDIT',
  });
  expect(userToCollectiveAmount).to.equal(parseInt(amount));
});

Then('{string} should have {string} in their balance', async function(collectiveName, value) {
  const [ amount, currency ] = value.split(' ');
  const collective = this.getValue(collectiveName);
  /* Doesn't ever sum up different currencies */
  const userToCollectiveAmount = await libtransactions.sum({
    CollectiveId: collective.id,
    currency,
  });
  expect(userToCollectiveAmount).to.equal(parseInt(amount));
});
<|endoftext|>


<commit_before>const binary = require('binary');
const encodings = require('encodings');
const asserts = require('test').asserts;

// Test data.
const e_accute_utf8 = binary.ByteString([0xC3,0xA9]);
const partial_utf8 = binary.ByteString([0x,68,0xC3]);
const invalid_utf8 = binary.ByteString([0x,68,0xC3,0x6C]);

const e_accute_utf16 = binary.ByteString([0x0,0xe9]);
const partial_utf16 = binary.ByteString([0x,68,0xC3]);
const invalid_utf16 = binary.ByteString([0x,68,0xC3,0x6C]);

const ligature_oe_iso8859_15 = binary.ByteString([0xBD]);

if (!this.exports) this.exports = {};

exports.test_convertSameEnc = function() {
  var blob = encodings.convert("utf-8", "utf-8", e_accute_utf8);

  asserts.ok(blob !== e_accute_utf8, "different blob returned");
  asserts.same(blob.toArray(), [195,169]);

}

exports.test_convertToString = function() {
  var str = encodings.convertToString("utf-8", e_accute_utf8);

  asserts.same(str, "\xE9")
}

exports.test_convertToStringUTF16 = function() {
  var str = encodings.convertToString("utf-16", e_accute_utf16);

  asserts.same(str, "\xE9") // é
}

exports.test_convertToStringISO8859_15 = function() {
  var str = encodings.convertToString("iso-8859-15", ligature_oe_iso8859_15);

  asserts.same(str, "\u0153"); //œ
}

exports.test_convert = function() {
  var blob = encodings.convert("utf-8", "UTF-16", e_accute_utf8);

  asserts.same(blob.toArray(), [254,255,0,233]);
}

// if (module.isMain)
  require('test').runner(exports);
<commit_msg>test/encoding: Add Transcoder tests using Shift_JIS and ISO-2022-JP<commit_after>const binary = require('binary');
const encodings = require('encodings');
const asserts = require('test').asserts;

// Test data.
const e_accute_utf8 = binary.ByteString([0xC3,0xA9]),
      partial_utf8 = binary.ByteString([0x,68,0xC3]),
      invalid_utf8 = binary.ByteString([0x,68,0xC3,0x6C]),

      e_accute_utf16 = binary.ByteString([0x0,0xe9]),
      partial_utf16 = binary.ByteString([0x,68,0xC3]),
      invalid_utf16 = binary.ByteString([0x,68,0xC3,0x6C]),

      ligature_oe_iso8859_15 = binary.ByteString([0xBD]),

      katakana_shift_jis = binary.ByteString([0x83,0x65,0x83,0x58,0x83,0x67]),
      katakana_iso2022 = binary.ByteString([0x1b,0x24,0x42,0x25,0x46,0x25,0x39,0x25,0x48,0x1b,0x28,0x42]),
      katakana_string = "\u30c6\u30b9\u30c8";

if (!this.exports) this.exports = {};

exports.test_convertSameEnc = function() {
  var blob = encodings.convert("utf-8", "utf-8", e_accute_utf8);

  asserts.instanceOf(blob, binary.Binary);
  asserts.ok(blob !== e_accute_utf8, "different blob returned");
  asserts.same(blob.toArray(), [195,169]);

}

exports.test_convertToString = function() {
  var str = encodings.convertToString("utf-8", e_accute_utf8);

  asserts.same(str, "\xE9")
}

exports.test_convertToStringUTF16 = function() {
  var str = encodings.convertToString("utf-16", e_accute_utf16);

  asserts.same(str, "\xE9") // é
}

exports.test_convertToStringISO8859_15 = function() {
  var str = encodings.convertToString("iso-8859-15", ligature_oe_iso8859_15);

  asserts.same(str, "\u0153"); //œ
}

exports.test_convert = function() {
  var blob = encodings.convert("utf-8", "UTF-16", e_accute_utf8);

  asserts.instanceOf(blob, binary.Binary);
  asserts.same(blob.toArray(), [254,255,0,233]);
}

exports.test_katakanaTranscoder_OneShot = function() {
  var c = new encodings.Transcoder("ISO-2022-JP", "Shift_JIS")

  asserts.instanceOf(c, encodings.Transcoder);

  asserts.same(
    c.pushAccumulate(katakana_iso2022),
    undefined,
    "transcoder.pushAccumulate(blob) returns undefined"
  );

  var blob = c.close();
  asserts.instanceOf(blob, binary.ByteString);

  asserts.same(
    blob.toArray(),
    katakana_shift_jis.toArray(),
    "Correct Shift_JIS output"
  );

  asserts.same(
    encodings.convertToString("Shift_JIS", blob),
    katakana_string,
    "Correct unicode string"
  );
}

exports.test_katakanaTranscoder_Chunks = function() {
  var c = new encodings.Transcoder("Shift_JIS", "ISO-2022-JP")
  var a = new binary.ByteArray();

  const iso2022 = katakana_iso2022.toArray();

  asserts.instanceOf(c, encodings.Transcoder);

  // Each 2 bytes of the Shift_JIS (when non-ascii) = 1 unicode character.

  // Send first two bytes
  asserts.same(
    c.push(katakana_shift_jis.substr(0,2), a),
    a
  );

  // Check we get the conversion seq + first code point
  asserts.same(
    a.toArray(),
    iso2022.slice(0,5), //[0x1b,0x24,0x42,0x25,0x46]
    "correct ISO-2022-JP opening"
  );

  // Rest of the data
  a = c.push(katakana_shift_jis.slice(2)),

  asserts.same(
    a.toArray(),
    [0x1b,0x24,0x42,0x25,0x46,100,100],
    "ISO-2022-JP->ascii not yet sent"
  );
}

// if (module.isMain)
  require('test').runner(exports);
<|endoftext|>


<commit_before>gw2traits = function() {
	//Class variables
	var m_Traits			= {};
	var m_MapCount 			= {};
	var m_MapLevels			= {};
	var m_Acquisitions		= {};
	var m_MaxLevel			= 80;
	var m_TooltipHandler	= function(){};

	//Constants
	var TRAIT_MAP 			= "map";
	var TRAIT_NUMBER		= "number";
	var TRAIT_UNLOCK		= "unlocked";
	var TRAIT_ACQUISITION	= "acquisition";
	var COOKIE_START 		= "cookie=";
	var ELEMENT_TRAIT_ID 	= "trait_";

	//Initialize stuff
	var initialize = function(tooltip) {
		//Save callback
		m_TooltipHandler = tooltip;

		//Initialize
		Parse.initialize("SDiJ7OLjISzQIt2RTOgQOTlCh8Nj0xPHwm17Isq2", "mkJfAEKHWnCkUgFT7a2Z7Btf0PGoUdBZzMbtqLTd");
		loadCookies();
	};

	//Load traits from database
	var loadTraits = function() {
		//Query all traits
		var TraitObject = Parse.Object.extend("Trait");
		var TraitQuery	= new Parse.Query(TraitObject);
		TraitQuery.ascending("createdAt");
		TraitQuery.include("map");
		TraitQuery.find({
			success: function(traits) {
				//Initialize
				var Tier 		= 0;
				var Column		= 0;
				var TraitList 	= "";
				var TierCounts	= [ 6, 10, 13 ];

				//For each result
				for (var i = 0; i < traits.length; i++) {
					//Check tier
					if (Column >= TierCounts[Tier]) {
						//Increase tier
						Tier++;
						if (Tier >= TierCounts.length) {
							//Reset
							Tier 	= 0;
							Column	= 0;
						}
					}

					//Initialize trait data
					var ID = traits[i].id;
					if (m_Traits[ID] == null) m_Traits[ID] = {};

					//Save data
					console.log("line " + traits[i].get("line") + " number " + traits[i].get("number"));
					m_Traits[ID][TRAIT_NUMBER]		= traits[i].get("number");
					m_Traits[ID][TRAIT_ACQUISITION] = traits[i].get(TRAIT_ACQUISITION).id;
					if (m_Traits[ID][TRAIT_UNLOCK] == null) m_Traits[ID][TRAIT_UNLOCK] = false;

					//Get map
					var Map = traits[i].get("map");
					if (Map != null) {
						//Save
						var MapName 			= Map.get("name");
						m_MapLevels[MapName]	= Map.get("minLevel");
						m_Traits[ID][TRAIT_MAP] = MapName;

						//Extend string
						//TraitList += " at " + MapName;
					}

					//If opener
					if (Column == 0) TraitList += '
';
					if (Column == 0 || Column == TierCounts[0] || Column == TierCounts[1]) TraitList += '
';

					//Set div
					var Content	= m_Traits[ID][TRAIT_UNLOCK] ? " " : "";
		  			TraitList += '
' + Content + '
';

					//Next column
					Column++;

					//if closer
					if (Column == TierCounts[0] || Column == TierCounts[1] || Column == TierCounts[2]) TraitList += '
';
					if (Column == TierCounts[2]) TraitList += '
';
				}

				//Write stuff
				document.getElementById('trait-panel').insertAdjacentHTML("beforeend", TraitList);
				if (m_TooltipHandler != null) m_TooltipHandler();
				refreshMaps();
			}
		});
	}

	//Load acquisition types from database
	var loadAcquisitionTypes = function() {
		//Query all acquisition
		var AcquisitionObject 	= Parse.Object.extend("Acquisition");
		var AcquisitionQuery	= new Parse.Query(AcquisitionObject);
		AcquisitionQuery.find({
			success: function(acquisitions) {
				//Initialize
				var FilterText = "";

				//For each type
				for (var i = 0; i < acquisitions.length; i++) {
					//Get ID
					var ID 	= acquisitions[i].id;
					if (m_Acquisitions[ID] == null) m_Acquisitions[ID]	= true;

					//Opens
					if (i % 3 == 0) FilterText += '
';

					//Set text
					FilterText += '<input type="checkbox" onclick="gw2traits.handleAcquisitionClick(this)"';
					if (m_Acquisitions[ID]) FilterText += ' checked="checked"';
					FilterText += ' id=acquisition-check_"' + ID + '" value="' + ID + '"> ' + acquisitions[i].get("name") + '
';

					//Close
					if (i % 3 == 2) FilterText += '
';
				}

				//Write
				document.getElementById('type-config').insertAdjacentHTML("beforeend", FilterText);
			}
		});
	}

	var loadCookies = function() {
		//Get cookie
		var RawCookie = document.cookie;
		if (RawCookie != null && RawCookie.length > 0) {
			//Get json text
			var RawJSON = RawCookie.substr(COOKIE_START.length);
			if (RawJSON != null && RawJSON.length > 0) {
				//Create object
				var Cookie = JSON.parse(decodeURI(RawJSON));

				//Get trait
				if (Cookie.traits != null) {
					//For each trait
					for (var i = 0; i < Cookie.traits.length; i++) {
						//Set
						if (m_Traits[Cookie.traits[i]] == null) m_Traits[Cookie.traits[i]] = {};
						m_Traits[Cookie.traits[i]][TRAIT_UNLOCK] = true;
					}
				}

				//Get acquisition filter
				if (Cookie.acquisitions != null) {
					//For each acquisition type
					for (var i = 0; i < Cookie.acquisitions.length; i++) m_Acquisitions[Cookie.acquisitions[i]] = false;
				}

				//Get max level
				if (Cookie.max_level != null) m_MaxLevel = Cookie.max_level;
				document.getElementById("level-filter").value = m_MaxLevel;
			}
		}
	}

	var saveCookies = function() {
		//Initialize object
		var Cookie = {
			traits: [],
			acquisitions: [],
			max_level: m_MaxLevel
		};

		//Populate
		for (var ID in m_Acquisitions) 	if (!m_Acquisitions[ID]) Cookie.acquisitions.push(ID);
		for (var Trait in m_Traits)		if (m_Traits[Trait][TRAIT_UNLOCK]) Cookie.traits.push(Trait);

		//Write
		var JSONText = encodeURI(JSON.stringify(Cookie));
		document.cookie = COOKIE_START + JSONText + "; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/";
	}

	var getTraitStyle = function(id) {
		//Initialize
		var Style = "";

		//If there's ID
		if (id != null) {
			//If trait exist
			var Trait = m_Traits[id];
			if (Trait != null) Style = "background-image: url(images/trait-" + Trait[TRAIT_NUMBER] + "-" + (Trait[TRAIT_UNLOCK] ? "unlocked" : "locked") + ".png);";
		}

		//Return
		return Style;
	}

	//Set trait unlocking status
	var setTraitUnlock = function(id, unlocked) {
		//Skip if no ID
		if (id == null) return;

		//Initialize
		var Trait 		= m_Traits[id];
		var Unlocked 	= Boolean(unlocked);
		var Changed		= false;

		//If trait exist
		if (Trait != null) {
			//Check old value
			var WasUnlocked = Trait[TRAIT_UNLOCK];
			if (WasUnlocked != Unlocked) {
				//Set data
				Changed				= true;
				Trait[TRAIT_UNLOCK] = Unlocked;

				//Get element
				var Element = document.getElementById(ELEMENT_TRAIT_ID + id);
				if (Element != null) {
					//Refresh element
					Element.innerHTML = Trait[TRAIT_UNLOCK] ? " " : "";
					Element.setAttribute("style", getTraitStyle(id));
				}
			}
		}

		//Return
		return Changed;
	}

	//Set all trait unlocking status
	var setAllTraitsUnlock = function(unlocked) {
		//For all traits
		var Changed = false;
		for (var ID in m_Traits) if (setTraitUnlock(ID, unlocked)) Changed = true;

		//If there's a change
		if (Changed) {
			//Do stuff
			saveCookies();
			refreshMaps();
		}
	}

	//Refresh map
	var refreshMaps = function() {
		//Recount
		countMaps();

		//Sort and display
		var Maps = sortMaps();
		displayMaps(Maps);
	}

	//Calculate map count
	var countMaps = function() {
		//Reset map counts
		for (var Name in m_MapCount) m_MapCount[Name] = 0;

		//For all traits
		for (var Trait in m_Traits) {
			//Validate map and trait
			var Map 	= m_Traits[Trait][TRAIT_MAP];
			var Valid	= Map != null;
			if (Valid) Valid = !m_Traits[Trait][TRAIT_UNLOCK];

			//If still valid
			if (Valid) {
				//Validate minimum level
				Valid = m_MapLevels[Map] == null;
				if (!Valid) Valid = m_MapLevels[Map] <= m_MaxLevel;
			}

			//If still valid
			if (Valid) {
				//Validate acquisition type
				Valid = m_Acquisitions[m_Traits[Trait][TRAIT_ACQUISITION]];
				if (Valid == null) Valid = true;
			}

			//If valid
			if (Valid) {
				//Add to count
				if (m_MapCount[Map] == null) 	m_MapCount[Map] = 1;
				else 							m_MapCount[Map]++;
			}
		}
	}

	//Sort maps from map count
	var sortMaps = function() {
		//For each map
		var Sorted = [];
		for (var Name in m_MapCount) {
			//If not sorted yet, just insert it
			if (Sorted.length <= 0) Sorted[0] = Name;
			else {
				//Find index to be inserted
				Index = -1;
				for (var i = 0; i < Sorted.length && Index < 0; i++) if (m_MapCount[Name] >= m_MapCount[Sorted[i]]) Index = i;
				if (Index < 0) Index = Sorted.length;

				//Insert at index
				Sorted.splice(Index, 0, Name);
			}
		}

		//Return sorted map
		return Sorted;
	}

	//Display maps
	var displayMaps = function(maps) {
		//Skip if no map
		if (maps == null) return;

		//For each map
		var MapList = "";
		for (var i = 0; i < maps.length; i++) {
			//Get data
			var MapName = maps[i];
			var Count 	= m_MapCount[MapName];
			if (Count != null && Count > 0) {
				//Extend string
				MapList += '<li class="map-item' + (i < 3 ? (i + 1) : '') + '">' + MapName + " (" + Count + " trait" + (Count > 1 ? 's' : '') + ")
";
			}
		}

		//Write
		document.getElementById('map-ul').innerHTML = MapList;
	}

	//Trait checkbox click
	var handleTraitClick = function(element) {
		//Skip if no element
		if (element == null) return;

		//Get data
		var ID 		= element.id.substr(ELEMENT_TRAIT_ID.length);
		var Value 	= element.innerHTML.length > 0;

		//Set unlocking
		if (setTraitUnlock(ID, !Value)) {
			//Do stuff
			saveCookies();
			refreshMaps();
		}
	}

	//Filter checkbox click
	var handleAcquisitionClick = function(element) {
		//Skip if no element
		if (element == null) return;

		//Change data
		m_Acquisitions[element.value] = element.checked;
		saveCookies();

		//Refresh
		refreshMaps();
	}

	//Level dropdown click
	var handleLevelChange = function(element) {
		//Skip if no element
		if (element == null) return;

		//Get level
		m_MaxLevel = parseInt(element.value);
		saveCookies();

		//Refresh
		refreshMaps();
	}

	//Return public members
	return {
		initialize: initialize,
		loadTraits: loadTraits,
		loadAcquisitionTypes: loadAcquisitionTypes,
		handleAcquisitionClick: handleAcquisitionClick,
		setAllTraitsUnlock: setAllTraitsUnlock,
		handleLevelChange: handleLevelChange,
		handleTraitClick: handleTraitClick
	};
}();
<commit_msg>Optimized script.<commit_after>/*jshint eqnull:true */

gw2traits = function() {
	//Class variables
	var m_Traits			= {};
	var m_MapCount			= {};
	var m_MapLevels			= {};
	var m_Acquisitions		= {};
	var m_MaxLevel			= 80;
	var m_TooltipHandler	= function(){};

	//Constants
	var TRAIT_MAP			= "map";
	var TRAIT_NUMBER		= "number";
	var TRAIT_UNLOCK		= "unlocked";
	var TRAIT_ACQUISITION	= "acquisition";
	var COOKIE_START		= "cookie=";
	var ELEMENT_TRAIT_ID	= "trait_";

	//Initialize stuff
	var initialize = function(tooltip) {
		//Save callback
		m_TooltipHandler = tooltip;

		//Initialize
		Parse.initialize("SDiJ7OLjISzQIt2RTOgQOTlCh8Nj0xPHwm17Isq2", "mkJfAEKHWnCkUgFT7a2Z7Btf0PGoUdBZzMbtqLTd");
		loadCookies();
	};

	//Load traits from database
	var loadTraits = function() {
		//Query all traits
		var TraitObject = Parse.Object.extend("Trait");
		var TraitQuery	= new Parse.Query(TraitObject);
		TraitQuery.ascending("createdAt");
		TraitQuery.include("map");
		TraitQuery.include("acquisition");
		TraitQuery.find({
			success: function(traits) {
				//Initialize
				var Tier		= 0;
				var Column		= 0;
				var TraitList	= "";
				var TierCounts	= [ 6, 10, 13 ];

				//For each result
				for (var i = 0; i < traits.length; i++) {
					//Check tier
					if (Column >= TierCounts[Tier]) {
						//Increase tier
						Tier++;
						if (Tier >= TierCounts.length) {
							//Reset
							Tier	= 0;
							Column	= 0;
						}
					}

					//Initialize trait data
					var ID = traits[i].id;
					if (m_Traits[ID] == null) m_Traits[ID] = {};

					//Save data
					m_Traits[ID][TRAIT_NUMBER]		= traits[i].get("number");
					m_Traits[ID][TRAIT_ACQUISITION] = traits[i].get(TRAIT_ACQUISITION).id;
					if (m_Traits[ID][TRAIT_UNLOCK] == null) m_Traits[ID][TRAIT_UNLOCK] = false;

					//Get map
					var Map = traits[i].get("map");
					if (Map != null) {
						//Save
						var MapName				= Map.get("name");
						m_MapLevels[MapName]	= Map.get("minLevel");
						m_Traits[ID][TRAIT_MAP] = MapName;

						//Extend string
						//TraitList += " at " + MapName;
					}

					//If opener
					if (Column === 0) TraitList += '
';
					if (Column === 0 || Column === TierCounts[0] || Column === TierCounts[1]) TraitList += '
';

					//Set div
					var Content	= m_Traits[ID][TRAIT_UNLOCK] ? " " : "";
					TraitList += '
' + Content + '
';

					//Next column
					Column++;

					//if closer
					if (Column === TierCounts[0] || Column === TierCounts[1] || Column === TierCounts[2]) TraitList += '
';
					if (Column === TierCounts[2]) TraitList += '
';
				}

				//Write stuff
				document.getElementById('trait-panel').insertAdjacentHTML("beforeend", TraitList);
				if (m_TooltipHandler != null) m_TooltipHandler();
				refreshMaps();
			}
		});
	};

	//Load acquisition types from database
	var loadAcquisitionTypes = function() {
		//Query all acquisition
		var AcquisitionObject	= Parse.Object.extend("Acquisition");
		var AcquisitionQuery	= new Parse.Query(AcquisitionObject);
		AcquisitionQuery.find({
			success: function(acquisitions) {
				//Initialize
				var FilterText = "";

				//For each type
				for (var i = 0; i < acquisitions.length; i++) {
					//Get ID
					var ID = acquisitions[i].id;
					if (m_Acquisitions[ID] == null) m_Acquisitions[ID] = true;

					//Opens
					if (i % 3 === 0) FilterText += '
';

					//Set text
					FilterText += '<input type="checkbox" onclick="gw2traits.handleAcquisitionClick(this)"';
					if (m_Acquisitions[ID]) FilterText += ' checked="checked"';
					FilterText += ' id=acquisition-check_"' + ID + '" value="' + ID + '"> ' + acquisitions[i].get("name") + '
';

					//Close
					if (i % 3 === 2) FilterText += '
';
				}

				//Write
				document.getElementById('type-config').insertAdjacentHTML("beforeend", FilterText);
			}
		});
	};

	var loadCookies = function() {
		//Get cookie
		var RawCookie = document.cookie;
		if (RawCookie != null && RawCookie.length > 0) {
			//Get json text
			var RawJSON = RawCookie.substr(COOKIE_START.length);
			if (RawJSON != null && RawJSON.length > 0) {
				//Create object
				var Cookie = JSON.parse(decodeURI(RawJSON));

				//Get trait
				var i = 0;
				if (Cookie.traits != null) {
					//For each trait
					for (i = 0; i < Cookie.traits.length; i++) {
						//Set
						if (m_Traits[Cookie.traits[i]] == null) m_Traits[Cookie.traits[i]] = {};
						m_Traits[Cookie.traits[i]][TRAIT_UNLOCK] = true;
					}
				}

				//Get acquisition filter
				if (Cookie.acquisitions != null) {
					//For each acquisition type
					for (i = 0; i < Cookie.acquisitions.length; i++) m_Acquisitions[Cookie.acquisitions[i]] = false;
				}

				//Get max level
				if (Cookie.max_level != null) m_MaxLevel = Cookie.max_level;
				document.getElementById("level-filter").value = m_MaxLevel;
			}
		}
	};

	var saveCookies = function() {
		//Initialize object
		var Cookie = {
			traits: [],
			acquisitions: [],
			max_level: m_MaxLevel
		};

		//Populate
		for (var ID in m_Acquisitions)	if (!m_Acquisitions[ID]) Cookie.acquisitions.push(ID);
		for (var Trait in m_Traits)		if (m_Traits[Trait][TRAIT_UNLOCK]) Cookie.traits.push(Trait);

		//Write
		var JSONText = encodeURI(JSON.stringify(Cookie));
		document.cookie = COOKIE_START + JSONText + "; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/";
	};

	var getTraitStyle = function(id) {
		//Initialize
		var Style = "";

		//If there's ID
		if (id != null) {
			//If trait exist
			var Trait = m_Traits[id];
			if (Trait != null) Style = "background-image: url(images/trait-" + Trait[TRAIT_NUMBER] + "-" + (Trait[TRAIT_UNLOCK] ? "unlocked" : "locked") + ".png);";
		}

		//Return
		return Style;
	};

	//Set trait unlocking status
	var setTraitUnlock = function(id, unlocked) {
		//Skip if no ID
		if (id == null) return;

		//Initialize
		var Trait		= m_Traits[id];
		var Unlocked	= Boolean(unlocked);
		var Changed		= false;

		//If trait exist
		if (Trait != null) {
			//Check old value
			var WasUnlocked = Trait[TRAIT_UNLOCK];
			if (WasUnlocked != Unlocked) {
				//Set data
				Changed				= true;
				Trait[TRAIT_UNLOCK] = Unlocked;

				//Get element
				var Element = document.getElementById(ELEMENT_TRAIT_ID + id);
				if (Element != null) {
					//Refresh element
					Element.innerHTML = Trait[TRAIT_UNLOCK] ? " " : "";
					Element.setAttribute("style", getTraitStyle(id));
				}
			}
		}

		//Return
		return Changed;
	};

	//Set all trait unlocking status
	var setAllTraitsUnlock = function(unlocked) {
		//For all traits
		var Changed = false;
		for (var ID in m_Traits) if (setTraitUnlock(ID, unlocked)) Changed = true;

		//If there's a change
		if (Changed) {
			//Do stuff
			saveCookies();
			refreshMaps();
		}
	};

	//Refresh map
	var refreshMaps = function() {
		//Recount
		countMaps();

		//Sort and display
		var Maps = sortMaps();
		displayMaps(Maps);
	};

	//Calculate map count
	var countMaps = function() {
		//Reset map counts
		for (var Name in m_MapCount) m_MapCount[Name] = 0;

		//For all traits
		for (var Trait in m_Traits) {
			//Validate map and trait
			var Map		= m_Traits[Trait][TRAIT_MAP];
			var Valid	= Map != null;
			if (Valid) Valid = !m_Traits[Trait][TRAIT_UNLOCK];

			//If still valid
			if (Valid) {
				//Validate minimum level
				Valid = m_MapLevels[Map] == null;
				if (!Valid) Valid = m_MapLevels[Map] <= m_MaxLevel;
			}

			//If still valid
			if (Valid) {
				//Validate acquisition type
				Valid = m_Acquisitions[m_Traits[Trait][TRAIT_ACQUISITION]];
				if (Valid == null) Valid = true;
			}

			//If valid
			if (Valid) {
				//Add to count
				if (m_MapCount[Map] == null)	m_MapCount[Map] = 1;
				else							m_MapCount[Map]++;
			}
		}
	};

	//Sort maps from map count
	var sortMaps = function() {
		//For each map
		var Sorted = [];
		for (var Name in m_MapCount) {
			//If not sorted yet, just insert it
			if (Sorted.length <= 0) Sorted[0] = Name;
			else {
				//Find index to be inserted
				Index = -1;
				for (var i = 0; i < Sorted.length && Index < 0; i++) if (m_MapCount[Name] >= m_MapCount[Sorted[i]]) Index = i;
				if (Index < 0) Index = Sorted.length;

				//Insert at index
				Sorted.splice(Index, 0, Name);
			}
		}

		//Return sorted map
		return Sorted;
	};

	//Display maps
	var displayMaps = function(maps) {
		//Skip if no map
		if (maps == null) return;

		//For each map
		var MapList = "";
		for (var i = 0; i < maps.length; i++) {
			//Get data
			var MapName = maps[i];
			var Count	= m_MapCount[MapName];
			if (Count != null && Count > 0) {
				//Extend string
				MapList += '<li class="map-item' + (i < 3 ? (i + 1) : '') + '">' + MapName + " (" + Count + " trait" + (Count > 1 ? 's' : '') + ")
";
			}
		}

		//Write
		document.getElementById('map-ul').innerHTML = MapList;
	};

	//Trait checkbox click
	var handleTraitClick = function(element) {
		//Skip if no element
		if (element == null) return;

		//Get data
		var ID		= element.id.substr(ELEMENT_TRAIT_ID.length);
		var Value	= element.innerHTML.length > 0;

		//Set unlocking
		if (setTraitUnlock(ID, !Value)) {
			//Do stuff
			saveCookies();
			refreshMaps();
		}
	};

	//Filter checkbox click
	var handleAcquisitionClick = function(element) {
		//Skip if no element
		if (element == null) return;

		//Change data
		m_Acquisitions[element.value] = element.checked;
		saveCookies();

		//Refresh
		refreshMaps();
	};

	//Level dropdown click
	var handleLevelChange = function(element) {
		//Skip if no element
		if (element == null) return;

		//Get level
		m_MaxLevel = parseInt(element.value, 10);
		saveCookies();

		//Refresh
		refreshMaps();
	};

	//Return public members
	return {
		initialize: initialize,
		loadTraits: loadTraits,
		loadAcquisitionTypes: loadAcquisitionTypes,
		handleAcquisitionClick: handleAcquisitionClick,
		setAllTraitsUnlock: setAllTraitsUnlock,
		handleLevelChange: handleLevelChange,
		handleTraitClick: handleTraitClick
	};
}();
<|endoftext|>


<commit_before>var gulp = require('gulp'),
  chai = require('chai'),
  expect = chai.expect,
  fs = require('fs'),
  multiline = require('multiline'),
  kssSplitter = require('../lib/modules/kss-splitter');

describe('KSS splitter', function() {

  describe('Splitter module', function() {
    it('Split 2 blocks of singleline comments', function(){
      var str = multiline(function() {
        /*
// Comment1
// Comment1

// Comment2
// Comment2
        */
      }),
        result = [
        { type: 'comment', content: '// Comment1\n// Comment1' },
        { type: 'code', content: '\n\n' },
        { type: 'comment', content: '// Comment2\n// Comment2' }
      ],
        split = kssSplitter.pureSplitter(str);

      expect(split).eql(result);

    });
  });

  describe('Singleline comment declarations', function() {
    it('should parse single KSS block', function() {
      var str = multiline(function() {
        /*
// Comment
// Styleguide 1.0

.a { b: c }
        */
      }),
      result = [
        {
          'kss': '// Comment\n// Styleguide 1.0',
          'code': '\n\n.a { b: c }'
        }
      ],
      kssBlocks = kssSplitter.getBlocks(str);
      expect(kssBlocks).eql(result);
    });
  });

  it('should be agnostic to spaces in reference declaration', function(){
    var str = multiline(function() {
      /*
// Comment
//Styleguide 1.0

.a { b: c }
      */
    }),
    result = [
      {
        'kss': '// Comment\n//Styleguide 1.0 ',
        'code': '\n\n.a { b: c }'
      }
    ],
    kssBlocks = kssSplitter.getBlocks(str);
    expect(kssBlocks).eql(result);
  });

  it('should take multiline code', function(){
    var str = multiline(function() {
      /*
// Comment
//Styleguide 1.0

.a { b: c }
$a: b;

.x { y: z }
      */
    }),
    result = [
      {
        'kss': '// Comment\n//Styleguide 1.0 ',
        'code': '\n\n.a { b: c }\n$a: b;\n\n.x { y: z }'
      }
    ],
    kssBlocks = kssSplitter.getBlocks(str);
    expect(kssBlocks).eql(result);
  });

  it('should allow code blocks to have comments', function(){
    var str = multiline(function() {
      /*
// Comment
//Styleguide 1.0

.a { b: c }

// Simple comment

.x { y: z }
      */
    }),
    result = [
      {
        'kss': '// Comment\n//Styleguide 1.0 ',
        'code': '\n\n.a { b: c }\n\n// Simple comment\n\n.x { y: z }'
      }
    ],
    kssBlocks = kssSplitter.getBlocks(str);
    expect(kssBlocks).eql(result);
  });

  it('should parse several blocks', function(){
    var str = multiline(function() {
      /*
// Comment1
// Styleguide 1.0

.a { b: c }

// Comment2
// Styleguide 2.0

.x { y: z }
      */
    }),
    result = [
      {
        'kss': '// Comment1\n// Styleguide 1.0',
        'code': '\n\n.a { b: c }\n\n'
      },
      {
        'kss': '// Comment2\n// Styleguide 2.0',
        'code': '\n\n.x { y: z }'
      }
    ],
    kssBlocks = kssSplitter.getBlocks(str);
    expect(kssBlocks).eql(result);
  });

  it('should allow blocks with no code', function(){
    var str = multiline(function() {
      /*
// Comment1
// Styleguide 1.0

.a { b: c }

// Comment2
// Styleguide 2.0

// Comment3
// Styleguide 3.0

.x { y: z }
      */
    }),
    result = [
      {
        'kss': '// Comment1\n// Styleguide 1.0',
        'code': '\n\n.a { b: c }\n\n'
      },
      {
        'kss': '// Comment2\n// Styleguide 2.0',
        'code': '\n\n'
      },
      {
        'kss': '// Comment3\n// Styleguide 3.0',
        'code': '\n\n.x { y: z }'
      }
    ],
    kssBlocks = kssSplitter.getBlocks(str);
    expect(kssBlocks).eql(result);
  });

  it('should take any reference number', function(){
    var str = multiline(function() {
      /*
// Comment
// Styleguide 1

.a { b: c }

// Comment
// Styleguide 1.1

// Comment
// Styleguide 5.1.2.6
      */
    }),
    result = [
      {
        'kss': '// Comment\n// Styleguide 1',
        'code': '\n\n.a { b: c }\n\n'
      },
      {
        'kss': '// Comment\n// Styleguide 1.1',
        'code': '\n\n'
      },
      {
        'kss': '// Comment\n// Styleguide 5.1.2.6',
        'code': ''
      }
    ],
    kssBlocks = kssSplitter.getBlocks(str);
    expect(kssBlocks).eql(result);
  });

  it('should take code before first KSS block', function() {
    var str = multiline(function() {
      /*
.x { y: x }

// Comment
// Styleguide 1.0

.a { b: c }
      */
    }),
    result = [
      {
        kss: '',
        code: '.x { y: x }\n\n'
      },
      {
        'kss': '// Comment\n// Styleguide 1.0',
        'code': '\n\n.a { b: c }'
      }
    ],
    kssBlocks = kssSplitter.getBlocks(str);
    expect(kssBlocks).eql(result);
  });

  it('should parse single KSS block in multiline comments', function() {
    var str = '' +
'/* Comment\n' +
'Styleguide 1.0\n' +
'*/\n' +
'\n' +
'.a { b: c }',
    result = [
      {
        'kss': '/* Comment\nStyleguide 1.0\n*/',
        'code': '\n\n.a { b: c }'
      }
    ],
    kssBlocks = kssSplitter.getBlocks(str);
    expect(kssBlocks).eql(result);
  });

  it('should parse multiline KSS with no ending linebreak', function() {
    var str = '' +
'/* Comment\n' +
'Styleguide 1.0    */' +
'\n' +
'.a { b: c }',
    result = [
      {
        'kss': '/* Comment\nStyleguide 1.0    */',
        'code': '\n.a { b: c }'
      }
    ],
    kssBlocks = kssSplitter.getBlocks(str);
    expect(kssBlocks).eql(result);
  });
  it('should parse multiline KSS with string prefixes', function() {
    var str = '' +
'/* Comment\n' +
' * Styleguide 1.0\n' +
'*/' +
'\n' +
'.a { b: c }',
    result = [
      {
        'kss': '/* Comment\n * Styleguide 1.0\n*/',
        'code': '\n.a { b: c }'
      }
    ],
    kssBlocks = kssSplitter.getBlocks(str);
    expect(kssBlocks).eql(result);
  });

  it('should allow code blocks to have multiline comments', function(){
    var str = multiline(function() {
      /*
// Comment
//Styleguide 1.0

.a { b: c }
      */}) +
'\n\n/* Simple comment */\n\n' +
multiline(function() {
    /*
.x { y: z }
      */
    }),
    result = [
      {
        'kss': '// Comment\n//Styleguide 1.0 ',
        'code': '\n\n.a { b: c }\n\n/* Simple comment */\n\n.x { y: z }'
      }
    ],
    kssBlocks = kssSplitter.getBlocks(str);
    expect(kssBlocks).eql(result);
  });

  it('should parse several KSS blocks with multiline comments', function(){
    var str = '/*\n' +
'Comment1\n' +
'Styleguide 1.0\n' +
'*/\n' +
'.a { b: c }\n' +
'\n' +
'/*\n' +
'Comment2\n' +
'Styleguide 2.0\n' +
'*/'
    '',
    result = [
      {
        'kss': '/*\nComment1\nStyleguide 1.0\n*/',
        'code': '\n.a { b: c }\n\n'
      },
      {
        'kss': '/*\nComment2\nStyleguide 2.0\n*/',
        'code': ''
      }
    ],
    kssBlocks = kssSplitter.getBlocks(str);
    expect(kssBlocks).eql(result);
  });

  /* TODO: Parser does not work with code after 2nd code block */

  it('should return array of blocks', function() {
    var str = multiline(function() {
      /*
@import "test";
// Comment
// Styleguide 1.0

.a { b: c }

// Comment
// Styleguide 2

// Comment
// Styleguide 2.0

.a { b: c }

      */
    }),
    result = [
      {
        kss: '',
        code: '@import "test";\n'
      },
      {
        kss: '// Comment\n// Styleguide 1.0',
        code: '\n\n.a { b: c }\n\n'
      },
      {
        kss: '// Comment\n// Styleguide 2',
        code: '\n\n'
      },
      {
        kss: '// Comment\n// Styleguide 2.0',
        code: '\n\n\n.a { b: c }'
      }
    ],
    kssBlocks = kssSplitter.getBlocks(str);
    expect(kssBlocks).eql(result);
  });

  describe('tricky CSS content', function() {

    it('should swallow content property with multiline comment', function() {
      var str = multiline(function() {
        /*
// Comment
// Styleguide 1.0

a:before { content: "/* ..." }

// Comment
// Styleguide 2

        */
      }),
      result = [
        {
          kss: '// Comment\n// Styleguide 1.0',
          code: '\n\na:before { content: "/* ..." }\n\n'
        },
        {
          kss: '// Comment\n// Styleguide 2',
          code: ''
        }
      ],
      kssBlocks = kssSplitter.getBlocks(str);
      expect(kssBlocks).eql(result);
    });

    it('should swallow content property with singleline comment', function() {
      var str = multiline(function() {
        /*
a:before { content: "// Comment inside content" }

// Comment
// Styleguide 2
        */
      }),
      result = [
        {
          kss: '',
          code: 'a:before { content: "// Comment inside content" }\n\n'
        },
        {
          kss: '// Comment\n// Styleguide 2',
          code: ''
        }
      ],
      kssBlocks = kssSplitter.getBlocks(str);
      expect(kssBlocks).eql(result);
    });
  });

});
<commit_msg>Tests for single line blocks of code in one place<commit_after>var gulp = require('gulp'),
  chai = require('chai'),
  expect = chai.expect,
  fs = require('fs'),
  multiline = require('multiline'),
  kssSplitter = require('../lib/modules/kss-splitter');

describe('KSS splitter', function() {

  describe('Splitter module', function() {
    it('Split 2 blocks of singleline comments', function(){
      var str = multiline(function() {
        /*
// Comment1
// Comment1

// Comment2
// Comment2
        */
      }),
        result = [
        { type: 'comment', content: '// Comment1\n// Comment1' },
        { type: 'code', content: '\n\n' },
        { type: 'comment', content: '// Comment2\n// Comment2' }
      ],
        split = kssSplitter.pureSplitter(str);

      expect(split).eql(result);

    });
  });

  describe('Singleline comment declarations', function() {
    it('should parse single KSS block', function() {
      var str = multiline(function() {
        /*
// Comment
// Styleguide 1.0

.a { b: c }
        */
      }),
      result = [
        {
          'kss': '// Comment\n// Styleguide 1.0',
          'code': '\n\n.a { b: c }'
        }
      ],
      kssBlocks = kssSplitter.getBlocks(str);
      expect(kssBlocks).eql(result);
    });

    it('should be agnostic to spaces in reference declaration', function(){
      var str = multiline(function() {
        /*
// Comment
//Styleguide 1.0

.a { b: c }
        */
      }),
      result = [
        {
          'kss': '// Comment\n//Styleguide 1.0 ',
          'code': '\n\n.a { b: c }'
        }
      ],
      kssBlocks = kssSplitter.getBlocks(str);
      expect(kssBlocks).eql(result);
    });

    it('should take multiline code', function(){
      var str = multiline(function() {
        /*
// Comment
//Styleguide 1.0

.a { b: c }
$a: b;

.x { y: z }
        */
      }),
      result = [
        {
          'kss': '// Comment\n//Styleguide 1.0 ',
          'code': '\n\n.a { b: c }\n$a: b;\n\n.x { y: z }'
        }
      ],
      kssBlocks = kssSplitter.getBlocks(str);
      expect(kssBlocks).eql(result);
    });

    it('should allow code blocks to have not KSS comments', function(){
      var str = multiline(function() {
        /*
// Comment
//Styleguide 1.0

.a { b: c }

// Simple comment

.x { y: z }
        */
      }),
      result = [
        {
          'kss': '// Comment\n//Styleguide 1.0 ',
          'code': '\n\n.a { b: c }\n\n// Simple comment\n\n.x { y: z }'
        }
      ],
      kssBlocks = kssSplitter.getBlocks(str);
      expect(kssBlocks).eql(result);
    });

    it('should parse several blocks', function(){
      var str = multiline(function() {
        /*
// Comment1
// Styleguide 1.0

.a { b: c }

// Comment2
// Styleguide 2.0

.x { y: z }
        */
      }),
      result = [
        {
          'kss': '// Comment1\n// Styleguide 1.0',
          'code': '\n\n.a { b: c }\n\n'
        },
        {
          'kss': '// Comment2\n// Styleguide 2.0',
          'code': '\n\n.x { y: z }'
        }
      ],
      kssBlocks = kssSplitter.getBlocks(str);
      expect(kssBlocks).eql(result);
    });

    it('should allow blocks with no code', function(){
      var str = multiline(function() {
        /*
// Comment1
// Styleguide 1.0

.a { b: c }

// Comment2
// Styleguide 2.0

// Comment3
// Styleguide 3.0

.x { y: z }
        */
      }),
      result = [
        {
          'kss': '// Comment1\n// Styleguide 1.0',
          'code': '\n\n.a { b: c }\n\n'
        },
        {
          'kss': '// Comment2\n// Styleguide 2.0',
          'code': '\n\n'
        },
        {
          'kss': '// Comment3\n// Styleguide 3.0',
          'code': '\n\n.x { y: z }'
        }
      ],
      kssBlocks = kssSplitter.getBlocks(str);
      expect(kssBlocks).eql(result);
    });

    it('should take any reference number', function(){
      var str = multiline(function() {
        /*
// Comment
// Styleguide 1

.a { b: c }

// Comment
// Styleguide 1.1

// Comment
// Styleguide 5.1.2.6
        */
      }),
      result = [
        {
          'kss': '// Comment\n// Styleguide 1',
          'code': '\n\n.a { b: c }\n\n'
        },
        {
          'kss': '// Comment\n// Styleguide 1.1',
          'code': '\n\n'
        },
        {
          'kss': '// Comment\n// Styleguide 5.1.2.6',
          'code': ''
        }
      ],
      kssBlocks = kssSplitter.getBlocks(str);
      expect(kssBlocks).eql(result);
    });

    it('should take code before first KSS block', function() {
      var str = multiline(function() {
        /*
.x { y: x }

// Comment
// Styleguide 1.0

.a { b: c }
        */
      }),
      result = [
        {
          kss: '',
          code: '.x { y: x }\n\n'
        },
        {
          'kss': '// Comment\n// Styleguide 1.0',
          'code': '\n\n.a { b: c }'
        }
      ],
      kssBlocks = kssSplitter.getBlocks(str);
      expect(kssBlocks).eql(result);
    });

  });

  it('should parse single KSS block in multiline comments', function() {
    var str = '' +
'/* Comment\n' +
'Styleguide 1.0\n' +
'*/\n' +
'\n' +
'.a { b: c }',
    result = [
      {
        'kss': '/* Comment\nStyleguide 1.0\n*/',
        'code': '\n\n.a { b: c }'
      }
    ],
    kssBlocks = kssSplitter.getBlocks(str);
    expect(kssBlocks).eql(result);
  });

  it('should parse multiline KSS with no ending linebreak', function() {
    var str = '' +
'/* Comment\n' +
'Styleguide 1.0    */' +
'\n' +
'.a { b: c }',
    result = [
      {
        'kss': '/* Comment\nStyleguide 1.0    */',
        'code': '\n.a { b: c }'
      }
    ],
    kssBlocks = kssSplitter.getBlocks(str);
    expect(kssBlocks).eql(result);
  });
  it('should parse multiline KSS with string prefixes', function() {
    var str = '' +
'/* Comment\n' +
' * Styleguide 1.0\n' +
'*/' +
'\n' +
'.a { b: c }',
    result = [
      {
        'kss': '/* Comment\n * Styleguide 1.0\n*/',
        'code': '\n.a { b: c }'
      }
    ],
    kssBlocks = kssSplitter.getBlocks(str);
    expect(kssBlocks).eql(result);
  });

  it('should allow code blocks to have multiline comments', function(){
    var str = multiline(function() {
      /*
// Comment
//Styleguide 1.0

.a { b: c }
      */}) +
'\n\n/* Simple comment */\n\n' +
multiline(function() {
    /*
.x { y: z }
      */
    }),
    result = [
      {
        'kss': '// Comment\n//Styleguide 1.0 ',
        'code': '\n\n.a { b: c }\n\n/* Simple comment */\n\n.x { y: z }'
      }
    ],
    kssBlocks = kssSplitter.getBlocks(str);
    expect(kssBlocks).eql(result);
  });

  it('should parse several KSS blocks with multiline comments', function(){
    var str = '/*\n' +
'Comment1\n' +
'Styleguide 1.0\n' +
'*/\n' +
'.a { b: c }\n' +
'\n' +
'/*\n' +
'Comment2\n' +
'Styleguide 2.0\n' +
'*/'
    '',
    result = [
      {
        'kss': '/*\nComment1\nStyleguide 1.0\n*/',
        'code': '\n.a { b: c }\n\n'
      },
      {
        'kss': '/*\nComment2\nStyleguide 2.0\n*/',
        'code': ''
      }
    ],
    kssBlocks = kssSplitter.getBlocks(str);
    expect(kssBlocks).eql(result);
  });

  /* TODO: Parser does not work with code after 2nd code block */

  it('should return array of blocks', function() {
    var str = multiline(function() {
      /*
@import "test";
// Comment
// Styleguide 1.0

.a { b: c }

// Comment
// Styleguide 2

// Comment
// Styleguide 2.0

.a { b: c }

      */
    }),
    result = [
      {
        kss: '',
        code: '@import "test";\n'
      },
      {
        kss: '// Comment\n// Styleguide 1.0',
        code: '\n\n.a { b: c }\n\n'
      },
      {
        kss: '// Comment\n// Styleguide 2',
        code: '\n\n'
      },
      {
        kss: '// Comment\n// Styleguide 2.0',
        code: '\n\n\n.a { b: c }'
      }
    ],
    kssBlocks = kssSplitter.getBlocks(str);
    expect(kssBlocks).eql(result);
  });

  describe('tricky CSS content', function() {

    it('should swallow content property with multiline comment', function() {
      var str = multiline(function() {
        /*
// Comment
// Styleguide 1.0

a:before { content: "/* ..." }

// Comment
// Styleguide 2

        */
      }),
      result = [
        {
          kss: '// Comment\n// Styleguide 1.0',
          code: '\n\na:before { content: "/* ..." }\n\n'
        },
        {
          kss: '// Comment\n// Styleguide 2',
          code: ''
        }
      ],
      kssBlocks = kssSplitter.getBlocks(str);
      expect(kssBlocks).eql(result);
    });

    it('should swallow content property with singleline comment', function() {
      var str = multiline(function() {
        /*
a:before { content: "// Comment inside content" }

// Comment
// Styleguide 2
        */
      }),
      result = [
        {
          kss: '',
          code: 'a:before { content: "// Comment inside content" }\n\n'
        },
        {
          kss: '// Comment\n// Styleguide 2',
          code: ''
        }
      ],
      kssBlocks = kssSplitter.getBlocks(str);
      expect(kssBlocks).eql(result);
    });
  });

});
<|endoftext|>