From 3d48ace5c16fc0e8161b93291cfffc5680b89795 Mon Sep 17 00:00:00 2001 From: "Jean M. Lescure" Date: Thu, 21 May 2020 12:15:44 -0600 Subject: [PATCH 1/3] version bump and feature creep a release prep script --- package.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 596dfa5..55e622a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "short-unique-id", - "version": "3.0.1", + "version": "3.0.2", "description": "Generate random or sequential UUID of any length", "keywords": [ "short", @@ -14,7 +14,7 @@ "license": "Apache-2.0", "main": "lib/short-unique-id", "module": "lib/short-unique-id", - "typings": "short_uuid/mod", + "typings": "typings/short-unique-id", "homepage": "https://jeanlescure.github.io/short-unique-id/", "repository": { "type": "git", @@ -24,10 +24,12 @@ "scripts": { "gen:version": "echo \"export default '`jq -r .version package.json`';\" > short_uuid/version.ts", "gen:docs": "cd short_uuid && typedoc --gaID UA-159642755-1 --readme ../README.md --theme ../node_modules/short_uuid_typedoc_template/bin/default --out ../docs . && cd .. && cp -r ./assets ./docs && mv ./docs/assets/favicon.ico ./docs/ && echo shortunique.id > ./docs/CNAME", + "gen:typings": "cd short_uuid && ../node_modules/typescript/bin/tsc --declaration --emitDeclarationOnly mod.ts ; mv mod.d.ts ../typings/short-unique-id.d.ts", "lib:build": "yarn gen:version && rm ./lib/* ; mkdir -p tmp && cd short_uuid && deno bundle mod.ts ../tmp/mod.js && deno bundle version.ts ../tmp/version.js && cd .. && sucrase ./tmp -d ./lib -t imports && mv ./lib/mod.js ./lib/short-unique-id.js && rm -rf ./tmp", "dist:build": "yarn lib:build && rm ./dist/* ; echo 'var __suid_module = ' > ./dist/short-unique-id.js && browserify ./lib/short-unique-id.js >> ./dist/short-unique-id.js && echo 'var ShortUniqueId = __suid_module(1)[\"default\"];' >> ./dist/short-unique-id.js && minify ./dist/short-unique-id.js > ./dist/short-unique-id.min.js", "test": "cd short_uuid && deno test && cd .. && yarn link && yarn link short-unique-id && node ./runkit.js", - "lint": "tslint ./short_uuid/*.ts" + "lint": "tslint ./short_uuid/*.ts", + "prepare:release": "yarn gen:typings && yarn lint && yarn lib:build && yarn dist:build && yarn test && yarn gen:docs" }, "devDependencies": { "browserify": "^16.5.1", From 29c8b55e8e9b5a7c743bbca86986a31de6585e27 Mon Sep 17 00:00:00 2001 From: "Jean M. Lescure" Date: Thu, 21 May 2020 12:16:39 -0600 Subject: [PATCH 2/3] fix all typings, docs, and npm pack issues --- .npmignore | 6 ++ README.md | 4 +- dist/short-unique-id.js | 6 +- dist/short-unique-id.min.js | 2 +- docs/classes/shortuniqueid.html | 8 +- docs/globals.html | 8 +- docs/index.html | 9 +- lib/short-unique-id.js | 6 +- lib/version.js | 2 +- typings/short-unique-id.d.ts | 185 ++++++++++++++++++++++++++++++++ 10 files changed, 218 insertions(+), 18 deletions(-) create mode 100644 .npmignore create mode 100644 typings/short-unique-id.d.ts diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..2c5a19e --- /dev/null +++ b/.npmignore @@ -0,0 +1,6 @@ +short_uuid +.gitmodules +*.log +*.tgz +.vscode +.github diff --git a/README.md b/README.md index 522d7cb..0635588 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Generate random or sequential UUID of any length. // Deno (web module) Import import ShortUniqueId from 'https://cdn.jsdelivr.net/npm/short-unique-id@latest/short_uuid/mod.ts'; -// ES6 Import +// ES6 / TypeScript Import import ShortUniqueId from 'short-unique-id'; //or Node.js require @@ -141,6 +141,8 @@ git clone --recurse-submodules git@github.com:jeanlescure/short-unique-id.git git clone --recurse-submodules https://github.com/jeanlescure/short-unique-id.git ``` +All feature development must happen under `./short_uuid/mod.ts`. + Tests run using [Deno](https://deno.land/std/testing/): ``` diff --git a/dist/short-unique-id.js b/dist/short-unique-id.js index 46bd28e..7c4b0cb 100644 --- a/dist/short-unique-id.js +++ b/dist/short-unique-id.js @@ -113,7 +113,7 @@ System.register("version", [], function (exports_1, context_1) { return { setters: [], execute: function () { - exports_1("default", "3.0.1"); + exports_1("default", "3.0.2"); }, }; }); @@ -174,8 +174,10 @@ System.register("mod", ["version"], function (exports_2, context_2) { * ```js * // Deno (web module) Import * import ShortUniqueId from 'https://cdn.jsdelivr.net/npm/short-unique-id@latest/short_uuid/mod.ts'; - * // ES6 Import + * + * // ES6 / TypeScript Import * import ShortUniqueId from 'short-unique-id'; + * * //or Node.js require * const {default: ShortUniqueId} = require('short-unique-id'); * diff --git a/dist/short-unique-id.min.js b/dist/short-unique-id.min.js index 5d74e45..a36b9f9 100644 --- a/dist/short-unique-id.min.js +++ b/dist/short-unique-id.min.js @@ -1 +1 @@ -var __suid_module=function t(e,i,n){function s(o,u){if(!i[o]){if(!e[o]){var h="function"==typeof require&&require;if(!u&&h)return h(o,!0);if(r)return r(o,!0);var d=new Error("Cannot find module '"+o+"'");throw d.code="MODULE_NOT_FOUND",d}var a=i[o]={exports:{}};e[o][0].call(a.exports,(function(t){return s(e[o][1][t]||t)}),a,a.exports,t,e,i,n)}return i[o].exports}for(var r="function"==typeof require&&require,o=0;o{const e=new Map;function i(i,n){return{id:i,import:n=>async function(i,n){let s=i.replace(/\.\w+$/i,"");if(s.includes("./")){const[t,...e]=s.split("/").reverse(),[,...i]=n.split("/").reverse(),r=[t];let o,u=0;for(;o=e.shift();)if(".."===o)u++;else{if("."===o)break;r.push(o)}ut(i))}(n,i),meta:{url:i,main:n}}}function o(t){return(e,i)=>{i="string"==typeof e?{[e]:i}:e;for(const[e,n]of Object.entries(i))Object.defineProperty(t,e,{value:n,writable:!0,enumerable:!0})}}function u(t){for(const[n,s]of e.entries()){const{f:e,exp:r}=s,{execute:u,setters:h}=e(o(r),i(n,n===t));delete s.f,s.e=u,s.s=h}}async function h(t){if(!e.has(t))return;const i=e.get(t);if(i.s){const{d:t,e:e,s:n}=i;delete i.s,delete i.e;for(let e=0;e(n=s=r=void 0,u(t),h(t)),r=t=>(n=s=r=void 0,u(t),function t(i){if(!e.has(i))return;const n=e.get(i);if(n.s){const{d:e,e:i,s:s}=n;delete n.s,delete n.e;for(let i=0;i1)this.setDictionary(r);else{let t;this.dictIndex=t=0,Object.keys(n).forEach(e=>{const i=e;for(this.dictRange=n[i],this.lowerBound=this.dictRange[0],this.upperBound=this.dictRange[1],this.dictIndex=t=this.lowerBound;this.lowerBound<=this.upperBound?tthis.upperBound;this.dictIndex=this.lowerBound<=this.upperBound?t+=1:t-=1)this.dict.push(String.fromCharCode(this.dictIndex))})}if(o){const t=.5;this.setDictionary(this.dict.sort(()=>Math.random()-t))}else this.setDictionary(this.dict);this.debug=e.debug,this.log(this.dict),this.log("Generator instantiated with Dictionary Size "+this.dictLength);const h=this.bind(this);return Object.getOwnPropertyNames(this).forEach(t=>{if(!/arguments|caller|callee|length|name|prototype/.test(t)){const e=t;h[t]=this[e]}}),h}log(...t){const e=[...t];if(e[0]="[short-unique-id] "+t[0],!0===this.debug&&"undefined"!=typeof console&&null!==console)return console.log(...e)}setDictionary(t){this.dict=t,this.dictLength=this.dict.length,this.counter=0}seq(){return this.sequentialUUID()}sequentialUUID(){let t,e,i="";for(t=this.counter;e=t%this.dictLength,t=Math.trunc(t/this.dictLength),i+=this.dict[e],0!==t;);return this.counter+=1,i}randomUUID(t=this.uuidLength||6){let e,i,n,s;if(null==t||t<1)throw new Error("Invalid UUID Length Provided");for(e="",s=n=0;0<=t?nt;s=0<=t?n+=1:n-=1)i=parseInt((Math.random()*this.dictLength).toFixed(0),10)%this.dictLength,e+=this.dict[i];return e}availableUUIDs(t=this.uuidLength){return parseFloat(Math.pow([...new Set(this.dict)].length,t).toFixed(0))}approxMaxBeforeCollision(t=this.availableUUIDs(this.uuidLength)){return parseFloat(Math.sqrt(Math.PI/2*t).toFixed(20))}collisionProbability(t=this.availableUUIDs(this.uuidLength),e=this.uuidLength){return parseFloat((this.approxMaxBeforeCollision(t)/this.availableUUIDs(e)).toFixed(20))}uniqueness(t=this.availableUUIDs(this.uuidLength)){const e=parseFloat((1-this.approxMaxBeforeCollision(t)/t).toFixed(20));return e>1?1:e<0?0:e}getVersion(){return this.version}})}}}));const o=r("mod");i.default=o.default},{}]},{},[1]),ShortUniqueId=__suid_module(1).default; +var __suid_module=function t(e,i,n){function s(o,u){if(!i[o]){if(!e[o]){var h="function"==typeof require&&require;if(!u&&h)return h(o,!0);if(r)return r(o,!0);var d=new Error("Cannot find module '"+o+"'");throw d.code="MODULE_NOT_FOUND",d}var a=i[o]={exports:{}};e[o][0].call(a.exports,(function(t){return s(e[o][1][t]||t)}),a,a.exports,t,e,i,n)}return i[o].exports}for(var r="function"==typeof require&&require,o=0;o{const e=new Map;function i(i,n){return{id:i,import:n=>async function(i,n){let s=i.replace(/\.\w+$/i,"");if(s.includes("./")){const[t,...e]=s.split("/").reverse(),[,...i]=n.split("/").reverse(),r=[t];let o,u=0;for(;o=e.shift();)if(".."===o)u++;else{if("."===o)break;r.push(o)}ut(i))}(n,i),meta:{url:i,main:n}}}function o(t){return(e,i)=>{i="string"==typeof e?{[e]:i}:e;for(const[e,n]of Object.entries(i))Object.defineProperty(t,e,{value:n,writable:!0,enumerable:!0})}}function u(t){for(const[n,s]of e.entries()){const{f:e,exp:r}=s,{execute:u,setters:h}=e(o(r),i(n,n===t));delete s.f,s.e=u,s.s=h}}async function h(t){if(!e.has(t))return;const i=e.get(t);if(i.s){const{d:t,e:e,s:n}=i;delete i.s,delete i.e;for(let e=0;e(n=s=r=void 0,u(t),h(t)),r=t=>(n=s=r=void 0,u(t),function t(i){if(!e.has(i))return;const n=e.get(i);if(n.s){const{d:e,e:i,s:s}=n;delete n.s,delete n.e;for(let i=0;i1)this.setDictionary(r);else{let t;this.dictIndex=t=0,Object.keys(n).forEach(e=>{const i=e;for(this.dictRange=n[i],this.lowerBound=this.dictRange[0],this.upperBound=this.dictRange[1],this.dictIndex=t=this.lowerBound;this.lowerBound<=this.upperBound?tthis.upperBound;this.dictIndex=this.lowerBound<=this.upperBound?t+=1:t-=1)this.dict.push(String.fromCharCode(this.dictIndex))})}if(o){const t=.5;this.setDictionary(this.dict.sort(()=>Math.random()-t))}else this.setDictionary(this.dict);this.debug=e.debug,this.log(this.dict),this.log("Generator instantiated with Dictionary Size "+this.dictLength);const h=this.bind(this);return Object.getOwnPropertyNames(this).forEach(t=>{if(!/arguments|caller|callee|length|name|prototype/.test(t)){const e=t;h[t]=this[e]}}),h}log(...t){const e=[...t];if(e[0]="[short-unique-id] "+t[0],!0===this.debug&&"undefined"!=typeof console&&null!==console)return console.log(...e)}setDictionary(t){this.dict=t,this.dictLength=this.dict.length,this.counter=0}seq(){return this.sequentialUUID()}sequentialUUID(){let t,e,i="";for(t=this.counter;e=t%this.dictLength,t=Math.trunc(t/this.dictLength),i+=this.dict[e],0!==t;);return this.counter+=1,i}randomUUID(t=this.uuidLength||6){let e,i,n,s;if(null==t||t<1)throw new Error("Invalid UUID Length Provided");for(e="",s=n=0;0<=t?nt;s=0<=t?n+=1:n-=1)i=parseInt((Math.random()*this.dictLength).toFixed(0),10)%this.dictLength,e+=this.dict[i];return e}availableUUIDs(t=this.uuidLength){return parseFloat(Math.pow([...new Set(this.dict)].length,t).toFixed(0))}approxMaxBeforeCollision(t=this.availableUUIDs(this.uuidLength)){return parseFloat(Math.sqrt(Math.PI/2*t).toFixed(20))}collisionProbability(t=this.availableUUIDs(this.uuidLength),e=this.uuidLength){return parseFloat((this.approxMaxBeforeCollision(t)/this.availableUUIDs(e)).toFixed(20))}uniqueness(t=this.availableUUIDs(this.uuidLength)){const e=parseFloat((1-this.approxMaxBeforeCollision(t)/t).toFixed(20));return e>1?1:e<0?0:e}getVersion(){return this.version}})}}}));const o=r("mod");i.default=o.default},{}]},{},[1]),ShortUniqueId=__suid_module(1).default; diff --git a/docs/classes/shortuniqueid.html b/docs/classes/shortuniqueid.html index 4ccdf43..0e403e1 100644 --- a/docs/classes/shortuniqueid.html +++ b/docs/classes/shortuniqueid.html @@ -4,7 +4,7 @@ Short Unique ID - Short UUID Generator - + @@ -33,7 +33,7 @@
  • Preparing search index...
  • The search index is not available
  • - short-unique-id - v3.0.1 + short-unique-id - v3.0.2
    @@ -139,8 +139,10 @@

    Use as module

    // Deno (web module) Import
     import ShortUniqueId from 'https://cdn.jsdelivr.net/npm/short-unique-id@latest/short_uuid/mod.ts';
    -// ES6 Import
    +
    +// ES6 / TypeScript Import
     import ShortUniqueId from 'short-unique-id';
    +
     //or Node.js require
     const {default: ShortUniqueId} = require('short-unique-id');
     
    diff --git a/docs/globals.html b/docs/globals.html
    index 1b3a542..8792c18 100644
    --- a/docs/globals.html
    +++ b/docs/globals.html
    @@ -4,7 +4,7 @@
     	
     	
     	Short Unique ID - Short UUID Generator
    -	
    +	
     	
     	
     	
    @@ -33,7 +33,7 @@
     						
  • Preparing search index...
  • The search index is not available
  • - short-unique-id - v3.0.1 + short-unique-id - v3.0.2
    @@ -58,7 +58,7 @@
    -

    short-unique-id - v3.0.1

    +

    short-unique-id - v3.0.2

    @@ -118,7 +118,7 @@

    Options

    {
       dictionary: ['z', 'a', 'p', 'h', 'o', 'd', ...],
    -  skipShuffle: false,
    +  shuffle: false,
       debug: false,
       length: 6,
     }
    diff --git a/docs/index.html b/docs/index.html index 327a9f0..6f3d50c 100644 --- a/docs/index.html +++ b/docs/index.html @@ -4,7 +4,7 @@ Short Unique ID - Short UUID Generator - + @@ -33,7 +33,7 @@
  • Preparing search index...
  • The search index is not available
  • - short-unique-id - v3.0.1 + short-unique-id - v3.0.2
    @@ -58,7 +58,7 @@
    -

    short-unique-id - v3.0.1

    +

    short-unique-id - v3.0.2

    @@ -180,7 +180,7 @@

    Use as module

    // Deno (web module) Import
     import ShortUniqueId from 'https://cdn.jsdelivr.net/npm/short-unique-id@latest/short_uuid/mod.ts';
     
    -// ES6 Import
    +// ES6 / TypeScript Import
     import ShortUniqueId from 'short-unique-id';
     
     //or Node.js require
    @@ -284,6 +284,7 @@ 

    Development

    # HTTPS git clone --recurse-submodules https://github.com/jeanlescure/short-unique-id.git
    +

    All feature development must happen under ./short_uuid/mod.ts.

    Tests run using Deno:

    yarn test

    Using airbnb rules for tslint:

    yarn lint
    diff --git a/lib/short-unique-id.js b/lib/short-unique-id.js index 2d91b5c..23b6f1a 100644 --- a/lib/short-unique-id.js +++ b/lib/short-unique-id.js @@ -111,7 +111,7 @@ System.register("version", [], function (exports_1, context_1) { return { setters: [], execute: function () { - exports_1("default", "3.0.1"); + exports_1("default", "3.0.2"); }, }; }); @@ -172,8 +172,10 @@ System.register("mod", ["version"], function (exports_2, context_2) { * ```js * // Deno (web module) Import * import ShortUniqueId from 'https://cdn.jsdelivr.net/npm/short-unique-id@latest/short_uuid/mod.ts'; - * // ES6 Import + * + * // ES6 / TypeScript Import * import ShortUniqueId from 'short-unique-id'; + * * //or Node.js require * const {default: ShortUniqueId} = require('short-unique-id'); * diff --git a/lib/version.js b/lib/version.js index 1759fa6..5e7fc00 100644 --- a/lib/version.js +++ b/lib/version.js @@ -111,7 +111,7 @@ System.register("version", [], function (exports_1, context_1) { return { setters: [], execute: function () { - exports_1("default", "3.0.1"); + exports_1("default", "3.0.2"); }, }; }); diff --git a/typings/short-unique-id.d.ts b/typings/short-unique-id.d.ts new file mode 100644 index 0000000..1ab5edf --- /dev/null +++ b/typings/short-unique-id.d.ts @@ -0,0 +1,185 @@ +/** + * ```js + * { + * dictionary: ['z', 'a', 'p', 'h', 'o', 'd', ...], + * shuffle: false, + * debug: false, + * length: 6, + * } + * ``` + */ +declare type Options = { + /** User-defined character dictionary */ + dictionary: string[]; + /** If true, sequentialUUID use the dictionary in the given order */ + shuffle: boolean; + /** If true the instance will console.log useful info */ + debug: boolean; + /** From 1 to infinity, the length you wish your UUID to be */ + length: number; +}; +/** + * Generate random or sequential UUID of any length. + * + * ### Use as module + * + * ```js + * // Deno (web module) Import + * import ShortUniqueId from 'https://cdn.jsdelivr.net/npm/short-unique-id@latest/short_uuid/mod.ts'; + * + * // ES6 / TypeScript Import + * import ShortUniqueId from 'short-unique-id'; + * + * //or Node.js require + * const {default: ShortUniqueId} = require('short-unique-id'); + * + * //Instantiate + * const uid = new ShortUniqueId(); + * + * // Random UUID + * console.log(uid()); + * + * // Sequential UUID + * console.log(uid.seq()); + * ``` + * + * ### Use in browser + * + * ```html + * + * + * + * + * + * ``` + * + * ### Options + * + * Options can be passed when instantiating `uid`: + * + * ```js + * const options = { ... }; + * + * const uid = new ShortUniqueId(options); + * ``` + * + * For more information take a look at the [Options type definition](/globals.html#options). + */ +declare class ShortUniqueId extends Function { + counter: number; + debug: boolean; + dict: string[]; + version: string; + dictIndex: number; + dictRange: number[]; + lowerBound: number; + upperBound: number; + dictLength: number; + uuidLength: number; + protected log(...args: any[]): void; + constructor(argOptions?: Partial); + /** Change the dictionary after initialization. */ + setDictionary(dictionary: string[]): void; + seq(): string; + /** + * Generates UUID based on internal counter that's incremented after each ID generation. + * @alias `const uid = new ShortUniqueId(); uid.seq();` + */ + sequentialUUID(): string; + /** + * Generates UUID by creating each part randomly. + * @alias `const uid = new ShortUniqueId(); uid(uuidLength: number);` + */ + randomUUID(uuidLength?: number): string; + /** + * Calculates total number of possible UUIDs. + * + * Given that: + * + * - `H` is the total number of possible UUIDs + * - `n` is the number of unique characters in the dictionary + * - `l` is the UUID length + * + * Then `H` is defined as `n` to the power of `l`: + * + * ![](https://render.githubusercontent.com/render/math?math=%5CHuge%20H=n%5El) + * + * This function returns `H`. + */ + availableUUIDs(uuidLength?: number): number; + /** + * Calculates approximate number of hashes before first collision. + * + * Given that: + * + * - `H` is the total number of possible UUIDs, or in terms of this library, + * the result of running `availableUUIDs()` + * - the expected number of values we have to choose before finding the + * first collision can be expressed as the quantity `Q(H)` + * + * Then `Q(H)` can be approximated as the square root of the of the product + * of half of pi times `H`: + * + * ![](https://render.githubusercontent.com/render/math?math=%5CHuge%20Q(H)%5Capprox%5Csqrt%7B%5Cfrac%7B%5Cpi%7D%7B2%7DH%7D) + * + * This function returns `Q(H)`. + */ + approxMaxBeforeCollision(rounds?: number): number; + /** + * Calculates probability of generating duplicate UUIDs (a collision) in a + * given number of UUID generation rounds. + * + * Given that: + * + * - `r` is the maximum number of times that `randomUUID()` will be called, + * or better said the number of _rounds_ + * - `H` is the total number of possible UUIDs, or in terms of this library, + * the result of running `availableUUIDs()` + * + * Then the probability of collision `p(r; H)` can be approximated as the result + * of dividing the square root of the of the product of half of pi times `H` by `H`: + * + * ![](https://render.githubusercontent.com/render/math?math=%5CHuge%20p(r%3B%20H)%5Capprox%5Cfrac%7B%5Csqrt%7B%5Cfrac%7B%5Cpi%7D%7B2%7Dr%7D%7D%7BH%7D) + * + * This function returns `p(r; H)`. + * + * (Useful if you are wondering _"If I use this lib and expect to perform at most + * `r` rounds of UUID generations, what is the probability that I will hit a duplicate UUID?"_.) + */ + collisionProbability(rounds?: number, uuidLength?: number): number; + /** + * Calculate a "uniqueness" score (from 0 to 1) of UUIDs based on size of + * dictionary and chosen UUID length. + * + * Given that: + * + * - `H` is the total number of possible UUIDs, or in terms of this library, + * the result of running `availableUUIDs()` + * - `Q(H)` is the approximate number of hashes before first collision, + * or in terms of this library, the result of running `approxMaxBeforeCollision()` + * + * Then `uniqueness` can be expressed as the additive inverse of the probability of + * generating a "word" I had previously generated (a duplicate) at any given iteration + * up to the the total number of possible UUIDs expressed as the quotiend of `Q(H)` and `H`: + * + * ![](https://render.githubusercontent.com/render/math?math=%5CHuge%201-%5Cfrac%7BQ(H)%7D%7BH%7D) + * + * (Useful if you need a value to rate the "quality" of the combination of given dictionary + * and UUID length. The closer to 1, higher the uniqueness and thus better the quality.) + */ + uniqueness(rounds?: number): number; + /** + * Return the version of this module. + */ + getVersion(): string; +} +export default ShortUniqueId; From 194b238ea7cd0651841ed34662c016aafb916033 Mon Sep 17 00:00:00 2001 From: "Jean M. Lescure" Date: Thu, 21 May 2020 12:20:03 -0600 Subject: [PATCH 3/3] update short_uuid to latest commit --- short_uuid | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/short_uuid b/short_uuid index b4d1164..19a5cbb 160000 --- a/short_uuid +++ b/short_uuid @@ -1 +1 @@ -Subproject commit b4d1164a8903be7e77d9b54e24ee1f55227a8caa +Subproject commit 19a5cbb5a90b4ac2c9cc86001b307e37f4ba8820