Страницы

Поиск по вопросам

четверг, 2 января 2020 г.

Активити создается с нуля при возвращении из нового активити

#android


Есть активити MainActivity, содержащее пару фрагментов прописанных через xml. Также
есть еще одно активити, запускаемое из MainActivity. При возвращении из это нового
активити в основное происходит следующее: сначала вызывается метод onDestroy основного
активити который также убивает все фрагменты, а затем все создается заново как при
простом запуске.

Может кто ни будь объяснить мне такое поведение андроида и как тогда сохранить между
такими пересоздаваниями состояния активити и фрагментов. Например Текст или изображения,
заданные не через xml, а в коде или массив данных?

ЗЫ. Руководствовался этой схемой, но вроде бы они все одинаковые в интернете и на
всех схемах onDestroy вызывается только при уничтожении активити

// Старт приложения
MainActivity.onCreate called

PlayerFragment.onCreate called
PlayerFragment.onCreateView called

PlaylistFragment.onCreate called
PlaylistFragment.onCreateView called

MainActivity.onResume called

// Запуск нового активити
PreferencesActivity.onCreate called

// Жмем кнопку назад
MainActivity.onDestroy called  // Почему это а не onResume?
PlayerFragment.onDestroy called
PlaylistFragment.onDestroy called

MainActivity.onCreate called
PlayerFragment.onCreate called
PlayerFragment.onCreateView called
PlaylistFragment.onCreate called
PlaylistFragment.onCreateView called

MainActivity.onResume called

    


Ответы

Ответ 1



Если вы делаете переход назад onBackPressed() или finish() покажите ваш манифест. Исходя из вашего ответа вы выставили определенную стратегию в launchMode, аналогичное поведение было бы если бы у вас стояло android:launchMode="singleInstance" или android:launchMode="singleTask" после этого вы заменили на android:launchMode="singleTop" и это standart condition, те обычное поведеине со стратегией не создавать новый экземплер если он на вершине стека. Возмоно также вы делали переход с помощью намерениея Intent, здесь тогда все становится намного сложней. Вам кажется что вы сделали переход назад, но по факту вам ещё нужно следить за PreferencesActivity она у вас ещё в стеке, вы выставили singleTop и просто не пересозадил активити с вершиной на стеке, будьте внимательны использую задачи и стек переходов, это очень важно. Вы можете, сделать серфинг по приложению - бесшовным и плавным при этом экономить проц время и объем потреблям трафика. Здесь есть все для того чтоб понять суть https://developer.android.com/guide/components/tasks-and-back-stack?hl=ru удачи

Ответ 2



Это очень странно, но помогло добавление атрибута основной активити android:launchMode="singleTop" После этого система перестала пересоздавать это активити с нуля

C++ Vector и его метод Push_back

#cpp #vector


Имеется некий код:

A a1;
A a2;
A a3;
std::vector a;
std::cout << "Push back a1" << std::endl;
a.push_back(a1);
std::cout << "Push back a2" << std::endl;
a.push_back(a2);
std::cout << "Push back a3" << std::endl;
a.push_back(a3);


И разумеется класс А.

class A {
static int ACount;
private:

public:
A() {
    std::cout << "Constructor called. Objects = " << ++ACount << std::endl;
}
~A() {
    std::cout << "Destructor called. Objects = " << --ACount << std::endl;
}
A(const A &a) {
    std::cout << "Copy Constructor called. Objects = " << ++ACount << 
std::endl;
}
};
int A::ACount;


Вывод с консоли такой:

Constructor called. Objects = 1
Constructor called. Objects = 2
Constructor called. Objects = 3
Push back a1;
Copy constructor called. Objects = 4
Push back a2;
Copy constructor called. Objects = 5
Copy constructor called. Objects = 6
Destructor called. Objects = 5
Push back a3;
Copy constructor called. Objects = 6
Copy constructor called. Objects = 7
Copy constructor called. Objects = 8
Destructor called. Objects = 7
Destructor called. Objects = 6
Destructor called. Objects = 5
Destructor called. Objects = 4
Destructor called. Objects = 3
Destructor called. Objects = 2
Destructor called. Objects = 1
Destructor called. Objects = 0


Не могу понять почему при вызове метода Push_back(а2) вызывается 2 раза конструктор
копирования, а при Push_back(а3) целых 3 раза. Пытаюсь создать некое подобие граф движка
и создание\уничтожение такого числа объектов мне очень навредит. Как быть? Или стоит
поискать некий иной контейнер?
    


Ответы

Ответ 1



Происходит переаллокация вектора при каждом push_back. Вы видите вызовы конструкторов копирования для копирования элементов со старого места на новое, а затем деструкцию элементов на старом месте. Сделайте предварительное a.reserve(100); и "лишние" копирования и деструкции пропадут.

Ответ 2



Не могу понять почему при вызове метода Push_back(а2) вызывается 2 раза конструктор копирования, а при Push_back(а3) целых 3 раза При увеличении размера вектора создается новый вектор, в него копируются все элементы старого и заpushенный элемент, а затем все элементы старого уничтожаются. Это связанно с тем, что вектор гарантирует последовательное непрерывное хранение элементов в памяти. Как быть? Можно заранее зарезервировать достаточное количество элементов. Или стоит поискать некий иной контейнер? Это зависит от того, что вам нужно от контейнера. Какие именно операции вы будете с ним делать. У вектора поиск произвольного элемента идет за константное время, а добавление нового (если специально не резервировать пространство) - за O(N). Также вектор можно передавать в функции как указатель на C-like массив. У списка за константное время идет поиск, добавление и удаление первого и последнего элемента, а произвольного элемента - за O(N).

git config для нескольких разработчиков

#git


Начинаю изучать гит, репозиторий использую битбакет, сразу возник вопрос:

Например подключился к боевому сайту по ssh, сделал git init в нужной директории.
Настраиваю git config user.email и git config user.name

Далее все мои действия будут фиксироваться с этими данными (я правильно понимаю?).

Далее, мой коллега подключится к этому же проекту через ssh, и прописывает git config
user.email и видит мой email. 

Соответственно его действия будут фиксироваться под моими данными? Как сделать чтобы
у него был свой user name и email? Если он пропишет свои данные через git config user.email,
то перезапишет мои.

Что я не так понял?
    


Ответы

Ответ 1



хотя вопрос и продиктован несколько неверным пониманием того, что же такое есть система управления версиями, и по этому поводу уже дан замечательный ответ, но… но иногда (пусть и редко) случается необходимость работать с git-хранилищем двум и более пользователям из-под одной и той же учётной записи (подключаясь к машине по протоколу ssh). как в такой ситуации пользователям передать команде commit разные данные (имя и почтовый адрес) о себе? для этого можно, например, использовать переменные окружения. их четыре и все они должны иметь значения (тогда и только тогда программа git ими воспользуется при выполнении команды commit): export GIT_AUTHOR_NAME="ваше имя" export GIT_AUTHOR_EMAIL="ваш@адр.ес" export GIT_COMMITTER_NAME="${GIT_AUTHOR_NAME}" export GIT_COMMITTER_EMAIL="${GIT_AUTHOR_EMAIL}" эти команды имеет смысл каждому из пользователей добавить в «ресурсный файл» своей оболочки. в случае, например, программы bash — это ~/.bashrc. чтобы они при подключении «попали» в экземпляр оболочки, запускаемый на удалённой машине, нужно: в конфигурации локальной программы ssh указать их отправку, добавив где-нибудь в начале файла ~/.ssh/config строку: sendenv GIT_* в конфигурации удалённой программы sshd указать их приём, добавив в файл /etc/ssh/sshd_config строку (программу надо будет после этого перезапустить): acceptenv GIT_* доп. чтение: man git-config man git-commit-tree man ssh_config man sshd_config

Ответ 2



есть понятия: репозиторий (у вас битбакет) и локальный репозиторий (который находится на вашем компе и доступен под вашим аккаунтом) в собственно репозитории никто напрямую не правит. код вы правите на своем локальном компьютере. и настраиваете git config user.email, git config user.name на локальном. первое, что вы должны сделать - клонировать к себе в локальный репозиторий файлы из общего битбакета. далее даете команду развернуть сами файлы из локального репозитория. далее правите файлы в локали. потом даете команду гиту, чтобы ваши измененные файлы сначала записал в локальный репозиторий (здесь то конфиг юзера и действует). в конце даете команду гиту, чтобы он синхронизировал локальный и общий репозиторий. некоторые действия выполняются гитом в одну команду.

Ответ 3



Если вы на своей машине, находясь в папке репозитория введете git config user.name "UserName" - эта настройка сохранится в настройках вашего репозитория. Но вы не сможете это закоммитить и потом запушить на удаленный сервер. Настройки не коммитятся, они есть только в вашем репозитории и никак не могут попасть на компьютер к вашему коллеге. Но судя по вашему вопросу вы как-то нестандартно используете гит. Похоже вы по очереди работаете с одной и той же машины. С гитом обычно работают так - есть центральный репозиторий, на сервере, в Bitbucket например. Разработчик, который хочет что-то в этот репозиторий закоммитить, клонирует репозиторий на свою машину, настраивает свое имя и почту (и эти настройки он никак не может отправить в центральный репозиторий, они есть только в его копии), потом что-то меняет, коммитит и вот этот коммит он уже может отправить в центральный репозиторий (git push) что-бы его увидели остальные разработчики.

Django Admin, SELECT по полям

#python #django


Есть модуль UserTask в которой есть очень тяжелые поля и они тормозят запрос, как
можно убрать их из запроса для Django Admin.

Они не выводятся на страницу, но Django использует примерно такой запрос:

SELECT * FROM UserTask;


А нужно:

SELECT id, name, is_user FROM UserTask;


P.S. Нужно убрать их именно в админке, вот регистрация модели:

class UserTaskAdmin(admin.ModelAdmin):
    list_filter = ('id', 'name')
    list_display = ('id', 'name')    


admin.site.register(UserTask, UserTaskAdmin)


кривой перевод на английский 
    


Ответы

Ответ 1



Вы можете переопределить get_queryset() и использовать only() метод: class UserTaskAdmin(admin.ModelAdmin): list_filter = ('id', 'name') list_display = ('id', 'name') def get_queryset(self, request): return self.model.objects.only('id', 'name') Немного изменил оригинал, там использовался UserTask.objects.only('id', 'name'), за места self.model.objects.only('id', 'name'), что ограничивало повторное использования кода с другими моделями. Оригинал от @neverwalkaloner.

Вывести сообщение, что каждый элемент списка содержит вхождение регулярного выражения

#python #python_3x #регулярные_выражения


1. Кратко

См. заголовок.



2. Минимальный пример

Имеется список.

sashalist = ['Sasha1', 'Sasha14', 'Sasha4147']


Необходимо проверить, что каждый элемент списка содержит $вхождение, и если действительно
содержит, вывести сообщение.

Положим, $вхождение — цифра 1. Работающий пример:


Демо на Ideone


sashalist = ['Sasha1', 'Sasha14', 'Sasha4147']

if all('1' in item for item in sashalist):
    print('Все элементы списка содержат «1»!')



Вывод:


Все элементы списка содержат «1»!


Если же $вхождение — это регулярное выражение, (например, \d), то не найду, что я
должен сделать.



3. Попытки справиться с проблемой самостоятельно

3.1. Аналогия


Демо на Ideone


import re


sashalist = ['Sasha1', 'Sasha14', 'Sasha4147']
sasharegex = r'\d'

if all(re.search(sasharegex, sashalist) in item for item in sashalist):
    print('Все элементы списка содержат цифру!')



Получаю traceback:


Traceback (most recent call last):
  File "./prog.py", line 7, in 
  File "./prog.py", line 7, in 
  File "/usr/lib/python3.5/re.py", line 173, in search
    return _compile(pattern, flags).search(string)
TypeError: expected string or bytes-like object


3.2. Цикл


Демо на Ideone


import re


sashalist = ['Sasha1', 'Sasha14', 'Sasha4147']
sasharegex = r'\d'

for item in sashalist:
    sasharegexsearch = re.search(sasharegex, item)
    if sasharegexsearch:
        print("Все пункты списка содержат цифру!")



Сообщение выводится после проверки каждого элемента:


