<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<!--Вот то, что я предложил -->
<h1>Page number {{ .Number }}</h1>
{{ range .Posts }}
<h2>{{ .Title }}</h2>
<p>{{ .Body }}</p>
{{ end }}
<!--А вот то, что вы хотели -->
<h1>Page number {{ .Number }}</h1>
{{ range .Posts.GetSublistByPagenumber .Number }}
<h2>{{ .Title }}</h2>
<p>{{ .Body }}</p>
{{ end }}
</body>
</html>
package main
import (
"html/template"
"log"
"os"
)
// Структура поста
type Post struct {
ID int
Author string
Title string
Body string
PostingTime string
UpdateTime string
Tags string
Lock int
}
type Posts []Post
func (posts Posts) GetSublistByPagenumber(pageNumber int) Posts {
return Posts{
Post{
ID: 1,
Author: "Vitaliy",
Title: "First post",
Body: "Hello, world!",
PostingTime: "2021-10-10 10:00:00",
UpdateTime: "2021-10-10 10:00:00",
Tags: "first, post",
Lock: 0,
},
Post{
ID: 2,
Author: "Alex",
Title: "Second post",
Body: "Hello, world!",
PostingTime: "2021-10-10 10:00:00",
UpdateTime: "2021-10-10 10:00:00",
Tags: "second, post",
Lock: 0,
},
}
}
// Структура с уже готовыми заполненными данными без всяких методов
type PostTemplate struct {
Number int
Posts Posts
}
func main() {
posts := Posts{}
// Подготавливаем список заранее
sublist := posts.GetSublistByPagenumber(1)
postVars := PostTemplate{
Number: 1,
Posts: sublist,
}
tmpl, err := template.ParseFiles("index.html")
if err != nil {
log.Println(err.Error())
return
}
w := os.Stdout
err = tmpl.Execute(w, postVars)
if err != nil {
log.Println(err.Error())
}
}
const permissions = {
"view answers": ["ROLE_GUEST", "ROLE_USER"],
"add answers": ["ROLE_USER"],
"delete answers": ["ROLE_MODERATOR"],
"delete own answers": ["ROLE_USER"],
"edit answers": ["ROLE_MODERATOR"],
"edit own answers": ["ROLE_USER"],
"change status": ["ROLE_MODERATOR"],
};
const user1 = {
roles: ["ROLE_USER"],
};
const user2 = {
roles: ["ROLE_USER", "ROLE_MODERATOR"],
};
function checkPermission(user, action) {
const activeRoles = permissions[action].filter((role) =>
user.roles.includes(role),
);
return activeRoles.length > 0;
}
console.log(checkPermission(user1, "view answers")); // true
console.log(checkPermission(user1, "delete answers")); // false
console.log(checkPermission(user1, "delete own answers")); // true
console.log(checkPermission(user2, "delete answers")); // true
console.log(checkPermission(user2, "delete own answers")); // true
class ClassWithPrivate {
#privateField;
publicField;
constructor() {
this.#privateField = "Доступ только изнутри класса";
}
}
const instance = new ClassWithPrivate();
instance.publicField = "Доступ извне класса";
instance.#privateField; // Ошибка: SyntaxError: Private field '#privateField' must be declared in an enclosing class
class Animal {
constructor(name) {
this.speed = 0;
this.name = name;
}
run(speed) {
this.speed = speed;
alert(`${this.name} бежит со скоростью ${this.speed}.`);
}
stop() {
this.speed = 0;
alert(`${this.name} стоит.`);
}
}
class Rabbit extends Animal {
hide() {
alert(`${this.name} прячется!`);
}
stop() {
super.stop(); // вызываем родительский метод stop
this.hide(); // и затем hide
}
}
let rabbit = new Rabbit("Белый кролик"); // используется конструктор родителя
rabbit.run(5); // Белый кролик бежит со скоростью 5.
rabbit.stop(); // Белый кролик стоит. Белый кролик прячется!
<html>
<body onload="Load()">
<dialog></dialog>
<script>
function Load() {
setTimeout(() => {
// Создаём колбэк, функцию, которая будет вызываться только после нажатия на кнопку
const callback = function () {
alert("!");
};
Myconfirmselect(
"Готовы?" +
"¤" +
"Да" +
"¥" +
"alert('Да');" +
"º" +
"Нет" +
"¥" +
"alert('Нет');",
callback, // Передаём колбэк в функцию создания диалога
);
}, 500);
}
function Myconfirmselect(VarInput, callback) {
const dialog = document.querySelector("dialog");
dialog.innerHTML += `
<div>
<textarea></textarea>
</div>
`;
const textarea = dialog.querySelector("textarea");
const div = dialog.querySelector("div");
dialog.style.textAlign = "center";
textarea.style.width = "100%";
textarea.style.textAlign = "center";
textarea.style.resize = "none";
textarea.readOnly = true;
textarea.value = VarInput.split("¤")[0];
for (
let i = 0;
i < VarInput.split("¤")[1].split("º").length;
i++
) {
const VarButton = document.createElement("button");
VarButton.textContent = VarInput.split("¤")[1]
.split("º")
[i].split("¥")[0];
VarButton.id = VarInput.split("¤")[1]
.split("º")
[i].split("¥")[1];
VarButton.style.marginLeft = "10px";
VarButton.style.marginTop = "10px";
VarButton.addEventListener("click", () => {
eval(event.target.id);
// Вызов того самого callback после нажатия на кнопку
callback();
//ButtonClosealert();
});
div.appendChild(VarButton);
}
function ButtonClosealert() {
dialog.style.animation = "AnimFormHide 0.1s both";
setTimeout(() => {
dialog.style.textAlign = "initial";
const div = dialog.querySelector("div");
dialog.removeChild(div);
dialog.close();
}, 100);
}
dialog.style.animation = "AnimFormShow 0.25s both";
dialog.showModal();
}
</script>
<style>
@keyframes AnimFormShow {
0% {
transform: translateY(-150%);
}
}
@keyframes AnimFormHide {
100% {
transform: translateY(-150%);
display: none;
}
}
dialog,
#DialogCycle {
border: 2px solid black;
border-radius: 15px;
}
dialog div,
#DialogCycle div {
position: initial;
}
dialog::backdrop,
#DialogCycle::backdrop {
background: rgba(0, 0, 0, 0.6);
}
</style>
</body>
</html>
package app
import (
"fmt"
"io"
"log/slog"
"os"
)
// SetupLogger создаёт логгер на основании конфига
// Конфигурируем дефолтный slog и возвращаем функцию закрытия файла логов,
// если был выбран файл как место логгирования.
func SetupLogger(cfg config.Config) func() error {
closer := func() error { return nil }
level := cfg.LogLevel
var w io.Writer
switch cfg.LogOutput {
case config.LogOutputStderr:
w = os.Stderr
case config.LogOutputStdout:
w = os.Stdout
case config.LogOutputFile:
w, closer = getFileWriter(cfg)
}
var handler slog.Handler
switch cfg.LogFormat {
case config.LogFormatText:
handler = slog.Handler(slog.NewTextHandler(w, &slog.HandlerOptions{Level: level}))
case config.LogFormatJSON:
handler = slog.Handler(slog.NewJSONHandler(w, &slog.HandlerOptions{Level: level}))
}
slog.SetDefault(slog.New(handler))
return closer
}
// getFileWriter возвращает файл, куда писать логи и функцию закрытия этого файла
func getFileWriter(cfg config.Config) (*os.File, func() error) {
logDir := fmt.Sprintf("%s/%s", cfg.VarDir, cfg.LogDir)
err := os.MkdirAll(logDir, 0755)
if err != nil {
panic(fmt.Sprintf("error creating directory: %s; %v", logDir, err))
}
filename := fmt.Sprintf("%s/%s.log", logDir, cfg.AppEnv)
f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
panic(fmt.Sprintf("error opening file: %s %v", filename, err))
}
return f, f.Close
}
package main
import "app"
func main() {
// .....
closeLogFile := app.SetupLogger(cfg)
defer closeLogFile()
// ...
}
docker run --detach \ # Запускаем контейнер в фоновом режиме
--publish 443:443 --publish 80:80 --publish 22:22 \ # Открываем порты. Можете поставить те, что вам нужны, если эти уже используются где-то
--name gitlab \ # Имя контейнера
--restart always \ # Перезапускать контейнер при его остановке или перезагрузке
--volume gitlab_config:/etc/gitlab \ # Подключаем том для конфигурации
--volume gitlab_logs:/var/log/gitlab \ # Подключаем том для логов
--volume gitlab_data:/var/opt/gitlab \ # Подключаем том для данных
--shm-size 2gb \ # Устанавливаем размер разделяемой памяти
gitlab/gitlab-ee:latest
docker compose up -d
version: '3.6'
services:
web:
image: 'gitlab/gitlab-ee:latest'
container_name: gitlab
restart: always
ports:
- '80:80'
- '443:443'
- '22:22'
volumes:
- 'gitlab_config:/etc/gitlab'
- 'gitlab_logs:/var/log/gitlab'
- 'gitlab_data:/var/opt/gitlab'
shm_size: '2gb'
volumes:
gitlab_config: {}
gitlab_logs: {}
gitlab_data: {}
docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password