Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89a4b4cf3e | ||
|
|
3eb1229590 | ||
|
|
f174e9ec34 | ||
|
|
928369cff7 | ||
|
|
29f4800e1a | ||
|
|
e706a67427 | ||
|
|
672de694ee | ||
|
|
c69eac3258 | ||
|
|
eca62e53c9 | ||
|
|
62cd3badfe | ||
|
|
4bd2568d94 | ||
|
|
b3c7947c67 | ||
|
|
6710f44646 | ||
|
|
f89be6bd19 | ||
|
|
9696336abc |
33
.github/workflows-disabled/ci.yml
vendored
Normal file
33
.github/workflows-disabled/ci.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
name: CI
|
||||||
|
run-name: ${{ github.actor}} runs CI
|
||||||
|
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
phpstan:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
# - uses: php-actions/composer@v6
|
||||||
|
# env:
|
||||||
|
# COMPOSER_ROOT_VERSION: dev-master
|
||||||
|
- name: "Restore result cache"
|
||||||
|
uses: actions/cache/restore@v4
|
||||||
|
with:
|
||||||
|
path: ./tmp
|
||||||
|
key: "result-cache-v1-${{ matrix.php-version }}-${{ github.run_id }}"
|
||||||
|
restore-keys: |
|
||||||
|
result-cache-v1-${{ matrix.php-version }}-
|
||||||
|
- name: PHPStan Static Analysis
|
||||||
|
uses: php-actions/phpstan@v3
|
||||||
|
with:
|
||||||
|
path: src/
|
||||||
|
- name: "Save result cache"
|
||||||
|
uses: actions/cache/save@v4
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
path: ./tmp
|
||||||
|
key: "result-cache-v1-${{ matrix.php-version }}-${{ github.run_id }}"
|
||||||
|
# - name: PHPunit Tests
|
||||||
|
# run: |
|
||||||
|
# vendor/bin/phpunit
|
||||||
2
.shellcheckrc
Normal file
2
.shellcheckrc
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
shell=bash
|
||||||
|
external-sources=true
|
||||||
37
ReadMe.md
37
ReadMe.md
@@ -9,16 +9,41 @@ For local install only
|
|||||||
- Template\SmartyExtended
|
- Template\SmartyExtended
|
||||||
- Admin\EditBase
|
- Admin\EditBase
|
||||||
|
|
||||||
## Setup from central composer
|
## Publish to gitea or gitlab server
|
||||||
|
|
||||||
Setup from gitea internal servers
|
Currently there are only gitea and gitlab supported, github does not have support for composer packages
|
||||||
|
|
||||||
```sh
|
`publish\publish.sh go` will run the publish script
|
||||||
composer config repositories.git.egplusww.jp.Composer composer https://git.egplusww.jp/api/packages/Composer/composer
|
|
||||||
|
All the configuration is done in the `publish\.env.deploy` file
|
||||||
|
|
||||||
|
```ini
|
||||||
|
# downlaod file name is "Repository name" "-" "version" where
|
||||||
|
# version is "vN.N.N"
|
||||||
|
GITEA_PUBLISH=1
|
||||||
|
GITEA_UPLOAD_FILENAME="Upload-File-Name";
|
||||||
|
GITEA_USER=gitea-user
|
||||||
|
GITEA_TOKEN=gitea-tokek
|
||||||
|
GITEA_URL_DL=https://[gitea.hostname]/[to/package/folder]/archive
|
||||||
|
GITEA_URL_PUSH=https://[gitea.hostname]/api/packages/[organization]/composer
|
||||||
|
|
||||||
|
GITLAB_PUBLISH=1
|
||||||
|
GITLAB_URL=gitlab URl to repository
|
||||||
|
GITLAB_DEPLOY_TOKEN=gitlab-token
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternative setup composer local zip file repot:
|
At the moment there is only one gitea or gitlab target setable
|
||||||
`composer config repositories.composer.egplusww.jp composer http://composer.egplusww.jp`
|
|
||||||
|
## Setup from central composer
|
||||||
|
|
||||||
|
Setup from gitea servers
|
||||||
|
|
||||||
|
[hostname] is the hostname for your gitea server (or wherever this is published)
|
||||||
|
[OrgName] is the organization name where the composer packages are hosted
|
||||||
|
|
||||||
|
```sh
|
||||||
|
composer config repositories.[hostname].Composer composer https://[hostname]/api/packages/[OrgName]/composer
|
||||||
|
```
|
||||||
|
|
||||||
## Install package
|
## Install package
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,8 @@
|
|||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"egrajp/smarty-extended": "^4.3",
|
"egrajp/smarty-extended": "^4.3",
|
||||||
"gullevek/dotenv": "dev-master"
|
"gullevek/dotenv": "dev-master",
|
||||||
|
"phpunit/phpunit": "^9"
|
||||||
},
|
},
|
||||||
"repositories": {
|
"repositories": {
|
||||||
"git.egplusww.jp.Composer": {
|
"git.egplusww.jp.Composer": {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
includes:
|
includes:
|
||||||
- phpstan-conditional.php
|
- phpstan-conditional.php
|
||||||
parameters:
|
parameters:
|
||||||
tmpDir: /tmp/phpstan-corelibs-composer
|
tmpDir: %currentWorkingDirectory%/tmp/phpstan-corelibs-composer
|
||||||
level: 8 # max is now 9
|
level: 8 # max is now 9
|
||||||
checkMissingCallableSignature: true
|
checkMissingCallableSignature: true
|
||||||
treatPhpDocTypesAsCertain: false
|
treatPhpDocTypesAsCertain: false
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
9.12.2
|
9.13.2
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
BASE_FOLDER=$(dirname $(readlink -f $0))"/";
|
BASE_FOLDER=$(dirname "$(readlink -f "$0")")"/";
|
||||||
PACKAGE_DOWNLOAD="${BASE_FOLDER}package-download/";
|
PACKAGE_DOWNLOAD="${BASE_FOLDER}package-download/";
|
||||||
if [ ! -d "${PACKAGE_DOWNLOAD}" ]; then
|
if [ ! -d "${PACKAGE_DOWNLOAD}" ]; then
|
||||||
mkdir "${PACKAGE_DOWNLOAD}";
|
mkdir "${PACKAGE_DOWNLOAD}";
|
||||||
@@ -15,30 +15,35 @@ if [ -z "${VERSION}" ]; then
|
|||||||
fi;
|
fi;
|
||||||
# compare version, if different or newer, deploy
|
# compare version, if different or newer, deploy
|
||||||
if [ -f "${file_last_published}" ]; then
|
if [ -f "${file_last_published}" ]; then
|
||||||
LAST_PUBLISHED_VERSION=$(cat ${file_last_published});
|
LAST_PUBLISHED_VERSION=$(cat "${file_last_published}");
|
||||||
if $(dpkg --compare-versions "${VERSION}" le "${LAST_PUBLISHED_VERSION}"); then
|
if dpkg --compare-versions "${VERSION}" le "${LAST_PUBLISHED_VERSION}"; then
|
||||||
echo "git tag version ${VERSION} is not newer than previous published version ${LAST_PUBLISHED_VERSION}";
|
echo "git tag version ${VERSION} is not newer than previous published version ${LAST_PUBLISHED_VERSION}";
|
||||||
exit;
|
exit;
|
||||||
fi;
|
fi;
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
# read in the .env.deploy file and we must have
|
# read in the .env.deploy file and we must have
|
||||||
|
# for gitea
|
||||||
|
# GITEA_PUBLISH: must be set with a value to trigger publish run
|
||||||
# GITEA_UPLOAD_FILENAME
|
# GITEA_UPLOAD_FILENAME
|
||||||
# GITLAB_USER
|
|
||||||
# GITLAB_TOKEN
|
|
||||||
# GITLAB_URL
|
|
||||||
# GITEA_USER
|
# GITEA_USER
|
||||||
# GITEA_DEPLOY_TOKEN
|
# GITEA_DEPLOY_TOKEN
|
||||||
# GITEA_URL_DL
|
# GITEA_URL_DL
|
||||||
# GITEA_URL_PUSH
|
# GITEA_URL_PUSH
|
||||||
|
# for gitlab
|
||||||
|
# GITLAB_PUBLISH: must be set with a value to trigger publish run
|
||||||
|
# GITLAB_USER
|
||||||
|
# GITLAB_TOKEN
|
||||||
|
# GITLAB_URL
|
||||||
if [ ! -f "${BASE_FOLDER}.env.deploy" ]; then
|
if [ ! -f "${BASE_FOLDER}.env.deploy" ]; then
|
||||||
echo "Deploy enviroment file .env.deploy is missing";
|
echo "Deploy enviroment file .env.deploy is missing";
|
||||||
exit;
|
exit;
|
||||||
fi;
|
fi;
|
||||||
set -o allexport;
|
set -o allexport;
|
||||||
cd ${BASE_FOLDER};
|
cd "${BASE_FOLDER}" || exit;
|
||||||
|
# shellcheck source=.env.deploy
|
||||||
source .env.deploy;
|
source .env.deploy;
|
||||||
cd -;
|
cd - || exit;
|
||||||
set +o allexport;
|
set +o allexport;
|
||||||
|
|
||||||
if [ "${go_flag}" != "go" ]; then
|
if [ "${go_flag}" != "go" ]; then
|
||||||
@@ -50,37 +55,42 @@ fi;
|
|||||||
|
|
||||||
echo "[START]";
|
echo "[START]";
|
||||||
# gitea
|
# gitea
|
||||||
if [ ! -z "${GITEA_UPLOAD_FILENAME}" ] &&
|
# skip iof
|
||||||
[ ! -z "${GITEA_URL_DL}" ] && [ ! -z "${GITEA_URL_PUSH}" ] &&
|
if [ -n "${GITEA_PUBLISH}" ]; then
|
||||||
[ ! -z "${GITEA_USER}" ] && [ ! -z "${GITEA_TOKEN}" ]; then
|
if [ -n "${GITEA_UPLOAD_FILENAME}" ] &&
|
||||||
if [ ! -f "${PACKAGE_DOWNLOAD}${GITEA_UPLOAD_FILENAME}-v${VERSION}.zip" ]; then
|
[ -n "${GITEA_URL_DL}" ] && [ -n "${GITEA_URL_PUSH}" ] &&
|
||||||
curl -LJO \
|
[ -n "${GITEA_USER}" ] && [ -n "${GITEA_TOKEN}" ]; then
|
||||||
--output-dir "${PACKAGE_DOWNLOAD}" \
|
if [ ! -f "${PACKAGE_DOWNLOAD}${GITEA_UPLOAD_FILENAME}-v${VERSION}.zip" ]; then
|
||||||
${GITEA_URL_DL}/v${VERSION}.zip;
|
curl -LJO \
|
||||||
fi;
|
--output-dir "${PACKAGE_DOWNLOAD}" \
|
||||||
if [ ! -f "${PACKAGE_DOWNLOAD}${GITEA_UPLOAD_FILENAME}-v${VERSION}.zip" ]; then
|
"${GITEA_URL_DL}"/v"${VERSION}".zip;
|
||||||
echo "Version file does not exist for ${VERSION}";
|
fi;
|
||||||
|
if [ ! -f "${PACKAGE_DOWNLOAD}${GITEA_UPLOAD_FILENAME}-v${VERSION}.zip" ]; then
|
||||||
|
echo "Version file does not exist for ${VERSION}";
|
||||||
|
else
|
||||||
|
curl --user "${GITEA_USER}":"${GITEA_TOKEN}" \
|
||||||
|
--upload-file "${PACKAGE_DOWNLOAD}${GITEA_UPLOAD_FILENAME}-v${VERSION}.zip" \
|
||||||
|
"${GITEA_URL_PUSH}"?version="${VERSION}";
|
||||||
|
echo "${VERSION}" > "${file_last_published}";
|
||||||
|
fi;
|
||||||
else
|
else
|
||||||
curl --user ${GITEA_USER}:${GITEA_TOKEN} \
|
echo "Missing either GITEA_UPLOAD_FILENAME, GITEA_URL_DL, GITEA_URL_PUSH, GITEA_USER or GITEA_TOKEN environment variable";
|
||||||
--upload-file "${PACKAGE_DOWNLOAD}${GITEA_UPLOAD_FILENAME}-v${VERSION}.zip" \
|
|
||||||
${GITEA_URL_PUSH}?version=${VERSION};
|
|
||||||
echo "${VERSION}" > "${file_last_published}";
|
|
||||||
fi;
|
fi;
|
||||||
else
|
|
||||||
echo "Missing either GITEA_UPLOAD_FILENAME, GITEA_URL_DL, GITEA_URL_PUSH, GITEA_USER or GITEA_TOKEN environment variable";
|
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
# gitlab
|
# gitlab
|
||||||
if [ ! -z "${GITLAB_URL}" ] && [ ! -z "${GITLAB_DEPLOY_TOKEN}" ]; then
|
if [ -n "${GITLAB_PUBLISH}" ]; then
|
||||||
curl --data tag=v${VERSION} \
|
if [ -n "${GITLAB_URL}" ] && [ -n "${GITLAB_DEPLOY_TOKEN}" ]; then
|
||||||
--header "Deploy-Token: ${GITLAB_DEPLOY_TOKEN}" \
|
curl --data tag=v"${VERSION}" \
|
||||||
"${GITLAB_URL}";
|
--header "Deploy-Token: ${GITLAB_DEPLOY_TOKEN}" \
|
||||||
curl --data branch=master \
|
"${GITLAB_URL}";
|
||||||
--header "Deploy-Token: ${GITLAB_DEPLOY_TOKEN}" \
|
curl --data branch=master \
|
||||||
"${GITLAB_URL}";
|
--header "Deploy-Token: ${GITLAB_DEPLOY_TOKEN}" \
|
||||||
echo "${VERSION}" > "${file_last_published}";
|
"${GITLAB_URL}";
|
||||||
else
|
echo "${VERSION}" > "${file_last_published}";
|
||||||
echo "Missing GITLAB_DEPLOY_TOKEN environment variable";
|
else
|
||||||
|
echo "Missing GITLAB_URL or GITLAB_DEPLOY_TOKEN environment variable";
|
||||||
|
fi;
|
||||||
fi;
|
fi;
|
||||||
echo "";
|
echo "";
|
||||||
echo "[DONE]";
|
echo "[DONE]";
|
||||||
|
|||||||
@@ -16,16 +16,22 @@ class Html
|
|||||||
/**
|
/**
|
||||||
* full wrapper for html entities
|
* full wrapper for html entities
|
||||||
*
|
*
|
||||||
|
* uses default params as: ENT_QUOTES | ENT_HTML5
|
||||||
|
* switches from ENT_HTML401 to ENT_HTML5 as we assume all our pages have <!DOCTYPE html>
|
||||||
|
* removed: ENT_SUBSTITUTE -> wrong characters will be replaced with space
|
||||||
|
* encodes in UTF-8
|
||||||
|
* does not double encode
|
||||||
|
*
|
||||||
* @param mixed $string string to html encode
|
* @param mixed $string string to html encode
|
||||||
|
* @param int $flags [default: ENT_QUOTES | ENT_HTML5]
|
||||||
* @return mixed if string, encoded, else as is (eg null)
|
* @return mixed if string, encoded, else as is (eg null)
|
||||||
*/
|
*/
|
||||||
public static function htmlent(mixed $string): mixed
|
public static function htmlent(mixed $string, int $flags = ENT_QUOTES | ENT_HTML5): mixed
|
||||||
{
|
{
|
||||||
if (is_string($string)) {
|
if (is_string($string)) {
|
||||||
return htmlentities($string, ENT_COMPAT | ENT_HTML401, 'UTF-8', false);
|
return htmlentities($string, $flags, 'UTF-8', false);
|
||||||
} else {
|
|
||||||
return $string;
|
|
||||||
}
|
}
|
||||||
|
return $string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,14 +60,10 @@ class Html
|
|||||||
*/
|
*/
|
||||||
public static function checked(array|string $haystack, string $needle, int $type = 0): ?string
|
public static function checked(array|string $haystack, string $needle, int $type = 0): ?string
|
||||||
{
|
{
|
||||||
if (is_array($haystack)) {
|
if (is_array($haystack) && in_array($needle, $haystack)) {
|
||||||
if (in_array($needle, $haystack)) {
|
return $type ? 'checked' : 'selected';
|
||||||
return $type ? 'checked' : 'selected';
|
} elseif (!is_array($haystack) && $haystack == $needle) {
|
||||||
}
|
return $type ? 'checked' : 'selected';
|
||||||
} else {
|
|
||||||
if ($haystack == $needle) {
|
|
||||||
return $type ? 'checked' : 'selected';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1324,8 +1324,12 @@ class IO
|
|||||||
// /s for matching new line in . list
|
// /s for matching new line in . list
|
||||||
// [disabled, we don't used ^ or $] /m for multi line match
|
// [disabled, we don't used ^ or $] /m for multi line match
|
||||||
// Matches in 1:, must be array_filtered to remove empty, count with array_unique
|
// Matches in 1:, must be array_filtered to remove empty, count with array_unique
|
||||||
|
$query_split = '[(=,?-]|->|->>|#>|#>>|@>|<@|\?\|\?\&|\|\||#-';
|
||||||
preg_match_all(
|
preg_match_all(
|
||||||
'/(?:\'.*?\')?\s*(?:\?\?|<>|[(=,])\s*(?:\d+|(?:\'.*?\')|(\$[1-9]{1}(?:[0-9]{1,})?))/s',
|
'/'
|
||||||
|
. '(?:\'.*?\')?\s*(?:\?\?|<>|' . $query_split . ')\s*'
|
||||||
|
. '(?:\d+|(?:\'.*?\')|(\$[1-9]{1}(?:[0-9]{1,})?))'
|
||||||
|
. '/s',
|
||||||
$query,
|
$query,
|
||||||
$match
|
$match
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -39,9 +39,11 @@ class ConvertPlaceholder
|
|||||||
): array {
|
): array {
|
||||||
$convert_to = strtolower($convert_to);
|
$convert_to = strtolower($convert_to);
|
||||||
$matches = [];
|
$matches = [];
|
||||||
|
$query_split = '[(=,?-]|->|->>|#>|#>>|@>|<@|\?\|\?\&|\|\||#-';
|
||||||
$pattern = '/'
|
$pattern = '/'
|
||||||
// prefix string part, must match towards
|
// prefix string part, must match towards
|
||||||
. '(?:\'.*?\')?\s*(?:\?\?|[(=,])\s*'
|
// seperator for ( = , ? - [and json/jsonb in pg doc section 9.15]
|
||||||
|
. '(?:\'.*?\')?\s*(?:\?\?|' . $query_split . ')\s*'
|
||||||
// match for replace part
|
// match for replace part
|
||||||
. '(?:'
|
. '(?:'
|
||||||
// digit -> ignore
|
// digit -> ignore
|
||||||
@@ -96,7 +98,10 @@ class ConvertPlaceholder
|
|||||||
$type = 'named';
|
$type = 'named';
|
||||||
$matches_return = $named_matches;
|
$matches_return = $named_matches;
|
||||||
// only check for :named
|
// only check for :named
|
||||||
$pattern_replace = '/((?:\'.*?\')?\s*(?:\?\?|[(=,])\s*)(\d+|(?:\'.*?\')|(:\w+))/s';
|
$pattern_replace = '/'
|
||||||
|
. '((?:\'.*?\')?\s*(?:\?\?|' . $query_split . ')\s*)'
|
||||||
|
. '(\d+|(?:\'.*?\')|(:\w+))'
|
||||||
|
. '/s';
|
||||||
// 0: full
|
// 0: full
|
||||||
// 1: pre part
|
// 1: pre part
|
||||||
// 2: keep part UNLESS '3' is set
|
// 2: keep part UNLESS '3' is set
|
||||||
@@ -134,7 +139,10 @@ class ConvertPlaceholder
|
|||||||
// order and data stays the same
|
// order and data stays the same
|
||||||
$params_new = $params;
|
$params_new = $params;
|
||||||
// only check for ?
|
// only check for ?
|
||||||
$pattern_replace = '/((?:\'.*?\')?\s*(?:\?\?|[(=,])\s*)(\d+|(?:\'.*?\')|(?:(?:\?\?)?\s*(\?{1})))/s';
|
$pattern_replace = '/'
|
||||||
|
. '((?:\'.*?\')?\s*(?:\?\?|' . $query_split . ')\s*)'
|
||||||
|
. '(\d+|(?:\'.*?\')|(?:(?:\?\?)?\s*(\?{1})))'
|
||||||
|
. '/s';
|
||||||
// 0: full
|
// 0: full
|
||||||
// 1: pre part
|
// 1: pre part
|
||||||
// 2: keep part UNLESS '3' is set
|
// 2: keep part UNLESS '3' is set
|
||||||
@@ -163,7 +171,10 @@ class ConvertPlaceholder
|
|||||||
$type = 'numbered';
|
$type = 'numbered';
|
||||||
$matches_return = $numbered_matches;
|
$matches_return = $numbered_matches;
|
||||||
// only check for $n
|
// only check for $n
|
||||||
$pattern_replace = '/((?:\'.*?\')?\s*(?:\?\?|[(=,])\s*)(\d+|(?:\'.*?\')|(\$[1-9]{1}(?:[0-9]{1,})?))/s';
|
$pattern_replace = '/'
|
||||||
|
. '((?:\'.*?\')?\s*(?:\?\?|' . $query_split . ')\s*)'
|
||||||
|
. '(\d+|(?:\'.*?\')|(\$[1-9]{1}(?:[0-9]{1,})?))'
|
||||||
|
. '/s';
|
||||||
// 0: full
|
// 0: full
|
||||||
// 1: pre part
|
// 1: pre part
|
||||||
// 2: keep part UNLESS '3' is set
|
// 2: keep part UNLESS '3' is set
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class CachedFileReader extends \CoreLibs\Language\Core\StringReader
|
|||||||
if (!is_resource($fd)) {
|
if (!is_resource($fd)) {
|
||||||
$this->error = 3; // Cannot read file, probably permissions
|
$this->error = 3; // Cannot read file, probably permissions
|
||||||
} else {
|
} else {
|
||||||
$this->fd_str = fread($fd, filesize($filename) ?: 0) ?: '';
|
$this->fd_str = fread($fd, filesize($filename) ?: 1) ?: '';
|
||||||
fclose($fd);
|
fclose($fd);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ class SmartyExtend extends \Smarty
|
|||||||
// call basic smarty
|
// call basic smarty
|
||||||
// or Smarty::__construct();
|
// or Smarty::__construct();
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
// iinit lang
|
// init lang
|
||||||
$this->l10n = $l10n;
|
$this->l10n = $l10n;
|
||||||
// parse and read, legacy stuff
|
// parse and read, legacy stuff
|
||||||
$locale = $this->l10n->getLocaleAsArray();
|
$locale = $this->l10n->getLocaleAsArray();
|
||||||
|
|||||||
2
tmp/.gitignore
vendored
Normal file
2
tmp/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*
|
||||||
|
!.gitignore
|
||||||
Reference in New Issue
Block a user