все на php7.3, mysql 5.7, nginx
location /project-42 { root /projects/project-42; ... }
### или целый блок
server {
listen 80;
server_name project42.dev;
...
}
nginx:
volumes:
- "/freelance/projects/Project-0/:/var/www/project0"
- "/freelance/projects/Project-42/:/var/www/project42"
# ...
php-fpm:
volumes:
# то же самое сюда
2) Как проектам дать не localhost:8080, а нормальный урл типа project.dev?
docker-compose.yml
пропишите вместо 8080:80
— 80:80
, а в локальном файле hosts допишите 127.0.0.1 project.dev project42.dev
[10, 20, 30, 50, 235, 3000].filter(n => !!~[1,2,5].indexOf(+n.toString()[0]))
// результат [ 10, 20, 50, 235 ]
Вывод на экран пилите самостоятельно.filter()
оставит только те элементы, для которых функция внутри вернёт true
. Функция аргумент (в скобках) применяется по очереди к каждому элементу массива (числу).+
).indexOf()
ищет полученную первую цифру в массиве допустимых: 1, 2, 5 и возврашает его индекс (0, 1 или 2) или -1, если не найдено.~
из -1 сделает 0. А из любого другого числа (из 0, 1 или 2) – сделает ненулевое число. Два !!
это два булевых оператора отрицания. Из аргумента делают true
или false
. Из 0 получится false
, из любого другого true
. Таким образом связка !!~
и indexOf()
даёт ответ на вопрос найден или не найден? getRangeAt(0)
Range
есть свойства startOffset
и endOffset
– то, про что спрашиваете.youtube.readonly
на доступ к своим данным.composer require google/apiclient:^2.0
, в API консоли создать проект, создать OAuth ключ, скачать его JSON. value=""
function reset() {
[...document.querySelectorAll('section.main input[type="text"]')]
.forEach( el => el.value='' )
;
}
document.getElementsByClassName('budget_day-value')[0]
document.querySelector('.budget_day-value')
<label>
, и либо указывать id
инпута в атрибуте for=""
, либо включать инпут внутрь этого лейбла. Так клик по названию поля сделает фокус внутри этого поля.(100% - 6.51%) = 93.49%
; операция равносильна умножению на 0.9349
0.94
x * 0.9349 * 0.94 = x * 0,878806
без погрешностей, точно.
Замыкания
В программировании есть общий термин: «замыкание», – которое должен знать каждый разработчик.
Замыкание – это функция, которая запоминает свои внешние переменные и может получить к ним доступ. В некоторых языках это невозможно, или функция должна быть написана специальным образом, чтобы получилось замыкание. Но, как было описано выше, в JavaScript, все функции изначально являются замыканиями (есть только одно исключение, про которое будет рассказано в Синтаксис "new Function
").
То есть, они автоматически запоминают, где были созданы, с помощью скрытого свойства[[Environment]]
и все они могут получить доступ к внешним переменным.
Когда на собеседовании фронтенд-разработчик получает вопрос: «что такое замыкание?», – правильным ответом будет определение замыкания и объяснения того факта, что все функции в JavaScript являются замыканиями, и, может быть, несколько слов о технических деталях: свойстве[[Environment]]
и о том, как работает лексическое окружение.
const onClick = event => {
const nodeList = document.querySelectorAll('.item');
for (let i=0; i<nodeList.length; i++ ) {
nodeList[i].style = (nodeList[i] === event.target ? 'background:red' : 'background:green');
};
}
.item {background: green } // по умолчанию все зелёные
.item-red {background: red } // тот самый
// clickedEl — item, по которому кликнули
[...document.querySelectorAll('.item')].forEach(el => {
if (clickedEl === el) el.classList.add('item-red');
else el.classList.remove('item-red');
});
docker network connect myapp_default mysql
mysql
, как и требовалось. while()
и не for()
— может, прокатит?// случайные:
const myArray = [...Array(3)]
.map(
row =>
[...Array(3)]
.map(
el => Math.floor(Math.random() * 10)
)
)
;
// диагональ, где оба индекса равны:
const diagonal = myArray
.map(
(row, rowIndex) =>
row
.map(
(el, elIndex) => rowIndex === elIndex ? 1 : 0
)
)
;
/**
* асинхрота с запросом. Возвращает Promise
*/
const doAsyncStuff = (urlIter, urlSite) => new Promise((resolve, reject) => {
needle.get(urlIter, (err, result) => { // Сама асинхронная функция
if (err) reject(err);
$('.product-card__link')
.each((i, val) => prodLink.push(urlSite + $(val).attr("href")));
resolve();
})
})
/**
* Тот самый цикл
* @param {number} quanPage число страниц
*/
const doStuff = async quanPage => {
for(let i = 1; i <= quanPage; i++) {
let urlIter = urlSite + i; // Ссылка, которая создается с каждой новой итерацией
await doAsyncStuff(urlIter, urlSite); // Ждём-с!
}
}
doStuff(10);
if(check){
if(true || check) { // временно убрали проверку заполнения всех полей. TODO убрать костыль
function sub(form_id){
$("#img_loader").val($("#files").find("img").attr("src"));
$.ajax({
type: 'POST',
url: '/php.php',
data: $('#'+form_id).serialize(),
success: function(data) {
$("#recall_wrapper").html("<p class='title_recall'>Ваш отзыв успешно отправлен</p>");
setTimeout(() => window.location.href='/recalls_ok.htm', 1000); // перекидывать не сразу, а через 1 сек
},
error: function(xhr, str){
$("#status__send").text('Возникла ошибка: ' + xhr.responseCode);
}
});
}