Все пункты списка содержат цифру!
Все пункты списка содержат цифру!
Все пункты списка содержат цифру!


А нужно, чтобы вывелось одно сообщение после успешной проверки всего списка.
    


Ответы

Ответ 1



https://ideone.com/msQnop import re sashalist = ['Sasha1', 'Sasha14', 'Sasha4147'] sasharegex = r'Sas' if all(re.search(sasharegex, item) for item in sashalist): print('All elements have sasharegex !')

Как сверстать такую обводку?

#html #css




Пробовал так:



.text p{
        position: relative;
	text-transform: uppercase;
  z-index: 1;
    margin-top: 30px;
    color: #fde428;
    display: inline-block;
    cursor: pointer;
border-bottom: 2px solid #fde428;

}

.text{
    position: relative;
    text-align: right;
	width: 50%;
 
  
}
.text h2{
position: relative;

}
.text::after{
    content: "";
    width: 180px;
    height: 220px;
    border: 5px solid #fde428;
    position: absolute;
    border-left: transparent;

    top: -20px;
right: calc(50px - 180px);
}
.text h2::after{

         content: "";
        width: 5px;
    height: 16px;
    background: #fde428;
    position: absolute;
    border-left: transparent;
top: -17px;
right: 50px;

}
.text p::after{
     content: "";
    text-decoration: none;
    width: 5px;
    height: 16px;
    
       cursor: default; background:#fde428;
    position: absolute;
    border-left: transparent;
    top: -22px;
    right: 50%;
}
.text p:before{
        text-decoration: none;
     content: "";
    width: 5px;
    height: 54px;
     cursor: default;  background:#fde428;
    position: absolute;
    border-left: transparent;
    top: 22px;
    right: 50%;
}
          

Consumer
Products
Consulting

LEARN MORE

Да уж больно криво и костыльно мне кажется.


Ответы

Ответ 1



Могу предложить такое решение на codePen.io. body { background-color: #555; } .text{ position: relative; margin: 0 auto; text-align: right; width: 180px; height: 220px; border: 5px solid #fde428; border-left: transparent; } .text::before, .text::after { content: ""; position: absolute; left: -5px; display: block; width: 5px; } .text::before { height: 20px; box-shadow: 5px 125px 0 #fde428; } .text::after { height: 40px; box-shadow: 5px 0 0 #fde428, 5px 180px 0 #fde428; } .text h2{ position: absolute; color: white; top: 10%; transform: translateX(-60%); } .text p{ position: absolute; bottom: 15%; transform: translateX(-50%); text-transform: uppercase; color: #fde428; cursor: pointer; border-bottom: 2px solid #fde428; }

Ответ 2



Если бы не промежуточный бордер все было бы совсем красиво. А так пока промежуточный вариант, может кто поправит... body { display: flex; min-height: 100vh; background-color: darkblue; font-family: sans-serif; --bordersize: 8px; } fieldset { margin: auto; min-width: 8em; min-height: 6em; transform: rotate(-90deg); border: var(--bordersize) solid yellow; } legend { transform: rotate(90deg); color: white; font-size: 160%; text-align: right; } legend a { color: yellow; font-size: 50%; font-weight: 600; text-transform: uppercase; display: block; margin: 1em 0; position: relative; } legend a::after { content: ''; border: calc(var(--bordersize) / 2) solid yellow; position: absolute; right: calc(50% - calc(var(--bordersize) / 2)); top: -1em; height: .4em; }
Lorem
ipsumLearn more


Ответ 3



Добавлю и свой вариант) .demo { background-color: black; padding: 50px; } /* example */ .container { position: relative; width: 250px; height: 220px; border: 10px solid yellow; border-left: none; font-family: Arial; margin: 0 auto; margin-left: 48%; padding-bottom: 40px; } .container .content p:after, .container .content p:before, .container .content a:after { content: ""; position: absolute; display: block; width: 10px; background-color: yellow; } .container:before { height: 40px; } .container:after { height: 40px; margin-top: 10px; } .container .content { display: inline-block; position: relative; left: -48%; text-align: right; } .container .content p { font-size: 35px; color: white; } .container .content p:after { height: 40px; left: 48%; } .container .content p:before { height: 40px; top: 0px; left: 48%; } .container .content a { font-size: 25px; color: yellow; display: block; } .container .content a, .container .content p { margin-right: 25%; } .container .content a:after { top: calc(100% + 5px); height: 40px; left: 48%; } .container .content a:hover { color: green; }

Consumer Products Consulting

Learn more


Как записать значение в переменную во время выполнения асинхронной функции JavaScript [дубликат]

#javascript


        
             
                
                    
                        
                            This question already has answers here:
                            
                        
                    
                
                        
                            Как вернуть значение из события или из функции обратного
вызова? Или хотя бы дождаться их окончания
                                
                                    (3 ответа)
                                
                        
                                Закрыт 1 год назад.
            
                    
Имеется метод

function user_info (login) {

    var info;

    this.pool.getConnection(function(err, connection) {
        if (err) throw err;
        connection.query('SELECT * FROM user WHERE login = ?', [login], function
(error, results, fields) {
            info = results;
            connection.release();

        });
    });

    return info;
}


В данном примере в info получаю undefined, тогда как в results записан объект(проверял
через дебаг)

Мне нужно вернуть методом user_info объект results, как это сделать?
Пробовал почти всё кроме промисов
    


Ответы

Ответ 1



function user_info (login, callback) { this.pool.getConnection(function(err, connection) { if (err) throw err; connection.query('SELECT * FROM user WHERE login = ?', [login], function (error, results, fields) { connection.release(); callback(results); }); }); } db.user_info(cookies.login, function(info){ /* code that uses user info */ });

Ответ 2



JS однопоточный, но не надо пытаться делать все по порядку: //Плохой подход для JS var данные; данные = запрашиваем_данные_из_далека(); обрабатываем_данные(данные); вместо этого на JS делается так: //Хороший подход для JS обрабатываем_данные(данные){ } запрашиваем_данные_из_далека(обрабатываем_данные); То есть не надо делать все при первом проходе (ждать данные). Указал функции для обратного вызова, вышел и ждешь. В вашем случае можно использовать Promise и async/await, но лучше, то что выполняется после: var data = user_info("Admin"); вынести в функцию обратного вызова (callback).

Ответ 3



Предлагаю вот такой вариант: import mysql from 'promise-mysql'; var mysqlConfig = { ... }; async function user_info (login) { try { var connection = await mysql.createConnection(mysqlConfig); var info = await connection.query(`SELECT * FROM user WHERE login="${ login }";`); connection.end(); return info; } catch (error) { throw error; } } Кстати, сохранил Ваш стиль, но заканчивайте уже использовать var)

Ответ 4



