├── .gitignore ├── .gitpmoji.env ├── prepare-commit-msg.sh ├── README.md ├── install.sh ├── LICENSE └── gpt.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # generic gitignore for mac 2 | .DS_Store 3 | #some test folders 4 | test/ 5 | test2/ 6 | test3/ 7 | 8 | # ignore gitpmoji directory 9 | .gitpmoji 10 | -------------------------------------------------------------------------------- /.gitpmoji.env: -------------------------------------------------------------------------------- 1 | # Your api key you can get one here https://platform.openai.com/account/api-keys 2 | #export GITPMOJI_API_KEY="sk-put-your-open-ai-api-key-here" 3 | # Regex for sed command. emoji will be placed after it if found 4 | #export GITPMOJI_PREFIX_RX="TICKET-[0-9]\{1,5\}:\{0,1\}" 5 | export GITPMOJI_API_BASE_URL="https://api.openai.com/v1" 6 | export GITPMOJI_API_MODEL="gpt-4o" 7 | -------------------------------------------------------------------------------- /prepare-commit-msg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The first argument is the path to the commit message file. 4 | COMMIT_MSG_FILE=$1 5 | COMMIT_SOURCE=$2 6 | 7 | # Skip the hook if this is a rebase or merge commit 8 | if [ "$COMMIT_SOURCE" = "rebase" ] || [ -d "$(git rev-parse --git-dir)/rebase-merge" ] || [ -d "$(git rev-parse --git-dir)/rebase-apply" ]; then 9 | exit 0 10 | fi 11 | 12 | COMMIT_MSG=$(cat $COMMIT_MSG_FILE) 13 | RESULT=$COMMIT_MSG 14 | 15 | # Get the directory of the script, resolving symlinks 16 | SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" 17 | 18 | EXTRA_ARGS="" 19 | 20 | # Check if commit message ends with * 21 | if [[ $COMMIT_MSG == *\* ]]; then 22 | echo "The commit message ends with '*' Rating will be added." 23 | COMMIT_MSG="${COMMIT_MSG%\*}" 24 | EXTRA_ARGS="-a -r" 25 | fi 26 | 27 | # Check if commit message ends with ~~~ / ~~ / ~ 28 | if [[ $COMMIT_MSG == *~~~ ]]; then 29 | echo "The commit message ends with '~~~' It will be replaced by AI. Emoji will be added." 30 | COMMIT_MSG="${COMMIT_MSG%~~~}" 31 | RESULT=$(git diff --cached | "$SCRIPT_DIR/gpt.sh" -d -g -e $EXTRA_ARGS -m "$COMMIT_MSG") 32 | elif [[ $COMMIT_MSG == *~~ ]]; then 33 | echo "The commit message ends with '~~' It will be replaced by AI. Emoji will not be added." 34 | COMMIT_MSG="${COMMIT_MSG%~~}" 35 | RESULT=$(git diff --cached | "$SCRIPT_DIR/gpt.sh" -d -g $EXTRA_ARGS -m "$COMMIT_MSG") 36 | elif [[ $COMMIT_MSG == *~ ]]; then 37 | echo "The commit message ends with '~'. Only Emoji will be added by AI." 38 | COMMIT_MSG="${COMMIT_MSG%\~}" 39 | RESULT=$(git diff --cached | "$SCRIPT_DIR/gpt.sh" -d -e $EXTRA_ARGS -m "$COMMIT_MSG") 40 | else 41 | if [ -z "$EXTRA_ARGS" ]; then 42 | echo "The commit message does not end with '~', '~~', or '~~~'. Nothing to do." 43 | else 44 | echo "The commit message does not end with '*' Only rating will be added." 45 | RESULT=$(git diff --cached | "$SCRIPT_DIR/gpt.sh" -d $EXTRA_ARGS -m "$COMMIT_MSG") 46 | fi 47 | fi 48 | 49 | # Check if the previous command was successful 50 | if [ $? -ne 0 ]; then 51 | echo "Error: Failed to run gpt.sh" 52 | echo "$RESULT" 53 | exit 1 54 | fi 55 | 56 | echo "$RESULT" 57 | 58 | # Overwrite the commit message file with the result 59 | echo -e "${RESULT}" > $COMMIT_MSG_FILE 60 | 61 | exit 0 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GITPMOJI 2 | ======== 3 | 4 | Enhanced Git commits using AI 5 | ----------------------------- 6 | 7 | GITPMOJI is a powerful AI-driven tool designed to enhance your Git workflow. It offers several key features: 8 | 9 | 1. Commit Message Generation: Analyzes your code changes (diff) and generates comprehensive commit messages, providing detailed context for each commit. 10 | 11 | 2. Code Change Evaluation: Assesses the impact and quality of your code changes, offering insights into the modifications made. 12 | 13 | 3. Emoji Decoration: Automatically adds relevant emojis to your commits, providing visual cues that make it easier to understand the nature of each change at a glance. 14 | 15 | This multi-functional approach transforms your commit history into a more informative, insightful, and visually appealing log of your project's development. By leveraging AI to generate, evaluate, and decorate your commits, GITPMOJI helps maintain a clear and meaningful record of your project's evolution. 16 | 17 | ## How It Works 18 | 19 | 1. When you make a commit, GITPMOJI intercepts the commit message using a Git hook. So it works with all git clients and IDEs that use git hooks. 20 | 2. The commit message and diff are sent to a custom script (`gpt.sh`) that communicates with the OpenAI API. 21 | 3. The API, using the GPT-4o model, analyzes the commit message and the diff and updates the commit message. 22 | 4. The suggested emoji is prepended to your original commit message. 23 | 5. The AI generates a commit message based on the diff changes added to at the end of the original commit message. 24 | 6. Rating of the commit message is added to the end of the commit message. 25 | 7. The process respects any existing prefix in your commit messages, as defined by the GITPMOJI_PREFIX_RX environment variable. 26 | 27 | This process happens seamlessly, requiring no additional action from the user after initial setup. 28 | 29 | ## How to use 30 | 31 | 1. add ~ to the end of your commit message to let AI update the commit message and add the emoji to it 32 | 2. add ~~ to the end of your commit message to let AI update the commit message based on the diff 33 | 3. add ~~~ to the end of your commit message to let AI for both update the commit message and add the emoji 34 | 4. add * as the last character of your commit message to let AI add the rating to the end of the commit message 35 | 5. use composition like ~~~* or ~~* or ~* to let AI update the commit accordingly 36 | 37 | ## Assessing Code Changes 38 | 39 | GITPMOJI also provides a feature to assess the quality of your code changes. You can use the `./gpt -a` command to evaluate the impact and quality of your code modifications. This command analyzes the git diff and provides a detailed assessment based on several factors such as code cleanliness, structure, readability, complexity, and overall code quality. 40 | 41 | To use this feature, simply run: 42 | ``` 43 | git diff | ./gpt.sh -a -d 44 | ``` 45 | ![Screenshot 2024-10-31 at 13 34 00](https://github.com/user-attachments/assets/7c190fd8-cfc3-4302-b44c-6cfd16a95329) 46 | 47 | 48 | 49 | ## Setup as one liner wizard 50 | 51 | Navigate to your project directory and run: 52 | ``` 53 | curl -o install.sh https://raw.githubusercontent.com/Fl0p/gitpmoji/main/install.sh && bash install.sh && rm install.sh 54 | ``` 55 | and follow the instructions. 56 | 57 | ### Installation Options 58 | 59 | The installer will prompt you to choose where to install gitpmoji: 60 | - **Default (`.gitpmoji`)**: Press Enter to install in a hidden `.gitpmoji` directory (recommended, automatically added to `.gitignore`) 61 | - **Project root**: Enter `.` to install scripts directly in your project root 62 | 63 | ### Global Configuration Support 64 | 65 | The installer now supports global configuration: 66 | - Create `~/.gitpmoji.env` to store your API key and settings globally 67 | - During installation, you can choose to use global settings or override them locally 68 | - Local `.gitpmoji.env` will source global config and can override specific values 69 | 70 | ## Setup manually 71 | 72 | - install jq 73 | ``` 74 | brew install jq 75 | ``` 76 | or 77 | ``` 78 | apt-get install jq 79 | ``` 80 | 81 | - download `prepare-commit-msg.sh` and `gpt.sh` 82 | 83 | - Create `.gitpmoji.env` file in your project root or globally at `~/.gitpmoji.env`: 84 | 85 | ```bash 86 | # Your api key you can get one here https://platform.openai.com/account/api-keys 87 | export GITPMOJI_API_KEY="your_openai_api_key" 88 | export GITPMOJI_API_BASE_URL="https://api.openai.com/v1" 89 | export GITPMOJI_API_MODEL="gpt-4o" 90 | # Regex for sed command. emoji will be placed after it if found 91 | export GITPMOJI_PREFIX_RX="TICKET-[0-9]\{1,5\} \{0,1\}" 92 | ``` 93 | 94 | > ❗ Note: 95 | > - GITPMOJI_API_BASE_URL is optional and defaults to https://api.openai.com/v1 96 | > - GITPMOJI_API_MODEL is optional and defaults to gpt-4o 97 | > - Local `.gitpmoji.env` can source global `~/.gitpmoji.env` and override specific values 98 | 99 | - make sure to have `prepare-commit-msg.sh` and `gpt.sh` executable 100 | 101 | - create symlink in `.git/hooks/`: 102 | ```bash 103 | ln -sf ../../.gitpmoji/prepare-commit-msg.sh .git/hooks/prepare-commit-msg 104 | ``` 105 | or if installed in project root: 106 | ```bash 107 | ln -sf ../../prepare-commit-msg.sh .git/hooks/prepare-commit-msg 108 | ``` 109 | 110 | ## Usage 111 | 112 | Simply write your commit messages as usual. GITPMOJI will automatically add relevant emojis to your commits. 113 | 114 | ## Examples 115 | 116 | Check out the [commit messages](https://github.com/Fl0p/gitpmoji/commits/main/) in this repo 117 | 118 | ![Screenshot 2024-08-22 at 11 43 32](https://github.com/user-attachments/assets/f69ff571-e304-41c1-baec-7d53219bd756) 119 | 120 | ``` 121 | 🩹️ typos fix. fix tilda removing~ 122 | 📝 Update README.md to provide a more comprehensive description of GITPMOJI features 123 | 🩹 fix emoji placement 124 | ⚰️ Remove redundant echo 125 | ♻️ Update with commit message generation 126 | 🔧 Add Prefix support and .env file 127 | ➕ Add some predefined Emojis 128 | 🛠️ Refacroring GPT script 129 | ``` 130 | 131 | ## Contributing 132 | 133 | (Add contribution guidelines here) 134 | 135 | ## License 136 | 137 | [LICENSE](LICENSE) 138 | 139 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #script for installing gitpmoji. oneliner 4 | # to run it as one liner you can use this command: 5 | # curl -s https://raw.githubusercontent.com/Fl0p/gitpmoji/main/install.sh | bash 6 | 7 | CURRENT_DIR=$(pwd) 8 | 9 | #check if jq is installed 10 | if ! command -v jq &> /dev/null 11 | then 12 | echo "jq could not be found, installing it" 13 | brew install jq 14 | fi 15 | 16 | echo "Current dir: $CURRENT_DIR" 17 | 18 | TOP_LEVEL_GIT_DIR=$(git rev-parse --show-toplevel 2>/dev/null || echo ".") 19 | 20 | echo "Top level project dir: $TOP_LEVEL_GIT_DIR" 21 | ls -la $TOP_LEVEL_GIT_DIR 22 | 23 | echo "Enter dir name where gitpmoji scripts will be installed." 24 | echo "Just press enter for default '.gitpmoji' or use '.' to install in project root" 25 | read -p "GITPMOJI_DIR=" GITPMOJI_DIR 26 | 27 | if [ -z "$GITPMOJI_DIR" ]; then 28 | GITPMOJI_DIR=".gitpmoji" 29 | fi 30 | 31 | if [ "$GITPMOJI_DIR" = "." ]; then 32 | GITPMOJI_INSTALL_DIR="$TOP_LEVEL_GIT_DIR" 33 | echo "gitpmoji will be installed in project root: $GITPMOJI_INSTALL_DIR" 34 | else 35 | GITPMOJI_INSTALL_DIR="$TOP_LEVEL_GIT_DIR/$GITPMOJI_DIR" 36 | echo "gitpmoji will be installed in $GITPMOJI_INSTALL_DIR" 37 | mkdir -p $GITPMOJI_INSTALL_DIR 38 | fi 39 | cd $GITPMOJI_INSTALL_DIR 40 | pwd 41 | 42 | #download from github 43 | curl -o prepare-commit-msg.sh https://raw.githubusercontent.com/Fl0p/gitpmoji/main/prepare-commit-msg.sh 44 | curl -o gpt.sh https://raw.githubusercontent.com/Fl0p/gitpmoji/main/gpt.sh 45 | 46 | #make executable 47 | chmod +x prepare-commit-msg.sh 48 | chmod +x gpt.sh 49 | 50 | echo "Do you want to add '$GITPMOJI_DIR' directory to gitignore? (y/n)" 51 | read GITPMOJI_ADD_TO_GITIGNORE 52 | 53 | if [ "$GITPMOJI_ADD_TO_GITIGNORE" = "y" ]; then 54 | echo "" >> $TOP_LEVEL_GIT_DIR/.gitignore 55 | echo "# ignore gitpmoji directory" >> $TOP_LEVEL_GIT_DIR/.gitignore 56 | echo "$GITPMOJI_DIR" >> $TOP_LEVEL_GIT_DIR/.gitignore 57 | fi 58 | 59 | #check if .gitpmoji.env exists 60 | if [ -f .gitpmoji.env ]; then 61 | echo "$GITPMOJI_DIR/.gitpmoji.env already exists, skipping setup environment variables" 62 | echo "--- start of .gitpmoji.env ---" 63 | cat .gitpmoji.env 64 | echo "--- end of .gitpmoji.env ---" 65 | else 66 | echo "Creating .gitpmoji.env file..." 67 | 68 | # Create file with header comment 69 | cat << 'EOF' > .gitpmoji.env 70 | # gitpmoji environment configuration file 71 | # This file contains environment variables for gitpmoji 72 | # You can also create a global config file at ~/.gitpmoji.env 73 | # Local settings in this file will override global settings from ~/.gitpmoji.env 74 | 75 | EOF 76 | 77 | # Source global config if exists 78 | echo "# Source global config if exists" >> .gitpmoji.env 79 | echo "if [ -f ~/.gitpmoji.env ]; then" >> .gitpmoji.env 80 | echo " source ~/.gitpmoji.env" >> .gitpmoji.env 81 | echo "fi" >> .gitpmoji.env 82 | echo "" >> .gitpmoji.env 83 | 84 | # Load global config to check for existing variables 85 | if [ -f ~/.gitpmoji.env ]; then 86 | source ~/.gitpmoji.env 87 | echo "Found global config at ~/.gitpmoji.env" 88 | fi 89 | 90 | # Process GITPMOJI_API_KEY 91 | if [ -n "$GITPMOJI_API_KEY" ]; then 92 | echo "Global GITPMOJI_API_KEY found" 93 | echo "Use global GITPMOJI_API_KEY? (y/n)" 94 | read USE_GLOBAL_API_KEY 95 | if [ "$USE_GLOBAL_API_KEY" = "y" ]; then 96 | echo "#export GITPMOJI_API_KEY=\"_your_api_key_\"" >> .gitpmoji.env 97 | else 98 | echo "Enter your OpenAI API key (https://platform.openai.com/account/api-keys):" 99 | read -p "GITPMOJI_API_KEY=" api_key 100 | echo "export GITPMOJI_API_KEY=\"$api_key\"" >> .gitpmoji.env 101 | fi 102 | else 103 | echo "Enter your OpenAI API key (https://platform.openai.com/account/api-keys):" 104 | read -p "GITPMOJI_API_KEY=" api_key 105 | echo "export GITPMOJI_API_KEY=\"$api_key\"" >> .gitpmoji.env 106 | fi 107 | 108 | # Process GITPMOJI_API_BASE_URL 109 | if [ -n "$GITPMOJI_API_BASE_URL" ]; then 110 | echo "Global GITPMOJI_API_BASE_URL found: $GITPMOJI_API_BASE_URL" 111 | echo "Use global GITPMOJI_API_BASE_URL? (y/n)" 112 | read USE_GLOBAL_BASE_URL 113 | if [ "$USE_GLOBAL_BASE_URL" = "y" ]; then 114 | echo "#export GITPMOJI_API_BASE_URL=\"https://api.openai.com/v1\"" >> .gitpmoji.env 115 | else 116 | echo "Enter base url for OpenAI API (leave empty for default 'https://api.openai.com/v1')" 117 | read -p "GITPMOJI_API_BASE_URL=" base_url 118 | if [ -z "$base_url" ]; then 119 | base_url="https://api.openai.com/v1" 120 | fi 121 | echo "export GITPMOJI_API_BASE_URL=\"$base_url\"" >> .gitpmoji.env 122 | fi 123 | else 124 | echo "Enter base url for OpenAI API (leave empty for default 'https://api.openai.com/v1')" 125 | read -p "GITPMOJI_API_BASE_URL=" base_url 126 | if [ -z "$base_url" ]; then 127 | base_url="https://api.openai.com/v1" 128 | fi 129 | echo "export GITPMOJI_API_BASE_URL=\"$base_url\"" >> .gitpmoji.env 130 | fi 131 | 132 | # Process GITPMOJI_API_MODEL 133 | if [ -n "$GITPMOJI_API_MODEL" ]; then 134 | echo "Global GITPMOJI_API_MODEL found: $GITPMOJI_API_MODEL" 135 | echo "Use global GITPMOJI_API_MODEL? (y/n)" 136 | read USE_GLOBAL_MODEL 137 | if [ "$USE_GLOBAL_MODEL" = "y" ]; then 138 | echo "#export GITPMOJI_API_MODEL=\"gpt-4o\"" >> .gitpmoji.env 139 | else 140 | echo "Enter model for OpenAI API (leave empty for default 'gpt-4o')" 141 | read -p "GITPMOJI_API_MODEL=" model 142 | if [ -z "$model" ]; then 143 | model="gpt-4o" 144 | fi 145 | echo "export GITPMOJI_API_MODEL=\"$model\"" >> .gitpmoji.env 146 | fi 147 | else 148 | echo "Enter model for OpenAI API (leave empty for default 'gpt-4o')" 149 | read -p "GITPMOJI_API_MODEL=" model 150 | if [ -z "$model" ]; then 151 | model="gpt-4o" 152 | fi 153 | echo "export GITPMOJI_API_MODEL=\"$model\"" >> .gitpmoji.env 154 | fi 155 | 156 | # Process GITPMOJI_PREFIX_RX 157 | if [ -n "$GITPMOJI_PREFIX_RX" ]; then 158 | echo "Global GITPMOJI_PREFIX_RX found: $GITPMOJI_PREFIX_RX" 159 | echo "Use global GITPMOJI_PREFIX_RX? (y/n)" 160 | read USE_GLOBAL_PREFIX 161 | if [ "$USE_GLOBAL_PREFIX" = "y" ]; then 162 | echo "#export GITPMOJI_PREFIX_RX=\"\"" >> .gitpmoji.env 163 | else 164 | echo "Enter prefix for commit messages which will be untouched as first keyword for each message" 165 | echo "In format of sed RegExp use double backslash (\\\\) for escaping special symbols like {, }, ?, etc." 166 | read -p "GITPMOJI_PREFIX_RX=" prefix 167 | echo "export GITPMOJI_PREFIX_RX=\"$prefix\"" >> .gitpmoji.env 168 | fi 169 | else 170 | echo "Enter prefix for commit messages which will be untouched as first keyword for each message" 171 | echo "In format of sed RegExp use double backslash (\\\\) for escaping special symbols like {, }, ?, etc." 172 | read -p "GITPMOJI_PREFIX_RX=" prefix 173 | echo "export GITPMOJI_PREFIX_RX=\"$prefix\"" >> .gitpmoji.env 174 | fi 175 | 176 | echo ".gitpmoji.env created successfully" 177 | echo "--- start of .gitpmoji.env ---" 178 | cat .gitpmoji.env 179 | echo "--- end of .gitpmoji.env ---" 180 | fi 181 | 182 | if [ "$GITPMOJI_ADD_TO_GITIGNORE" != "y" ]; then 183 | echo -e "\033[0;31m Do you want to add environment file '$GITPMOJI_DIR/.gitpmoji.env' to .gitignore to keep your API key secret? (y/n)\033[0m" 184 | read GITPMOJI_ADD_ENV_TO_GITIGNORE 185 | if [ "$GITPMOJI_ADD_ENV_TO_GITIGNORE" = "y" ]; then 186 | echo "" >> $TOP_LEVEL_GIT_DIR/.gitignore 187 | echo "# ignore environment file for gitpmoji" >> $TOP_LEVEL_GIT_DIR/.gitignore 188 | echo "$GITPMOJI_DIR/.gitpmoji.env" >> $TOP_LEVEL_GIT_DIR/.gitignore 189 | fi 190 | fi 191 | 192 | cd $TOP_LEVEL_GIT_DIR 193 | 194 | echo "Gitpmoji files installed in: $GITPMOJI_INSTALL_DIR" 195 | 196 | 197 | HOOKS_DIR="$TOP_LEVEL_GIT_DIR/.git/hooks" 198 | echo "git hooks dir: $HOOKS_DIR" 199 | 200 | echo "Going to install git hook for prepare-commit-msg" 201 | 202 | cd $HOOKS_DIR 203 | 204 | # Simple relative path: from .git/hooks go up twice (../../) then into GITPMOJI_DIR 205 | if [ "$GITPMOJI_DIR" = "." ]; then 206 | SYMLINK_PATH="../../prepare-commit-msg.sh" 207 | else 208 | SYMLINK_PATH="../../$GITPMOJI_DIR/prepare-commit-msg.sh" 209 | fi 210 | 211 | echo "Creating symlink for prepare-commit-msg" 212 | echo "ln -sf $SYMLINK_PATH prepare-commit-msg" 213 | 214 | ln -sf $SYMLINK_PATH prepare-commit-msg 215 | 216 | cd $TOP_LEVEL_GIT_DIR 217 | 218 | echo "Git hooks successfully installed" 219 | echo "You can now commit with gitpmoji. 🚀" 220 | echo "To uninstall just remove $HOOKS_DIR/prepare-commit-msg and $GITPMOJI_INSTALL_DIR" 221 | 222 | exit 0 223 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /gpt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #bash script to run gpt-4o 4 | 5 | #cd to the directory of the script 6 | cd "$(dirname "$0")" 7 | 8 | #load from env variable 9 | if [ -f .gitpmoji.env ]; then 10 | source .gitpmoji.env 11 | fi 12 | 13 | # load from env variable 14 | API_KEY=$GITPMOJI_API_KEY 15 | API_BASE_URL=${GITPMOJI_API_BASE_URL:-https://api.openai.com/v1} 16 | API_MODEL=${GITPMOJI_API_MODEL:-gpt-4o} 17 | 18 | # check if API_KEY is set 19 | if [ -z "$API_KEY" ]; then 20 | echo "GITPMOJI_API_KEY is not set" 21 | exit 1 22 | fi 23 | 24 | # check if jq is installed 25 | if ! command -v jq &> /dev/null 26 | then 27 | echo "jq could not be found, please install it" 28 | exit 1 29 | fi 30 | 31 | # Function to display help message 32 | display_help() { 33 | echo "Usage: $0 [options]" 34 | echo 35 | echo "Options:" 36 | echo " -h Display this help message" 37 | echo " -d Pipe diff to stdin" 38 | echo " -f DIFF.file Specify the diff file. Will be used to generate the commit message" 39 | echo " -g Generate the commit message (and emoji)" 40 | echo " -a Assess the diff or file." 41 | echo " -r Give starts the rating of the assessment only" 42 | echo " -w Output the assessment in Markdown format" 43 | echo " -m \"MESSAGE\" Specify the commit message" 44 | echo " -e Will analyze message and add the emoji" 45 | echo " -v Verbose mode" 46 | echo 47 | echo "Example:" 48 | echo " $0 -e -m \"Implement new feature\"" 49 | } 50 | 51 | # Parse command line arguments 52 | DIFF_CONTENT="" 53 | DIFF_FILE="" 54 | GENERATE=false 55 | ASSESS=false 56 | RATING=false 57 | MARKDOWN=false 58 | MESSAGE="" 59 | RESULT="" 60 | VERBOSE=false 61 | EMOJI=false 62 | 63 | while getopts "hdf:garwm:ev" opt; do 64 | case $opt in 65 | h) 66 | display_help 67 | exit 0 68 | ;; 69 | d) 70 | DIFF_CONTENT=$(cat) 71 | ;; 72 | f) 73 | DIFF_FILE="$OPTARG" 74 | ;; 75 | g) 76 | GENERATE=true 77 | ;; 78 | a) 79 | ASSESS=true 80 | ;; 81 | r) 82 | RATING=true 83 | ;; 84 | w) 85 | MARKDOWN=true 86 | ;; 87 | m) 88 | MESSAGE="$OPTARG" 89 | ;; 90 | e) 91 | EMOJI=true 92 | ;; 93 | v) 94 | VERBOSE=true 95 | ;; 96 | \?) 97 | echo "Invalid option: -$OPTARG" >&2 98 | display_help 99 | exit 1 100 | ;; 101 | :) 102 | echo "Option -$OPTARG requires an argument." >&2 103 | display_help 104 | exit 1 105 | ;; 106 | esac 107 | done 108 | 109 | # Shift the parsed options out of the argument list 110 | shift $((OPTIND-1)) 111 | 112 | if [ "$VERBOSE" = true ]; then 113 | echo -e "DIFF_FILE: $DIFF_FILE" 114 | echo -e "DIFF_CONTENT: $DIFF_CONTENT" 115 | echo -e "ASSESS: $ASSESS" 116 | echo -e "RATING: $RATING" 117 | echo -e "MARKDOWN: $MARKDOWN" 118 | echo -e "MESSAGE: $MESSAGE" 119 | echo -e "EMOJI: $EMOJI" 120 | fi 121 | 122 | # Check if both emoji and message are provided 123 | if [ "$GENERATE" = true ] && [ -z "$DIFF_CONTENT" ] && [ -z "$DIFF_FILE" ] && [ -z "$MESSAGE" ]; then 124 | echo "At least one of the following options is required: -d, -f, -m" 125 | display_help 126 | exit 1 127 | fi 128 | 129 | # Check if both emoji and message are provided 130 | if [ "$ASSESS" = true ] && [ -z "$DIFF_CONTENT" ] && [ -z "$DIFF_FILE" ]; then 131 | echo "At least one of the following options is required: -d, -f for assessment" 132 | display_help 133 | exit 1 134 | fi 135 | 136 | get_diff_content() { 137 | if [ "$VERBOSE" = true ]; then 138 | echo -e "get_diff_content" 139 | fi 140 | 141 | #read diff from file 142 | if [ ! "$DIFF_CONTENT" ] && [ "$DIFF_FILE" ]; then 143 | if [ ! -f "$DIFF_FILE" ]; then 144 | echo "no such file $DIFF_FILE" 145 | exit 1 146 | fi 147 | DIFF_CONTENT=$(cat $DIFF_FILE) 148 | fi 149 | 150 | # Check the size of DIFF_CONTENT 151 | if [ ${#DIFF_CONTENT} -gt 100000 ]; then 152 | echo "Error: The diff is too large. Maximum allowed is 100000 characters. (30000 tokens)" 153 | exit 1 154 | fi 155 | } 156 | 157 | 158 | check_for_errors() { 159 | local response=$1 160 | ERROR=$(echo $response | jq -r '.error.message') 161 | if [ "$ERROR" == 'null' ]; then 162 | return 163 | fi 164 | if [ "$ERROR" ]; then 165 | echo -e "ERROR: $ERROR" 166 | echo -e "RESPONSE: $response" 167 | exit 1 168 | fi 169 | } 170 | 171 | generate_message() { 172 | if [ "$VERBOSE" = true ]; then 173 | echo -e "generate_message" 174 | fi 175 | 176 | get_diff_content 177 | 178 | # Prepare the data for the API call 179 | SYSTEM_PROMPT="You are a system that generates git commit messages from diff. 180 | You will be given a diff and your task is to generate a git commit message. 181 | You will provide only one commit message for each diff. 182 | Your answer should contain only single commit message, nothing else. 183 | Use english language only. 184 | Use multiple lines for the response. 185 | Try to use maximum 100 words in the response. 186 | " 187 | 188 | PREFIX_RX="\"" 189 | 190 | JSON='{ 191 | "model": $api_model, 192 | "messages": [ 193 | { 194 | "role": "system", 195 | "content": $system_prompt 196 | }, 197 | { 198 | "role": "user", 199 | "content": $prompt 200 | } 201 | ], 202 | "max_tokens": 200, 203 | "temperature": 0.999, 204 | "top_p": 1, 205 | "frequency_penalty": 0.0, 206 | "presence_penalty": 0.0 207 | }' 208 | 209 | DATA=$(jq -n --arg system_prompt "$SYSTEM_PROMPT" --arg prompt "$DIFF_CONTENT" --arg api_model "$API_MODEL" "$JSON") 210 | 211 | # Make the API call 212 | RESPONSE=$(curl -s \ 213 | -X POST "$API_BASE_URL/chat/completions" \ 214 | -H "Content-Type: application/json" \ 215 | -H "Authorization: Bearer $API_KEY" \ 216 | -d "$DATA") 217 | 218 | check_for_errors "$RESPONSE" 219 | 220 | # Extract and display the answer 221 | GPT_MESSAGE=$(echo $RESPONSE | jq -r '.choices[0].message.content' | sed 's/^"//;s/"$//') 222 | 223 | if [ -z "$MESSAGE" ]; then 224 | MESSAGE=$(echo -e "${GPT_MESSAGE}") 225 | else 226 | MESSAGE=$(echo -e "${MESSAGE}""${GPT_MESSAGE}") 227 | fi 228 | RESULT=$(echo -e "${MESSAGE}") 229 | } 230 | 231 | generate_emoji() { 232 | if [ "$VERBOSE" = true ]; then 233 | echo -e "generate_emoji" 234 | fi 235 | 236 | # Prepare the data for the API call 237 | SYSTEM_PROMPT="You are a system that generates emoji for incoming messages. 238 | You will be given a message and your task is to generate an emoji that best represents the message. 239 | You will provide only one emoji for each message. 240 | Your answer should contain only single emoji, nothing else. 241 | If possible, use the emoji that is already in the message. 242 | If possible, use the emoji from the list below: 243 | | Emoji | Message | 244 | |-------|-------------| 245 | | 🎉 | Begin a project. start new priject. initial commit | 246 | | 🪲 | Fix a bug. bugfix | 247 | | 🚑 | Critical bug fix. hotfix. | 248 | | ✨ | Introduce new features. | 249 | | 📝 | Add or update documentation. | 250 | | 🚀 | Deploy stuff. | 251 | | 💄 | Add or update the UI and style files. | 252 | | 🎨 | Improve structure. cosmetic changes | 253 | | 🧹 | Run linter or formatter | 254 | | ⚡ | Improve performance. | 255 | | 🗑️ | Deprecate code. Remove code or files.| 256 | | ✅ | Add, update, or pass tests. unit-tests | 257 | | 🔒 | Fix security issues. | 258 | | 🔐 | Add or update secrets. | 259 | | 🔖 | Release / Version tags. | 260 | | 🚨 | Fix compiler / linter warnings. | 261 | | 🚧 | Work in progress. | 262 | | 💚 | Fix CI Build. | 263 | | ⬇️ | Downgrade dependencies. | 264 | | ⬆️ | Upgrade dependencies. | 265 | | 📌 | Pin dependencies to specific versions. | 266 | | 👷 | Add or update CI build system. | 267 | | 📈 | Add or update analytics. | 268 | | ♻️ | Refactor code. | 269 | | ➕ | Add a dependency. | 270 | | ➖ | Remove a dependency. | 271 | | 🔧 | Add or update configuration files. | 272 | | 🔨 | Add or update development scripts. | 273 | | 🌐 | Internationalization and localization. | 274 | | ✏️ | Fix typos. | 275 | | ⏪ | Revert changes. | 276 | | 🔀 | Merge branches. | 277 | | 📦 | Add or update compiled files or packages. | 278 | | 👽 | Update code due to external API changes. | 279 | | 🚚 | Move or rename resources. | 280 | | 📄 | Add or update license. | 281 | | 💥 | Introduce breaking changes. | 282 | | 🍱 | Add or update assets. | 283 | | ♿ | Add or improve accessibility. | 284 | | 💡 | Add or update comments in source code. | 285 | | 🗯 | Add or update text and literals. | 286 | | 🗃 | Perform database changes. | 287 | | 👥 | Add or update contributor(s). | 288 | | 🚸 | Improve user experience. | 289 | | 🏗 | Make architectural changes. | 290 | | 📱 | Work on responsive design. | 291 | | 🤡 | Mock things. | 292 | | 🙈 | Add or update a .gitignore file. | 293 | | 📸 | Add or update snapshots. | 294 | | 🏷️ | Add or update types. | 295 | | 🚩 | Add or update feature flags. | 296 | | 🥅 | Catch errors. | 297 | | 💫 | Add or update animations. | 298 | | 🛂 | Work on authorization. | 299 | | 🩹 | Simple fix for a non-critical issue. | 300 | | 🧐 | Data exploration/inspection. | 301 | | ⚰️ | Remove dead code. | 302 | | 🧪 | Add a failing test. | 303 | | 👔 | Add or update business logic. | 304 | | 🩺 | Add or update healthcheck. | 305 | | 🧱 | Infrastructure changes. | 306 | | 🧑‍💻 | Improve developer experience. | 307 | " 308 | 309 | PREFIX_RX="\"" 310 | 311 | JSON='{ 312 | "model": $api_model, 313 | "messages": [ 314 | { 315 | "role": "system", 316 | "content": $system_prompt 317 | }, 318 | { 319 | "role": "user", 320 | "content": $prompt 321 | } 322 | ], 323 | "max_tokens": 100, 324 | "temperature": 0.999, 325 | "top_p": 1, 326 | "frequency_penalty": 0.0, 327 | "presence_penalty": 0.0 328 | }' 329 | 330 | DATA=$(jq -n --arg system_prompt "$SYSTEM_PROMPT" --arg prompt "$MESSAGE" --arg api_model "$API_MODEL" "$JSON") 331 | 332 | # Make the API call 333 | RESPONSE=$(curl -s \ 334 | -X POST "$API_BASE_URL/chat/completions" \ 335 | -H "Content-Type: application/json" \ 336 | -H "Authorization: Bearer $API_KEY" \ 337 | -d "$DATA") 338 | 339 | check_for_errors "$RESPONSE" 340 | 341 | # Extract and display the answer 342 | EMOJI=$(echo $RESPONSE | jq -r '.choices[0].message.content' | sed 's/^"//;s/"$//') 343 | 344 | PREFIX="###" 345 | 346 | # check if GITPMOJI_PREFIX_RX is set 347 | GITPMOJI_PREFIX_RX=$GITPMOJI_PREFIX_RX 348 | if [ -z "$GITPMOJI_PREFIX_RX" ]; then 349 | PREFIX="###" 350 | else 351 | PREFIX=$GITPMOJI_PREFIX_RX 352 | fi 353 | 354 | RESULT=$(echo -e "${MESSAGE}" | sed "1s/^\($PREFIX\)\{0,1\}\(.*\)$/\1$EMOJI \2/") 355 | } 356 | 357 | assess_diff() { 358 | if [ "$VERBOSE" = true ]; then 359 | echo -e "assess_diff" 360 | fi 361 | 362 | get_diff_content 363 | 364 | # Prepare the data for the API call 365 | SYSTEM_PROMPT="You are a system that evaluate code quality and assesses the git diff. 366 | You will be given a diff and your task is to assess this diff. 367 | Analyze code changes in the diff and provide a detailed evaluation of the changes. 368 | You will provide only one assessment for each diff. 369 | Based on the provided git diff evaluate the code changes on several factors: code cleanliness, structure, readability, complexity, and overall code quality. 370 | Use english language for the response only. 371 | Use multiple lines for the response. 372 | Try to use maximum 250 words in the response. 373 | Add the final rating on the scale from 1 to 10 at the end of the response. 374 | Use 10 emoji ⭐ and 💩 to indicate the rating. 375 | For example: ⭐⭐⭐⭐⭐⭐⭐💩💩💩 means 7 out of 10 and ⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐ means 10 out of 10. 376 | " 377 | 378 | if [ "$RATING" = true ]; then 379 | RATING_PROMPT=" 380 | Your answer should contain only the rating (10 emoji) and nothing else. 381 | " 382 | SYSTEM_PROMPT=$(echo -e "${SYSTEM_PROMPT}""${RATING_PROMPT}") 383 | elif [ "$MARKDOWN" = true ]; then 384 | RATING_PROMPT=" 385 | Provide all the answer in Markdown format. 386 | " 387 | SYSTEM_PROMPT=$(echo -e "${SYSTEM_PROMPT}""${RATING_PROMPT}") 388 | else 389 | RATING_PROMPT=" 390 | Provide the answer in plain text format no additional formatting required. Do not use any Markdown formatting. 391 | " 392 | SYSTEM_PROMPT=$(echo -e "${SYSTEM_PROMPT}""${RATING_PROMPT}") 393 | fi 394 | 395 | JSON='{ 396 | "model": $api_model, 397 | "messages": [ 398 | { 399 | "role": "system", 400 | "content": $system_prompt 401 | }, 402 | { 403 | "role": "user", 404 | "content": $prompt 405 | } 406 | ], 407 | "max_tokens": 500, 408 | "temperature": 1, 409 | "top_p": 1, 410 | "frequency_penalty": 0.0, 411 | "presence_penalty": 0.0 412 | }' 413 | 414 | DATA=$(jq -n --arg system_prompt "$SYSTEM_PROMPT" --arg prompt "$DIFF_CONTENT" --arg api_model "$API_MODEL" "$JSON") 415 | 416 | # Make the API call 417 | RESPONSE=$(curl -s \ 418 | -X POST "$API_BASE_URL/chat/completions" \ 419 | -H "Content-Type: application/json" \ 420 | -H "Authorization: Bearer $API_KEY" \ 421 | -d "$DATA") 422 | 423 | check_for_errors "$RESPONSE" 424 | 425 | # Extract and display the answer 426 | GPT_MESSAGE=$(echo $RESPONSE | jq -r '.choices[0].message.content' | sed 's/^"//;s/"$//') 427 | 428 | if [ -z "$RESULT" ]; then 429 | RESULT=$(echo -e "${GPT_MESSAGE}") 430 | else 431 | RESULT=$(echo -e "${RESULT}" && echo -e "${GPT_MESSAGE}") 432 | fi 433 | } 434 | 435 | 436 | if [ "$GENERATE" = true ] && ([ "$DIFF_CONTENT" ] || [ "$DIFF_FILE" ]); then 437 | generate_message 438 | fi 439 | 440 | if [ "$EMOJI" = true ]; then 441 | generate_emoji 442 | fi 443 | 444 | if [ "$ASSESS" = true ]; then 445 | assess_diff 446 | fi 447 | 448 | echo -e "${RESULT}" 449 | exit 0 450 | --------------------------------------------------------------------------------