-
Notifications
You must be signed in to change notification settings - Fork 7
/
check-markit
executable file
·268 lines (239 loc) · 18.5 KB
/
check-markit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
#!/bin/bash
# check-markit 4.2.1.1114 2020-12-22T21:01:38.222906-06:00 (CST) https://github.com/BradleyA/markit.git master uadmin three-rpi3b.cptx86.com 4.1.146-24-g68844ef
# check-markit find-code.sh markit --> release ready for production
#86# check-markit - check file release with repository release
### Production standard 5.3.559 Copyright # 3.559
# Copyright (c) 2020 Bradley Allen # 3.555
# MIT License is online in the repository as a file named LICENSE" # 3.559
### Production standard 3.0 shellcheck
### Production standard 1.3.614 DEBUG variable
# Order of precedence: environment variable, default code
if [[ "${DEBUG}" == "" ]] ; then DEBUG="0" ; fi # 0 = debug off, 1 = debug on, 'export DEBUG=1', 'unset DEBUG' to unset environment variable (bash)
if [[ "${DEBUG}" == "2" ]] ; then set -x ; fi # Print trace of simple commands before they are executed
if [[ "${DEBUG}" == "3" ]] ; then set -v ; fi # Print shell input lines as they are read
if [[ "${DEBUG}" == "4" ]] ; then set -e ; fi # Exit immediately if non-zero exit status
if [[ "${DEBUG}" == "5" ]] ; then set -e -o pipefail ; fi # Exit immediately if non-zero exit status and exit if any command in a pipeline errors
#
BOLD=$(tput -Txterm bold)
UNDERLINE=$(tput -Txterm sgr 0 1) # 0.3.583
NORMAL=$(tput -Txterm sgr0)
RED=$(tput setaf 1)
YELLOW=$(tput setaf 3)
BLUE=$(tput setaf 4)
PURPLE=$(tput setaf 5)
CYAN=$(tput setaf 6)
WHITE=$(tput setaf 7)
### Production standard 7.0 Default variable value
FILE_NAME=""
MARKIT_FILE=""
TMP_MARKIT_DIR=$(mktemp --directory /tmp/TMP_MARKIT_DIRXXXXXX) # Create a temporary directory
### Production standard 8.3.541 --usage
COMMAND_NAME=$(echo "${0}" | sed 's/^.*\///') # 3.541
display_usage() {
echo -e "\n${NORMAL}${COMMAND_NAME}\n check file release with repository release"
echo -e "\n${BOLD}USAGE${NORMAL}"
echo " ${COMMAND_NAME} <FILE_NAME>"
echo -e " ${COMMAND_NAME} [--filename <PATH>/<FILE_NAME> | -f <PATH>/<FILE_NAME>]\n"
echo " ${COMMAND_NAME} [--help | -help | help | -h | h | -?]"
echo " ${COMMAND_NAME} [--usage | -usage | -u]"
echo " ${COMMAND_NAME} [--version | -version | -v]"
}
### Production standard 0.3.615 --help
display_help() {
display_usage
# Displaying help DESCRIPTION in English en_US.UTF-8, en.UTF-8, C.UTF-8 # 3.550
echo -e "\n${BOLD}DESCRIPTION${NORMAL}"
echo "Check the release of a file that was marked using markit with the GitHub"
echo "repository or Bitbucket repository or GitLab project release. Check-markit may"
echo "require --filename option to include the relative or absolute path with the"
echo "file name."
echo -e "\nCheck-markit only works on files that are marked after 2018-02-27."
echo -e "\nCheck-markit only works with markit files that used the https:// URLs for"
echo "GitHub, Bitbucket, and GitLab repositories. Check-markit does not currently"
echo "support files with SSH URLs for GitHub, Bitbucket, and GitLab repositories."
### Production standard 4.3.587 Documentation Language # 3.550
# Displaying help DESCRIPTION in French fr_CA.UTF-8, fr_FR.UTF-8, fr_CH.UTF-8
if [[ "${LANG}" == "fr_CA.UTF-8" ]] || [[ "${LANG}" == "fr_FR.UTF-8" ]] || [[ "${LANG}" == "fr_CH.UTF-8" ]] ; then
echo -e "\n--> ${LANG}"
echo "<Votre aide va ici>" # Your help goes here
echo "Souhaitez-vous traduire la section description?" # Would you like to translate the description section?
elif ! [[ "${LANG}" == "en_US.UTF-8" || "${LANG}" == "en.UTF-8" || "${LANG}" == "C.UTF-8" ]] ; then # 3.550
new_message "${LINENO}" "${YELLOW}INFO${WHITE}" " Your language, ${LANG}, is not supported. Would you like to translate the description section?" 1>&2
fi
echo -e "\n${BOLD}ENVIRONMENT VARIABLES${NORMAL}"
echo "If using the bash shell, enter; 'export DEBUG=1' on the command line to set"
echo "the environment variable DEBUG to '1' (0 = debug off, 1 = debug on). Use the"
echo "command, 'unset DEBUG' to remove the exported information from the environment"
echo "variable DEBUG. You are on your own defining environment variables if"
echo "you are using other shells."
### Production standard 1.3.614 DEBUG variable
echo " DEBUG (default off '0') The DEBUG environment variable can be set" # 3.550
echo " to 0, 1, 2, 3, 4 or 5. The setting '' or 0 will turn off" # 3.550
echo " all DEBUG messages during execution of this script. The" # 3.550
echo " setting 1 will print all DEBUG messages during execution." # 3.550
echo " Setting 2 (set -x) will print a trace of simple commands" # 3.550
echo " before they are executed. Setting 3 (set -v) will print" # 3.550
echo " shell input lines as they are read. Setting 4 (set -e) will" # 3.550
echo " exit immediately if non-zero exit status is recieved with" # 3.550
echo " some exceptions. Setting 5 (set -e -o pipefail) will do" # 3.550
echo " setting 4 and exit if any command in a pipeline errors. For" # 3.550
echo " more information about the set options, see man bash." # 3.550
echo -e "\n${BOLD}OPTIONS${NORMAL}"
echo -e "Order of precedence: CLI options, environment variable, default value.\n" # 0.3.595
echo " --help, -help, help, -h, h, -?" # 0.3.595
echo -e "\tOn-line brief reference manual\n" # 0.3.595
echo " --usage, -usage, -u" # 0.3.595
echo -e "\tOn-line command usage\n" # 0.3.595
echo " --version, -version, -v" # 0.3.595
echo -e "\tOn-line command version\n" # 0.3.595
#
echo " --filename <PATH>/<FILE_NAME>, -f"
echo -e "\tInclude the relative or absolute path with the file name"
echo -e "\n${BOLD}DOCUMENTATION${NORMAL}"
echo " ${UNDERLINE}https://github.com/BradleyA/markit/blob/master/README.md${NORMAL}" # 0.3.583
echo -e "\n${BOLD}EXAMPLES${NORMAL}"
echo -e " Check file named sample.c release in relative path testfile/ with\n repository release." # 0.3.550
echo -e "\t${BOLD}${COMMAND_NAME} -f testfiles/sample.c${NORMAL}\n" # 0.3.550
echo " Check file named markit release with repository release." # 0.3.550
echo -e "\t${BOLD}${COMMAND_NAME} markit${NORMAL}" # 0.3.550
echo -e "\n${BOLD}SEE ALSO${NORMAL}" # 0.3.615
echo " ${BOLD}markit${NORMAL} Mark tracked modified file(s), in your local" # 0.3.615
echo -e "\tGit repository and push those changes to a remote Git repository" # 0.3.615
echo -e "\t(${UNDERLINE}https://github.com/BradleyA/markit/blob/master/README.md${NORMAL})\n" # 0.3.615
echo " ${BOLD}find-code.sh${NORMAL} Search each system found in" # 0.3.615
echo -e "\t<DATA_DIR>/<SYSTEMS_FILE> file for .git repositories in ~/.. directories" # 0.3.615
echo -e "\t(${UNDERLINE}https://github.com/BradleyA/markit/blob/master/README.md#usage-find-codesh${NORMAL})\n" # 0.3.615
echo -e "\n${BOLD}AUTHOR${NORMAL}" # 3.550
echo " ${COMMAND_NAME} was written by Bradley Allen <[email protected]>" # 3.550
echo -e "\n${BOLD}REPORTING BUGS${NORMAL}" # 3.550
echo " Report ${COMMAND_NAME} bugs ${UNDERLINE}https://github.com/BradleyA/markit/issues/new/choose${NORMAL}" # 0.3.583
### Production standard 5.3.559 Copyright # 3.559
echo -e "\n${BOLD}COPYRIGHT${NORMAL}" # 3.550
echo " Copyright (c) 2020 Bradley Allen" # 3.550
echo " MIT License is online in the repository as a file named LICENSE" # 3.559
}
# Date and time function ISO 8601
get_date_stamp() {
DATE_STAMP=$(date +%Y-%m-%dT%H:%M:%S.%6N%:z)
TEMP=$(date +%Z)
DATE_STAMP="${DATE_STAMP} (${TEMP})"
}
# Fully qualified domain name FQDN hostname
LOCALHOST=$(hostname -f)
# Version
# Assumptions for the next two lines of code: The second line in this script includes the script path & name as the second item and
# the script version as the third item separated with space(s). The tool I use is called 'markit'. See example line below:
# template/template.sh 3.517.783 2019-09-13T18:20:42.144356-05:00 (CDT) https://github.com/BradleyA/user-files.git uadmin one-rpi3b.cptx86.com 3.516
SCRIPT_NAME=$(head -2 "${0}" | awk '{printf $2}') # Different from ${COMMAND_NAME}=$(echo "${0}" | sed 's/^.*\///'), SCRIPT_NAME = includes Git repository directory and can be used any where in script (for dev, test teams)
SCRIPT_VERSION=$(head -2 "${0}" | awk '{printf $3}')
if [[ "${SCRIPT_NAME}" == "" ]] ; then SCRIPT_NAME="${0}" ; fi
if [[ "${SCRIPT_VERSION}" == "" ]] ; then SCRIPT_VERSION="v?.?" ; fi
# GID
GROUP_ID=$(id -g)
### Production standard 2.3.614 Log format (WHEN WHERE WHAT Version Line WHO UID:GID [TYPE] Message)
new_message() { # $1="${LINENO}" $2="DEBUG INFO ERROR WARN" $3="message"
get_date_stamp
echo -e "${NORMAL}${DATE_STAMP} ${LOCALHOST} ${BOLD}${CYAN}${SCRIPT_NAME}${NORMAL}[$$] ${BOLD}${BLUE}${SCRIPT_VERSION} ${PURPLE}${1}${NORMAL} ${USER} ${UID}:${GROUP_ID} ${BOLD}[${2}]${NORMAL} ${3}" # 2.3.614
}
# INFO
if [[ "${DEBUG}" == "1" ]] ; then new_message "${LINENO}" "${YELLOW}INFO${WHITE}" "${BOLD}${CYAN} Started...${NORMAL}" 1>&2 ; fi # 1.3.614
# Added following code because USER is not defined in crobtab jobs
if ! [[ "${USER}" == "${LOGNAME}" ]] ; then USER=${LOGNAME} ; fi
if [[ "${DEBUG}" == "1" ]] ; then new_message "${LINENO}" "${YELLOW}DEBUG${WHITE}" " Setting USER to support crobtab... USER >${YELLOW}${USER}${WHITE}< LOGNAME >${YELLOW}${LOGNAME}${WHITE}<" 1>&2 ; fi # 1.3.614
# DEBUG # 1.3.614
if [[ "${DEBUG}" == "1" ]] ; then new_message "${LINENO}" "${YELLOW}DEBUG${WHITE}" " Name_of_command >${YELLOW}${SCRIPT_NAME}${WHITE}< Name_of_arg1 >${YELLOW}${1}${WHITE}< Name_of_arg2 >${YELLOW}${2}${WHITE}< Name_of_arg3 >${YELLOW}${3}${WHITE}< Version of bash ${YELLOW}${BASH_VERSION}${WHITE}" 1>&2 ; fi # 1.3.614
### Production standard 9.3.606 Parse CLI options and arguments
while [[ "${#}" -gt 0 ]] ; do
case "${1}" in
--help|-help|help|-h|h|-\?) display_help | more ; exit 0 ;;
--usage|-usage|usage|-u) display_usage ; exit 0 ;;
--version|-version|version|-v) echo "${SCRIPT_NAME} ${SCRIPT_VERSION}" ; exit 0 ;;
#
-f|--filename) if [[ "${2}" == "" ]] ; then echo -e "\n${BOLD} Argument for ${YELLOW}${1}${WHITE} is not found on command line.${NORMAL}\n" ; exit 1 ; fi ; MARKIT_FILE=${2} ; shift 2 ;; # 9.3.605
-f=*|--filename=*) MARKIT_FILE="${1#*=}" ; if [[ "${MARKIT_FILE}" == "" ]] ; then echo -e "\n${BOLD} Argument for ${YELLOW}${1}${WHITE} is not found on command line.${NORMAL}\n" ; exit 1 ; fi ; shift ;; # 9.3.605
# *) echo -e "\n${BOLD} Invalid option, ${YELLOW}${1}${WHITE}, try ${YELLOW}--usage${NORMAL}\n" ; exit 1 ; ;; # 9.3.606
*) break ;; # 9.3.607
esac
done
if [[ "${DEBUG}" == "1" ]] ; then new_message "${LINENO}" "${YELLOW}DEBUG${WHITE}" " Variable... MARKIT_FILE >${BOLD}${CYAN}${MARKIT_FILE}${NORMAL}<" 1>&2 ; fi # 1.3.614
###
### Check if argument 1 is blank
if [[ "${1}" == "" ]] && [[ "${MARKIT_FILE}" == "" ]] ; then
display_usage
new_message "${LINENO}" "${RED}ERROR${WHITE}" " File not found on command line" 1>&2
exit 1
fi
# Check if argument 1 is found on system
if [[ "${MARKIT_FILE}" == "" ]] ; then
# check if first character is a '-'
if [[ "${1:0:1}" == "-" ]] ; then echo -e "\n${BOLD} Invalid option, ${YELLOW}${1}${WHITE}, try ${YELLOW}--usage${NORMAL}\n" ; exit 1 ; fi
# Locate file in the PATH
TEMP=$(whereis "${1}")
MARKIT_FILE=$(echo "${TEMP}" | awk '{print $2}' )
if [[ "${DEBUG}" == "1" ]] ; then new_message "${LINENO}" "${YELLOW}DEBUG${WHITE}" " Locate file in the PATH... MARKIT_FILE >${BOLD}${CYAN}${MARKIT_FILE}${NORMAL}<" 1>&2 ; fi # 1.3.614
# Check if MARKIT_FILE is blank, not found on system
if [[ "${MARKIT_FILE}" == "" ]] ; then
new_message "${LINENO}" "${RED}ERROR${WHITE}" " ${1} not found; use --file <path>/<file_name> or -f <path>/<file_name> option" 1>&2
display_usage
exit 1
fi
fi
# Parse file FILE_NAME from MARKIT_FILE
FILE_NAME=$(echo "${MARKIT_FILE}" | sed 's/.*\///')
# Check if file exists and has a size greater than zero || if file exists and is readable
if [[ ! -s "${MARKIT_FILE}" ]] || [[ ! -r "${MARKIT_FILE}" ]] ; then
new_message "${LINENO}" "${RED}ERROR${WHITE}" " ${MARKIT_FILE} file is not found or is empty or is not readable" 1>&2
exit 1
fi
REPOSITORY_COMMAND=$(grep git "${MARKIT_FILE}" | grep -m 1 "${FILE_NAME}" | awk '{print $6}' | sed 's/\.git$//')
MARKIT_FILE_RELEASE=$(grep git "${MARKIT_FILE}" | grep -m 1 "${FILE_NAME}" | awk '{print $3}')
MARKIT_FILE_DATE=$(grep git "${MARKIT_FILE}" | grep -m 1 "${FILE_NAME}" | awk '{print $4}')
#
if [[ "${DEBUG}" == "1" ]] ; then new_message "${LINENO}" "${YELLOW}DEBUG${WHITE}" " MARKIT_FILE >${BOLD}${CYAN}${MARKIT_FILE}${NORMAL}< FILE_NAME >${BOLD}${CYAN}${FILE_NAME}${NORMAL}< REPOSITORY_COMMAND >${BOLD}${CYAN}${REPOSITORY_COMMAND}${NORMAL}< MARKIT_FILE_RELEASE >${BOLD}${CYAN}${MARKIT_FILE_RELEASE}${NORMAL}<" 1>&2 ; fi # 1.3.614
# Check file to determine if it was marked before markit release 3.10.142 2018-02-27.
if ! grep -q "https" <<< ${REPOSITORY_COMMAND} ; then
new_message "${LINENO}" "${RED}ERROR${WHITE}" " ${MARKIT_FILE} is not marked with markit or the --file option was not used or git origin did not include https address (git remote -v) when marked or file was marked after 2018-02-27." 1>&2
exit 1
fi
### >>>
# need to make sure that script is able to contact GitHib or Bitbucket or GitLab before using curl
# add a test
### >>>
### Determine name of repository
if grep -q "github" <<< ${REPOSITORY_COMMAND} ; then
if [[ "${DEBUG}" == "1" ]] ; then new_message "${LINENO}" "${YELLOW}DEBUG${WHITE}" " Checking GitHub for ${BOLD}${CYAN}${FILE_NAME}${NORMAL} repository release information" 1>&2 ; fi # 1.3.614
REPOSITORY_COMMAND=$(echo "${REPOSITORY_COMMAND}" | sed 's/github.com/api.github.com\/repos/')
REPOSITORY_COMMAND="curl \-L ${REPOSITORY_COMMAND}/tarball | tar --directory ${TMP_MARKIT_DIR} -xzf - "
if [[ "${DEBUG}" == "1" ]] ; then new_message "${LINENO}" "${YELLOW}DEBUG${WHITE}" " REPOSITORY_COMMAND >${BOLD}${CYAN}${REPOSITORY_COMMAND}${NORMAL}<" 1>&2 ; fi # 1.3.614
elif grep -q "gitlab" <<< ${REPOSITORY_COMMAND} ; then
if [[ "${DEBUG}" == "1" ]] ; then new_message "${LINENO}" "${YELLOW}DEBUG${WHITE}" " Checking GitLab for ${BOLD}${FILE_NAME}${NORMAL} repository release information" 1>&2 ; fi # 1.3.614
REPOSITORY_PROJECT_NAME=$(echo "${REPOSITORY_COMMAND}" | sed 's/^https:\/\/.*\/.*\///' | sed 's/\.git$//')
REPOSITORY_COMMAND=$(echo "${REPOSITORY_COMMAND}" | sed 's/\.git$/\/-\/archive\/master\//')
if [[ "${DEBUG}" == "1" ]] ; then new_message "${LINENO}" "${YELLOW}DEBUG${WHITE}" " MARKIT_FILE >${BOLD}${CYAN}${MARKIT_FILE}${NORMAL}< FILE_NAME >${BOLD}${CYAN}${FILE_NAME}${NORMAL}< REPOSITORY_COMMAND >${BOLD}${CYAN}${REPOSITORY_COMMAND}${NORMAL}< MARKIT_FILE_RELEASE >${BOLD}${CYAN}${MARKIT_FILE_RELEASE}${NORMAL}<" 1>&2 ; fi # 1.3.614
REPOSITORY_COMMAND="curl \-L ${REPOSITORY_COMMAND}${REPOSITORY_PROJECT_NAME}-master.tar.gz | tar --directory ${TMP_MARKIT_DIR} -xzf - "
elif grep -q "bitbucket" <<< ${REPOSITORY_COMMAND} ; then
if [[ "${DEBUG}" == "1" ]] ; then new_message "${LINENO}" "${YELLOW}DEBUG${WHITE}" " Checking Bitbucket for ${BOLD}${FILE_NAME}${NORMAL} repository release information" 1>&2 ; fi # 1.3.614
REPOSITORY_COMMAND=$(echo "${REPOSITORY_COMMAND}" | sed 's/\/\/.*@/\/\//')
REPOSITORY_COMMAND=$(echo "curl \-L ${REPOSITORY_COMMAND}/get/master.zip -o ${TMP_MARKIT_DIR}/master.zip ; unzip -qq ${TMP_MARKIT_DIR}/master.zip -d ${TMP_MARKIT_DIR}/")
if [[ "${DEBUG}" == "1" ]] ; then new_message "${LINENO}" "${YELLOW}DEBUG${WHITE}" " REPOSITORY_COMMAND >${BOLD}${CYAN}${REPOSITORY_COMMAND}${NORMAL}<" 1>&2 ; fi # 1.3.614
else
if [[ "${DEBUG}" == "1" ]] ; then new_message "${LINENO}" "${YELLOW}DEBUG${WHITE}" " MARKIT_FILE >${BOLD}${CYAN}${MARKIT_FILE}${NORMAL}< FILE_NAME >${BOLD}${CYAN}${FILE_NAME}${NORMAL}< REPOSITORY_COMMAND >${BOLD}${CYAN}${REPOSITORY_COMMAND}${NORMAL}< MARKIT_FILE_RELEASE >${BOLD}${CYAN}${MARKIT_FILE_RELEASE}${NORMAL}<" 1>&2 ; fi # 1.3.614
new_message "${LINENO}" "${RED}ERROR${WHITE}" " Repository using SSH URLs or other repository like bitbucket, Codebase, Assembla, Fog Creek Kiln, etc." 1>&2
exit 1
fi
###
if [[ "${DEBUG}" == "1" ]] ; then new_message "${LINENO}" "${YELLOW}DEBUG${WHITE}" " MARKIT_FILE >${BOLD}${CYAN}${MARKIT_FILE}${NORMAL}< FILE_NAME >${BOLD}${CYAN}${FILE_NAME}${NORMAL}< REPOSITORY_COMMAND >${BOLD}${CYAN}${REPOSITORY_COMMAND}${NORMAL}< MARKIT_FILE_RELEASE >${BOLD}${CYAN}${MARKIT_FILE_RELEASE}${NORMAL}<" 1>&2 ; fi # 1.3.614
#
eval "${REPOSITORY_COMMAND}"
REPOSITORY_FILE_NAME_LOCATION=$(find "${TMP_MARKIT_DIR}" -type f -name "${FILE_NAME}" -print)
REPOSITORY_MARKIT_FILE_RELEASE=$(grep git "${REPOSITORY_FILE_NAME_LOCATION}" | grep -m 1 "${FILE_NAME}" | awk '{print $3}')
REPOSITORY_MARKIT_FILE_DATE=$(grep git "${REPOSITORY_FILE_NAME_LOCATION}" | grep -m 1 "${FILE_NAME}" | awk '{print $4}')
cp -f "${REPOSITORY_FILE_NAME_LOCATION}" /tmp/"${FILE_NAME}"
rm -rf "${TMP_MARKIT_DIR}"
###
echo -e "\n ${BOLD}${CYAN}${MARKIT_FILE}${NORMAL} release ${BOLD}${YELLOW}${MARKIT_FILE_RELEASE}${NORMAL}, commit date ${MARKIT_FILE_DATE}" 1>&2
echo -e "\n ${BOLD}${CYAN}${FILE_NAME}${NORMAL} repository release ${BOLD}${YELLOW}${REPOSITORY_MARKIT_FILE_RELEASE}${NORMAL}, commit date ${REPOSITORY_MARKIT_FILE_DATE}\n" 1>&2
echo "Repository copy placed in /tmp/${FILE_NAME}"
#
new_message "${LINENO}" "${YELLOW}INFO${WHITE}" "${BOLD}${CYAN} Operation finished...${NORMAL}" 1>&2 # 1.3.614
###