fix(ci): fix named import shelljs usage
[e-mobility-charging-stations-simulator.git] / README.md
index f34f12290b851089e84414a247458b1bd0177add..14843e47de80b3efe41cd31a73328ec47ecd7a0e 100644 (file)
--- a/README.md
+++ b/README.md
@@ -108,7 +108,7 @@ But the modifications to test have to be done to the files in the build target d
 | log                        |                                              | {<br />"enabled": true,<br />"file": "logs/combined.log",<br />"errorFile": "logs/error.log",<br />"statisticsInterval": 60,<br />"level": "info",<br />"console": false,<br />"format": "simple",<br />"rotate": true<br />} | {<br />enabled?: boolean;<br />file?: string;<br />errorFile?: string;<br />statisticsInterval?: number;<br />level?: string;<br />console?: boolean;<br />format?: string;<br />rotate?: boolean;<br />maxFiles?: string \| number;<br />maxSize?: string \| number;<br />}    | Log configuration section:<br />- _enabled_: enable logging<br />- _file_: log file relative path<br />- _errorFile_: error log file relative path<br />- _statisticsInterval_: seconds between charging stations statistics output in the logs<br />- _level_: emerg/alert/crit/error/warning/notice/info/debug [winston](https://github.com/winstonjs/winston) logging level</br >- _console_: output logs on the console<br />- _format_: [winston](https://github.com/winstonjs/winston) log format<br />- _rotate_: enable daily log files rotation<br />- _maxFiles_: maximum number of log files: https://github.com/winstonjs/winston-daily-rotate-file#options<br />- _maxSize_: maximum size of log files in bytes, or units of kb, mb, and gb: https://github.com/winstonjs/winston-daily-rotate-file#options                                                                                         |
 | worker                     |                                              | {<br />"processType": "workerSet",<br />"startDelay": 500,<br />"elementStartDelay": 0,<br />"elementsPerWorker": 'auto',<br />"poolMinSize": 4,<br />"poolMaxSize": 16<br />}                                                | {<br />processType?: WorkerProcessType;<br />startDelay?: number;<br />elementStartDelay?: number;<br />elementsPerWorker?: number \| 'auto' \| 'all';<br />poolMinSize?: number;<br />poolMaxSize?: number;<br />resourceLimits?: ResourceLimits;<br />}                       | Worker configuration section:<br />- _processType_: worker threads process type (`workerSet`/`fixedPool`/`dynamicPool`)<br />- _startDelay_: milliseconds to wait at worker threads startup (only for `workerSet` worker threads process type)<br />- _elementStartDelay_: milliseconds to wait at charging station startup<br />- _elementsPerWorker_: number of charging stations per worker threads for the `workerSet` process type (`auto` means (number of stations) / (number of CPUs) \* 1.5 if (number of stations) > (number of CPUs), otherwise 1; `all` means a unique worker will run all charging stations)<br />- _poolMinSize_: worker threads pool minimum number of threads</br >- _poolMaxSize_: worker threads pool maximum number of threads<br />- _resourceLimits_: worker threads [resource limits](https://nodejs.org/api/worker_threads.html#new-workerfilename-options) object option |
 | uiServer                   |                                              | {<br />"enabled": false,<br />"type": "ws",<br />"version": "1.1",<br />"options": {<br />"host": "localhost",<br />"port": 8080<br />}<br />}                                                                                | {<br />enabled?: boolean;<br />type?: ApplicationProtocol;<br />version?: ApplicationProtocolVersion;<br />options?: ServerOptions;<br />authentication?: {<br />enabled: boolean;<br />type: AuthenticationType;<br />username?: string;<br />password?: string;<br />}<br />} | UI server configuration section:<br />- _enabled_: enable UI server<br />- _type_: 'http' or 'ws'<br />- _version_: HTTP version '1.1' or '2.0'<br />- _options_: node.js net module [listen options](https://nodejs.org/api/net.html#serverlistenoptions-callback)<br />- _authentication_: authentication type configuration section                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
-| performanceStorage         |                                              | {<br />"enabled": false,<br />"type": "jsonfile",<br />"uri": "file:///performance/performanceRecords.json"<br />}                                                                                                            | {<br />enabled?: boolean;<br />type?: string;<br />uri?: string;<br />}                                                                                                                                                                                                         | Performance storage configuration section:<br />- _enabled_: enable performance storage<br />- _type_: 'jsonfile' or 'mongodb'<br />- _uri_: storage URI                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
+| performanceStorage         |                                              | {<br />"enabled": true,<br />"type": "none",<br />}                                                                                                                                                                           | {<br />enabled?: boolean;<br />type?: string;<br />uri?: string;<br />}                                                                                                                                                                                                         | Performance storage configuration section:<br />- _enabled_: enable performance storage<br />- _type_: 'jsonfile', 'mongodb' or 'none'<br />- _uri_: storage URI                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
 | stationTemplateUrls        |                                              | {}[]                                                                                                                                                                                                                          | {<br />file: string;<br />numberOfStations: number;<br />}[]                                                                                                                                                                                                                    | array of charging station configuration templates URIs configuration section (charging station configuration template file name and number of stations)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
 
 #### Worker process model
@@ -131,11 +131,12 @@ But the modifications to test have to be done to the files in the build target d
 | supervisionUrls                                      |               | []                                                                                                                                 | string \| string[]                                                                                                                                                            | string or strings array containing connection URIs to OCPP-J servers                                                                                                                                                                       |
 | supervisionUser                                      |               | undefined                                                                                                                          | string                                                                                                                                                                        | basic HTTP authentication user to OCPP-J server                                                                                                                                                                                            |
 | supervisionPassword                                  |               | undefined                                                                                                                          | string                                                                                                                                                                        | basic HTTP authentication password to OCPP-J server                                                                                                                                                                                        |
-| supervisionUrlOcppConfiguration                      | true/false    | false                                                                                                                              | boolean                                                                                                                                                                       | allow supervision URL configuration via a vendor OCPP parameter key                                                                                                                                                                        |
+| supervisionUrlOcppConfiguration                      | true/false    | false                                                                                                                              | boolean                                                                                                                                                                       | enable supervision URL configuration via a vendor OCPP parameter key                                                                                                                                                                       |
 | supervisionUrlOcppKey                                |               | 'ConnectionUrl'                                                                                                                    | string                                                                                                                                                                        | the vendor string that will be used as a vendor OCPP parameter key to set the supervision URL                                                                                                                                              |
+| autoStart                                            | true/false    | true                                                                                                                               | boolean                                                                                                                                                                       | enable automatic start of added charging station from template                                                                                                                                                                             |
 | ocppVersion                                          | 1.6/2.0/2.0.1 | 1.6                                                                                                                                | string                                                                                                                                                                        | OCPP version                                                                                                                                                                                                                               |
 | ocppProtocol                                         | json          | json                                                                                                                               | string                                                                                                                                                                        | OCPP protocol                                                                                                                                                                                                                              |
-| ocppStrictCompliance                                 | true/false    | true                                                                                                                               | boolean                                                                                                                                                                       | strict adherence to the OCPP version and protocol specifications with OCPP commands PDU validation against [OCA](https://www.openchargealliance.org/) JSON schemas                                                                         |
+| ocppStrictCompliance                                 | true/false    | true                                                                                                                               | boolean                                                                                                                                                                       | enable strict adherence to the OCPP version and protocol specifications with OCPP commands PDU validation against [OCA](https://www.openchargealliance.org/) JSON schemas                                                                  |
 | ocppPersistentConfiguration                          | true/false    | true                                                                                                                               | boolean                                                                                                                                                                       | enable persistent OCPP parameters storage by charging stations 'hashId'. The persistency is ensured by the charging stations configuration files in [dist/assets/configurations](dist/assets/configurations)                               |
 | stationInfoPersistentConfiguration                   | true/false    | true                                                                                                                               | boolean                                                                                                                                                                       | enable persistent station information and specifications storage by charging stations 'hashId'. The persistency is ensured by the charging stations configuration files in [dist/assets/configurations](dist/assets/configurations)        |
 | automaticTransactionGeneratorPersistentConfiguration | true/false    | true                                                                                                                               | boolean                                                                                                                                                                       | enable persistent automatic transaction generator configuration storage by charging stations 'hashId'. The persistency is ensured by the charging stations configuration files in [dist/assets/configurations](dist/assets/configurations) |
@@ -498,18 +499,15 @@ All kind of OCPP parameters are supported in charging station configuration or c
 
 ## UI protocol
 
-Protocol to control the simulator via a Websocket or HTTP server.
+Protocol to control the simulator via a Websocket or HTTP server:
 
 ```mermaid
 sequenceDiagram
 Client->>UI Server: request
 UI Server->>Client: response
+Note over UI Server,Client: Transport protocol: HTTP, Websocket
 ```
 
-### HTTP Protocol
-
-To learn how to use the HTTP protocol to pilot the simulator, an [Insomnia](https://insomnia.rest/) HTTP requests collection is available in [src/assets/ui-protocol](./src/assets/ui-protocol) directory.
-
 ### Websocket Protocol
 
 SRPC protocol over Websocket. PDU stands for 'Protocol Data Unit'.
@@ -525,7 +523,7 @@ SRPC protocol over Websocket. PDU stands for 'Protocol Data Unit'.
   `uuid`: String uniquely linking the response to the request  
   `PDU`: Response parameters to requested procedure
 
-An [Insomnia](https://insomnia.rest/) WebSocket requests collection is available in [src/assets/ui-protocol](./src/assets/ui-protocol) directory.
+To learn how to use the Websocket protocol to pilot the simulator, an [Insomnia](https://insomnia.rest/) Websocket requests collection is available in [src/assets/ui-protocol](./src/assets/ui-protocol) directory.
 
 #### Version 0.0.1
 
@@ -541,7 +539,7 @@ Set the Websocket header _Sec-Websocket-Protocol_ to `ui0.0.1`.
 
 - Response:  
   `PDU`: {  
-  `status`: 'success' | 'failure'  
+   `status`: 'success' | 'failure'  
   }
 
 ###### Stop Simulator
@@ -552,7 +550,88 @@ Set the Websocket header _Sec-Websocket-Protocol_ to `ui0.0.1`.
 
 - Response:  
   `PDU`: {  
-  `status`: 'success' | 'failure'  
+   `status`: 'success' | 'failure'  
+  }
+
+###### List Charging Station Templates
+
+- Request:  
+  `ProcedureName`: 'listTemplates'  
+  `PDU`: {}
+
+- Response:  
+  `PDU`: {  
+   `status`: 'success' | 'failure',  
+   `templates`: string[]  
+  }
+
+###### Add Charging Stations
+
+- Request:  
+  `ProcedureName`: 'addChargingStations'  
+  `PDU`: {  
+   `template`: string,  
+   `numberOfStations`: number,  
+   `options?`: {  
+   `supervisionUrls`: string | string[],  
+   `persistentConfiguration?`: boolean,  
+   `autoStart?`: boolean,  
+   `autoRegister?`: boolean,  
+   `enableStatistics?`: boolean,  
+   `ocppStrictCompliance?`: boolean,  
+   `stopTransactionsOnStopped?`: boolean  
+   }  
+  }
+
+- Response:  
+  `PDU`: {  
+   `status`: 'success' | 'failure'  
+  }
+
+###### Delete Charging Stations
+
+- Request:  
+  `ProcedureName`: 'deleteChargingStations'  
+  `PDU`: {  
+   `hashIds`: charging station unique identifier strings array (optional, default: all charging stations),  
+   `deleteConfiguration?`: boolean  
+  }
+
+- Response:  
+  `PDU`: {  
+   `status`: 'success' | 'failure',  
+   `hashIdsSucceeded`: charging station unique identifier strings array,  
+   `hashIdsFailed`: charging station unique identifier strings array (optional),  
+   `responsesFailed`: failed responses payload array (optional)  
+  }
+
+###### Set Charging Station Supervision Url
+
+- Request:  
+  `ProcedureName`: 'setSupervisionUrl'  
+  `PDU`: {  
+   `hashIds`: charging station unique identifier strings array (optional, default: all charging stations),  
+   `url`: string  
+  }
+
+- Response:  
+  `PDU`: {  
+   `status`: 'success' | 'failure',  
+   `hashIdsSucceeded`: charging station unique identifier strings array,  
+   `hashIdsFailed`: charging station unique identifier strings array (optional),  
+   `responsesFailed`: failed responses payload array (optional)  
+  }
+
+###### Performance Statistics
+
+- Request:  
+  `ProcedureName`: 'performanceStatistics'  
+  `PDU`: {}
+
+- Response:  
+  `PDU`: {  
+   `status`: 'success' | 'failure'  
+   `performanceStatistics`: Statistics[]  
   }
 
 ###### List Charging Stations
@@ -563,8 +642,8 @@ Set the Websocket header _Sec-Websocket-Protocol_ to `ui0.0.1`.
 
 - Response:  
   `PDU`: {  
-  `status`: 'success' | 'failure',  
-  `chargingStations`: ChargingStationData[]  
+   `status`: 'success' | 'failure',  
+   `chargingStations`: ChargingStationData[]  
   }
 
 ###### Start Charging Station
@@ -572,15 +651,15 @@ Set the Websocket header _Sec-Websocket-Protocol_ to `ui0.0.1`.
 - Request:  
   `ProcedureName`: 'startChargingStation'  
   `PDU`: {  
-  `hashIds`: charging station unique identifier strings array (optional, default: all charging stations)  
+   `hashIds`: charging station unique identifier strings array (optional, default: all charging stations)  
   }
 
 - Response:  
   `PDU`: {  
-  `status`: 'success' | 'failure',  
-  `hashIdsSucceeded`: charging station unique identifier strings array,  
-  `hashIdsFailed`: charging station unique identifier strings array (optional)  
-  `responsesFailed`: failed responses payload array (optional)  
+   `status`: 'success' | 'failure',  
+   `hashIdsSucceeded`: charging station unique identifier strings array,  
+   `hashIdsFailed`: charging station unique identifier strings array (optional),  
+   `responsesFailed`: failed responses payload array (optional)  
   }
 
 ###### Stop Charging Station
@@ -588,15 +667,15 @@ Set the Websocket header _Sec-Websocket-Protocol_ to `ui0.0.1`.
 - Request:  
   `ProcedureName`: 'stopChargingStation'  
   `PDU`: {  
-  `hashIds`: charging station unique identifier strings array (optional, default: all charging stations)  
+   `hashIds`: charging station unique identifier strings array (optional, default: all charging stations)  
   }
 
 - Response:  
   `PDU`: {  
-  `status`: 'success' | 'failure',  
-  `hashIdsSucceeded`: charging station unique identifier strings array,  
-  `hashIdsFailed`: charging station unique identifier strings array (optional),  
-  `responsesFailed`: failed responses payload array (optional)  
+   `status`: 'success' | 'failure',  
+   `hashIdsSucceeded`: charging station unique identifier strings array,  
+   `hashIdsFailed`: charging station unique identifier strings array (optional),  
+   `responsesFailed`: failed responses payload array (optional)  
   }
 
 ###### Open Connection
@@ -604,15 +683,15 @@ Set the Websocket header _Sec-Websocket-Protocol_ to `ui0.0.1`.
 - Request:  
   `ProcedureName`: 'openConnection'  
   `PDU`: {  
-  `hashIds`: charging station unique identifier strings array (optional, default: all charging stations)  
+   `hashIds`: charging station unique identifier strings array (optional, default: all charging stations)  
   }
 
 - Response:  
   `PDU`: {  
-  `status`: 'success' | 'failure',  
-  `hashIdsSucceeded`: charging station unique identifier strings array,  
-  `hashIdsFailed`: charging station unique identifier strings array (optional),  
-  `responsesFailed`: failed responses payload array (optional)  
+   `status`: 'success' | 'failure',  
+   `hashIdsSucceeded`: charging station unique identifier strings array,  
+   `hashIdsFailed`: charging station unique identifier strings array (optional),  
+   `responsesFailed`: failed responses payload array (optional)  
   }
 
 ###### Close Connection
@@ -620,15 +699,15 @@ Set the Websocket header _Sec-Websocket-Protocol_ to `ui0.0.1`.
 - Request:  
   `ProcedureName`: 'closeConnection'  
   `PDU`: {  
-  `hashIds`: charging station unique identifier strings array (optional, default: all charging stations)  
+   `hashIds`: charging station unique identifier strings array (optional, default: all charging stations)  
   }
 
 - Response:  
   `PDU`: {  
-  `status`: 'success' | 'failure',  
-  `hashIdsSucceeded`: charging station unique identifier strings array,  
-  `hashIdsFailed`: charging station unique identifier strings array (optional),  
-  `responsesFailed`: failed responses payload array (optional)  
+   `status`: 'success' | 'failure',  
+   `hashIdsSucceeded`: charging station unique identifier strings array,  
+   `hashIdsFailed`: charging station unique identifier strings array (optional),  
+   `responsesFailed`: failed responses payload array (optional)  
   }
 
 ###### Start Automatic Transaction Generator
@@ -636,16 +715,16 @@ Set the Websocket header _Sec-Websocket-Protocol_ to `ui0.0.1`.
 - Request:  
   `ProcedureName`: 'startAutomaticTransactionGenerator'  
   `PDU`: {  
-  `hashIds`: charging station unique identifier strings array (optional, default: all charging stations),  
-  `connectorIds`: connector id integer array (optional, default: all connectors)  
+   `hashIds`: charging station unique identifier strings array (optional, default: all charging stations),  
+   `connectorIds`: connector id integer array (optional, default: all connectors)  
   }
 
 - Response:  
   `PDU`: {  
-  `status`: 'success' | 'failure',  
-  `hashIdsSucceeded`: charging station unique identifier strings array,  
-  `hashIdsFailed`: charging station unique identifier strings array (optional),  
-  `responsesFailed`: failed responses payload array (optional)  
+   `status`: 'success' | 'failure',  
+   `hashIdsSucceeded`: charging station unique identifier strings array,  
+   `hashIdsFailed`: charging station unique identifier strings array (optional),  
+   `responsesFailed`: failed responses payload array (optional)  
   }
 
 ###### Stop Automatic Transaction Generator
@@ -653,16 +732,16 @@ Set the Websocket header _Sec-Websocket-Protocol_ to `ui0.0.1`.
 - Request:  
   `ProcedureName`: 'stopAutomaticTransactionGenerator'  
   `PDU`: {  
-  `hashIds`: charging station unique identifier strings array (optional, default: all charging stations),  
-  `connectorIds`: connector id integer array (optional, default: all connectors)  
+   `hashIds`: charging station unique identifier strings array (optional, default: all charging stations),  
+   `connectorIds`: connector id integer array (optional, default: all connectors)  
   }
 
 - Response:  
   `PDU`: {  
-  `status`: 'success' | 'failure',  
-  `hashIdsSucceeded`: charging station unique identifier strings array,  
-  `hashIdsFailed`: charging station unique identifier strings array (optional),  
-  `responsesFailed`: failed responses payload array (optional)  
+   `status`: 'success' | 'failure',  
+   `hashIdsSucceeded`: charging station unique identifier strings array,  
+   `hashIdsFailed`: charging station unique identifier strings array (optional),  
+   `responsesFailed`: failed responses payload array (optional)  
   }
 
 ###### OCPP commands trigger
@@ -672,15 +751,15 @@ Set the Websocket header _Sec-Websocket-Protocol_ to `ui0.0.1`.
   `PDU`: {  
    `hashIds`: charging station unique identifier strings array (optional, default: all charging stations),  
    ...`commandPayload`  
-   } (the OCPP command payload with some optional fields added to target the simulated charging stations)
+  } (the OCPP command payload with some optional fields added to target the simulated charging stations)
 
 - Response:  
-   `PDU`: {  
+  `PDU`: {  
    `status`: 'success' | 'failure',  
    `hashIdsSucceeded`: charging station unique identifier strings array,  
    `hashIdsFailed`: charging station unique identifier strings array (optional),  
    `responsesFailed`: failed responses payload array (optional)  
-   }
+  }
 
 Examples:
 
@@ -689,17 +768,17 @@ Examples:
   - Request:  
     `ProcedureName`: 'startTransaction'  
     `PDU`: {  
-    `hashIds`: charging station unique identifier strings array (optional, default: all charging stations),  
-    `connectorId`: connector id integer,  
-    `idTag`: RFID tag string  
+     `hashIds`: charging station unique identifier strings array (optional, default: all charging stations),  
+     `connectorId`: connector id integer,  
+     `idTag`: RFID tag string  
     }
 
   - Response:  
     `PDU`: {  
-    `status`: 'success' | 'failure',  
-    `hashIdsSucceeded`: charging station unique identifier strings array,  
-    `hashIdsFailed`: charging station unique identifier strings array (optional),  
-    `responsesFailed`: failed responses payload array (optional)  
+     `status`: 'success' | 'failure',  
+     `hashIdsSucceeded`: charging station unique identifier strings array,  
+     `hashIdsFailed`: charging station unique identifier strings array (optional),  
+     `responsesFailed`: failed responses payload array (optional)  
     }
 
 - **Stop Transaction**
@@ -707,16 +786,16 @@ Examples:
   - Request:  
     `ProcedureName`: 'stopTransaction'  
     `PDU`: {  
-    `hashIds`: charging station unique identifier strings array (optional, default: all charging stations),  
-    `transactionId`: transaction id integer  
+     `hashIds`: charging station unique identifier strings array (optional, default: all charging stations),  
+     `transactionId`: transaction id integer  
     }
 
   - Response:  
     `PDU`: {  
-    `status`: 'success' | 'failure',  
-    `hashIdsSucceeded`: charging station unique identifier strings array,  
-    `hashIdsFailed`: charging station unique identifier strings array (optional),  
-    `responsesFailed`: failed responses payload array (optional)  
+     `status`: 'success' | 'failure',  
+     `hashIdsSucceeded`: charging station unique identifier strings array,  
+     `hashIdsFailed`: charging station unique identifier strings array (optional),  
+     `responsesFailed`: failed responses payload array (optional)  
     }
 
 - **Status Notification**
@@ -724,18 +803,18 @@ Examples:
   - Request:  
     `ProcedureName`: 'statusNotification'  
     `PDU`: {  
-    `hashIds`: charging station unique identifier strings array (optional, default: all charging stations),  
-    `connectorId`: connector id integer,  
-    `errorCode`: connector error code,  
-    `status`: connector status  
+     `hashIds`: charging station unique identifier strings array (optional, default: all charging stations),  
+     `connectorId`: connector id integer,  
+     `errorCode`: connector error code,  
+     `status`: connector status  
     }
 
   - Response:  
     `PDU`: {  
-    `status`: 'success' | 'failure',  
-    `hashIdsSucceeded`: charging station unique identifier strings array,  
-    `hashIdsFailed`: charging station unique identifier strings array (optional),  
-    `responsesFailed`: failed responses payload array (optional)  
+     `status`: 'success' | 'failure',  
+     `hashIdsSucceeded`: charging station unique identifier strings array,  
+     `hashIdsFailed`: charging station unique identifier strings array (optional),  
+     `responsesFailed`: failed responses payload array (optional)  
     }
 
 - **Heartbeat**
@@ -743,17 +822,21 @@ Examples:
   - Request:  
     `ProcedureName`: 'heartbeat'  
     `PDU`: {  
-    `hashIds`: charging station unique identifier strings array (optional, default: all charging stations),  
+     `hashIds`: charging station unique identifier strings array (optional, default: all charging stations),  
     }
 
   - Response:  
     `PDU`: {  
-    `status`: 'success' | 'failure',  
-    `hashIdsSucceeded`: charging station unique identifier strings array,  
-    `hashIdsFailed`: charging station unique identifier strings array (optional),  
-    `responsesFailed`: failed responses payload array (optional)  
+     `status`: 'success' | 'failure',  
+     `hashIdsSucceeded`: charging station unique identifier strings array,  
+     `hashIdsFailed`: charging station unique identifier strings array (optional),  
+     `responsesFailed`: failed responses payload array (optional)  
     }
 
+### HTTP Protocol
+
+To learn how to use the HTTP protocol to pilot the simulator, an [Insomnia](https://insomnia.rest/) HTTP requests collection is available in [src/assets/ui-protocol](./src/assets/ui-protocol) directory.
+
 ## Support, Feedback, Contributing
 
 This project is open to feature requests/suggestions, bug reports etc. via [GitHub issues](https://github.com/SAP/e-mobility-charging-stations-simulator/issues). Contribution and feedback are encouraged and always welcome. For more information about how to contribute, the project structure, as well as additional contribution information, see our [Contribution Guidelines](CONTRIBUTING.md).