diff --git a/NodeApp/.idea/jetbrainsConfiguration b/NodeApp/.idea/jetbrainsConfiguration index 4d703a2dd39ec0c2b71bbbbda8900588c4e360bd..ffc5d65f9f0f0e825688177425e526131aa84631 160000 --- a/NodeApp/.idea/jetbrainsConfiguration +++ b/NodeApp/.idea/jetbrainsConfiguration @@ -1 +1 @@ -Subproject commit 4d703a2dd39ec0c2b71bbbbda8900588c4e360bd +Subproject commit ffc5d65f9f0f0e825688177425e526131aa84631 diff --git a/NodeApp/src/app.ts b/NodeApp/src/app.ts index 236e2d79bff4df0a07333e01c129ca008994c0cc..be01e40ef06b23244940be8b6e228a38344a74d3 100644 --- a/NodeApp/src/app.ts +++ b/NodeApp/src/app.ts @@ -1,11 +1,15 @@ // Read from the .env file -// ATTENTION : This lines MUST be the first of this file (except for the path import) -const path = require('node:path'); -const myEnv = require('dotenv').config({ - path : path.join(__dirname, '../.env'), - DOTENV_KEY: 'dotenv://:key_fc323d8e0a02349342f1c6a119bb38495958ce3a43a87d19a3f674b7e2896dcb@dotenv.local/vault/.env.vault?environment=development' - }); -require('dotenv-expand').expand(myEnv); +// ATTENTION : These lines MUST be the first of this file (except for the path import) +import path = require('node:path'); +import myEnv = require('dotenv'); +import dotenvExpand = require('dotenv-expand'); + + +dotenvExpand.expand(myEnv.config({ + path : path.join(__dirname, '../.env'), + DOTENV_KEY: 'dotenv://:key_fc323d8e0a02349342f1c6a119bb38495958ce3a43a87d19a3f674b7e2896dcb@dotenv.local/vault/.env.vault?environment=development' + })); + require('./shared/helpers/TypeScriptExtensions'); // ATTENTION : This line MUST be the second of this file @@ -15,4 +19,5 @@ import HttpManager from './managers/HttpManager'; HttpManager.registerAxiosInterceptor(); + new CommanderApp(); \ No newline at end of file diff --git a/NodeApp/src/commander/CommanderCommand.ts b/NodeApp/src/commander/CommanderCommand.ts index 7d2c2ccb1e9dd7be9ad3478f79664f08b848c4e7..b5fd5e7d363c8d9d8d16e6022b8529397685a4af 100644 --- a/NodeApp/src/commander/CommanderCommand.ts +++ b/NodeApp/src/commander/CommanderCommand.ts @@ -10,13 +10,13 @@ abstract class CommanderCommand { this.defineCommand(); this.defineSubCommands(); - }; + } protected abstract defineCommand(): void; protected defineSubCommands() {} - protected abstract commandAction(...args: Array<any>): Promise<void>; + protected abstract commandAction(...args: Array<unknown>): Promise<void>; } diff --git a/NodeApp/src/commander/assignment/AssignmentCommand.ts b/NodeApp/src/commander/assignment/AssignmentCommand.ts index d78a64aa54d0920f49377a029e7de78806b338d1..70f09e2ff18e17774067e71a3d6e773dbf201f18 100644 --- a/NodeApp/src/commander/assignment/AssignmentCommand.ts +++ b/NodeApp/src/commander/assignment/AssignmentCommand.ts @@ -20,7 +20,7 @@ class AssignmentCommand extends CommanderCommand { AssignmentUnpublishCommand.registerOnCommand(this.command); } - protected async commandAction(options: any): Promise<void> { } + protected async commandAction(): Promise<void> { } } diff --git a/NodeApp/src/commander/assignment/subcommands/AssignmentCheckCommand.ts b/NodeApp/src/commander/assignment/subcommands/AssignmentCheckCommand.ts index d46efaa66632054313f3bf246b419c280841287e..718b7b97d11a74390d2de9e53753566f8f8565b1 100644 --- a/NodeApp/src/commander/assignment/subcommands/AssignmentCheckCommand.ts +++ b/NodeApp/src/commander/assignment/subcommands/AssignmentCheckCommand.ts @@ -1,16 +1,11 @@ import CommanderCommand from '../../CommanderCommand'; import Config from '../../../config/Config'; import ora from 'ora'; -import util from 'util'; -import { exec } from 'child_process'; import chalk from 'chalk'; import AssignmentValidator from '../../../sharedByClients/helpers/Dojo/AssignmentValidator'; import ClientsSharedAssignmentHelper from '../../../sharedByClients/helpers/Dojo/ClientsSharedAssignmentHelper'; -const execAsync = util.promisify(exec); - - class AssignmentCheckCommand extends CommanderCommand { protected commandName: string = 'check'; @@ -76,13 +71,13 @@ class AssignmentCheckCommand extends CommanderCommand { } }); - assignmentValidator.events.on('finished', (success: boolean, exitCode: number) => { + assignmentValidator.events.on('finished', (success: boolean) => { success ? resolve() : reject(); }); assignmentValidator.run(true); }); - } catch ( error ) { } + } catch ( error ) { /* empty */ } ClientsSharedAssignmentHelper.displayExecutionResults(assignmentValidator, `The assignment is ready to be pushed.`, { INFO : chalk.bold, diff --git a/NodeApp/src/commander/assignment/subcommands/AssignmentCreateCommand.ts b/NodeApp/src/commander/assignment/subcommands/AssignmentCreateCommand.ts index 7a5bea4403c7e963a948ccc04c945ee17e35fa4d..623f9b64116a5229814aa481de7087914ed7b82d 100644 --- a/NodeApp/src/commander/assignment/subcommands/AssignmentCreateCommand.ts +++ b/NodeApp/src/commander/assignment/subcommands/AssignmentCreateCommand.ts @@ -22,7 +22,7 @@ class AssignmentCreateCommand extends CommanderCommand { .action(this.commandAction.bind(this)); } - protected async commandAction(options: any): Promise<void> { + protected async commandAction(options: { name: string, template?: string, members_id?: Array<number>, members_username?: Array<string> }): Promise<void> { let members!: Array<GitlabUser> | false; let templateIdOrNamespace: string | null = null; diff --git a/NodeApp/src/commander/exercise/ExerciseCommand.ts b/NodeApp/src/commander/exercise/ExerciseCommand.ts index bc122a864f7cc7fd9b32c00879b4427cdaae67e6..a475d4f91bf8d7a39bf74acc7c131cf32b7564f4 100644 --- a/NodeApp/src/commander/exercise/ExerciseCommand.ts +++ b/NodeApp/src/commander/exercise/ExerciseCommand.ts @@ -16,7 +16,7 @@ class ExerciseCommand extends CommanderCommand { ExerciseRunCommand.registerOnCommand(this.command); } - protected async commandAction(options: any): Promise<void> { } + protected async commandAction(): Promise<void> { } } diff --git a/NodeApp/src/commander/exercise/subcommands/ExerciseCreateCommand.ts b/NodeApp/src/commander/exercise/subcommands/ExerciseCreateCommand.ts index 5b547df82b9c26433806d861a5ae5f7da581a8c7..9660a3e753c67c3e2c590c39cef4adae763a3e9f 100644 --- a/NodeApp/src/commander/exercise/subcommands/ExerciseCreateCommand.ts +++ b/NodeApp/src/commander/exercise/subcommands/ExerciseCreateCommand.ts @@ -21,7 +21,7 @@ class ExerciseCreateCommand extends CommanderCommand { .action(this.commandAction.bind(this)); } - protected async commandAction(options: any): Promise<void> { + protected async commandAction(options: { assignment: string, members_id?: Array<number>, members_username?: Array<string> }): Promise<void> { let members!: Array<GitlabUser> | false; let assignment!: Assignment | undefined; diff --git a/NodeApp/src/commander/exercise/subcommands/ExerciseRunCommand.ts b/NodeApp/src/commander/exercise/subcommands/ExerciseRunCommand.ts index e10f030ee540b0170c11113ad5c231566dc1c99f..cc139fe0a399909a51bee3a976d2d8debf2d5fce 100644 --- a/NodeApp/src/commander/exercise/subcommands/ExerciseRunCommand.ts +++ b/NodeApp/src/commander/exercise/subcommands/ExerciseRunCommand.ts @@ -188,13 +188,13 @@ class ExerciseRunCommand extends CommanderCommand { } }); - exerciseDockerCompose.events.on('finished', (success: boolean, exitCode: number) => { + exerciseDockerCompose.events.on('finished', (success: boolean) => { success ? resolve() : reject(); }); exerciseDockerCompose.run(true); }); - } catch ( error ) { } + } catch ( error ) { /* empty */ } fs.rmSync(composeOverridePath, { force: true }); fs.writeFileSync(this.fileComposeLogs, exerciseDockerCompose.allLogs); diff --git a/NodeApp/src/commander/session/SessionCommand.ts b/NodeApp/src/commander/session/SessionCommand.ts index bbf0374ee9617ccc44e4463bd84554db2f8d4aa7..6dff026f2eae88717b4ca3bebe53f2db8025e749 100644 --- a/NodeApp/src/commander/session/SessionCommand.ts +++ b/NodeApp/src/commander/session/SessionCommand.ts @@ -18,7 +18,7 @@ class SessionCommand extends CommanderCommand { SessionTestCommand.registerOnCommand(this.command); } - protected async commandAction(options: any): Promise<void> { } + protected async commandAction(): Promise<void> { } } diff --git a/NodeApp/src/commander/session/subcommands/SessionLoginCommand.ts b/NodeApp/src/commander/session/subcommands/SessionLoginCommand.ts index 53610a2fab179d5577f373cce51f3633209464df..d9061e261f67f35104d1836d75cc78adea55dbc1 100644 --- a/NodeApp/src/commander/session/subcommands/SessionLoginCommand.ts +++ b/NodeApp/src/commander/session/subcommands/SessionLoginCommand.ts @@ -17,9 +17,7 @@ class SessionLoginCommand extends CommanderCommand { try { console.log(chalk.cyan('Please wait while we login you into Dojo...')); await SessionManager.login(options.cli); - } catch ( error ) { - - } + } catch ( error ) { /* empty */ } } } diff --git a/NodeApp/src/commander/session/subcommands/SessionLogoutCommand.ts b/NodeApp/src/commander/session/subcommands/SessionLogoutCommand.ts index e0c7bb374c5138cd01ee3fd08db04d38e1e6472c..e71d882d4935b8b3f8cc1b4f248a2a3d9ae6ab33 100644 --- a/NodeApp/src/commander/session/subcommands/SessionLogoutCommand.ts +++ b/NodeApp/src/commander/session/subcommands/SessionLogoutCommand.ts @@ -14,7 +14,7 @@ class SessionLogoutCommand extends CommanderCommand { .action(this.commandAction.bind(this)); } - protected async commandAction(options: any): Promise<void> { + protected async commandAction(options: { force: boolean }): Promise<void> { if ( !options.force ) { const confirm: boolean = (await inquirer.prompt({ name : 'confirm', diff --git a/NodeApp/src/config/LocalConfigFile.ts b/NodeApp/src/config/LocalConfigFile.ts index 33cabe255728f5c990ceab23a4143fb0271877ed..c69c89c71a67fc2ff100c28c6e8b38987c0686a2 100644 --- a/NodeApp/src/config/LocalConfigFile.ts +++ b/NodeApp/src/config/LocalConfigFile.ts @@ -10,7 +10,7 @@ class LocalConfigFile { return `${ Config.localConfig.folder }/${ this.filename }`; } - private _config: { [key: string]: any } = {}; + private _config: { [key: string]: unknown } = {}; loadConfig() { if ( !fs.existsSync(this.configPath) ) { @@ -26,7 +26,7 @@ class LocalConfigFile { } } - getParam(key: string): any | null { + getParam(key: string): unknown | null { const value = key in this._config ? this._config[key] : null; if ( value === null ) { return null; @@ -37,8 +37,8 @@ class LocalConfigFile { } } - setParam(key: string, value: any): void { - let previousValue = this.getParam(key); + setParam(key: string, value: unknown): void { + const previousValue = this.getParam(key); if ( JSON5.stringify(previousValue) === JSON5.stringify(value) ) { return; } diff --git a/NodeApp/src/helpers/AccessesHelper.ts b/NodeApp/src/helpers/AccessesHelper.ts index 0327ed2ddc644e485460ec3903df3d74219ba70b..e49e5819e59c74042fb5f23f79ace5587ae128c3 100644 --- a/NodeApp/src/helpers/AccessesHelper.ts +++ b/NodeApp/src/helpers/AccessesHelper.ts @@ -4,7 +4,7 @@ import GitlabManager from '../managers/GitlabManager'; class AccessesHelper { async checkStudent(): Promise<boolean> { - let sessionResult = await SessionManager.testSession(true, [ 'student' ]); + const sessionResult = await SessionManager.testSession(true, [ 'student' ]); if ( !sessionResult ) { return false; @@ -14,7 +14,7 @@ class AccessesHelper { } async checkTeachingStaff(): Promise<boolean> { - let sessionResult = await SessionManager.testSession(true, [ 'teachingStaff' ]); + const sessionResult = await SessionManager.testSession(true, [ 'teachingStaff' ]); if ( !sessionResult || !sessionResult.teachingStaff ) { return false; @@ -22,6 +22,6 @@ class AccessesHelper { return (await GitlabManager.testToken(true)).every(result => result); } -}; +} export default new AccessesHelper(); \ No newline at end of file diff --git a/NodeApp/src/managers/DojoBackendManager.ts b/NodeApp/src/managers/DojoBackendManager.ts index 42bda3fa67ec31b4f9be6bba3e5da406c8f8224e..d3711009cf433867a339eb495161397d895a0fd4 100644 --- a/NodeApp/src/managers/DojoBackendManager.ts +++ b/NodeApp/src/managers/DojoBackendManager.ts @@ -107,7 +107,7 @@ class DojoBackendManager { if ( error.response.status === StatusCodes.CONFLICT ) { spinner.fail(`The assignment name is already used. Please choose another one.`); } else { - if ( (error.response.data as DojoBackendResponse<any>).code === DojoStatusCode.ASSIGNMENT_CREATION_GITLAB_ERROR ) { + if ( (error.response.data as DojoBackendResponse<unknown>).code === DojoStatusCode.ASSIGNMENT_CREATION_GITLAB_ERROR ) { spinner.fail(`Assignment creation error: An unknown error occurred while creating the assignment on Gitlab. Please try again later or contact an administrator.`); } else { spinner.fail(`Assignment creation error: An unknown error occurred while creating the assignment on Dojo server. Please try again later or contact an administrator.`); @@ -145,7 +145,7 @@ class DojoBackendManager { if ( error.response.status === StatusCodes.CONFLICT ) { spinner.fail(`You've already reached the max number of exercise of this assignment.`); } else { - if ( (error.response.data as DojoBackendResponse<any>).code === DojoStatusCode.EXERCISE_CREATION_GITLAB_ERROR ) { + if ( (error.response.data as DojoBackendResponse<unknown>).code === DojoStatusCode.EXERCISE_CREATION_GITLAB_ERROR ) { spinner.fail(`Exercise creation error: An unknown error occurred while creating the exercise on Gitlab. Please try again later or contact an administrator.`); } else { spinner.fail(`Exercise creation error: An unknown error occurred while creating the exercise on Dojo server. Please try again later or contact an administrator.`); diff --git a/NodeApp/src/managers/GitlabManager.ts b/NodeApp/src/managers/GitlabManager.ts index 6562ad9980914e02cb7ef3b67b96cd85342e0748..67de5c9dad4cfe101e7c270410bd80448b9e727e 100644 --- a/NodeApp/src/managers/GitlabManager.ts +++ b/NodeApp/src/managers/GitlabManager.ts @@ -1,8 +1,9 @@ -import axios from 'axios'; -import ora from 'ora'; -import GitlabUser from '../shared/types/Gitlab/GitlabUser'; -import GitlabRoute from '../shared/types/Gitlab/GitlabRoute'; -import SharedConfig from '../shared/config/SharedConfig'; +import axios from 'axios'; +import ora from 'ora'; +import GitlabUser from '../shared/types/Gitlab/GitlabUser'; +import GitlabRoute from '../shared/types/Gitlab/GitlabRoute'; +import SharedConfig from '../shared/config/SharedConfig'; +import GitlabRepository from '../shared/types/Gitlab/GitlabRepository'; class GitlabManager { @@ -15,7 +16,7 @@ class GitlabManager { ora('Checking Gitlab token: ').start().info(); } - let result: [ boolean, boolean ] = [ false, false ]; + const result: [ boolean, boolean ] = [ false, false ]; type NotificationSettings = { level: string } @@ -84,7 +85,7 @@ class GitlabManager { return axios.get(this.getApiUrl(GitlabRoute.NOTIFICATION_SETTINGS)); } - public setNotificationSettings(newSettings: any) { + public setNotificationSettings(newSettings: Record<string, string>) { return axios.put(this.getApiUrl(GitlabRoute.NOTIFICATION_SETTINGS), { params: new URLSearchParams(newSettings) }); } @@ -98,7 +99,7 @@ class GitlabManager { if ( verbose ) { spinner.start(); } - const params: any = {}; + const params: { [key: string]: unknown } = {}; params[paramName] = param; const user = await axios.get<Array<GitlabUser>>(this.getApiUrl(GitlabRoute.USERS_GET), { params: params }); @@ -128,19 +129,19 @@ class GitlabManager { return await this.getGitlabUsers(usernames, 'search', verbose, verboseIndent); } - public async getRepository(repoId: number): Promise<any> { + public async getRepository(repoId: number): Promise<GitlabRepository> { return await axios.get(this.getApiUrl(GitlabRoute.REPOSITORY_GET).replace('{{id}}', repoId.toString())); } - public async fetchMembers(options: any): Promise<Array<GitlabUser> | false> { + public async fetchMembers(options: { members_id?: Array<number>, members_username?: Array<string> }): Promise<Array<GitlabUser> | false> { if ( options.members_id || options.members_username ) { ora('Checking Gitlab members:').start().info(); } let members: Array<GitlabUser> = []; - async function getMembers<T>(context: any, functionName: string, paramsToSearch: Array<T>): Promise<boolean> { - const result = await (context[functionName] as (arg: Array<T>, verbose: boolean, verboseIndent: number) => Promise<Array<GitlabUser | undefined>>)(paramsToSearch, true, 8); + async function getMembers<T>(context: unknown, functionName: string, paramsToSearch: Array<T>): Promise<boolean> { + const result = await ((context as { [functionName: string]: (arg: Array<T>, verbose: boolean, verboseIndent: number) => Promise<Array<GitlabUser | undefined>> })[functionName])(paramsToSearch, true, 8); if ( result.every(user => user) ) { members = members.concat(result as Array<GitlabUser>); diff --git a/NodeApp/src/managers/HttpManager.ts b/NodeApp/src/managers/HttpManager.ts index e90f666c4967739d857af9a604a39ca0e82fad34..a0f54387fe3c53b166aa9b8a14f8c44a0071edcd 100644 --- a/NodeApp/src/managers/HttpManager.ts +++ b/NodeApp/src/managers/HttpManager.ts @@ -1,14 +1,14 @@ -import axios, { AxiosRequestHeaders } from 'axios'; -import SessionManager from './SessionManager'; -import FormData from 'form-data'; -import { StatusCodes } from 'http-status-codes'; -import ClientsSharedConfig from '../sharedByClients/config/ClientsSharedConfig'; -import { version } from '../config/Version'; -import DojoBackendResponse from '../shared/types/Dojo/DojoBackendResponse'; -import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode'; -import boxen from 'boxen'; -import Config from '../config/Config'; -import SharedConfig from '../shared/config/SharedConfig'; +import axios, { AxiosError, AxiosRequestHeaders } from 'axios'; +import SessionManager from './SessionManager'; +import FormData from 'form-data'; +import { StatusCodes } from 'http-status-codes'; +import ClientsSharedConfig from '../sharedByClients/config/ClientsSharedConfig'; +import { version } from '../config/Version'; +import DojoBackendResponse from '../shared/types/Dojo/DojoBackendResponse'; +import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode'; +import boxen from 'boxen'; +import Config from '../config/Config'; +import SharedConfig from '../shared/config/SharedConfig'; class HttpManager { @@ -84,17 +84,19 @@ class HttpManager { await SessionManager.refreshTokens(); return axios(originalConfig); - } catch ( _error: any ) { - if ( _error.response && _error.response.data ) { - return Promise.reject(_error.response.data); + } catch ( error: unknown ) { + if ( error instanceof AxiosError ) { + if ( error.response && error.response.data ) { + return Promise.reject(error.response.data); + } } - return Promise.reject(_error); + return Promise.reject(error); } } if ( error.response.status === StatusCodes.METHOD_NOT_ALLOWED && isFromApi && error.response.data ) { - const data: DojoBackendResponse<{}> = error.response.data; + const data: DojoBackendResponse<void> = error.response.data; switch ( data.code ) { case DojoStatusCode.CLIENT_NOT_SUPPORTED: diff --git a/NodeApp/src/managers/SessionManager.ts b/NodeApp/src/managers/SessionManager.ts index 580b6d854da7fa201243682ee8cd126aff84e8af..9bbd640f523b04e530b5fcaadf591ee2b208e6e0 100644 --- a/NodeApp/src/managers/SessionManager.ts +++ b/NodeApp/src/managers/SessionManager.ts @@ -36,7 +36,7 @@ class LoginServer { }; if ( req.url?.match(Config.login.server.route) ) { - let urlParts = req.url.split('='); + const urlParts = req.url.split('='); if ( urlParts.length > 0 ) { this.events.emit('code', urlParts[1]); @@ -84,7 +84,7 @@ class SessionManager { } get apiToken(): string { - const apisToken = this.configFile.getParam(LocalConfigKeys.APIS_TOKEN); + const apisToken = this.configFile.getParam(LocalConfigKeys.APIS_TOKEN) as null | { [key: string]: string }; if ( apisToken !== null && ClientsSharedConfig.apiURL in apisToken ) { return apisToken[ClientsSharedConfig.apiURL]; @@ -94,7 +94,7 @@ class SessionManager { } set apiToken(token: string) { - let apisToken = this.configFile.getParam(LocalConfigKeys.APIS_TOKEN); + let apisToken = this.configFile.getParam(LocalConfigKeys.APIS_TOKEN) as null | { [key: string]: string }; if ( apisToken === null ) { apisToken = {}; } @@ -113,7 +113,7 @@ class SessionManager { } get gitlabCredentials(): DojoGitlabCredentials { - return this.configFile.getParam(LocalConfigKeys.GITLAB); + return this.configFile.getParam(LocalConfigKeys.GITLAB) as DojoGitlabCredentials; } set gitlabCredentials(credentials: DojoGitlabCredentials) { @@ -216,10 +216,10 @@ class SessionManager { gitlabCode = await this.getGitlabCodeFromHeadlessEnvironment(); } - let gitlabTokensSpinner = ora({ - text : 'Retrieving gitlab tokens', - indent: 4 - }).start(); + const gitlabTokensSpinner = ora({ + text : 'Retrieving gitlab tokens', + indent: 4 + }).start(); let gitlabTokens: GitlabToken; try { gitlabTokens = await SharedGitlabManager.getTokens(gitlabCode); @@ -239,10 +239,10 @@ class SessionManager { } ora(`Login to Dojo backend:`).start().info(); - let dojoLoginSpinner = ora({ - text : 'Login to Dojo backend', - indent: 4 - }).start(); + const dojoLoginSpinner = ora({ + text : 'Login to Dojo backend', + indent: 4 + }).start(); try { await DojoBackendManager.login(gitlabTokens); @@ -256,7 +256,7 @@ class SessionManager { } async refreshTokens() { - let gitlabTokens = await DojoBackendManager.refreshTokens(this.gitlabCredentials.refreshToken!); + const gitlabTokens = await DojoBackendManager.refreshTokens(this.gitlabCredentials.refreshToken!); this.gitlabCredentials = { refreshToken: gitlabTokens.refresh_token, @@ -274,7 +274,7 @@ class SessionManager { checkPermissions(verbose: boolean = true, indent: number = 8, checkPermissions: Array<string> | null = []): Permissions { const hasPermission = (permissionPredicate: () => boolean, verboseText: string): boolean => { - let isAllowed: boolean = this.profile !== undefined && permissionPredicate(); + const isAllowed: boolean = this.profile !== undefined && permissionPredicate(); if ( verbose ) { const spinner: ora.Ora = ora({ diff --git a/NodeApp/src/shared b/NodeApp/src/shared index 4a5eb68209ae9204b6d4cc8020bd62cf6a5be989..101cc26895eb0b5fe97e03bb96039e0cddd94391 160000 --- a/NodeApp/src/shared +++ b/NodeApp/src/shared @@ -1 +1 @@ -Subproject commit 4a5eb68209ae9204b6d4cc8020bd62cf6a5be989 +Subproject commit 101cc26895eb0b5fe97e03bb96039e0cddd94391