Кстати, если максимально использовать Ваш код, предлагаю такой вариант: function user_info (login) { var info = this.pool.getConnection(function(err, connection) { if (err) throw err; connection.query('SELECT * FROM user WHERE login = ?', [login], function (error, results, fields) { if (error) throw error; // здесь то тоже ошибку стоит обработать connection.release(); return results; // кстати, т.к. мы то знаем, что у нас только 1 пользователь с таким логином, // я бы сразу возвращал results[0] }); }); return info; }

Обучение нейронной сети теореме Пифагора

#python #нейронные_сети #машинное_обучение #keras #обучение_с_подкреплением


Хочу обучить НС теореме Пифагора. Всё вроде правильно сделал, нормализовал данные,
модель правильная, а вот в чём ошибка не понятно..

import numpy as np

from keras.models import Sequential
from keras.layers.core import Dense, Activation
from keras.utils import np_utils

np.random.seed()

NB_EPOCH = 500
VERBOSE = 1

X_in = [[ 0 , 44 ], [ 0 , 18 ], [ 38 , 0 ], [ 48 , 14 ], [ 0 , 36 ], [ 14 , 0 ],
[ 34 , 0 ], [ 0 , 0 ], [ 0 , 38 ], [ 32 , 0 ], [ 28 , 0 ], [ 36 , 0 ], [ 20 , 48 ],
[ 0 , 6 ], [ 0 , 20 ], [ 0 , 42 ], [ 0 , 8 ], [ 24 , 32 ], [ 4 , 0 ], [ 6 , 8 ], [
24 , 10 ], [ 0 , 22 ], [ 16 , 12 ], [ 30 , 40 ], [ 0 , 32 ], [ 0 , 32 ], [ 16 , 0 ],
[ 48 , 20 ], [ 0 , 8 ], [ 32 , 0 ], [ 0 , 46 ], [ 0 , 22 ], [ 0 , 8 ], [ 10 , 24 ],
[ 0 , 36 ], [ 14 , 0 ], [ 0 , 22 ], [ 42 , 0 ], [ 16 , 12 ], [ 40 , 30 ], [ 44 , 0
], [ 40 , 0 ], [ 34 , 0 ], [ 0 , 32 ], [ 40 , 30 ], [ 32 , 0 ], [ 0 , 30 ], [ 24 ,
18 ], [ 0 , 26 ], [ 22 , 0 ], [ 0 , 4 ], [ 16 , 0 ], [ 10 , 0 ], [ 0 , 32 ], [ 0 ,
42 ], [ 2 , 0 ], [ 0 , 38 ], [ 32 , 24 ], [ 48 , 0 ], [ 20 , 0 ], [ 0 , 18 ], [ 0 ,
38 ], [ 14 , 48 ], [ 40 , 42 ], [ 16 , 12 ], [ 26 , 0 ], [ 0 , 20 ], [ 40 , 30 ], [
16 , 30 ], [ 36 , 48 ], [ 36 , 0 ], [ 18 , 24 ], [ 34 , 0 ], [ 16 , 0 ], [ 0 , 24 ],
[ 0 , 24 ], [ 0 , 18 ], [ 38 , 0 ], [ 28 , 0 ], [ 0 , 34 ], [ 0 , 36 ], [ 24 , 32 ],
[ 16 , 30 ], [ 40 , 30 ], [ 24 , 0 ], [ 0 , 14 ], [ 8 , 6 ], [ 12 , 0 ], [ 16 , 0 ],
[ 16 , 30 ], [ 48 , 14 ], [ 0 , 30 ], [ 38 , 0 ], [ 38 , 0 ], [ 0 , 8 ], [ 36 , 48
], [ 0 , 32 ], [ 10 , 24 ], [ 46 , 0 ], [ 24 , 10 ], [ 30 , 0 ], [ 0 , 48 ], [ 40 ,
0 ], [ 42 , 0 ], [ 32 , 24 ], [ 32 , 0 ], [ 12 , 16 ], [ 0 , 4 ], [ 0 , 28 ], [ 32
, 0 ], [ 40 , 42 ], [ 46 , 0 ], [ 0 , 24 ], [ 30 , 16 ], [ 36 , 48 ], [ 40 , 0 ], [
24 , 0 ], [ 0 , 22 ], [ 40 , 42 ], [ 10 , 24 ], [ 0 , 16 ], [ 14 , 48 ], [ 22 , 0 ],
[ 0 , 22 ], [ 30 , 0 ], [ 0 , 2 ], [ 48 , 20 ], [ 6 , 0 ], [ 6 , 0 ], [ 28 , 0 ], [
20 , 0 ], [ 0 , 40 ], [ 42 , 0 ], [ 48 , 36 ], [ 14 , 0 ], [ 10 , 24 ], [ 0 , 30 ],
[ 48 , 20 ], [ 40 , 30 ], [ 0 , 0 ], [ 42 , 40 ], [ 0 , 48 ], [ 32 , 24 ]]
X_answer = [[44] ,[18] ,[38] ,[50] ,[36] ,[14] ,[34] ,[0] ,[38] ,[32] ,[28] ,[36]
,[52] ,[6] ,[20] ,[42] ,[8] ,[40] ,[4] ,[10] ,[26] ,[22] ,[20] ,[50] ,[32] ,[32] ,[16]
,[52] ,[8] ,[32] ,[46] ,[22] ,[8] ,[26] ,[36] ,[14] ,[22] ,[42] ,[20] ,[50] ,[44] ,[40]
,[34] ,[32] ,[50] ,[32] ,[30] ,[30] ,[26] ,[22] ,[4] ,[16] ,[10] ,[32] ,[42] ,[2] ,[38]
,[40] ,[48] ,[20] ,[18] ,[38] ,[50] ,[58] ,[20] ,[26] ,[20] ,[50] ,[34] ,[60] ,[36]
,[30] ,[34] ,[16] ,[24] ,[24] ,[18] ,[38] ,[28] ,[34] ,[36] ,[40] ,[34] ,[50] ,[24]
,[14] ,[10] ,[12] ,[16] ,[34] ,[50] ,[30] ,[38] ,[38] ,[8] ,[60] ,[32] ,[26] ,[46]
,[26] ,[30] ,[48] ,[40] ,[42] ,[40] ,[32] ,[20] ,[4] ,[28] ,[32] ,[58] ,[46] ,[24]
,[34] ,[60] ,[40] ,[24] ,[22] ,[58] ,[26] ,[16] ,[50] ,[22] ,[22] ,[30] ,[2] ,[52]
,[6] ,[6] ,[28] ,[20] ,[40] ,[42] ,[60] ,[14] ,[26] ,[30] ,[52] ,[50] ,[0] ,[58] ,[48]
,[40]]
X_in = np.asarray(X_in, dtype=np.float32)
X_answer = np.asarray(X_answer, dtype=np.float32)

X_in /= np.amax(X_in)
X_answer /= np.amax(X_answer)

model = Sequential()
model.add(Dense(10, input_dim = 2, activation='relu'))
model.add(Dense(10, activation='relu'))
model.add(Dense(1, activation='softmax'))

model.compile(loss='mean_squared_error', optimizer='adam', metrics=['accuracy'])

history = model.fit(X_in, X_answer, epochs=NB_EPOCH, verbose=VERBOSE)


Что до 100 эпох, что до 500 один и тот же результат:

Epoch 1/100
143/143 [==============================] - 0s 2ms/step - loss: 0.2966 - acc: 0.0280
Epoch 2/100
143/143 [==============================] - 0s 52us/step - loss: 0.2966 - acc: 0.0280
Epoch 3/100
143/143 [==============================] - 0s 52us/step - loss: 0.2966 - acc: 0.0280
Epoch 4/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 5/100
143/143 [==============================] - 0s 52us/step - loss: 0.2966 - acc: 0.0280
Epoch 6/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 7/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 8/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 9/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 10/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 11/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 12/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 13/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 14/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 15/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 16/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 17/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 18/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 19/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 20/100
143/143 [==============================] - 0s 35us/step - loss: 0.2966 - acc: 0.0280
Epoch 21/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 22/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 23/100
143/143 [==============================] - 0s 35us/step - loss: 0.2966 - acc: 0.0280
Epoch 24/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 25/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 26/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 27/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 28/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 29/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 30/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 31/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 32/100
143/143 [==============================] - 0s 52us/step - loss: 0.2966 - acc: 0.0280
Epoch 33/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 34/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 35/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 36/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 37/100
143/143 [==============================] - 0s 49us/step - loss: 0.2966 - acc: 0.0280
Epoch 38/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 39/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 40/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 41/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 42/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 43/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 44/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 45/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 46/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 47/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 48/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 49/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 50/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 51/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 52/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 53/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 54/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 55/100
143/143 [==============================] - 0s 49us/step - loss: 0.2966 - acc: 0.0280
Epoch 56/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 57/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 58/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 59/100
143/143 [==============================] - 0s 35us/step - loss: 0.2966 - acc: 0.0280
Epoch 60/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 61/100
143/143 [==============================] - 0s 35us/step - loss: 0.2966 - acc: 0.0280
Epoch 62/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 63/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 64/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 65/100
143/143 [==============================] - 0s 52us/step - loss: 0.2966 - acc: 0.0280
Epoch 66/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 67/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 68/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 69/100
143/143 [==============================] - 0s 52us/step - loss: 0.2966 - acc: 0.0280
Epoch 70/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 71/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 72/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 73/100
143/143 [==============================] - 0s 39us/step - loss: 0.2966 - acc: 0.0280
Epoch 74/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 75/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 76/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 77/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 78/100
143/143 [==============================] - 0s 49us/step - loss: 0.2966 - acc: 0.0280
Epoch 79/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 80/100
143/143 [==============================] - 0s 49us/step - loss: 0.2966 - acc: 0.0280
Epoch 81/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 82/100
143/143 [==============================] - 0s 35us/step - loss: 0.2966 - acc: 0.0280
Epoch 83/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 84/100
143/143 [==============================] - 0s 35us/step - loss: 0.2966 - acc: 0.0280
Epoch 85/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 86/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 87/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 88/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 89/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 90/100
143/143 [==============================] - 0s 49us/step - loss: 0.2966 - acc: 0.0280
Epoch 91/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 92/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 93/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280
Epoch 94/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 95/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 96/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 97/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 98/100
143/143 [==============================] - 0s 45us/step - loss: 0.2966 - acc: 0.0280
Epoch 99/100
143/143 [==============================] - 0s 42us/step - loss: 0.2966 - acc: 0.0280
Epoch 100/100
143/143 [==============================] - 0s 38us/step - loss: 0.2966 - acc: 0.0280

    


Ответы

Ответ 1



Как уже сказал @L.Murashov функция активации softmax применяется в задачах мультиклассовой классификации - она помогает посчитать вероятности принадлежности образца каждому из классов. Есть еще несколько моментов, на которые стоит обратить внимание: В обучающей выборке слишком много (около половины) нулевых значений - это вырожденный случай для теоремы Пифагора, когда одна из сторон треугольника имеет нулевую длину. Для того, чтобы лучше обучить модель можно выборку взять побольше - в вашем случае не проблема сгенерировать столько данных сколько нужно. Для данной (простой) задачи хватит одного скрытого слоя В качестве функции активации выходного слоя можно использовать linear В качестве функции потери и метрики можно выбрать mean_squared_error Пример: import numpy as np from keras.models import Sequential from keras.layers.core import Dense, Activation N = 5000 np.random.seed(1234) X = np.random.randint(0, 50, size=(N,2)) y = np.linalg.norm(X, axis=1) NB_EPOCHS = 100 VERBOSE = 1 model = Sequential() model.add(Dense(20, input_dim = 2, activation='relu')) model.add(Dense(1, activation='linear')) model.compile(loss='mse', optimizer='adam', metrics=['mean_squared_error']) model.fit(X, y, epochs=NB_EPOCHS, verbose=VERBOSE) Обучение: ... 5000/5000 [==============================] - 0s 22us/step - loss: 0.0057 - mean_squared_error: 0.0057 Epoch 98/100 5000/5000 [==============================] - 0s 22us/step - loss: 0.0048 - mean_squared_error: 0.0048 Epoch 99/100 5000/5000 [==============================] - 0s 22us/step - loss: 0.0045 - mean_squared_error: 0.0045 Epoch 100/100 5000/5000 [==============================] - 0s 22us/step - loss: 0.0043 - mean_squared_error: 0.0043 Out[70]: Предсказание: In [71]: model.predict(np.array([[3,4], [10,10], [5,6]])) Out[71]: array([[ 5.018393], [14.130004], [ 7.841759]], dtype=float32)

Ответ 2



У вас неправильная функция активации на последнем слое. Softmax ограничен [0..1] model.add(Dense(1, activation='softmax')) заменить на # После слоя не применяется функция активации model.add(Dense(1)) Еще accuracy здесь бесполезна т.к. задача регрессии. metrics=['accuracy']

Bootstrap 4: зачем нужен метод $('.alert').alert()

#javascript #html #css #bootstrap


Приведённый пример (скопирован 1 в 1 из документации) состоит из одного лишь только
HTML-кода. Alert прекрасно закрывается без единой строчки самостоятельно написанного
JS-кода (пример на JSFiddle).













Но тогда возникает вопрос: зачем же нужен метод $('.alert').alert()? В документации
сказано:


  Not necessary when using the data-api’s auto-initialization.


но я не понял, что это за data-api’s auto-initialization.
    


Ответы

Ответ 1



Бутстрап предусмотрел два способа использовать свои JS плагины: Написать скрипт с помощью методов и событий из документации Бутстрапа. Расставить атрибуты data, как указано в документации. Во втором случае Бутстрап запустит всё сам, а данные, необходимые для инициализации и работы, возьмёт из data атрибутов. Именно это и подразумевает фраза, которую вы процитировали. Вы можете выбрать, какой способ вам больше подходит, или объединить их: базовое поведение инициализировать через data атрибуты, а остальное запрограммировать скриптом. Авто-инициализация не сработает, если HTML-блок добавляется скриптом после загрузки страницы. Тогда придётся запускать вручную, через $('.alert').alert(), например. И, если нужно, авто-инициализацию можно отключить полностью $(document).off('.data-api') или для какого-нибудь конкретного плагина $(document).off('.alert.data-api')

Как в обобщенном классе (generic) задать ограничение “только float или int” для типа?

#c_sharp #net #generics


Есть класс Parameter:

public abstract class Parameter
{
    public T Value { get; }
    //...
}


Как в таком классе для типа T задать ограничение только на определенные базовые типы?
Хотелось бы иметь что-то наподобие этого:

public abstract class Parameter where T : int, float, double, string
{
    public T Value { get; }
    //...
}


IntelliSense сразу ругается на каждый тип:


  "int" не является допустимым ограничением. Тип, использованный в
  качестве ограничения, должен быть интерфейсом, незапечатанным классом
  или параметром-типом.


UPD. Или просто оставить тип без ограничений и ничего страшного в этом нет, что можно
случайно создать класс с не таким типом, который ожидалось видеть?

UPD 2. Отвечаю на вопрос для какой цели нужно ограничение типа. Есть некоторая абстракция
Параметр, которая инкапсулирует в себе данные определенного базового типа. У него есть
поля Значение, Имя и Максимальное и минимальное значение. Читая ответы на вопросы,
я понял, что нет смысла ограничивать данный тип параметра.
    


Ответы

Ответ 1



Есть несколько причин, по которым этот код не может работать в C# where T : int, float, double, string Когда вы указываете ограничение T : Type то это значит, что T может быть как типа Type так и потомком типа Type. Следовательно, конструкция where T : int, float семантически означает следующее — тип T должен наследовать от типов int и float. Это не сработает по двум причинам: В C# запрещено множественное наследование Конструкция T : int не может работать, так как int это структура, а структуры не поддерживают наследование. Это свойство классов. Можете проверить это на примере: Generic where T : struct where U : T. (замените struct на class и все заработает) Зато компилятор предлагает вам рабочие варианты: Тип, использованный в качестве ограничения, должен быть интерфейсом, незапечатанным классом или параметром-типом. Cтруктуры и классы могут имплементировать интерфейсы, поэтому ограничение типа на интерфейс может иметь смысл как для структур, так и для классов, например в ограничение T : IComparable можно подставить как int так и string так как оба этих типа имплементируют этот интерфейс. Или просто оставить тип без ограничений и ничего страшного в этом нет, что можно случайно создать класс с не таким типом, который ожидалось видеть Для этого следует ответить на вопрос, для чего вы задаете ограничение типа? Вы видите что-то общее между типами int и string? Вы хотите обращаться к общим членам этих типов или использовать их как-то иначе в полиморфном контексте? Если нет, то, наверное, и нет смысла искусственно ограничивать тип-параметр.

Ответ 2



К сожалению, никак. Можно использовать только constraints указанные в документации: https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters В качестве обходного пути можно создать класс-обёртку для нужных типов: public class WrappedInt { public int Value { get; } public WrappedInt(int value) { this.Value = value; } } public class Foo where T : WrappedInt, WrappedFloat, ... { public Foo(T ariphmeticValue) { } } UPD. Касаемо последнего вопроса: сильно зависит от задачи. Если использование других типов будут вызывать unhandled exceptions - это плохо.

Как программно получить список всех разрешений (permissions) из Android Manifest

#java #android #android_manifest #manifest


В связи с тем, что с 1 ноября 2018 года обязали во всех опубликованных в Google Play
Market приложениях установить "targetSdkVersion=26", остро встает необходимость обработки
всех разрешений приложения.

В связи с этим, стало актуальным получение списка наименований всех разрешений из
Манифеста с дальнейшей их обработкой.

Подскажите какими способами это можно осуществить!?
    


Ответы

Ответ 1



Utility класс, который позволяет получать разрешения, используемые в файле манифеста public final class PermissionUtils { private PermissionUtils() { } /** * Retrieves permissions listed in the manifest file * @param context Context * @return Returns String array of permissions */ public static String[] retrievePermissions(Context context) { try { return context .getPackageManager() .getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS) .requestedPermissions; } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException("This should have never happened.", e); } } }

Странные (лишние) инструкции после компиляции

#c_sharp #ассемблер #компиляция #компилятор


Игрался с замером скорости доступа к L1,L2,L3 кэша процессора средствами C# и случайно
наткнулся на странное поведение компилятора (vs2017, х86, со включенной оптимизацией).

Приведу адаптированный кусок кода:

fixed (uint** array = new uint*[256])
{
    var p = array;
    uint iters = 1024;

    for (uint i = 0; i < iters; i++)
        p = (uint**)*p;
}


На выходе, цикл компилится абсолютно корректно:

011E0884  xor         edx,edx              //uint i = 0
011E0886  mov         eax,dword ptr [eax]  //p = (uint**)*p;
011E0888  inc         edx                  //i++
011E0889  cmp         edx,400h             //i < 1024 
011E088F  jb          011E0886


Но если изменить тип переменной iters, начинается магия:

fixed (uint** array = new uint*[256])
{
    var p = array;
    ulong iters = 1024; //  <---  отличие в этой строке

    for (uint i = 0; i < iters; i++)
        p = (uint**)*p;
}


В этом случае цикл компилится вот в такое:

00BA0888  xor         edi,edi              //uint i = 0
00BA088A  mov         esi,dword ptr [esi]  //p = (uint**)*p;
00BA088C  inc         edi                  //i++
00BA088D  xor         eax,eax      // Д
00BA088F  test        eax,eax      // И
00BA0891  ja          00BA089D     // Ч
00BA0893  jb          00BA088A     // Ь
00BA0895  cmp         edi,400h             //i < 1024 
00BA089B  jb          00BA088A


Вопросы:


Почему после изменения типа переменной iters, которая оптимизатором заменяется на
константу, и которой по сути вообще нет, появляются лишние бестолковые инструкции?
В чем сакральный смысл помеченных четырех инструкций? Сперва обнуляем eax. Потом
проверяем, а не ноль ли там случаем. И потом эти джампы, которые, насколько я понимаю,
никогда не сработают... Это баг или фича?

    


Ответы

Ответ 1



Похоже что оптимизатор не осилил убрать смесь каста uint в ulong и последующего сравнения. Каст был из (edi) в (eax, edi), и выглядит как заполнение eax нулём (через xor). 00BA088C inc edi //i++ // каст uint i в ulong. Результат в паре eax, edi 00BA088D xor eax,eax // поразрядное сравнение двух ulong // старший разряд 00BA088F test eax,eax // вместо cmp eax, 0 00BA0891 ja 00BA089D 00BA0893 jb 00BA088A // младший разряд 00BA0895 cmp edi,400h 00BA089B jb 00BA088A Т.е. вроде как оптимизатор мог догадаться, что верхний разряд можно не сравнивать, но не догадался. Оптимизатор x86 старый, не ждите от него слишком многого :)

Перебор ключ-значение в 2-х и более словарях и запись совпадения в новый словарь через *args

#python #python_3x #список #словари


Имеется два словаря, нужно перебрать ключ-значение в обоих словарях.
Сравнить если одинаковые ключ-значения с помощью цикла for и параметра *args. Добавить
в новый словарь одинаковые найденные ключ-значения.

operator_one = { 2: 'break',
         1: 'pass',
         3: 'print',
         4: 'yield',
         5 :'try' ,
         }


operator_two = { 1: 'pass',
         2:'global',
         3: 'yield',
         4: 'print',
         5: 'try',
         }

def operator_important(farg, *args):
    """Перебор ключ-значения в двух словарях при помощи args и записи в новый словарь."""
    operator_main = dict()             # создание словаря и запись в перем
    print("vocabulary_one:", farg)     # вывод первого аргумента
    for key, value in args:            # перебор ключ-значение в обоих словарях
        print("vocabulary_two:", arg)  # вывод второго аргумента
        if key in args and value == args[key]: # если ключ-значение равно аргументу
ключ-значение, то создаем новый словарь с ключом и значение
            operator_main[key] = value # добавляем в нов. словарь найденное  ключ-значение,
которое совпало


Ошибка: 


  ValueError: too many values to unpack (expected 2)

    


Ответы

Ответ 1



У меня вот так получилось: operator_one = {2: 'break', 1: 'pass', 3: 'print', 4: 'yield', 5: 'try', } operator_two = {1: 'pass', 2: 'global', 3: 'yield', 4: 'print', 5: 'try', } operator_three = {1: 'pass', 2: 'global', 3: 'yield', 4: 'print', 5: 'try', } def operator_important(*args: dict): operator_main = dict() # Создаем пустой словарь for key, value in args[0].items(): # Для ключа и значения из первого словаря... check = True # Устанавливаем флаг проверки в значение "Истина" for i in range(1, len(args)): # Проверяем все словари на совпадение if key not in args[i] or value != args[i][key]: # Если ключ отсутствует в другом словаре # или его значение отлично от проверяемого check = False # Устанавливаем флаг в значение "Ложь" break # И прерываем проверку ключа if check: # Если флаг сохранил значение "Истина" (То есть ключ присутствует во всех проверяемых словарях # и значения ключа во всех словарях равны operator_main[key] = value # Добавляем ключ и значение в новый словарь return operator_main print(operator_important(operator_one, operator_two, operator_three)) Немного упростил функцию: def operator_important(*args: dict): operator_main = dict() # Создаем пустой словарь for key, value in args[0].items(): # Для ключа и значения из первого словаря... for i in range(1, len(args)): # Проверяем все словари на совпадение if key not in args[i] or value != args[i][key]: # Если ключ отсутствует в другом словаре # или его значение отлично от проверяемого break # Прерываем проверку ключа else: # Если цикл не прерывался (То есть ключ присутствует во всех проверяемых словарях # и значения ключа во всех словарях равны operator_main[key] = value # Добавляем ключ и значение в новый словарь return operator_main

Ответ 2



Вы можете послать параметры в функцию с помощью распаковки, привожу возможные варианты для это функции: operator_one = { 2: 'break', 1: 'pass', 3: 'print', 4: 'yield', 5 :'try' , } operator_two = { 1: 'pass', 2:'global', 3: 'yield', 4: 'print', 5: 'try', } def my_dict(d1, d2): d3 = dict() for k in d1: if k in d2 and d1[k] == d2[k]: d3[k] = d1[k] return d3 print (my_dict(*(operator_one, operator_two))) print (my_dict(operator_one, *(operator_two, ))) print (my_dict(operator_one, operator_two, *())) # {1: 'pass', 5: 'try'} Если вы хотите посылать неограниченное количество словарей в функцию то можно так: operator_three = { 1: 'qwerty', 2:'global', 3: 'yield', 4: 'print', 5: 'try', } def my_dict(*d_tuple): w = [x.items() for x in d_tuple] first = w[0] other = w[1:] res = [] for f in first: s = 1 for elem in other: if f not in elem: s = 0 break if s: res.append(f) return dict(res) print (my_dict(*(operator_one, operator_two, operator_three))) # {5: 'try'}

Ответ 3



Ошибка в комманде for key, value in args: # перебор ключ-значение в обоих словарях так как args - кортеж из одного элемента (словаря, заданного как параметр). И так, вместо args нужно везде писать args[0] (и в цикле for добавить ещё .items()): for key, value in args[0].items(): # перебор ключ-значение в обоих словарях print("vocabulary_two:", args[0]) # вывод второго аргумента if key in args and value == args[0][key]: # если ключ-значение равно аргументу ключ-значение, то создаем новый словарь с ключом и значение Но луже вашу функцию слишком изменить - исключить параметр farg, т.к оба параметра могут быть в кортежи args: def operator_important(*args): """Перебор ключ-значения в двух словарях при помощи args и записи в новый словарь.""" operator_main = dict() # создание словаря и запись в перем print("vocabulary_one:", args[0]) # вывод первого аргумента for key, value in args[0].items(): # перебор ключ-значение в обоих словарях print("vocabulary_two:", args[1]) # вывод второго аргумента if key in args and value == args[key]: # если ключ-значение равно аргументу ключ-значение, то создаем новый словарь с ключом и значение operator_main[key] = value # добавляем в нов. словарь найденное ключ-значение, которое совпало

Integer promotions в c

#c


Вопрос короткий.

unsigned char c = 1, d = 2;
printf("%d %d %d",sizeof(c),sizeof(d),sizeof(c&d)); // выводит 1 1 4


Скажите, почему при конъюнкции получившееся выражение становится типа int? В стандарте
C99 четко сказано, что:


  The integer promotions are applied only: as part of the usual arithmetic conversions,
to certain
  argument expressions, to the operands of the unary +, -, and ~ operators, and to
both operands of the
  shift operators, as specified by their respective subclauses.


В чем причина? Буду благодарен за ответ. 
    


Ответы

Ответ 1



Так это и есть действие the usual arithmetic conversions, о которых говорится в вашей цитате. Спецификация бинарного & ясно говорит 6.5.10 Bitwise AND operator 3 The usual arithmetic conversions are performed on the operands. Для целочисленных типов the usual arithmetic conversions начинаются с integer promotions. В вашем случае сработали именно integer promotions и тип unsigned char был превращен в тип int.

C# 8.0 Records. Зачем нужно?

#c_sharp #net #c_sharp_80


Наткнулся на вот эту статью, которая посвящена фишкам, которые с высокой вероятностью
будут добавлены в новую версию языка.

Наткнулся там на Records.

Немного не понятно, зачем нужен кастрированный класс.
    


Ответы

Ответ 1



record class - это не "кастрированный класс", а иммутабельный класс, у которого часть важных методов уже реализована компилятором. Слово "иммутабельный" тут - не недостаток, а важная фича. Такие классы просто необходимы для следующих задач: использование в качестве ключа в словаре: каждый раз, когда вам нужен словарь по двум параметрам, приходится или использовать кортежи, или использовать анонимные типы, или писать свой класс с методами Equals и GetHashCode, причем использовать кортежи в публичном API - дурной тон, а анонимные типы так и вовсе приводят к нетипизированному ключу; кеширование данных: данные в кеше обязаны быть неизменяемыми, чего можно достигнуть или защитным копированием - или иммутабельностью; многопоточный доступ: к иммутабельным данным можно обращаться из любых потоков без блокировок.

Ответ 2



С каждой новой версией C# в него добавляют все больше фишек из функционального программирования, и Records - одна из таких фишек. Из парадигмы функционального программирования: Основной особенностью функционального программирования, определяющей как преимущества, так и недостатки данной парадигмы, является то, что в ней реализуется модель вычислений без состояний. Если императивная программа на любом этапе исполнения имеет состояние, то есть совокупность значений всех переменных, и производит побочные эффекты, то чисто функциональная программа ни целиком, ни частями состояния не имеет и побочных эффектов не производит. То, что в императивных языках делается путём присваивания значений переменным, в функциональных достигается путём передачи выражений в параметры функций. Непосредственным следствием становится то, что чисто функциональная программа не может изменять уже имеющиеся у неё данные, а может лишь порождать новые путём копирования и/или расширения старых. Records является просто иммутабельным классом, состояние которого невозможно изменить. В некоторых случаях такой подход уменьшает количество возможных ошибок. Возьмем простой код: MyClass something = new MyClass(arg1, arg2, arg3); MyMethod(something); Что произошло в MyMethod? Никто не знает. Изменилось ли состояние something? Находиться ли он валидном состоянии или нужно после вызова метода сразу проверить что-то и вбросить Exception? Самый известный и частоиспользуемый иммутабельный класс в C# это String. Я думаю все согласятся, что допустить ошибку при работе со строками очень сложно. Этот класс только выиграл от иммутабельности. Конечно, это не совсем хорошая аналогия с Records, потому что в строк есть свои методы, но если очень нужно мы можем добавлять методы расширения для Records. Несмотря на то, что это не совсем удобно, все равно кода в итоге получиться меньше, чем при имлементации иммутабельного класса вручную.

Ответ 3



Это синтаксический сахар для более короткого объявления класса, который просто содержит набор полей. В примере из статьи показано, что следующий класс: public class Sword : IEquatable { public int Damage { get; } public int Durability { get; } public Sword(int Damage, int Durability) { this.Damage = Damage; this.Durability = Durability; } public bool Equals(Sword other) { return Equals(Damage, other.Damage) && Equals(Durability, other.Durability); } public override bool Equals(object other) { return (other as Sword)?.Equals(this) == true; } public override int GetHashCode() { return (Damage.GetHashCode() * 17 + Durability.GetHashCode()); } public void Deconstruct(out int Damage, out int Durability) { Damage = this.Damage; Durability = this.Durability; } public Sword With(int Damage = this.Damage, int Durability = this.Durability) => new Sword(Damage, Durability); } Можно будет объявить так: public class Sword(int Damage, int Durability); И компилятор сам додумает все остальное: конструкторы, свойства, сравнение. Если нужен класс с функционалом не по-умолчанию, то всегда можно воспользоваться полным синтаксисом объявления класса. Это нововведение позволит сэкономить код в тех случаях, когда нужен именно класс с набором полей и ничего больше. Экономия кода указывается как основное обоснование в предложении на Github: Motivation A significant number of type declarations in C# are little more than aggregate collections of typed data. Unfortunately, declaring such types requires a great deal of boilerplate code. Records provide a mechanism for declaring a datatype by describing the members of the aggregate along with additional code or deviations from the usual boilerplate, if any. Обоснование Значительная часть объявленных типов в C# немногим отличается от набора типизированных данных. К сожалению, объявление таких типов требует большого количества шаблонного кода. Записи предоставляют механизм для объявления типа данных путем перечисления членов набора либо отличий от стандартного шаблона, если таковые имеются.

Ответ 4



Ниже представлен некоторый псведокод, в котором опущены многие детали, включая спецификаторы доступа и прочую шелуху, которая не важна для понимания. Так же используется минимальное количество полей, чтобы сократить код. Представьте, что у Вас есть такой класс: class Person { string name; } И вот такой класс для хранения экземпляров предыдущего: class CompanyRegister { List persons; } CompanyRegister — главное хранилище всех персон в программе, поэтому, если кому-то нужно добавить персону, или получить по ней данные, он обращается к этому классу. Для получения персоны по какому-то признаку нам понадобится функция GetPerson(), но что она будет возвращать? Пусть она возвращает Person, является ли это проблемой? Безусловно. Если мы возвращаем Person то любая сущность может изменить этот объект вне CompanyRegister! Но это противоречит основам нашего класса: только он отвечает за изменения (он может оповещать другие сущности, либо же заниматься каким-то слежением за изменениями — не важно). Как нам решить проблему? Если бы мы писали на C++, то мы бы сделали возвращаемый тип const Person&, и проблема была бы решена. Но у нас C#, который при всех своих достоинствах, не может похвастаться наличием таких средства как C++ в части «оконстанивания» и предотвращения лишних копий. Кстати о копиях, мы могли быть сделать Person структурой, но это повлекло бы излишнее копирование, которого по возможности все стараются избегать. Исходя из того, что язык в C++ превращать никто не собирается, а в C# [почти] всё есть ссылка, то разработчики обратили свой взор в сторону функционального программирования и взяли на вооружение неизменяемые типы. Реализация таких типов в C# это куча кода, который нужно писать для каждого класса, либо же использовать всяческие кодогенераторы. Вот как, к примеру, мы могли бы сделать наш Person неизменяемым: class Person { string name; Person(string name) { name = name; } Builder GetBuilder() { return new Builder(this); } class Builder { string name; Builder(Person person) { name = person.name; } Person ToImmutable() { return new Person(name: name); } } } Выглядит чудесно, не правда ли? А теперь представьте, что у нас не одно поле, а с десяток полей. Как Вам? Так вот Records делает то же самое, только писать всё это не нужно, а синтаксис создания новых объектов на основании старых становится куда удобнее. Как часто всё это нужно? Очень. Ведь у нас очень часто есть данные, за которые кто-то отвечает, и этот кто-то не хочет, чтобы их меняли все кому не лень за пределами этого класса. Это очень часто встречается в GUI-приложениях, когда из модели данные передаются в представление (VM и прочие).

Extension Everything. Зачем оно нужно?

#c_sharp #net #c_sharp_80


Наткнулся на еще одно новшество новой редакции языка под названием Extension Everything
(Имхо спорное).

С точки зрения синтаксиса, что не нужно иметь статический класс, вроде, прикольно.

Однако теперь, как я понимаю, позволяетется,  расширять абсолютно все:

extension MyPersonExtension extends Person
{
    public int CountFingers()
    {
        this. // it call the current instance of Person
    }
}

extension MyPersonExtension extends Person
{
    public int NumberOfFingers()
    {
        get { ... }
    }
}

extension MyPersonExtension extends Person
{
    static int ... // You can add static things
}


Как видно в примере добавляются новые поля в класс.

Собственно, вопрос: Зачем это нужно, если в таком случае правильнее сделать наследование?

Если эта штука позволяет еще и запечатанные классы расширять, то это же противоречит
инкапсуляции..
    


Ответы

Ответ 1



Зачем это нужно? Это логичное продолжение подхода extension, позволяя описывать в расширениях не только методы, но и свойства, а так же статические поля. Как и в случае с extensions сейчас - исходный класс НЕ меняется. Так что никаких проблем с инкапсуляцией нет, как их нет сейчас с использованием extensions. Кроме того, в вопросе не упомянуто еще одна возможность: указывать что класс имплементирует нужный интерфейс extension MyPersonExtension extends Person : IEmployee // The Person class implements now the IEmployee interface in your assembly { [ ... ] }

Как узнать, что невозможно преобразовать int в enum?

#c_sharp #cast


Дано:

enum LANGUAGES{
    EN,
    RU,
    FR
}
int res = 7;


Как узнать правильно, что (LANGUAGES)res выдаст неверный результат (результат не
принадлежит LANGUAGES)?
    


Ответы

Ответ 1



Используйте Enum.IsDefined как указано в документации (раз, два). if (Enum.IsDefined(typeof(LANGUAGES), res)) Console.WriteLine("{0} is into language enumeration.", res); else Console.WriteLine("{0} is not into language enumeration.", res);

Оператор throws и исключения

#java


Всем привет, друзья! Хотелось бы спросить:
checked исключения, как я понял обязательно должны содержать оператор throws в сигнатуре
метода или обрабатываться в конструкции try, catch?
Подскажите пожалуйста, заранее спасибо!
    


Ответы

Ответ 1



Если написать что-то которое относится допустим к checked исключениям: тот же FileNotFoundException, то Idea вас попросит либо обернуть это в try, catch конструкцию либо вам нужно будет добавить в сигнатуру метода оператор throws и класс (FileNotFoundException) это для checked. А для unchecked вы можете написать: int a = 5; int b = 0; int c = a/b; System.out.print(c) //выведет Arithmetic exception, но так как Arithmetic exception это класс unchecked, Idea вас не будет просить обернуть это в конструкцию try, catch либо добавить оператор throws в сигнатуру метода потому что это UNCHECKED исключения

Ответ 2



Да, это все написано в спецификации, в главе 11 «Исключения». Виды исключений определены в §11.1.1 11.1.1. The Kinds of Exceptions ... Exception is the superclass of all the exceptions from which ordinary programs may wish to recover. The class RuntimeException is a direct subclass of Exception. RuntimeException is the superclass of all the exceptions which may be thrown for many reasons during expression evaluation, but from which recovery may still be possible. RuntimeException and all its subclasses are, collectively, the run-time exception classes. Error is the superclass of all the exceptions from which ordinary programs are not ordinarily expected to recover. Error and all its subclasses are, collectively, the error classes. The unchecked exception classes are the run-time exception classes and the error classes. The checked exception classes are all exception classes other than the unchecked exception classes. 11.1.1. Виды исключений ... Exception является суперклассом для всех исключений, от которых программы могут пожелать восстановиться. Класс RuntimeException является непосредственным наследником Exception. RuntimeException представляет собой суперкласс всех исключений, которые могут быть сгенерированы по разным причинам в процессе определения выражения, но восстановление после которых еще возможно. RuntimeException и его подклассы коллективно представляют собой классы исключений времени выполнения. Error является суперклассом всех исключений, при которых восстановление обычных программ невозможно. Error и его подклассы коллективно представляют собой классы ошибок. Классами непроверяемых исключений являются классы исключений времени выполнения и ошибок. Классами проверяемых исключений являются все классы исключений, кроме проверяемых. Проверяемое исключение должно быть либо поймано, либо определено в throws метода или конструктора, в противном случае возникает ошибка компиляции. При этом в throws может быть определено Это описано в §11.2.3 11.2.3. Exception Checking It is a compile-time error if a method or constructor body can throw some exception class E when E is a checked exception class and E is not a subclass of some class declared in the throws clause of the method or constructor. 11.2.3. Проверка исключений Если тело метода или конструктора может генерировать некоторый класс исключений E, где E — класс проверяемого исключения и E не является подклассом некоторого класса, объявленного в конструкции throws метода или конструктора, то генерируется ошибка компиляции. Какие блоки и в каких случаях могут генерировать те или иные исключения описано в §11.2.1 и §11.2.2. Для лучшего понимания, советую прочитать всю 11-ю главу, она достаточно коротка, содержит примеры и полно описывает работу с исключениями в Java.

Количество созданий новых строк в куче

#java #строки #heap


Один из вопросов в OCA7 выглядит так:

public class Mounds {
public static void main(String[] args) {
    StringBuilder sb = new StringBuilder();
    String s = new String();
    for (int i = 0; i < 1000; i++) {
        s += " " + i;
        sb.append(s);
    }
    // done with loop
} }



  Если сборщик мусора не будет работать во время исполнения кода, сколько примерно
объектов будет существовать в памяти, когда цикл завершится?
  
  A. Меньше 10;
  
  B. Примерно 1000;
  
  C. Примерно 2000;
  
  D. Примерно 3000;
  
  E. Примерно 4000.


Со StringBuilder все понятно: он mutable, как создался, так один и остался.
А поскольку String является immutable классом, каждый раз создается новый объект.
Сперва я подумал, что правильный ответ - B, 1000 объектов по количеству итераций. Но
потом присмотрелся к телу цикла:

s += " " + i;


Здесь мы видим, что каждый раз к пробелу (который создается в пуле строк лишь единожды)
каждый раз конкатенируется значения i, которое, соответственно, каждый раз создает
новую строку со значением i, то есть "0", "1", "2" и так далее, которые затем превращаются
в новые строки "0", "0 1", "0 1 2" и так далее. И подумал, что правильный ответ - C,
2000 объектов - по одному на каждую новую строку s и каждую новую строку значения i.

Однако в книжке приводится, что правильный ответ - B. Объясните, пожалуйста, в чем
я ошибся?
    


Ответы

Ответ 1



Оператор += можно расписать так s = s + " " + i; Поэтому на каждой итерации будет создаваться по одной строке и присваиваться переменной s. Т.е. Java сразу сложит все в одну строку вместо того, чтобы создавать её по частям. Если бы мы вынесли " " + i в отдельную переменную, а потом добавили к s, тогда бы был вариант, о котором Вы подумали.

Ответ 2



Давайте посмотрим чем будет заниматься JVM при выполнении этого задания. Декомпиляция примера дает такой результат: public class Mounds { public Mounds() { // тут конструктор по умолчанию } public static void main(String[] args) { StringBuilder sb = new StringBuilder(); String s = new String(); for(Object i = 0; i < 1000; ++i) { sb.append((String)i); // а тут сюрприз! } } } Хотя классическое описание операции объединения строк с помощью оператора + предполагает следующую конструкцию: s = new StringBuilder(s).append(" ").append((String)i)).toString() в которой будет создано аж три объекта: сам new StringBuilder() новая строка (String)i и new String()в результате работы последнего toString(), мы видим что компилятор не стал размениваться на подобные мелочи и использовал имеющийся StringBuilder чтобы сократить количество объектов и операций к мнимому. Т.о. каждый цикл создается только новый объект String в момент преобразования числа к строке, и ответ 1000 похож на правду.

Ошибка при определении функции xor

#cpp


#include 
#include 
using namespace std;
bool xor(bool a,bool b);   
int main ()

{
    bool p,q;
    cout<<"vvedite P (0 ili 1): ";
    cin>>p;
    cout<<"vvedite Q (0 ili 1): ";
    cin>>q;
    cout<<"P i Q: "<<(p&&q)<<' \n';
    cout<<"P ili Q: "<<(p||q)<<' \n';
    cout<<"P xor Q: "<


Ответы

Ответ 1



xor - это альтернативная лексема (см. тут). Они нужны на системах с ограниченным набором символов, например где нет символа ^ или &. Эта лексема будет рассматриваться как оператор ^. Следовательно объявление функции будет рассматриваться как bool ^(bool a, bool b); Замените имя xor на другое, например my_xor - и все заработает.

Линия соединяющая чекбоксы, находящиеся в разных блоках

#html #jquery #css


У меня есть два блока с чекбоксами, и нужно чтобы выбранные чекбоксы (как правило
 один из каждого блока) соединялись линией. Как и какими средствами это можно сделать? 



function setWordCombination(){
    let child1Text = $(".w_option_left input:checked + .word_opt").text();
    let child2Text = $(".w_option_right input:checked + .word_opt").text();
    $("#word_combination").text(child1Text + ' + ' + child2Text);
}

/*<--1 чекбокс-->*/
    $(".w_option_left input").on("click", function() {
    $('.w_option_left input').not(this).prop('checked', false); 
    $(this).prop("checked", true);
    setWordCombination();
});

$(".w_option_right input").on("click", function() {
    $('.w_option_right input').not(this).prop('checked', false);
    $(this).prop("checked", true);
    setWordCombination();
});
.words_status {
    border: 1px solid black;
    width: 100%;
    display: inline-block;
}
  
.w_option_right {
    border: 1px solid black;
    display: inline-block;
    width: 48%;
    text-align: center;
}
  
.w_option_left {
    border: 1px solid black;
    display: inline-block;
    width: 50%;
    text-align: center;
}
  
.word_opt {
    display: inline-block;
    width: 150px;
    height: 26px;
    -webkit-appearance: none;
    -moz-appearance: none;
    background: #fefefe;
    outline: none;
    border-radius: 19px;
    transition: 0.2s;
    position: relative;
    cursor: pointer;
}
  
:checked[type="checkbox"] + .word_opt {
    background: #7f2929;
    color: #fefefe;
}







вот такая линия, только черная


Ответы

Ответ 1



Немного внёс изменения в CSS, т.ч. будьте внимательны: function setWordCombination() { let child1Text = $(".w_option_left input:checked + .word_opt"); let child2Text = $(".w_option_right input:checked + .word_opt"); $("#word_combination").text($(child1Text).text() + ' + ' + $(child2Text).text()); let oMidLine = $(".mid_line"); $(oMidLine).height(Math.abs($(child1Text).position().top - $(child2Text).position().top)); $(oMidLine).css("top", Math.min($(child1Text).position().top, $(child2Text).position().top) + 13 + "px"); } /*<--1 чекбокс-->*/ $(".w_option_left input").on("click", function() { $('.w_option_left input').not(this).prop('checked', false); $(this).prop("checked", true); setWordCombination(); }); $(".w_option_right input").on("click", function() { $('.w_option_right input').not(this).prop('checked', false); $(this).prop("checked", true); setWordCombination(); }); * { box-sizing: border-box; } .words_status { border: 1px solid blue; position: relative; display: inline-block; width: 100%; } .words_status input[type="checkbox"] { display: none; } .w_option_left, .w_option_right { height: 100%; width: 50%; padding: .5em 0; overflow: hidden; text-align: center; } .w_option_left { float: left; } .w_option_right { float: right; } .word_opt { display: inline-block; width: 150px; height: 26px; line-height: 24px; background: #fefefe; outline: none; border-radius: 13px; transition: 0.2s; cursor: pointer; position: relative; } :checked[type="checkbox"]+.word_opt { background: #7f2929; color: #fefefe; } .w_option_left input[type="checkbox"]:checked+.word_opt:after, .w_option_right input[type="checkbox"]:checked+.word_opt:after { content: ''; top: 50%; position: absolute; width: 300%; height: 0; border: 1px solid red; } .w_option_left input[type="checkbox"]:checked+.word_opt:after { left: 105%; } .w_option_right input[type="checkbox"]:checked+.word_opt:after { right: 105%; } .mid_line { position: absolute; top: 21px; left: 50%; z-index: 300; height: 0; width: 0; border: 1px solid red; }








Gulp 4 выдает ошибку

#javascript #nodejs #gulp #npm


Исходники: Gulp4.zip

Ошибка:

assert.js:42
  throw new errors.AssertionError({
  ^

AssertionError [ERR_ASSERTION]: Task function must be specified
    at Gulp.set [as _setTask] (E:\Web\test\node_modules\undertaker\lib\set-task.js:10:3)
    at Gulp.task (E:\Web\test\node_modules\undertaker\lib\task.js:13:8)
    at Object. (E:\Web\test\gulpfile.js:224:6)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)


Версия Gulp:

PS E:\Web\test> gulp -v
[06:20:13] CLI version 2.0.1
[06:20:13] Local version 4.0.0


Версия Npm:

PS E:\Web\test> npm -v
6.5.0


package.json



{
  "name": "html-ready",
  "version": "1.0.0",
  "description": "",
  "main": "gulpfile.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Devinora",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.2.0",
    "@babel/preset-env": "^7.2.0",
    "babel-cli": "^6.26.0",
    "babel-core": "^6.26.3",
    "browser-sync": "^2.26.3",
    "gulp": "^4.0.0",
    "gulp-autoprefixer": "^6.0.0",
    "gulp-babel": "^8.0.0",
    "gulp-file-include": "^2.0.1",
    "gulp-imagemin": "^5.0.3",
    "gulp-minify-css": "^1.2.4",
    "gulp-plumber": "^1.2.1",
    "gulp-rename": "^1.4.0",
    "gulp-sass": "^4.0.2",
    "gulp-sourcemaps": "^2.6.4",
    "gulp-terser": "^1.1.6",
    "gulp-watch": "^5.0.1",
    "gulp.spritesmith": "^6.9.0",
    "imagemin-pngquant": "^6.0.0",
    "rimraf": "^2.6.2"
  },
  "dependencies": {
    "npm": "^6.5.0"
  }
}




gulpfile.js



'use strict';

var gulp = require('gulp'),
  watch = require('gulp-watch'),
  plumber = require('gulp-plumber'),
  prefixer = require('gulp-autoprefixer'),
  babel = require('gulp-babel'),
  terser = require('gulp-terser'), //альтернатива gulp-uglifyes
  sass = require('gulp-sass'),
  sourcemaps = require('gulp-sourcemaps'),
  fileinclude = require('gulp-file-include'),
  cssmin = require('gulp-minify-css'),
  imagemin = require('gulp-imagemin'),
  pngquant = require('imagemin-pngquant'),
  rimraf = require('rimraf'),
  browserSync = require("browser-sync"),
  rename = require('gulp-rename'),
  spritesmith = require('gulp.spritesmith'),
  reload = browserSync.stream;

var path = {
  dist: {
    html: 'dist/',
    php: 'dist/',
    js: 'dist/js/',
    css: 'dist/css/',
    img: 'dist/img/',
    fonts: 'dist/fonts/'
  },
  app: {
    html: 'app/*.html',
    php: 'app/*.php',
    js: 'app/js/main.js',
    jsInit: 'app/js/init.js',
    style: 'app/scss/main.scss',
    sprite: 'app/img/sprite/**/*.*',
    img: 'app/img/*.*',
    fonts: 'app/fonts/**/*.*',
  },
  watch: {
    html: 'app/**/*.html',
    php: 'app/*.php',
    js: 'app/js/**/*.js',
    style: 'app/scss/**/*.scss',
    img: 'app/img/*.*',
    sprite: 'app/img/sprite/**/*.*',
    fonts: 'app/fonts/**/*.*'
  },
  export: {
    img: 'app/img/',
    style: 'app/scss/imports/'
  },
  spriteTemplate: 'sass.template.mustache',
  clean: './dist'
};

var config = {
  server: {
    baseDir: "dist" // or ./dist
  },
  // tunnel: true,
  // host: "178.150.110.97",
  // notify: false,
  logPrefix: "Frontend_Devil"
};

gulp.task('webserver', function() {
  browserSync(config);
});

gulp.task('clean', function(cb) {
  rimraf(path.clean, cb);
});

gulp.task('html:dist', function() {
  gulp.src(path.app.html)
    .pipe(plumber())
    .pipe(fileinclude({
      prefix: '@@',
      basepath: '@file'
    }))
    .pipe(gulp.dest(path.dist.html))
    .pipe(reload());
});

gulp.task('php:dist', function() {
  gulp.src(path.app.php)
    .pipe(plumber())
    .pipe(fileinclude({
      prefix: '@@',
      basepath: '@file'
    }))
    .pipe(gulp.dest(path.dist.php))
    .pipe(reload());
});

gulp.task('js:dist', function() {
  //init.js
  //Файл для инициации
  // gulp.src(path.app.jsInit)
  // .pipe(plumber())
  // .pipe(sourcemaps.init())
  // .pipe(fileinclude({
  // 	prefix: '@@',
  // 	basepath: '@file'
  // }))
  // .pipe(babel({
  // 	presets: ["@babel/preset-env"]
  // }))
  // .pipe(terser())
  // .pipe(sourcemaps.write())
  // .pipe(rename({suffix: '.babel-min', prefix : ''}))
  // .pipe(gulp.dest(path.dist.js))

  //Обычный js файл.
  gulp.src(path.app.js)
    .pipe(plumber())
    .pipe(sourcemaps.init())
    .pipe(fileinclude({
      prefix: '@@',
      basepath: '@file'
    }))
    .pipe(sourcemaps.write())
    .pipe(gulp.dest(path.dist.js))
  //Babel-js файл.
  gulp.src(path.app.js)
    .pipe(plumber())
    .pipe(sourcemaps.init())
    .pipe(fileinclude({
      prefix: '@@',
      basepath: '@file'
    }))
    .pipe(babel({
      presets: ["@babel/preset-env"]
    }))
    .pipe(rename({
      suffix: '.babel',
      prefix: ''
    }))
    .pipe(sourcemaps.write())
    .pipe(gulp.dest(path.dist.js))
  //Mini-js файл.
  gulp.src(path.app.js)
    .pipe(plumber())
    .pipe(sourcemaps.init())
    .pipe(fileinclude({
      prefix: '@@',
      basepath: '@file'
    }))
    .pipe(terser()) //альтернатива uglifyes
    .pipe(sourcemaps.write())
    .pipe(rename({
      suffix: '.min',
      prefix: ''
    }))
    .pipe(gulp.dest(path.dist.js));
  //Babel-mini-js файл.
  gulp.src(path.app.js)
    .pipe(plumber())
    .pipe(sourcemaps.init())
    .pipe(fileinclude({
      prefix: '@@',
      basepath: '@file'
    }))
    .pipe(babel({
      presets: ["@babel/preset-env"]
    }))
    .pipe(terser())
    .pipe(sourcemaps.write())
    .pipe(rename({
      suffix: '.babel-min',
      prefix: ''
    }))
    .pipe(gulp.dest(path.dist.js))
    .pipe(reload());
});

gulp.task('style:dist', function() {
  gulp.src(path.app.style)
    .pipe(plumber())
    .pipe(sourcemaps.init())
    .pipe(sass({
      sourceMap: true,
      errLogToConsole: true
    }))
    .pipe(prefixer())
    .pipe(sourcemaps.write())
    .pipe(gulp.dest(path.dist.css))
    .pipe(cssmin())
    .pipe(sourcemaps.write())
    .pipe(rename({
      suffix: '.min',
      prefix: ''
    }))
    .pipe(gulp.dest(path.dist.css))
    .pipe(reload());
});

gulp.task('image:dist', function() {
  gulp.src(path.app.img)
    .pipe(plumber())
    .pipe(imagemin({
      progressive: true,
      svgoPlugins: [{
        removeViewBox: false
      }],
      use: [pngquant()],
      interlaced: true
    }))
    .pipe(gulp.dest(path.dist.img))
    .pipe(reload());
});

gulp.task('sprite:dist', function() {
  var spriteData =
    gulp.src(path.app.sprite)
    .pipe(plumber())
    .pipe(spritesmith({
      imgName: 'sprite.png',
      cssName: '_sprite.scss',
      cssFormat: 'scss',
      algorithm: 'binary-tree',
      cssTemplate: path.spriteTemplate,
      cssVarMap: function(sprite) {
        sprite.name = 's-' + sprite.name
      }
    }));
  spriteData.img.pipe(gulp.dest(path.export.img));
  spriteData.css.pipe(gulp.dest(path.export.style));
});

gulp.task('fonts:dist', function() {
  gulp.src(path.app.fonts)
    .pipe(plumber())
    .pipe(gulp.dest(path.dist.fonts))
});

gulp.task('dist', [
  'html:dist',
  'php:dist',
  'js:dist',
  'sprite:dist',
  'style:dist',
  'fonts:dist',
  'image:dist'
]);

gulp.task('watch', function() {
  watch(path.watch.html, function(event, cb) {
    gulp.start('html:dist');
  });
  watch(path.watch.php, function(event, cb) {
    gulp.start('php:dist');
  });
  watch(path.watch.style, function(event, cb) {
    gulp.start('style:dist');
  });
  watch(path.watch.js, function(event, cb) {
    gulp.start('js:dist');
  });
  watch(path.watch.img, function(event, cb) {
    gulp.start('image:dist');
  });
  watch(path.watch.sprite, function(event, cb) {
    gulp.start('sprite:dist');
  });
  watch(path.watch.fonts, function(event, cb) {
    gulp.start('fonts:dist');
  });
});

gulp.task('default', ['dist', 'webserver', 'watch']);




Частичное решение

Проблема была в том, что при переходе на новый Gulp 4, не сделали обратной совместимости.
Не знаю почему, и оправдано ли это, но ниже я приведу пример, который мне помог.

Они добавили два новых метода: gulp.series, gulp.parallel.

Было: 



gulp.task('dist', [
	'html:dist',
	'php:dist',
	'js:dist',
	'sprite:dist',
	'style:dist',
	'fonts:dist',
	'image:dist'
]);

gulp.task('watch', function() {
	watch(path.watch.html, function(event, cb) {
		gulp.start('html:dist');
	});
	watch(path.watch.php, function(event, cb) {
		gulp.start('php:dist');
	});
	watch(path.watch.style, function(event, cb) {
		gulp.start('style:dist');
	});
	watch(path.watch.js, function(event, cb) {
		gulp.start('js:dist');
	});
	watch(path.watch.img, function(event, cb) {
		gulp.start('image:dist');
	});
	watch(path.watch.sprite, function(event, cb) {
		gulp.start('sprite:dist');
	});
	watch(path.watch.fonts, function(event, cb) {
		gulp.start('fonts:dist');
	});
});

gulp.task('default', ['dist', 'webserver', 'watch']);




Стало:



//Удалил 

// gulp.task('dist', [
// 	'html:dist',
// 	'php:dist',
// 	'js:dist',
// 	'sprite:dist',
// 	'style:dist',
// 	'fonts:dist',
// 	'image:dist'
// ]);

gulp.task('watch', function() {
	gulp.watch(path.watch.html, function(event, cb) {
		gulp.start('html:dist');
	});
	gulp.watch(path.watch.php, function(event, cb) {
		gulp.start('php:dist');
	});
	gulp.watch(path.watch.style, function(event, cb) {
		gulp.start('style:dist');
	});
	gulp.watch(path.watch.js, function(event, cb) {
		gulp.start('js:dist');
	});
	gulp.watch(path.watch.img, function(event, cb) {
		gulp.start('image:dist');
	});
	gulp.watch(path.watch.sprite, function(event, cb) {
		gulp.start('sprite:dist');
	});
	gulp.watch(path.watch.fonts, function(event, cb) {
		gulp.start('fonts:dist');
	});
});

gulp.task('default', gulp.parallel(
	'html:dist',
	'php:dist',
	'js:dist',
	'sprite:dist',
	'style:dist',
	'fonts:dist',
	'image:dist',
	'webserver',
	'watch'
));




P.S: На счет правильности написания  gulp.task('watch') я сомневаюсь, но такое решение
мне помогло.

P.S.S: Это малая часть проблем. Буду благодарен, если отредактируете gulpfile.js
так как нужно. Если нужны будет исходники, дайте знать.

[07:12:09] Starting ''...
[07:12:09] '' errored after 2.72 ms
[07:12:09] TypeError: gulp.start is not a function
    at E:\Web\test\gulpfile.js:227:8
    at bound (domain.js:301:14)
    at runBound (domain.js:314:12)
    at asyncRunner (E:\Web\test\node_modules\async-done\index.js:55:18)
    at _combinedTickCallback (internal/process/next_tick.js:131:7)
    at process._tickDomainCallback (internal/process/next_tick.js:218:9)

    


Ответы

Ответ 1



В Gulp 4 изменили способ определения задач, если задача зависит от выполнения другой задачи, другими словами параметр списка [] для указания задач на выполнение - устарел. У вас описан вотчер следующим образом (обратите внимание на gulp.start, его нужно будет заменить, так как запуск должен производиться иначе): gulp.task('watch', function() { watch(path.watch.js, function(event, cb) { gulp.start('js:dist'); }); watch(path.watch.html, function(event, cb) { gulp.start('html:dist'); }); // some code here... }); Вотчер нужно переделать так (вместо start используй series) : gulp.task('watch', function() { gulp.watch(path.watch.js, gulp.series('js:dist')); gulp.watch(path.watch.html, gulp.series('html:dist')); // some code here... }); Это примера запуска вотчера на JS и HTML (остальные по подобию). Единсвенное замечание - следите за правильностью указания пути к файлам в шаблонах (к примеру 'app/**/*.html'). Также переделайте запуск следующей таски (замените параметра списка []): gulp.task('dist', [ 'html:dist', 'php:dist', 'js:dist', 'sprite:dist', 'style:dist', 'fonts:dist', 'image:dist' ]); К примеру на следующий код: gulp.task('dist', gulp.parallel( 'html:dist', 'php:dist', 'js:dist', 'sprite:dist', 'style:dist', 'fonts:dist', 'image:dist' )); Далее, запуск 'default' задачи, у вас он выглядит так (как писал ранее - параметр указания списка задач через [] - устарел): gulp.task('default', ['dist', 'webserver', 'watch']); Сделайте запуск 'default' задачи вот так (чтобы они работали параллельно через gulp.parallel, также убрали запуск через параметр списка []): gulp.task('default', gulp.parallel('dist', 'webserver', 'watch')); В Gulp 4 принято использовать вместо параметра списка [] следующие функции gulp.series(...tasks) и gulp.parallel(...tasks). По использованным функциям: gulp.parallel(...tasks) — запускает указанные задачи параллельно, при этом, если возникает ошибка, то выполнение будет завершено gulp.series(...tasks) — запускает задачи последовательно в указанном порядке, при этом, если возникает ошибка, то выполнение будет завершено Ссылка на документацию по запуску задач внутри gulp.series: Running tasks in series Сссылка на похожую проблему и ее решение: Everytime I run gulp anything, I get a assertion error. - Task function must be specified А также ссылка на гайд по переходу на Gulp 4: A quick guide for switching to gulp 4 Также, хочу обратить внимание на то, что все пакеты, которые вы используете в своем gulpfile необходимо обновить, обязательно удостоверьтесь в том, что они поддерживают Gulp 4. Про основные нюансы я рассказал, других проблем не должно возникнуть при переходе на Gulp 4, как правило основной проблемой является параметра списка [], и иногда слишком старые пакеты. Пример работы вашего приложения. Для начала, версии, которые установлены на моем компьютере (версии node, npm, gulp): После этого я запустил gulp и в браузере открылась страница: Я внес правки в html файл и сохранил изменения, при этом вотчер сработал и отобразилось в консоли изменение, также попробовал изменить js файл и в консоли эти изменения тоже отобразились: В браузере отобразились изменения практически моментально: Вот, собственно сам gulpfile который я запустил: 'use strict'; var gulp = require('gulp'), watch = require('gulp-watch'), plumber = require('gulp-plumber'), prefixer = require('gulp-autoprefixer'), babel = require('gulp-babel'), terser = require('gulp-terser'), //альтернатива gulp-uglifyes sass = require('gulp-sass'), sourcemaps = require('gulp-sourcemaps'), fileinclude = require('gulp-file-include'), cssmin = require('gulp-minify-css'), imagemin = require('gulp-imagemin'), pngquant = require('imagemin-pngquant'), rimraf = require('rimraf'), browserSync = require("browser-sync"), rename = require('gulp-rename'), spritesmith = require('gulp.spritesmith'), reload = browserSync.stream; var path = { dist: { html: 'dist/', php: 'dist/', js: 'dist/js/', css: 'dist/css/', img: 'dist/img/', fonts: 'dist/fonts/' }, app: { html: 'app/*.html', php: 'app/*.php', js: 'app/js/main.js', jsInit: 'app/js/init.js', style: 'app/scss/main.scss', sprite: 'app/img/sprite/**/*.*', img: 'app/img/*.*', fonts: 'app/fonts/**/*.*', }, watch: { html: 'app/**/*.html', php: 'app/*.php', js: 'app/js/**/*.js', style: 'app/scss/**/*.scss', img: 'app/img/*.*', sprite: 'app/img/sprite/**/*.*', fonts: 'app/fonts/**/*.*' }, export: { img: 'app/img/', style: 'app/scss/imports/' }, spriteTemplate: 'sass.template.mustache', clean: './dist' }; var config = { server: { baseDir: "dist" // or ./dist }, // tunnel: true, // host: "178.150.110.97", // notify: false, logPrefix: "Frontend_Devil" }; gulp.task('webserver', function() { browserSync(config); }); gulp.task('clean', function(cb) { rimraf(path.clean, cb); }); gulp.task('html:dist', function(done) { gulp.src(path.app.html) .pipe(plumber()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(gulp.dest(path.dist.html)) .pipe(reload()); done(); }); gulp.task('php:dist', function(done) { gulp.src(path.app.php) .pipe(plumber()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(gulp.dest(path.dist.php)) .pipe(reload()); done(); }); gulp.task('js:dist', function(done) { //init.js //Файл для инициации // gulp.src(path.app.jsInit) // .pipe(plumber()) // .pipe(sourcemaps.init()) // .pipe(fileinclude({ // prefix: '@@', // basepath: '@file' // })) // .pipe(babel({ // presets: ["@babel/preset-env"] // })) // .pipe(terser()) // .pipe(sourcemaps.write()) // .pipe(rename({suffix: '.babel-min', prefix : ''})) // .pipe(gulp.dest(path.dist.js)) //Обычный js файл. gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(sourcemaps.write()) .pipe(gulp.dest(path.dist.js)) //Babel-js файл. gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(babel({ presets: ["@babel/preset-env"] })) .pipe(rename({suffix: '.babel', prefix : ''})) .pipe(sourcemaps.write()) .pipe(gulp.dest(path.dist.js)) //Mini-js файл. gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(terser()) //альтернатива uglifyes .pipe(sourcemaps.write()) .pipe(rename({suffix: '.min', prefix : ''})) .pipe(gulp.dest(path.dist.js)); //Babel-mini-js файл. gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(babel({ presets: ["@babel/preset-env"] })) .pipe(terser()) .pipe(sourcemaps.write()) .pipe(rename({suffix: '.babel-min', prefix : ''})) .pipe(gulp.dest(path.dist.js)) .pipe(reload()); done(); }); gulp.task('style:dist', function(done) { gulp.src(path.app.style) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(sass({ sourceMap: true, errLogToConsole: true })) .pipe(prefixer()) .pipe(sourcemaps.write()) .pipe(gulp.dest(path.dist.css)) .pipe(cssmin()) .pipe(sourcemaps.write()) .pipe(rename({suffix: '.min', prefix : ''})) .pipe(gulp.dest(path.dist.css)) .pipe(reload()); done(); }); gulp.task('image:dist', function(done) { gulp.src(path.app.img) .pipe(plumber()) .pipe(imagemin({ progressive: true, svgoPlugins: [{removeViewBox: false}], use: [pngquant()], interlaced: true })) .pipe(gulp.dest(path.dist.img)) .pipe(reload()); done(); }); gulp.task('sprite:dist', function(done) { var spriteData = gulp.src(path.app.sprite) .pipe(plumber()) .pipe(spritesmith({ imgName: 'sprite.png', cssName: '_sprite.scss', cssFormat: 'scss', algorithm: 'binary-tree', cssTemplate: path.spriteTemplate, cssVarMap: function(sprite) { sprite.name = 's-' + sprite.name } })); spriteData.img.pipe(gulp.dest(path.export.img)); spriteData.css.pipe(gulp.dest(path.export.style)); done(); }); gulp.task('fonts:dist', function(done) { gulp.src(path.app.fonts) .pipe(plumber()) .pipe(gulp.dest(path.dist.fonts)) done(); }); gulp.task('dist', gulp.parallel( 'html:dist', 'php:dist', 'js:dist', 'sprite:dist', 'style:dist', 'fonts:dist', 'image:dist' )); gulp.task('watch', function() { gulp.watch(path.watch.html, gulp.series('html:dist')); gulp.watch(path.watch.php, gulp.series('php:dist')); gulp.watch(path.watch.style, gulp.series('style:dist')); gulp.watch(path.watch.js, gulp.series('js:dist')); gulp.watch(path.watch.sprite, gulp.series('sprite:dist')); gulp.watch(path.watch.fonts, gulp.series('fonts:dist')); }); gulp.task('default', gulp.parallel('dist', 'webserver', 'watch')); Поскольку некоторые задачи могут содержать асинхронный код, вы должны сигнализировать gulp, когда ваша задача завершит выполнение. В Gulp 3 версий вы могли не делать этого. Если вы не указали явно асинхронное завершение, gulp просто предположил бы, что ваша задача является синхронной и что она завершена, как только ваша задача завершится. В Gulp 4 был внедрен более строгий режим в этом отношении. Вы должны явно сигнализировать о завершении задачи. Это можно сделать пятью разными способами, о которых подробно описано в следующем ответе: Gulp error: The following tasks did not complete: Did you forget to signal async completion? Самый простой способ - это вызвать функцию обратного вызова, которую Gulp автоматически передает вашей задаче в качестве первого аргумента. Нужно просто вызвать эту функцию в конце задачи (внес правку в ответ, в параметрах добавлена колбэк функция done).

Ответ 2



Ответ Denis Bubnov актуальный, но я хочу предоставить свой конечный вариант. Отдельное спасибо Max Manchak, так как он в комментариях предоставил работающий код, и помог довести (до совершенства) конечный ответ. 'use strict'; var gulp = require('gulp'), watch = require('gulp-watch'), plumber = require('gulp-plumber'), prefixer = require('gulp-autoprefixer'), babel = require('gulp-babel'), terser = require('gulp-terser'), //альтернатива gulp-uglifyes sass = require('gulp-sass'), sourcemaps = require('gulp-sourcemaps'), fileinclude = require('gulp-file-include'), cssmin = require('gulp-minify-css'), imagemin = require('gulp-imagemin'), pngquant = require('imagemin-pngquant'), rimraf = require('rimraf'), browserSync = require("browser-sync"), rename = require('gulp-rename'), spritesmith = require('gulp.spritesmith'), reload = browserSync.stream; var path = { dist: { html: 'dist/', php: 'dist/', js: 'dist/js/', css: 'dist/css/', img: 'dist/img/', fonts: 'dist/fonts/', videos: 'dist/videos/', files: 'dist/files/' }, app: { html: 'app/*.html', php: 'app/*.php', js: 'app/js/main.js', jsInit: 'app/js/init.js', style: 'app/scss/main.scss', img: 'app/img/*.*', sprite: 'app/img/sprite/**/*.*', fonts: 'app/fonts/**/*.*', videos: 'app/videos/*.*', files: 'app/files/*.*' }, watch: { html: 'app/**/*.html', php: 'app/*.php', js: 'app/js/**/*.js', style: 'app/scss/**/*.scss', img: 'app/img/*.*', sprite: 'app/img/sprite/**/*.*', fonts: 'app/fonts/**/*.*', videos: 'app/videos/*.*', files: 'app/files/*.*' }, export: { img: 'app/img/', style: 'app/scss/imports/' }, spriteTemplate: 'sass.template.mustache', clean: './dist' }; var config = { server: { baseDir: "dist" // or ./dist }, // tunnel: true, // host: "178.150.110.97", // notify: false, logPrefix: "Frontend_Devil" }; gulp.task('webserver', function(cb) { browserSync(config); cb(); }); gulp.task('clean', function(cb) { rimraf(path.clean, cb); }); gulp.task('html:dist', function(cb) { gulp.src(path.app.html) .pipe(plumber()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(gulp.dest(path.dist.html)) .pipe(reload()); cb(); }); gulp.task('php:dist', function(cb) { gulp.src(path.app.php) .pipe(plumber()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(gulp.dest(path.dist.php)) .pipe(reload()); cb(); }); gulp.task('js:dist', function(cb) { //init.js //Файл для инициации // gulp.src(path.app.jsInit) // .pipe(plumber()) // .pipe(sourcemaps.init()) // .pipe(fileinclude({ // prefix: '@@', // basepath: '@file' // })) // .pipe(babel({ // presets: ["@babel/preset-env"] // })) // .pipe(terser()) // .pipe(sourcemaps.write()) // .pipe(rename({suffix: '.babel-min', prefix : ''})) // .pipe(gulp.dest(path.dist.js)) //Обычный js файл. gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(sourcemaps.write()) .pipe(gulp.dest(path.dist.js)); gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(babel({ presets: ["@babel/preset-env"] })) .pipe(rename({ suffix: '.babel', prefix: '' })) .pipe(sourcemaps.write()) .pipe(gulp.dest(path.dist.js)) //Mini-js файл. gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(terser()) //альтернатива uglifyes .pipe(sourcemaps.write()) .pipe(rename({ suffix: '.min', prefix: '' })) .pipe(gulp.dest(path.dist.js)); //Babel-mini-js файл. gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(babel({ presets: ["@babel/preset-env"] })) .pipe(terser()) .pipe(sourcemaps.write()) .pipe(rename({ suffix: '.babel-min', prefix: '' })) .pipe(gulp.dest(path.dist.js)) .pipe(reload()); cb(); }); gulp.task('style:dist', function(cb) { gulp.src(path.app.style) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(sass({ sourceMap: true, errLogToConsole: true })) .pipe(prefixer()) .pipe(sourcemaps.write()) .pipe(gulp.dest(path.dist.css)) .pipe(cssmin()) .pipe(sourcemaps.write()) .pipe(rename({ suffix: '.min', prefix: '' })) .pipe(gulp.dest(path.dist.css)) .pipe(reload()); cb(); }); gulp.task('image:dist', function(cb) { gulp.src(path.app.img) .pipe(plumber()) .pipe(imagemin({ progressive: true, svgoPlugins: [{ removeViewBox: false }], use: [pngquant()], interlaced: true })) .pipe(gulp.dest(path.dist.img)) .pipe(reload()); cb(); }); gulp.task('sprite:dist', function(cb) { var spriteData = gulp.src(path.app.sprite) .pipe(plumber()) .pipe(spritesmith({ imgName: 'sprite.png', cssName: '_sprite.scss', cssFormat: 'scss', algorithm: 'binary-tree', cssTemplate: path.spriteTemplate, cssVarMap: function (sprite) { sprite.name = 's-' + sprite.name } })); spriteData.img.pipe(gulp.dest(path.export.img)); spriteData.css.pipe(gulp.dest(path.export.style)); reload(); cb(); }); gulp.task('fonts:dist', function(cb) { gulp.src(path.app.fonts) .pipe(plumber()) .pipe(gulp.dest(path.dist.fonts)) .pipe(reload()); cb(); }); gulp.task('videos:dist', function(cb) { gulp.src(path.app.videos) .pipe(plumber()) .pipe(gulp.dest(path.dist.videos)) .pipe(reload()); cb(); }); gulp.task('files:dist', function(cb) { gulp.src(path.app.files) .pipe(plumber()) .pipe(gulp.dest(path.dist.files)) .pipe(reload()); cb(); }); gulp.task('dist', gulp.parallel( 'html:dist', 'php:dist', 'js:dist', 'style:dist', 'image:dist', 'sprite:dist', 'fonts:dist', 'videos:dist', 'files:dist' )); gulp.task('watch', function() { gulp.watch(path.watch.html, gulp.series('html:dist')); gulp.watch(path.watch.php, gulp.series('php:dist')); gulp.watch(path.watch.js, gulp.series('js:dist')); gulp.watch(path.watch.style, gulp.series('style:dist')); gulp.watch(path.watch.img, gulp.series('image:dist')); gulp.watch(path.watch.sprite, gulp.series('sprite:dist')); gulp.watch(path.watch.fonts, gulp.series('fonts:dist')); gulp.watch(path.watch.videos, gulp.series('videos:dist')); gulp.watch(path.watch.files, gulp.series('files:dist')); }); gulp.task('default', gulp.parallel('dist', 'webserver', 'watch'));

Ответ 3



При переходе с gulp 3 на gulp 4 есть в принципе 2 проблемы, первая вроде как очевидная при первых попытка поиска решения проблемы: вместо массива с названиями тасков использовать метод gulp.parallel или gulp.series - между ними разница лишь в том, что метод .parallel запускает таски параллельно друг с другом, а вот метод .series не начинает выполнение второго таска указанного в нем до того как закончится первый... итого можно использовать метод .parallel везде если нет строгой зависимости в чередности выполнения тасков переданных данному методу. было: gulp.task('default', ['dist', 'webserver', 'watch']); стало: `gulp.task('default', gulp.parallel('dist', 'webserver', 'watch'));` Вторая же проблема не такая очевидная, т.к. всё зависит от того как ранее настраивали gulpfile. дело в том что таски в gulp представляют из себя поток, и если не "сказать" gulp, что поток завершен, то может вылезть ошибка. Чтобы сообщить gulp что вызванный таск завершился есть 2 способа: 1) передать в параметры функции некий параметр (назовём его callback) и после выполнения всех действий вызвать этот параметр; 2) воспользоваться return для действий в таске. на примере было: `gulp.task('html:dist', function() { gulp.src(path.app.html) .pipe(plumber()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(gulp.dest(path.dist.html)) .pipe(reload()); });` закроем поток таска использовав return: `gulp.task('html:dist', function() { return gulp.src(path.app.html) .pipe(plumber()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(gulp.dest(path.dist.html)) .pipe(reload()); });` предыдущий способ хорош, НО мы можем наблюдать в данном проекте таск js:dist, где мы не можем использовать return так как в таком случае прервется выполнение таска после выполнения первой задачи (т.к. return возвращает результат выполнения и дальше функция не выполняется): `gulp.task('js:dist', function() { gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(sourcemaps.write()) .pipe(gulp.dest(path.dist.js)) //Babel-js файл. gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(babel({ presets: ["@babel/preset-env"] })) .pipe(rename({ suffix: '.babel', prefix: '' })) .pipe(sourcemaps.write()) .pipe(gulp.dest(path.dist.js)) //..... и далее другие задачи таска });` И вот в этом случае лучшим решением будет передать в параметры функции callback и вызвать его после всех необходимых нам действий: `gulp.task('js:dist', function(callback) { gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(sourcemaps.write()) .pipe(gulp.dest(path.dist.js)) //Babel-js файл. gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(babel({ presets: ["@babel/preset-env"] })) .pipe(rename({ suffix: '.babel', prefix: '' })) .pipe(sourcemaps.write()) .pipe(gulp.dest(path.dist.js)) //..... и далее другие задачи таска callback(); });`