Страницы

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

четверг, 2 мая 2019 г.

Повесить команду на событие

Подскажите пожалуйста как можно повесить команду (ICommand) из ViewModel на событие Window.Closed? Ради соблюдения принципов MVVM не хочется пользоваться обычным обработчиком.


Ответ

Используйте EventTrigger в сочетании с InvokeCommandAction из неймспейса Windows.Interactivity

команда USE Sercver в запросе

Господа, прошу объяснить не мыслимое
Есть простой запрос, который у меня работает, и в C# и в МС студии
//c# string slim_sqlquery = "SELECT * FROM sys.Tables"; //Ms SQL Server Management Studio SELECT * FROM sys.Tables
Но на некоторых серверах таблички не находятся, в студии делаю по другому
//Ms SQL Server Management Studio Use MyServerName GO SELECT * FROM sys.Tables
А как это же самое реализовать на c# ?
//p.s. string slim_sqlquery = "Use MyServerName GO SELECT * FROM sys.Tables"; SqlCommand cmd = new SqlCommand(slim_sqlquery, conn_my_servak); SqlDataReader reader = cmd.ExecuteReader();//вот тут лезут ошибки, что SQL запрос надо в 1 строку


Ответ

SqlClient не понимает GO так, как это делает SSMS.
Либо используйте three-part naming
SqlCommand cmd = new SqlCommand("SELECT * FROM MyServerName.sys.Tables", conn_my_servak); SqlDataReader reader = cmd.ExecuteReader();
Либо вынесите смену контекста в отдельную команду:
conn_my_servak.ChangeDatabase("MyServerName");
SqlCommand cmd = new SqlCommand("SELECT * FROM sys.Tables", conn_my_servak); SqlDataReader reader = cmd.ExecuteReader();

Как добиться однородного фона (TextView внутри CardView)?

В моей программе мне нужно использовать TextView внутри Cardview из библиотеки поддержки. Нужны скругленные углы. Нужно иметь возможность изменять цвет элемента программно. Следующий код:

приводит к такому результату:

Эти странные полосы и черточки меня совершенно не устраивают.
Следующий же код:

приводит к другому результату:

Второй результат мне не подходит из-за белых краев.
Третья моя попытка: Создала файл rownded_corners.xml в папке drawable

и в разметке второй попытки задала его в качестве фона TextView
android:background="@drawable/rounded_corner"
Вот что получилось:

Здесь меня не устраивает белая рамка.
В общем, вопрос: Как мне добиться однородного цвета, заполняющего весь CardView, и сохранить возможность программно установить другой цвет.
UPDATE. Описанное в вопросе недоразумение уже разрешилось. См. мой ответ.


Ответ

Представляете, описанное в вопросе недоразумение было вызвано тем, что используемый мною цвет (colorPrimary) был полупрозрачным (что-то вроде #a03F51B5) и через него была видна "кухня" построения CardView. Я изменила его на #3F51B5 и первый вариант дал желаемый результат даже без атрибута, предложенного @ЮрийСПб.

Работа с XML в MS SQL?

Допустим, есть XML такого вида:

Можно ли получить выборку такого вида?
value --------------- значение field1 значение field2 значение field3 значение field1 значение field2 значение field3
Можно ли это сделать без явного перечисления названия узлов? Допустим, известно, что все узлы field+цифра. Можно ли сделать запрос по маске?


Ответ

Вы можете отфильтровать узлы с нужными именами с помощью функций local-name и substring
declare @xml xml = N' value 1 value 2 value 3 AA value 4 value 5 value 6 BB ';
select x.c.value('text()[1]', 'varchar(20)') value from @xml.nodes('/root[1]/TableRow/*[substring(local-name(), 0, 6)="field"]') x(c);
Результат:
value -------- value 1 value 2 value 3 value 4 value 5 value 6
В XQuery запросах использовать * в XPath (также как и выражения наподобие '//field'), если без них можно обойтись, не рекомендуется. Если выбираете узлы от корня, то лучше указать '/root[1]' в начале XPath. Если точно известен путь до узлов - указывайте его явно. Если берёте значение из элемента, то лучше взять его не через , а через text()[1]. Чем больше информации об узлах вы дадите XQuery процессору, тем проще будет ему распарсить xml и тем ниже будет стоимость запроса.
В данном случае, например, оценочная стоимость такого запроса
select x.c.value('text()[1]', 'varchar(20)') value from @xml.nodes('/root[1]/TableRow/*[substring(local-name(), 0, 6)="field"]') x(c);
и такого
select x.c.value('.', 'varchar(20)') value from @xml.nodes('*/*/*[substring(local-name(), 0, 6)="field"]') x(c);
соотносятся примерно как 2 к 136.

Как создать типизированный массив объектов?

Предыстория: пишу свою реализацию коллекции на основе массива (задание такое). И дошел до метода toArray()
Есть классический массив:
private E[] array;
как его проинициализировать так что бы когда я возвращаю этот массив он был не Object а именно того типа который поступил на вход в класс.
Такой вариант при возвращении все равно возвращает Object[]
array =(E[]) new Object[length]
Просмотрел уже несколько лекций по дженерикам в джаве и основная суть ясна, но нигде не говорят о типизированных массивах.


Ответ

Тут есть подробное описание проблемы на английском языке.
Вроде должно сработать как-то так:
public E[] getArray(Class clazz, int size) { @SuppressWarnings("unchecked") E[] arr = (E[]) Array.newInstance(clazz, size);
return arr; }

Как исполнить скрипт при запуске docker-контейнера?

Здравствуйте!
Вопрос, возможно, несколько избит, но ответа на него я не нашел. А похожие вопросы на тостере, как в и гугле не помогли. Я буду премного благодарен тем людям, что уделят немного своего времени и дадут развернутый ответ!
И так, задача минимум - запустить apache при старте контейнера
Задача максимум - выполнить bash скрипт при старте контейнера
Я опишу варианты которые я пробовал.
1. Сборка простейшего образа и запуск контейнера из консоли
Dockerfile FROM ubuntu:14.04
RUN apt-get update && \ apt-get install -y apache2
В консоли: sudo docker build -t apache . sudo docker run -dit --name cont_apache apache /bin/bash service apache2 start
В ответ код контейнера, docker ps чист. docker logs cont_apache сообщает о запуске апача - Starting web server apache2 ... Но сам контейнер почему-то умирает. хотя флаг -d установлен.
Попытался: sudo docker run -dit --name cont_apache apache service apache2 start
Результат точно такой же.
2. Сборка образа и запуск апача при помощи CMD
Dockerfile: FROM ubuntu:14.04
RUN apt-get update && \ apt-get install -y apache2
CMD ["service" "apache2", "start"]
В консоли: sudo docker build -t apache . sudo docker run -dit --name cont_apache apache /bin/bash service apache2 start
Контейнер запущем, висит как демон, перехожу в контейнер: root@2a97628fd78b:/# service apache2 status * apache2 is not running Апач не запустился. Почему?
3. Сборка образа с проброской bash скрипта и его выполнение
Dockerfile: FROM ubuntu:14.04
RUN apt-get update && \ apt-get install -y apache2
COPY ./apache2_start.sh /root/apache2_start.sh
CMD ["chmod", "777", "/root/apache2_start.sh"]
CMD ["/root/apache2_start.sh"]
Script apache2_start.sh: #!/bin/bash
service apache2 start echo "127.0.0.1"
В консоли: sudo docker build -t apache . sudo docker run -dit --name cont_apache apache
В docker ps контейнера нет. В логах docker logs cont_apache: * Starting web server apache2 AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.3. Set the 'ServerName' directive globally to suppress this message * 127.0.0.1
Пробовал также с запуском bash из консоли: sudo docker run -dit --name cont_apache apache /bin/bash
В результате контейнер висит в docker ps. Docker logs conf_apache чист.
А в самом контейнере: root@d2c9831773a9:/# service apache2 status * apache2 is not running
Итог.
Я попытался добиться нужного результата разными способами, но ни одним у меня не вышло.
Очевидно, что я допускаю ошибки в работе с докером.
Я буду очень! благодарен за конструктивную помощь в данном вопросе как в целом, так и что в каком конкретном случае я делал не так.
Конечно, эти примеры высосаны из пальца, и можно найти кучу примеров запуска окружения при помощи docker compose. Но моя цель разобраться в вопросе, и уже в дальнейшем использовать всякие крутые штуки вроде docker compose


Ответ

Докер-контейнер - это один процесс, обернутый в изолированную среду. Этот процесс может порождать дочерние процессы, но основной постулат остается одинаковым: время жизни контейнера - это время жизни процесса, указанного в ENTRYPOINT/CMD. Насколько понимаю, команда apache2 service start попытается запустить апач в фоновом режиме и тут же закончит свое выполнение; как только докер увидит, что процесс закончился, он прибьет контейнер. Таким образом, ваша конечная цель - выполнить в начале скрипта требуемые действия, а потом сделать так, чтобы он выполнялся все время жизни приложения (в случае с апачем - условно бесконечно). Проще всего это сделать следующим образом:
выполнить требуемые действия последней командой в шелл-скрипте запустить апач с отключенным фоновым режимом (-DFOREGROUND), предварив команду инструкцией exec. Эта инструкция позволит текущему процессу (выполняющемуся шелл-скрипту) стать процессом, вызванным exec. После этого ctrl-c и прочие плюшки будут отправляться на обработку напрямую апачу.
пример такой работы можно увидеть прямо в официальном изображении library

Как вычислить координаты всех точек лежащих на окружности


Предположим мне нужны координаты 360 точек на окружности, по одной на каждый градус поворота
Есть предположение:
int x = (int)Math.Cos(2 * Math.PI * i / n) * R + x[0]; int y = (int)Math.Sin(2 * Math.PI * i / n) * R + y[0];
Где i - номер точки, n - кол-во точек = 360, R - радиус, x[0] и y[0] - координаты центра окружности
Вот только таким способом вычисляются только эти четыре точки:

Как пройтись по всем 360-ти точкам?


Ответ

int x = (int)Math.Cos(2 * Math.PI * i / n) * R + x[0]; int y = (int)Math.Sin(2 * Math.PI * i / n) * R + y[0];
Я предполагаю, что нужны именно целочисленные координаты. В таком случае следует выполнять округление после умножения на радиус.
int x = (int)(Math.Cos(2 * Math.PI * i / n) * R + 0.5) + x0; int y = (int)(Math.Sin(2 * Math.PI * i / n) * R + 0.5) + y0;
Это по-прежнему не гарантирует, что получатся все 360 точек, но теперь их не всегда будет 4.
http://ideone.com/fxzB8V
4 of 360 when radius is 1 76 of 360 when radius is 10 140 of 360 when radius is 20 268 of 360 when radius is 40 356 of 360 when radius is 80 360 of 360 when radius is 90 360 of 360 when radius is 100
Если же целочисленные координаты не требуются, то вместо int следует использовать double:
double x = Math.Cos(2 * Math.PI * i / n) * R + x0; double y = Math.Sin(2 * Math.PI * i / n) * R + y0;

Проверка числа при вводе scanf

Вопрос такой: Как считать с консоли целое число, которое влезает в диапазон int? То есть, как обработать ситуацию ввода с консоли большой последовательности чисел которая не влезает в int?
scanf_s("%d", &n)
Вводим сюда 9999999999999999999999999999999999 например и получаем нестабильную работу программы. Как с этим бороться?


Ответ

Не используйте scanf_s() используйте функции read() getc() fgets() проверяйте введенный массив, а потом преобразуйте int в char используй stroul()

Почему у меня SetPixel не отрисовывает пиксель?

Почему у меня SetPixel не отрисовывает пиксель на форме?
WndProc proc uses ebx edi esi, hwnd:DWORD, wmsg:DWORD, wparam:DWORD, lparam:DWORD switch wmsg case WM_INITDIALOG invoke SendMessage, hwnd, WM_SETICON, 1, FUNC(LoadIcon, NULL, IDI_ASTERISK) case WM_PAINT invoke SetPixel, hwnd, 15, 20, 65285 case WM_CLOSE exit_program: invoke EndDialog, hwnd, 0 endsw xor eax,eax ret WndProc endp


Ответ

В качестве первого параметра SetPixel принимает не идентификатор окна, а идентификатор контекста устройства (в данном случае, идентификатор контекста окна). Контекст устройства упрощенно можно сравнить с холстом, на котором происходит рисование.
В вашем случае нужно получить этот идентификатор с помощью функции BeginPaint, нарисовать пиксель, потом освободить контекст при помощи EndPaint
Код для обработки сообщения WM_PAINT будет примерно такой:
invoke BeginPaint, hwnd, addr ps invoke SetPixel, eax, 15, 20, 65285 invoke EndPaint, hwnd, addr ps
Также необходимо объявить переменную ps, которая является структурой PAINTSTRUCT. Скорее всего определение этой структуры уже есть в каком-то из подключаемых файлов пакета MASM. addr - ключевое слово для подстановки адреса переменной.
Для нескольких вызовов SetPixel можно сделать например так:
invoke BeginPaint, hwnd, addr ps push ebx mov ebx, eax invoke SetPixel, ebx, 15, 20, 65285 invoke SetPixel, ebx, 30, 20, 65285 invoke SetPixel, ebx, 45, 20, 65285 pop ebx invoke EndPaint, hwnd, addr ps
Это вариант без использования дополнительной переменной. По соглашениям stdcall и cdecl, вызываемые процедуры не должны модифицировать регистры ebx, edi, esi (но могут модифицировать eax, ecx, edx), поэтому ebx, например, можно использовать для временного хранения значений, которые не должны затираться вызовами процедур. Но так как процедура WndProc тоже должна соответствовать соглашению stdcall, то перед модификацией ebx его значение нужно сохранить, а потом восстановить. Это можно сделать либо локально, вокруг места, где происходит модификция ebx (как показано в этом примере), либо сохранить в начале процедуры, а в конце (перед ret) - восстановить.
Еще одно замечание - код цвета лучше писать в шестнацатеричном виде, в данном случае это будет 00FF05h, тогда будет сразу понятно, что этот цвет ближе к зеленому (порядок цветов - 0x00bbggrr, согласно описанию типа COLORREF).

Указатель на функтор

У меня есть следующие классы:
class A { public: B* b; }
class B { public: double operator()(double val); }
Дальше я в какой-то момент пытаюсь вызвать класс B как функцию через указатель на класс A
a->b(val); //a - указатель на экземпляр класса A
При компиляции я получаю ошибку:
error: 'A::b' cannot be used as a function
Вопрос: как это исправить? Т.е. как использовать функторы по указателю?


Ответ

Можно и так:
a->b->operator()(val);
если a - указатель на A
Если же, как вы написали в вопросе, //a - экземпляр класса A, то тогда
(*a.b)(val); a.b->operator()(val);
Судя по вашему ответу на свой вопрос, вы все же ошиблись в самом вопросе, и a у вас - указатель на экземпляр, а не сам экземпляр...

Оставить только дубли в таблице

Имеется таблица вида:
a|b|c
Как оставить только те строки, где значение "a" встречается больше одного раза?
UPD: a|b|c - это три столбца, столбцы b и с всегда уникальны и имеют разные значения, а значение столбца "а" может встречаться несколько раз


Ответ

Пусть таблица называется tbl, и содержит три столбца a, b и c. Тогда для решения задачи можно поступить следующим образом
DELETE tbl FROM tbl JOIN ( SELECT a, b, c FROM tbl GROUP BY a HAVING COUNT(*) <= 1 ) AS t ON tbl.a = t.a AND tbl.b = t.b AND tbl.c = t.c

error: method does not override or implement a method from a supertype.

Не работает alertdialog во фрагменте
Код fmonday.java (P.S.: Чтобы код не получился слишком длинным, я удалил некоторые куски где используется loader):
public class fmonday extends Fragment implements LoaderManager.LoaderCallbacks { final int DIALOG_ITEMS = 1; final CharSequence[] items = {"1", "2", "3"}; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); }
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fmonday, container, false); Button button12 = (Button) rootView.findViewById(R.id.button12); button12.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { getActivity().showDialog(DIALOG_ITEMS); } }); } @Override //Здесь ошибка protected Dialog onCreateDialog(int id) { switch (id) { case DIALOG_ITEMS: AlertDialog.Builder adb = new AlertDialog.Builder(getActivity()); adb.setTitle("Adding class"); adb.setItems(items, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int item) { Toast.makeText(getActivity().getApplicationContext(), "Your choice: " + items[item], Toast.LENGTH_SHORT).show(); } }); adb.setCancelable(false); return adb.create(); default: return null; } }
logcat:
Error:(88, 5) error: method does not override or implement a method from a supertype
Как решить эту проблему?


Ответ

Вы не верно указали сигнатуру метода (тип возвращаемого значения, имя метода, список аргументов(их кол-во, порядок и типы)) и создали новый, не существующий в классе метод, после чего сказали, что этот метод якобы существует в супер-классе. IDE заметила вашу ошибку и сказала об этом.
На этом этапе вам надо было заглянуть в доки и убедиться, что в классе DialogFragment нет метода Dialog onCreateDialog(int id)
Зато есть Dialog onCreateDialog(Bundle savedInstanceState)
Итого вы допустили ошибку в списке аргументов метода, а именно в типе аргумента, написав int вместо Bundle

Выравнивание текста по левой и правой границе виджета

Добрый день! Подскажите, пожалуйста, есть ли в SDK атрибут, выравнивающий текст по правому и по левому краю одновременно, чтобы он занимал все выделенное пространство?
Вот это я имею в виду.
А у меня пока так.


Ответ

Android не поддерживает выравнивание по ширине. Воспользуйтесь сторонними библиотеками.
https://github.com/ufo22940268/android-justifiedtextview
https://github.com/navabi/JustifiedTextView
https://github.com/programingjd/justified
и т.д.
P.S. Можно использовать WebView как альтернативный вариант

Webstorm, не работает emmet в jade файлах

Столкнулся с проблемой автодополнения emmet в jade файлах после Sublime Text 3. Например пишем "!", а получаем:
html head meta(charset="UTF-8") title Document link(rel="stylesheet", href="") body
Есть ли способ добиться такого в Webstorm? (плагин jade у меня стоит)


Ответ

К сожалению, Emmet для Jade шаблонов сейчас не поддерживается. Пожалуйста, проголосуйте за WEB-18099

Компиляция методов в шаблонном классе в зависимости от параметра шаблона

Хочу написать шаблонный класс, который будет получать в качестве параметра шаблона другой шаблонный класс.
Проблема в том, что среди шаблонов, которые будут параметрами, есть различные классы, которые имеют несколько отличающийся интерфейс и поэтому при компиляции возможны ошибки из-за несоответствия интерфейсов.
Как, например, ниже:
#include
template class FirstCreator { public: typedef T object_type;
T* GetNewObject() { T* pT = new T(); return pT; } };
template class SecondCreator { public: typedef T object_type;
std::shared_ptr GetNewObjectEx() { std::shared_ptr pT; return pT; } };
template class CreatorUser { public: TCreator* m_pData;
CreatorUser(TCreator& data) { m_pData = &data; }
typename TCreator::object_type* GetNewObjectPtr() { return m_pData->GetNewObject(); }
std::shared_ptr GetNewObjectSharedPtr() { return m_pData->GetNewObjectEx(); }
void SimpleFunction() { //Здесь на самом деле нужен вызов только одной фукнции: //GetNewObjectPtr, если параметр шаблона FirstCreator //GetNewObjectSharedPtr, если параметр шаблона SecondCreator //но как дать понять компилятору это? typename TCreator::object_type* pObj = GetNewObjectPtr(); delete pObj;
std::shared_ptr pObjShared = GetNewObjectSharedPtr(); } };
typedef FirstCreator IntCreatorFirst; typedef SecondCreator IntCreatorSecond;
int main() { IntCreatorFirst creator1; IntCreatorSecond creator2;
CreatorUser* pCreatorUser1 = new CreatorUser(creator1); CreatorUser* pCreatorUser2 = new CreatorUser(creator2);
pCreatorUser1->SimpleFunction(); pCreatorUser2->SimpleFunction();
return 0; }
При попытке вызвать SimpleFunction компилятор выдает ошибку
Error 1 error C2039: 'GetNewObjectEx' : is not a member of 'FirstCreator'
Что совершенно справедливо, так как такой функции у FirstCreator действительно нет.
Мне нужно написать SimpleFunction таким образом, чтобы если параметром CreatorUser является FirstCreator, то вызывался метод GetNewObjectPtr, а метод GetNewObjectSharedPtr вообще не создавался и наоборот.
Есть ли в C++ возможность сделать подобное?
UPD:
Исправил в соответствии с первым ответом, заработало. Пришлось правда завернуть функции в другую функцию - но тут, наверное, проблема старого компилятора (компилятор студии MS VS 2010), который все время ругался, что функция не может иметь шаблонных параметров по умолчанию:
void SimpleFunctionEx() { SimpleFunction(); }
template void SimpleFunction(typename std::enable_if >::value>::type* = nullptr) { typename TCreator::object_type* pObj = GetNewObjectPtr(); delete pObj; }
template void SimpleFunction(typename std::enable_if >::value>::type* = nullptr) { std::shared_ptr pObjShared = GetNewObjectSharedPtr(); }


Ответ

Можно попробовать использовать SFINAE
template void SimpleFunction(typename std::enable_if::value>::type* = nullptr) { // Используем GetNewObjectPtr. }
template void SimpleFunction(typename std::enable_if::value>::type* = nullptr) { // Используем GetNewObjectSharedPtr. }

Как изменить тип колонки на serial?

Есть таблица с заполненными данными:
CREATE TABLE "Виплата" ( old integer NOT NULL, "Код_договору" integer, "Дата" timestamp(0) without time zone, "Сума_виплат" text, "Оплата" boolean, "Код" integer, CONSTRAINT "Виплата_pkey" PRIMARY KEY (old) ) WITH ( OIDS=FALSE ); ALTER TABLE "Виплата" OWNER TO postgres;
Обязательно нужно изменить тип колонки "Код" на serial! Обычным ALTER: ALTER TABLE "Виплата" ALTER COLUMN "Код" type serial; не получается это сделать, потому что serial не тип ERROR: type "serial" does not exist ! Но сделать это очень нужно.
Каким способом можно это реализовать ?


Ответ

Тип SERIAL аналогичен полю, значение которого устанавливается из последовательности. Поэтому делаем так:
CREATE SEQUENCE code_seq; ALTER TABLE "Виплата" ALTER COLUMN "Код" SET DEFAULT nextval('code_seq');
Не знаю как на мове правильно будет "Последовательность_коду", поэтому просто code_seq В nextval() передаётся строка с название последовательности, поэтому там одинарные кавычки должны быть.

Атомарная группировка, сверхжадный квантификатор

Расскажите как работает атомарная группировка и сверхжадный квантификатор Объясните как работают данные регулярные выражения
(?>#.*#) (?:(?>#.*#)|(A))


Ответ

Чтобы понять, что такое атомарная группировка и сверхжадная кванификация- нужно хоть немного понять как устроен движок регулярных выражений внутри, а точнее, нужно иметь представление о точках возврата. С этого и начнем.

Точка возврата
Встретив квантификацию или альтернативу (я рассматриваю простые случаи, на самом деле точки возврата создаются и в других конструкциях регулярных выражений- везде, где может потребоваться вернуться назад) движок регулярных выражений (далее просто "движок") создает точку, куда ему следует вернуться, если выражение не совпадет с текстом. Тогда вернувшись в эту точку он попробует применить альтернативу или прекратить квантификацию. Что это означает? Посмотрим на простое регулярное выражение .*x примененное к тексту text (точки возврата буду обозначать символом :
Движок начинает обрабатывать текст с самого начала и видит .*, так как данное выражение может совпать с "ничем", то создаем точку возврата сюда .text Смотрим дальше - далее по тексту литерал t, захватываем его как часть .* и надо бы создать точку возврата снова в позиции 0, но это было сделано уже в пункте 1. .text Далее по тексту литерал e, захватываем его как часть .* и создаем точку возврата перед ним .t.ext Далее по тексту литерал x, захватываем его как часть .* и создаем точку возврата перед ним .t.e.xt Далее по тексту литерал t, захватываем его как часть .* и создаем точку возврата перед ним .t.e.x.t Литералы кончились, это конец строки, но выражение не совпало, потому что требуется обязательно литерал x Возвращаемся в точку возврата перед литералом t, теперь у нас выражению .* соответствует текст tex, и пытаемся найти за ним литерал x - неудача, так как за ним литерал t Снова пробуем вернуться назад. Для этого возвращаемся в точку возврата перед литералом x. Теперь выражению .* соответствует текст te, ищем за ним литерал x и успешно находим Регулярное выражение закончилось, значит найдено совпадение. Итак: Выражению .* соответствует текст te, выражению x соответствует текст x, значит полное совпадение будет с текстом tex
Если бы у нас кончились точки возврата, и совпадения так и не найдено- значит текст не соответствует регулярному выражению. Важно проникнуться механикой создания точек возврата- с пониманием этого быстро придет понимание различных видов квантификаций и атомарной группировки.

Атомарная группировка: теория
Это группировка ВНУТРИ которой нет точек возврата. Это означает, что как только будет найдено совпадение для выражения внутри такой группировки - это совпадение будет считаться единственным и вернуться внутрь него будет нельзя, даже, если это помешает общему совпадению. https://regex101.com/r/cH7rO2/1
Выражение (?>#.*#)a применено к тексту aaa#aaaaaa#aaaaaaaa#a# - нет совпадений, потому что #.*# захватит самое большое совпадение #aaaaaa#aaaaaaaa#a# и внутри этого текста нет точек возврата - вернуться некуда, поэтому невозможно будет захватить литерал a, который следует за (?>#.*#)
Рассмотрим пошагово на тексте покороче b#c#a#
По тексту литерал b - не совпадает с обязательным #, переходим к следующему литералу По тексте литерал # - совпадает с обязательным литералом #, переходим к выражению .* и запоминаем, что мы находимся внутри атомарной группировки и как только найдем совпадение для нее, то удалим все точки возврата, которые были созданы внутри нее Захватываем литерал c, так как он соответствует , создаем точку возврата перед ним b#.c#a# Захватываем литерал #, так как он соответствует , создаем точку возврата перед ним b#.c.#a# Захватываем литерал a, так как он соответствует , создаем точку возврата перед ним b#.c.#.a# Захватываем литерал #, так как он соответствует , создаем точку возврата перед ним b#.c.#.a.# Достигли конца текста, но не нашли совпадения для литерала #. Вернемся в точку возврата перед последней решеткой. Теперь выражению .* соответствует текст c#a, выражению # - текст # Мы достигли конца атомарной группировки, значит можно удалить все точки возврата, которые были созданы внутри нее. В итоге не останется ни одной точки возврата. Нет точек возврата, а нужно еще совпадение с выражением a, которого нет после текста #c#a#. Результат - нет совпадений.
Подведем итог: пока ищется совпадение с атомарной группировкой - могут быть созданы точки возврата, но как только совпадение найдено - все точки возврата внутри атомарной группировки будут удалены.

Атомарная группировка: практика
На практике атомарная группировка означает очень простую вещь - текст, который захвачен этой группировкой будет рассматриваться далее как единое целое внутрь которого нельзя вернуться. Если что-то совпало - значит оно и будет результатом для атомарной группировки, иначе никак. Поэтому она и называется атомарной, то есть неделимой на отдельные части.
На практике атомарная группировка служит обычно для оптимизации регулярных выражений, наиболее часто ее можно увидеть в рекурсивных регулярных выражениях. Примеры оптимизаций приведу при рассказе о сверхжадной квантификации.
Сверхжадная квантификация
Это частный случай атомарной группировки, когда атомарная группировка применена в пределах одного квантификатора. Вот и все, что следует о ней сказать. Выражение a++ полностью равносильно выражению (?>a+).
Например выражение a++a не даст совпадения на тексте aaaa, потому что a++ захватит все литералы a, которые есть в тексте и не вернет ни одного из них, хоть это и помешает общему совпадению.
Сверхжадная квантификация может выглядеть в регулярных выражениях следующим образом:
*+ ++ ?+ {m,n}+
Примеры применения
Оптимизируем минимальную квантификацию .*?
Пусть есть выражение a.*?bcd и текст a-----bcd----bcd https://regex101.com/r/cH7rO2/8 Совпадение найдено за 11 шагов. Теперь изменим регулярное выражение на такое a(?:[^b]++|b)*?bcd https://regex101.com/r/cH7rO2/9 Совпадение найдено за 9 шагов.
Даже на таком маленьком тексте мы получили прирост примерно 20%
Смысл оптимизации в том, что смотрим литерал, который следует за минимальной квантификацией - в данном случае это b, и разлагаем минимальную квантификацию на две альтернативы из b++ и b к которым тоже применена минимальная квантификация. Такая конструкция создает меньше точек возврата, поэтому быстрее происходит нахождение совпадения.
Оптимизируем рекурсивные регулярные выражения
Возьмем каноническую задачу по поиску сбалансированных скобок <> Сначала напишем регулярное выражение:
<(?:[^<>]*|(?R))*>
https://regex101.com/r/cH7rO2/4
Оно даже работает и мы могли бы радоваться жизни, но попробуйте добавить в начало текста < и по одному символу a постепенно ;) Радость будет таять на глазах при виде цифры шагов - количество шагов удваивается с каждым введенным символом, а потом и вовсе видим Catastrophic backtracking https://regex101.com/r/cH7rO2/5 А оптимизируется все очень просто - достаточно не возвращаться назад внутри выражения [^<>]* Таким способом:
<(?:[^<>]*+|(?R))*>
https://regex101.com/r/cH7rO2/6
Или таким:
<(?:(?>[^<>]*)|(?R))*>
https://regex101.com/r/cH7rO2/7

Сравнить Object и Int

Как сравнить Object и Int.
Object может быть (примитивные типы) 1.byte 2.int 3.long 4.double (чем оно может быть заранее известно)
При сравнении выскакивают исключения(нельзя сравнить Int и Long). Как это можно реализовать без приведений к String.


Ответ

Если я правильно понял ваш вопрос, то как-то так (ideone):
public static int compare(Object lhs, Integer rhs) { if (lhs instanceof Double) { return Double.compare((Double) lhs, rhs); } else if (lhs instanceof Long) { return Long.compare((Long) lhs, rhs); } else if (lhs instanceof Integer) { return Integer.compare((Integer) lhs, rhs); } else if (lhs instanceof Byte) { return Integer.compare(((Byte) lhs).intValue(), rhs); } else { throw new IllegalArgumentException(); } }

Может ли транслятор работать без интерпретатора или компилятора?

Может ли транслятор работать без интерпретатора или компилятора и почему?


Ответ

Если придерживаться самых распространенных определений транслятора, интерпретатора и компилятора, то да.
Транслятор - переводчик с какого-то языка на другой язык. Компилятор - переводчик на некий низкоуровневый язык, в форму подлежащую исполнению. Например в машинный код Интерпретатор - штука которая программу сразу исполняет. Например на некоторой виртуальной машине, а виртуальная машина уже на лету компилирует в машинный код.
То есть штука, которая нашу программу переводит скажем с паскаля на javascript, это транслятор, но не компилятор. Если конечно наша машина не предназначена для исполнения сразу javascript.
Вообще все эти три понятия на практике очень взаимосвязаны и переплетаются.

Увеличение картинки при нажатии

Необходимо, чтобы при нажатии на картинку(уменьшенную версию) на экране по центру появлялась её увеличенная версия. Проблема в том, что если картинок много и открывается картинка внизу, то по закрытии картинки происходит переход вверх страницы. Как можно это реализовать без перехода. Мне посоветовали использовать checkbox, но я не особо понимаю, как через них делать.
.pictures { -webkit-column-count: 4; -moz-column-count: 4; column-count: 4; -webkit-column-gap: 1em; -moz-column-gap: 1em; column-gap: 1em; margin-bottom: -1em; } a { display: inline-block; } img { display: block; width: 100%; margin-bottom: 1em; } .full { display: none; position: fixed; left: 0; top: 0; right: 0; bottom: 0; padding: 8%; background: #CCC center no-repeat; background: rgba(0, 0, 0, 0.5) center no-repeat; background-size: contain; background-origin: content-box; } .full:target { display: block; }



Ответ

Если для вас принципиально использование CSS и структура разметки будет как в вашем примере, то вместо псевдокласса :target на самом показывающемся блоке можно использовать псевдокласс :focus на ссылке, по которой происходит клик, и делать видимой следующую за ней ссылку, будет выглядеть так:
a:focus + .full { display: block; }
Это устранит скроллирование вверх. Пример на JSFiddle
P.S. Но лучше, по-моему, для полноценных модальных окон использовать JS

Конструктор класса с++, принимающий на вход многомерный initalizer_list

Задался задачей по написанию шаблонного контейнера, который в памяти хранится как одномерный. При этом со всей необходимой математикой и прочими преобразованиями. Для начала хотелось написать конструктор, который принимал бы на вход многомерный initalizer_list (brace-enclosed initializer_list).
Начал реализацию с этого:
#ifndef ARRAY_H #define ARRAY_H
#include #include #include
using namespace std;
template class array{ private:
T* data; int* shape;
public:
array(){ this->data = new T[1]{1}; this->shape = new int[1]{1}; }
template array(initializer_list input_data){
const char* TypeName = typeid(input_data).name(); // const char* iter = TypeName; // iter += strlen(TypeName) - 1; // // Костыльно определяем размерность int dimensionality = 0; // while (*iter-- == 'E'){ // dimensionality++; // } //
this->shape = new int [dimensionality]; this->shape[0] = input_data.size(); // Костыльно заполняем shape
int input_size = input_data.size();
this->data = new T [input_data.size()]; // // const B* item = input_data.begin(); // // for (int index_data = 0 ; index_data < input_size ; index_data++){ // Костыльно заполняем data this->data[index_data] = *item++; // } //
}
int size(){ return this->shape[0]; }
};
#endif // ARRAY_H
При этом интересующий конструктор работает на одномерных объектах, но, при выполнении следующего кода:
#include #include "array.h"
using namespace std;
int main(){
array first_test_array;
cout << "Тест конструктора без аргументов :
" << first_test_array.size() << endl;
array second_test_array {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
cout << "Тест конструктора с одномерным initializer_list :
" << second_test_array.size() << endl << endl;
array third_test_array {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}}; // Падает здесь
cout << "Тест конструктора с многомерным initializer_list :
" << third_test_array.size() << endl;
}
Пишет вот такую ошибку:
In funstion 'int main()': /home/artyom/CPP/array/main.cpp:16: ошибка: no matching function for call to 'array::array()' array third_test_array {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}}; ^ /home/artyom/CPP/array/main.cpp:16: candidates are: /home/artyom/CPP/array/main.cpp:2: In file included from ../array/main.cpp:2:0: /home/artyom/CPP/array/array.h:25: template array::array(std::initializer_list) array(initializer_list input_data){ ^
/home/artyom/CPP/array/array.h:25: note: template argument deduction/substitution failed: /home/artyom/CPP/array/main.cpp:16: note: candidate expects 1 argument, 2 provided array third_test_array {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}}; ^ /home/artyom/CPP/array/main.cpp:2: In file included from ../array/main.cpp:2:0: /home/artyom/CPP/array/array.h:19: array::array() [with T = int] array(){ ^ /home/artyom/CPP/array/array.h:19: note: candidate expects 0 arguments, 2 provided /home/artyom/CPP/array/array.h:11: constexpr array::array(const array&) class array{ ^ /home/artyom/CPP/array/array.h:11: note: candidate expects 1 argument, 2 provided /home/artyom/CPP/array/array.h:11: constexpr array::array(array&&) /home/artyom/CPP/array/array.h:11: note: candidate expects 1 argument, 2 provide
Может ли мне кто-либо объяснить как это сделать?


Ответ

Скорее всего вам поможет: http://christophercrouzet.com/blog/post/2015/01/12/Nested-Initializer-Lists-for-Multidimensional-Arrays
Код можно посмотреть тут: https://github.com/christophercrouzet/m3ta/blob/master/src/m3ta/. Например, реализация вложенного initializer_list: https://github.com/christophercrouzet/m3ta/blob/master/src/m3ta/nestedinitializerlists.h

Будет ли равномерным распределение заданий в очереди?

Нужно что-то вроде RR.
Будет ли равномерным распределение заданий в очереди Queue.Queue() по тредам? Смущает то что задания появляться будут медленней чем выполнение команд по ним.
Запускаю несколько тредов (с разным кодом под разные устройства) и тред который принимает задания по http. Задание попадает в очередь, а до этого воркеры висят заблокированном queue.get().
Я использовал в другом проекте multiprocessing.dummy.Pool - там все красиво и равномерно, но сейчас треды имеют разный код внутри и одной функцией не обойдешься.
Задача разгрузить исполнительные устройсва, а не процессор.


Ответ

Сперва почему-то хотелось ответить, что распределение неравномерное - то есть часть потоков будет простаивать, а тот, что был создан первее всех будет отдуваться за всех. Видимо такой поспешный вывод из-за наивного представления потоков в воображении. Но вот эксперимент (py3) - задания появляются в два раза медленнее, чем обрабатываются:
import queue import threading import time import random
counter = {} lock = threading.Lock()
def worker(): while True: try: sleep = q.get() if sleep == "DIE": q.task_done() return print(threading.current_thread().name) with lock: counter[threading.current_thread().name] = counter.get(threading.current_thread().name, 0) + 1 time.sleep(sleep) q.task_done() except queue.Empty: pass
q = queue.Queue() pool = [threading.Thread(target=worker, name="Worker " + str(i)) for i in range(4)] [t.start() for t in pool] for i in range(100): rand_sleep = random.random() / 8 q.put(rand_sleep) time.sleep(rand_sleep * 2) for i in range(4): q.put("DIE")
q.join()
print("Report: ", counter)
Вот что скрипт выводит:
output: ('Report: ', {'Worker 2': 25, 'Worker 3': 25, 'Worker 0': 25, 'Worker 1': 25})
Как видно из результатов - для моего кода распределение равномерное.
Если задания поступают без задержек - то распределение неравномерное и зависит от того, как долго обрабатывает задание каждый поток.
Дополнение: данный скрипт был протестирован в Windows и Ubuntu, использовался Python3.4 и Python2.7. Во всех четырех случаях результаты одинаковы.

Как правильно вставить переменную в запрос?

Здравствуйте, с го знаком не долго, поэтому вопрос немного "Ламерский". Есть запрос Mysql
rows, err := db.Query("SELECT * FROM users WHERE user='login"';)
Login я получил раньше и он в в формате string. Подскажите как вставить сюда переменную?
rows, err := db.Query("SELECT * FROM users WHERE user='Моя переменная"';)


Ответ

Открываем документацию и видим:
age := 27 // v vvv rows, err := db.Query("SELECT name FROM users WHERE age=?", age)
Обычные "порядковые параметры на заглушках": вместо значений ставятся ?-заглушки, а последующие аргументы по порядку эти заглушки заполняют.
Пример чуточку сложнее:
age := 27 name := "Кнопкатык" rows, err := db.Query("SELECT name FROM users WHERE age=? AND name=?", age, name)

Запись считанной строки из консоли в enum

Возможно ли считанную с консоли строку добавить в enum в кач-ве его нового элемента во время run-time в C#?


Ответ

Нет, модифицировать типы в рантайме нельзя (т.е. например, добавлять в типы поля, методы и т.п.). Но можно создавать новые типы, используя классы из System.Reflection.Emit. В частности, для создания перечисления можно использовать EnumBuilder. Но, к сожалению, такие типы не могут замещать уже существующие.
В вашем случае я бы рассмотрел возможность использования Dictionary вместо перечисления.

Релизация смс-рассылки с помощью API smsc

Необходимо реализовать смс-рассылку абонентам с помощью API smsc
Есть у меня две таблицы. В первую заносятся данные об абоненте: логин, моб. телефон и тип подключаемой рассылки

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

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

Необходимо каким-то образом подставлять номера телефонов и сообщения для них. Но в силу своих скудных знаний - придумать как это сделать пока не могу. Очень надеюсь на помощь.
UPD:
Так я добавляю данные в первую таблицу:
$table = $system_site_prefix . 'erps_services_sms'; database_insert("INSERT INTO `$table` VALUES (\"$index\", \"$abon_login\", \"$telephone\", \"$pay\", \"$orders\", \"$news\", \"$other\")");
Так во вторую:
$table = $system_site_prefix . 'erps_messages_sms'; database_insert("INSERT INTO `$table` VALUES (\"$index\", \"$group\", \"$title\", \"$message\")");
UPD2:
Структура таблиц:




Ответ

$result = file_get_contents("https://smsc.ru/sys/send.php?login=login&psw=psw&phones=".urlencode($phones)."&mes=".urlencode($message));
Для того, что бы выбрать сразу абонентов с номерами и текстами сообщений, необходимо сделать join двух таблиц по типу отправляемого сообщения.
Для контроля кодов ответа сервера (200, 404, 403, etc...) лучше использовать curl в PHP
-- Структура таблицы для связи сообщений и абонентов CREATE TABLE `erps_services_messages` ( `index` int(11) NOT NULL AUTO_INCREMENT, `service` int(11) NOT NULL, `message` int(11) NOT NULL, PRIMARY KEY (`index`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
-- Запрос для выборки sms SELECT sm.index AS `index`, m.message AS message, s.telephone AS telephone FROM `erps_services_messages` AS sm INNER JOIN `erps_messages_sms` AS m ON m.index = sm.message INNER JOIN `erps_services_sms` AS s ON s.index = sm.service
+-------+----------------------+-------------+ | index | message | telephone | +-------+----------------------+-------------+ | 1 | Сообщение 1 | +7999999999 | | 2 | Сообщение 3 | +7999999999 | | 3 | Сообщение 1 | +7888888888 | | 4 | Сообщение 4 | +7888888888 | +-------+----------------------+-------------+

-- После успешной отправки сообещния просто выполните DELETE FROM `erps_services_messages` WHERE `index` = %
-- Пример заполнения данными моих тестовых таблиц select * from erps_messages_sms; +-------+----------------------+ | index | message | +-------+----------------------+ | 1 | Сообщение 1 | | 2 | Сообщение 2 | | 3 | Сообщение 3 | | 4 | Сообщение 4 | +-------+----------------------+
select * from erps_services_sms; +-------+-------------+ | index | telephone | +-------+-------------+ | 1 | +7999999999 | | 2 | +7888888888 | +-------+-------------+
select * from erps_services_messages; +-------+---------+---------+ | index | service | message | +-------+---------+---------+ | 1 | 1 | 1 | | 2 | 1 | 3 | | 3 | 2 | 1 | | 4 | 2 | 4 | +-------+---------+---------+
Для добавления команды на отправку sms достаточно просто создать запись в таблице erps_services_messages и указать index из таблицы абонентов и index из таблицы сообщений. Скрипт отправки sms можно запускать по крону.

Unity 5 движение по кругу через поворот

Тело двигается по следующему алгоритму. Сначала выбирается случайный угол, на который происходит поворот тела, затем задается Vector2.up и тело летит в направлении поворота. Как сделать чтобы тело двигалось по кругу? Знаю, что необходимо использовать тригонометрические функции, но как конкретно - не знаю.


Ответ

Вспоминаем геометрию. Уравнение окружности имеет вид:
(x - a)² + (x - b)² = R²
где
a, b - координаты центра окружности
R - радиус окружности
Уравнение окружности радиуса R с центром в начале координат:
x² + y² = R²
Это поможет нам узнать переменные в другом представлении окружности: в параметрическом уравнении:
x = R * cos(alpha) + a y = R * sin(alpha) + b
в центре координат:
x = R * cos(alpha) y = R * sin(alpha)
Видим знакомые данные и еще дополнительную: alpha. Думаю понятно, что это угол. Меняем угол альфа и получаем движение по окружности.
Все это переносим в Unity.
Итак:
public float angle = 0; // угол public float radius = 0.5f; // радиус public bool isCircle = false; // условие движения по кругу
Допустим в какой-то момент времени нужно, чтоб объект начал движение по кругу, а значит нужно изменять постепенно угол и передавать значение в координаты. Угол можно менять например в Update, который будет каждый фрейм вызываться. Тогда получится простая формула:
void Update () { if (isCircle) { angle += Time.deltaTime; // меняется плавно значение угла
var x = Mathf.Cos (angle * speed) * radius; var y = Mathf.Sin (angle * speed) * radius; transform.position = new Vector2(x, y); } }
Когда нужно прекратить движение по кругу, выставляем isCircle в false и обнуляем угол angle = 0;
Всё.
Для движения вокруг какого-то центра не забываем добавить это условие в координаты. Например центр с координатами 1, 1.5; Формула будет например такая:
var x = Mathf.Cos (angle * speed) * radius; var y = Mathf.Sin (angle * speed) * radius; transform.position = new Vector2(x, y) + new Vector2(1, 1.5);

По часовой или против часовой?
Тут всё банально просто. Нужно одну из координат умножить дополнительно на -1. Если умножить X, то движение пойдет так, как будто находитесь на отметке 180°

Если умножить Y, то с отметки 0°:

Если я ничего не путаю))
Вот банальное и в очень сыром виде движение тела вперед, а при изменении параметра isCircle в true летит против часовой стрелки ровно с того места, где находится (для этого в формуле еще один параметр new Vector2(radius, 0) для компенсации направления движения).
using UnityEngine; public class Testy: MonoBehaviour { public float angle = 0; public float speed = 1; public float radius = 0.5f; public bool isCircle = false; // запоминать свое нахождение и делать его центром окружности public Vector2 cachedCenter; void Update() { if (isCircle) { angle += Time.deltaTime; var x = Mathf.Cos(angle * speed) * radius; var y = Mathf.Sin(angle * speed) * radius; transform.position = new Vector2(x, y) + cachedCenter - new Vector2(radius, 0); } else { angle = 0; cachedCenter = transform.position; var x = transform.position.x; var y = transform.position.y; x += 0.5f * Time.deltaTime; transform.position = new Vector2(x, y); } } }

Ну и по поводу движения по синусоиде. Тут немного по-другому. По одной оси мы просто движемся, а по другой, так сказать "вихляем".
Я попробую просто написать две формулы, попробуйте разобраться с ними сами)))
1) Движение вперед, "вихляет" вниз-вверх:
using UnityEngine; public class Testy2: MonoBehaviour { public float MoveSpeed = 0.5f; public float frequency = 3.0f; // Скорость виляния по синусоиде public float magnitude = 0.5f; // Размер синусоиды (радиус, по сути..можно заменить на "R") private Vector3 axis; private Vector3 pos; void Start() { pos = transform.position; axis = transform.up; } void Update() { pos += transform.right * Time.deltaTime * MoveSpeed; transform.position = pos + axis * Mathf.Sin(Time.time * frequency) * magnitude; } }
2) Движение вверх, "вихляет" влево-вправо:
using UnityEngine; public class Testy2: MonoBehaviour { public float MoveSpeed = 0.5f; public float frequency = 3.0f; // Скорость виляния по синусоиде public float magnitude = 0.5f; // Размер синусоиды (радиус, по сути..можно заменить на "R") private Vector3 axis; private Vector3 pos; void Start() { pos = transform.position; axis = transform.right; } void Update() { pos += transform.up * Time.deltaTime * MoveSpeed; transform.position = pos + axis * Mathf.Sin(Time.time * frequency) * magnitude; } }

Прибавить 7 дней к текущей дате

Есть таблица, где имеется три поля с датами. Дата добавления объявления, дата отправки и дата прибытия.
Хочется написать скрипт где я получаю все старые даты и обновляю их.
1) Шаг 1. Получаю все старые даты.
SELECT * FROM vehicle_country WHERE discharge_date < NOW() LIMIT 50
2) Шаг 2. Получаю текущую дату в нужном формате.
$today = date("Y-m-d");
3) Шаг 3. Нужно к этой дате прибавить 7 дней.
Вопрос как сделать так что бы $today был + 7 дней. $today = $today + 7. Как быть?


Ответ

$date = new DateTime(); $date->add(new DateInterval('P7D')); echo $date->format('Y-m-d') . "
";

Элементы внутри div по центру и ширине

При попытке растянуть span по ширине div ничего не вышло. И text-align, который работает только для текста не помог, и inline-block тоже.
Как можно решить эту проблему?


.iconBox { width: 50%; margin: auto; }
.iconBox span { margin: auto; }


Ответ

.iconBox { width: 50%; margin: auto; background: #646464; display: table; } .glyphicon { background: #F0F4F8; display: table-cell; }


Как в метод передавать только строго определённые аргументы (enum or string). Язык C#

Есть метод и в него нужно предать заранее определённые "буквенные" варианты аргументов, для того что бы InteliSence давал подсказки того, что вобще можно ввести в это поле. Далее обработать это с помощью конструкции swich case.
Как я это себе представляю, но не представлю как сделать что бы работало.
public enum position { Director, Manager, Administrator, Secretary, Developer };
public float Salary (int position, int standing) { switch (position) { case Director: Console.WriteLine("Case Director"); break; case Manager: Console.WriteLine("Case Manager"); break; default: Console.WriteLine("Default case"); break; } return ...; }
position в аргументных скобках никак не связан с enum.
Класс должен выглядеть как то так.
class Employee { private string name; private string lastName; public enum Position { Director, Manager, Administrator, Secretary, Developer }; Position position = Position.Developer;
public Employee(string name, string lastName) { this.name = name; this.lastName = lastName; }
public float Salary(Position position, int standing) { switch (this.position) { case Director: Console.WriteLine("Case 1"); break; case Manager: Console.WriteLine("Case 2"); break; default: Console.WriteLine("Default case"); break; } return; } }


Ответ

Мне кажется, вы хотите добиться такого эффекта:
public enum Position { Director, Manager, Administrator, Secretary, Developer };
static void Main(string[] args) { Position position = Position.Developer; Salary(position); }
public static void Salary(Position position) { switch (position) { case Position.Developer: Console.WriteLine("Case Developer"); break; case Position.Administrator: Console.WriteLine("Case Administrator"); break; //и т.д. } }

Если нужно принимать именно строку, то можно сделать так:
public enum Position { Director, Manager, Administrator, Secretary, Developer };
static void Main(string[] args) { Salary("Developer"); }
public static void Salary(string str) { Position position; var isValid = Enum.TryParse(str, out position); if (isValid) switch (position) { case Position.Developer: Console.WriteLine("Case Developer"); break; case Position.Administrator: Console.WriteLine("Case Administrator"); break; //и т.д. } }

Адаптация под ваш класс:
public enum Position { Director, Manager, Administrator, Secretary, Developer }; class Employee { private string name; private string lastName; Position _position = Position.Developer;
public Employee(string name, string lastName) { this.name = name; this.lastName = lastName; Salary(_position, 5); }
public float Salary(Position position, int standing) { switch (position) { case Position.Developer: Console.WriteLine("Case 1"); break; case Position.Manager: Console.WriteLine("Case 2"); break; default: Console.WriteLine("Default case"); break; } return 0; } }

Не понятна логика возникновения DeadLock

public void transferMoney(Account fromAccount, Account toAccount, Amount amount) throws InsufficientFundsException { synchronized (fromAccount) { synchronized (toAccount) { if (fromAccount.getBalance().compareTo(amount) < 0) throw new InsufficientFundsException(); else { fromAccount.debit(amount); toAccount.credit(amount); } } } }
Описание: Если со счета A на счет B перевести x денег, а со счета B на счет A – y, то при неудачном стечении обстоятельств, транзакция 1 займет монитор счета A, транзакция 2 займет монитор счета B. Результат – взаимная блокировка.
Я никак не могу понять: Как же второй трэд доберётся до второго synchronized, если первый synchronized уже был заблокирован первым трэдом? Пересмотрел уже кучу лекций и перечитал про synchronized.


Ответ

Он не будет заблокирован. synchronized воспользуется intrinsic lock того объекта, который будет указан в самом synchronized, поэтому два потока могут войти во внешний synchronized при том условии, что они используют два разных объекта: де-факто, synchronized(lockObject) - это гарантия использования объекта только одним потоком, но не гарантия исполнения кода максимум одним потоком в любой момент времени. Для достижения дедлока в этом случае достаточно, чтобы ни один из потоков не смог войти во внутренний synchronized - и это условие выполняется, если используются те же два аккаунта, но в противоположных потоках:
Thread 1 | Thread 2 -------------------|------------------- обычное состояние | обычное состояние взял лок объекта А | взял лок объекта Б ждет лок объекта Б | ждет лок объекта А
В этом случае прогресс невозможен, потому что для освобождения ресурса требуется прогресс любого из потоков, а это возможно только в случае освобождения ресурса.

Как правильно устанавливать Docker?

На оф сайте не нашёл нормального вменяемого объяснения , не ужели он устанавливается через Командную строку ?


Ответ

Цитирую документацию Docker
Installation If you have VirtualBox running, you must shut it down before running the installer. Go to the Docker Toolbox page. Click the installer link to download. Install Docker Toolbox by double-clicking the installer.
Перед этим вам необходимо убедиться, что виртуализация поддерживается вашим CPU и разрешена в настройках BIOS и вашей ОС.

Как установить значение по умолчанию для столбца в многотабличном запросе?

У меня есть три таблицы: Book(Id), Topic(Id), BookTopic(BookId, TopicId). Есть запрос который для каждого Topic возвращает количество Book в этом Topic:
SELECT T.Id, T.TopicName, count(BT.TopicId) AS 'BooksCount' FROM Topic T, BookTopic BT WHERE T.Id = BT.TopicId GROUP BY T.Id, T.TopicName
Но есть проблема: если с топиком не связана ни одна книга то такой топик не возвращается. А я хотел что бы такой топик возвращался со значение BooksCount=0. Как это можно сделать?


Ответ

Для этого следует воспользоваться LEFT JOIN
SELECT T.Id, T.TopicName, count(BT.TopicId) AS 'BooksCount' FROM Topic T LEFT JOIN BookTopic BT ON T.Id = BT.TopicId GROUP BY T.Id, T.TopicName

Как создать коллекцию из своих объектов и переопределить метод сравнивания?

В общем, есть класс Obj, нужно создать коллекцию объектов Obj и переопределить метод сравнивания объектов. Ибо могут добавляться дубликаты и сравнивать надо по конкретными атрибутами (atr1, atr2), а не по всем. (желательно) P.S. пока что пользовался Obj[] array, но нужно решить проблему дубликатов. (да, в гугле все есть)


Ответ

Здесь подойдет коллекция HashSet, которой в конструктор можно передать IEqualityComparer в котором можно определить правила сравнения объектов нужного типа.
Пример реализации IEqualityComparer из MSDN
class BoxEqualityComparer : IEqualityComparer { public bool Equals(Box b1, Box b2) { if (b2 == null && b1 == null) return true; else if (b1 == null | b2 == null) return false; else if(b1.Height == b2.Height & b1.Length == b2.Length & b1.Width == b2.Width) return true; else return false; }
public int GetHashCode(Box bx) { int hCode = bx.Height ^ bx.Length ^ bx.Width; return hCode.GetHashCode(); } }
И при создании коллекции:
var hashSet = new HashSet(new BoxEqualityComparer());
Теперь при добавлении в эту коллекцию объекта типа Box дубликат не добавится.

При восстановлении размера формы, элементы грузятся вконце

Имеется 2 формы, одна из которых является формой заполненной одной картинкой (Form3), вторая (Form1) - мейн. При нажатии на кнопку в Form1 - мейн сворачивается таким образом, открывая F3:
Form3 formButton = new Form3(); formButton.Owner = this; formButton.Show(); formButton.Opacity = 0; while (this.Opacity != 0) { Thread.Sleep(30); this.Opacity -= 0.1; }
while (formButton.Opacity != 1) { Thread.Sleep(30); formButton.Opacity += 0.1; }
Проблема в том, что при появлении, пока выполняется цикл, на форме нет ничего, кроме дырок от элементов. Сами элементы загружаются только когда программа выходит из цикла.
Вот обратное возвращение мейна:
formMain.Opacity = 0; formMain.Show(); while (formMain.Opacity != 1) { Thread.Sleep(30); formMain.Opacity += 0.1; } while (this.Opacity != 0) { Thread.Sleep(30); this.Opacity -= 0.1; }
Может есть у кого простое или не очень решение этой проблемы. Хотелось бы чтобы весь интерфейс появлялся плавно, а не только форма, и по окончанию мгновенно элементы.


Ответ

Как уже сказано в комментариях, циклы while c Thread.Sleep внутри работают в потоке GUI, что приводит к "замерзанию" формы.
Давайте сделаем это с помощью таймера.
Таймеров в дотнете имеется несколько штук разных, нам понадобится тот, который в пространстве имён System.Windows.Forms.Timer - он может работать с контролами на форме напрямую, так как его событие Tick вызывается в том же потоке.
Добавьте в класс вашей основной формы два поля:
System.Windows.Forms.Timer timer; Form3 formButton;
И обработчик события таймера:
private void Timer_Tick(object sender, EventArgs e) { if (Opacity > 0) this.Opacity -= 0.1; else if (formButton.Opacity < 1) formButton.Opacity += 0.1; else { timer.Stop(); timer.Tick -= Timer_Tick; } }
Теперь ваш код будет выглядеть следующим образом:
formButton = new Form3(); formButton.Owner = this; formButton.Show(); formButton.Opacity = 0;
timer = new System.Windows.Forms.Timer(); timer.Interval = 30; timer.Tick += Timer_Tick; timer.Start();
Обратите внимание, что свойство Opacity формы имеет тип double. Поэтому я заменил точные сравнения != 0 и != 1 на > 0 и < 1 - это связано со спецификой представления вещественных чисел - точное сравнение может не сработать.
Также обратите внимание на необходимость отписки таймера от события: timer.Tick -= Timer_Tick; - это необходимо, чтобы избежать утечки памяти.
При желании, таймер можно создать в дизайнере формы, задав ему необходимые свойства и события.

Как обработать критическую ошибку при старте службы Windows?

При старте службы windows возникает критическая ошибка требующая останова еще не стартовавшей службы. Ошибку логирую. Но что делать с ней дальше? Как сообщить windows, чтобы она не считала службу запущенной? Можно ли как то информировать пользователя о том что служба не запущена?
Спасибо.


Ответ

Если сервис не смог корректно запуститься - то достаточно просто остановить его из кода, вызовом Stop():
protected override void OnStart(string[] args) { // случилась ошибка? this.Stop(); }
Он перейдет обратно в Stopped. Если при этом попытка запуска была инициирована пользователем - тому покажется стандартное сообщение вида
The Service12 service on Local Computer started and then stopped. Some services stop automatically if they are not in use by other services or programs.

Округление до 2 знаков после запятой Haskell

Недавно начал пробовать Haskell на примере маленьких задачек - хеллоуворлдов. Сама задача состоит в том, что нужно посчитать некоторое выражение при разных x - ничего сложного. Но для красоты решил округлить ответ до 2 знаков после запятой и тут столкнулся со сложностями. Так как стандартной реализации такого округления не нашел, завелосипедил свою:
main :: IO () main = do let x = 1.7 in putStrLn $ show $ roundTo2 ((x + 1) ^ 2 + 3 * (x + 1))
roundTo2 :: Num a => a -> Float roundTo2 x = truncate (x * 100) / 100
Ругань компилятора:
Could not deduce (RealFrac a) arising from a use of \`truncate' from the context (Num a) bound by the type signature for roundTo2 :: Num a => a -> Float at prog.hs:6:13-31 Possible fix: add (RealFrac a) to the context of the type signature for roundTo2 :: Num a => a -> Float In the first argument of \`(/)', namely \`truncate (x * 100)' In the expression: truncate (x * 100) / 100 In an equation for `roundTo2': roundTo2 x = truncate (x * 100) / 100
Понимаю что проблема где-то в типах, но не понимаю, как эту проблему решить


Ответ

Используйте функцию printf из модуля Text.Printf.
import Text.Printf
main :: IO () main = do let x = 1.7 printf "%.2f
" ((x + 1) ^ 2 + 3 * (x + 1))

QThread Потоки ( как правильно закрыть поток )

Привет всем! накидал маленький рабочий пример за 5 минут, но возник вопрос, как правильно закрыть поток? При старте создаётся новый поток, а старый сохраняется... Возможно, что то не учёл или сделал не так. Вот исходники:
main.cpp
#include "mainwindow.h" #include
int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show();
return a.exec(); }
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include #include
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); connect(this->ui->pushButton_start, SIGNAL(clicked()), this, SLOT(startGUI())); connect(this->ui->pushButton_stop, SIGNAL(clicked()), this, SLOT(stopGUI())); }
MainWindow::~MainWindow() { delete ui; }
void MainWindow::startGUI() {
// Создание потока QThread* thread = new QThread; Worker* worker = new Worker();
// Передаем права владения "рабочим" классом, классу QThread. worker->moveToThread(thread);
//connect(worker, SIGNAL(sendBool(bool)), this, SLOT(stopGUI(bool)));
// Связываем сигнал об ошибки со слотом обработки ошибок(не показан). //connect(worker, SIGNAL(error(QString)), this, SLOT(errorHandler(QString)));
// Соединяем сигнал started потока, со слотом process "рабочего" класса, т.е. начинается выполнение нужной работы. connect(thread, SIGNAL(started()), worker, SLOT(process()));
// Отображаем в главном потоке Gui, значения из вторичного потока connect(worker, SIGNAL(sendNumber(int)), this, SLOT(LineEditUi(int)));
// Оповещаем поток, что нужно остановиться connect(this, SIGNAL(sendNumberBoolStop(bool)), worker, SLOT(reciveBoolStop(bool)), Qt::DirectConnection);
// По завершению выходим из потока, и удаляем рабочий класс connect(worker, SIGNAL(finished()), thread, SLOT(quit())); connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
// Удаляем поток, после выполнения операции connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start(); }
void MainWindow::LineEditUi(int number) { ui->lineEdit->setText(QString::number(number)); }
void MainWindow::stopGUI() { Stop = true; qDebug() << Stop; sendNumberBoolStop(Stop); qDebug() << "sendMumberBoolStop = " << Stop; }
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H
#include #include "worker.h"
namespace Ui { class MainWindow; }
class MainWindow : public QMainWindow { Q_OBJECT
public: explicit MainWindow(QWidget *parent = 0); ~MainWindow();
bool Stop;
public slots: void startGUI();
void stopGUI(); void LineEditUi(int number);
signals: void sendNumberBoolStop(bool);
private: Ui::MainWindow *ui; };
#endif // MAINWINDOW_H
worker.cpp
#include "worker.h" #include
Worker::Worker(QObject *parent) : QObject(parent) { Stop = false; temp = 0; }
Worker::~Worker() { qDebug() << "destruction Thread"; }
void Worker::process() { Stop = false; if(!Stop == true) { for (temp; temp <= 1000; temp++) { if(!Stop == true) { emit(sendNumber(temp)); //ui->lineEdit->setText(QString::number(temp)); //QCoreApplication::processEvents(); qDebug() << temp; } else { return; } } } }
void Worker::reciveBoolStop(bool Numb) { Stop = Numb; qDebug() << "reciveBoolStop = " << Stop; }
worker.h
#ifndef WORKER_H #define WORKER_H
#include
class Worker : public QObject { Q_OBJECT public: //Worker(); //virtual ~Worker(); explicit Worker(QObject *parent = 0); ~Worker();
bool Stop; int temp;
signals: void finished(); //void error(QString err);
void sendNumber(int);
public slots: void process();
void reciveBoolStop(bool Numb); };
#endif // WORKER_H
mainwindow.ui
MainWindow 0 0 395 165 MainWindow Start Stop 0 0 395 21 TopToolBarArea false


Ответ

В приведенном коде не испускается сигнал Worker::finished, следовательно поток не понимает, что ему нужно остановиться. Испустить сигнал нужно на выходе из функции Worker::process
Добавлю, что для задачи единоразово запустить какой-то процесс в отдельном потоке лучше подойдет QtConcurrent::run
void MainWindow::startGUI() { Worker* worker = new Worker();
// Отображаем в главном потоке Gui, значения из вторичного потока connect(worker, SIGNAL(sendNumber(int)), this, SLOT(LineEditUi(int)));
// Оповещаем поток, что нужно остановиться connect(this, SIGNAL(sendNumberBoolStop(bool)), worker, SLOT(reciveBoolStop(bool)), Qt::DirectConnection);
//Запланируем удаление воркера после окончания расчета connect(worker,SIGNAL(finished()), worker,SLOT(deleteLater())); QtConcurrent::run(worker,&Worker::process); }

Инкремент в javascript

'use strict'; var years = prompt('Сколько вам лет?', 100); years = years++; alert('Вам ' + years + ' лет!');
Почему после выражения years = years++; переменная years не увеличивается на единицу, а остается равной 100?
Я понимаю, что выражение не корректное, но меня интересует механизм языка в данном случае. По идее, переменной years должно было сначала присвоиться ее же старое значение, то есть 100, а затем эта же переменная должна была увеличиться на 1 инкрементом. Но alert выводит все равно 100. Почему так?


Ответ

years = years++ эквивалентно:
tmp = years; years++; years = tmp;
В отличие от years = ++years;, как справедливо отметил @Doofy. Постфиксный инкремент возвращает значение переменной ДО увеличения на 1, префиксный - значение после.
Насколько я знаю, инкремент работает именно так во всех ЯП, в которых он есть. Поэтому, кстати, в циклах предпочтительно использовать префиксный инкремент при прочих равных - меньше накладных расходов.
Например i++ выведет 0-1-2-3-4, а не 1-2-3-4-5
for (i=0; i<5;) console.log(i++);
for (i=0; i<5;) console.log(++i);

Какие существуют способы сохранения состояния списка (ArrayList) в БД?

Пишу приложение на Android, где у меня есть некоторый список (RecyclerView), в котором есть возможность перетаскивания (drag & drop) строк в нужное для пользователя место (выше/ниже относительно друг друга). Элементы списка (строки) могут быть разных классов (под общим интерфейсом). Информация о созданных экземплярах, соответственно, хранится в SQLite.
На данный момент, сортировка списка всех элементов списка происходит по дате (при создании списка сортируются в TreeSet'е и потом ArrayList'ом отдаются в адаптер). Таким образом, при изменении порядка отображения элементов списка мне необходимо зафиксировать этот порядок и сохранить его в БД (или может просто в JSON?). Какие существуют, так сказать, лучшие практики сохранения и извлечения состояния такого списка (да и вообще, подобных данных)?
Заранее благодарен!


Ответ

Вам не нужно перегонять данные из БД в какие то локальные массивы. Работайте напрямую с базой данных, она имеет на порядок более мощный, чем "жалкие" методы коллекций, язык SQL, специально предназначеный для обработки, сортировки и тп. данных, содержащихся в базе, а так же выполняет эту обработку на порядки же быстрее, чем Java.
Сам подход, который вы пытаетесь применить выглядит несколько нелогично. Зачем хранить данные в БД, но обрабатывать их какими то примитивными и медленными способами, при этом еще тратя время и на промежуточное извлечение из БД в массив, потом еще в другой массив.
По вопросу - вам не нужно сохранять какой то измененный порядок сортировки, переписывая БД. Вам нужен правильный запрос в БД, который вернет данные (курсор), отсортированные в нужном порядке, именно так это делается. Затем этот курсор, в котором уже все отсортированно как надо через SQL-запрос, вы передаете непосредственно в адаптер списка и заполняете сам список данными из курсора, а не из каких то ArrayList-ов.
UPD Если нужно сохранить произвольную пользовательскую сортировку, то опять же нужно модифицировать не следование записей в базе, а добавить к каждой записи еще один столбец для хранения порядка сортировки. При перетаскивании записывать в этот столбец позицию в списке элемента, в которую его перетащили. При выборке делать запрос с сортировкой по этому столбцу.
То есть, примерная схема - делаем выборку из БД с сортировкой по времени, заполняем этой выборкой список, при перетаскивании пишем в БД позицию, в которую перетащили (в столбец пользовательской сортировки для записи, которую перетащили), обновляем адаптер через выборку с сортировкой по столбцу с этими позициями - все просто и прозрачно
Это будет правильная архитектура работы с БД, а то, что пытаетесь сделать вы, какой то любительский костыль, простите за резкость, надеюсь это поможет понять вам всю глубину заблуждений :)
Так же смотрите этот ответ по сортировке в БД

Ansible и Windows

Существует ли поддержка Ansible в Windows powershell? Или его возможно поднять только по Cygwin? Как его установить?


Ответ

Windows - клиент.
Это стандартный случай использования ansible, описанный в документации. Требования:
На управляющей машине
Ansible версии 1.7+ Python модуль pywinrm: pip install "pywinrm>=0.1.1" В соответствующем group_vars установить несколько переменных для настройки соединения с windows-хостами. Этот group_vars должен быть зашифрован с помощью ansible-vault. Если необходима авторизация через kerberos: pip install kerberos и дополнительная конфигурация kerberos
На клиенте
Для работы большей части модулей ansible понадобится Powershell 3.0, доступный начиная с Windows 7 SP1, Windows Server 2008 SP1. Есть также скрипт для быстрой установки Powershell 3.0
Windows - управляющая машина
Официальная документация говорит о том, что эта возможность не поддерживается и не планируется. Но варианты решения всё-таки есть.
Очевидный способ решения: вылить воду из чайника, чем свести задачу к предыдущей поставить Linux в виртуальной машине и работать с него.
Jeff Geerling описывает способ установки через cygwin. Если кратко, требования такие:
Cygwin c набором необходимых модулей Отдельно установить и сконфигурировать Ansible, PyYAML, Jinja2 При необходимости работы через прокси, дополнительно сконфигурировать .bash_profile вашего cygwin.

Как запускать Python на других компьютерах [закрыт]

Очень нравится Python, начал изучать и поражаюсь его простоте.
Я пишу телеграмм бота, хочу его запустить на постоянной основе на сервере Windows 2012. Мне необходимо установить Python на этот сервер и еще скачать всю кучу библиотек, которую я использовал? Есть какой-нибудь иной способ?
И как быть, если у меня будет к примеру запущен Бот и плюс пару других программ, одна из которых к примеру сканирует сеть и записывает все в базу, то есть как мне запустить одновременно несколько разных приложений на сервере?


Ответ

Добрый день, попробуйте изучить возможности виртуализации и контейнеров. Идея в том, что вы можете настроить среду один раз и далее передавать контейнер в другие системы . Посмотрите такие технологии как vagrant и docker .
Альтернативным способом является создание рецепта по настройке среды для ваших нужд, так, что вы передаете на сервер только этот рецепт, а обязанности по конфигурации и установке берут на себя такие технологии как chef или puppet.

Как восстановить проект имея только папку .git?

Как восстановить проект имея только папку .git?
Размер папки нормальный (не ноль) и git log выводит все коммиты.


Ответ

вы можете резетнуться на коммит (git reset --hard) или сделать git checkout . в корне репозитория - если не закоммитили удаление всех файлов. если закоммитили - вам надо резетнуться на последний коммит (git log)
в приведенном примере мы создаем репу, добавляем файл, удаляем, остается только папка .git, восстанавливаемся из нее обоими способами. (до нового коммита и с помощью резета)
-user~/temp$ mkdir gtest -user~/temp$ cd gtest -user~/temp/gtest$ git init Initialized empty Git repository in /home/user/temp/gtest/.git/ -user~/temp/gtest (master)$ touch 123 -user~/temp/gtest (master)$ echo 123 > 123 -user~/temp/gtest (master)$ kommit done ## Initial commit on master ?? 123 [master (root-commit) d6089c5] done 1 file changed, 1 insertion(+) create mode 100644 123 -user~/temp/gtest (master)$ rm 123 -user~/temp/gtest (master)$ git status On branch master Changes not staged for commit: (use "git add/rm ..." to update what will be committed) (use "git checkout -- ..." to discard changes in working directory)
deleted: 123
no changes added to commit (use "git add" and/or "git commit -a") -user~/temp/gtest (master)$ git checkout . -user~/temp/gtest (master)$ git status On branch master nothing to commit, working directory clean -user~/temp/gtest (master)$ ls 123 -user~/temp/gtest (master)$ git log commit d6089c549be7b2e922f1d1b31960ee34166d1ae6 Author: user <“user@user.com”> Date: Sat Jul 30 2016 +0300
done -user~/temp/gtest (master)$ git reset --hard d6089c549be7b2e922f1d1b31960ee34166d1ae6 HEAD is now at d6089c5 done -user~/temp/gtest (master)$ ls 123 -user~/temp/gtest (master)$
P.S. команда kommit это алиас типа
function gitAddAndCommit(){ git status -bs git add . ; git commit -m "$1" --no-verify } alias kommit=gitAddAndCommit
P.P.S. (master) в prompt - это имя текущей ветки, что-то в этом духе. Очень удобная штука.

Как сделать плавную анимацию c выезжающим блоком?

Пытался реализовать анимацию появления блока с правой стороны, получилось почти то что я хотел. Но есть две проблемы.
Во первых анимация срабатывает только при 2 отображении элемента, во вторых анимация не срабатывает на скрытие элемента. Как это все исправить?
$(document).on("click", ".project__discr--active", function () { // $(' .modal-dark').removeClass('js-module-hide').show(600, 'swing'); module(); }); $(document).on("click", ".js-close-modal", function () { // $(' .modal-dark').addClass('js-module-hide').hide(600, 'swing'); module(); }); var box = $('.modal-dark, .modal'); function module () { if (box.hasClass('js-module-hide')) { box.removeClass('js-module-hide'); setTimeout(function () { box.removeClass('visuallyhidden'); }, 20); } else { box.addClass('visuallyhidden'); box.one('transitionend', function(e) { box.addClass('js-module-hide'); }); } }; body { overflow: hidden; } .project__discr--active { display: inline-block; background: rgba(0, 2, 45, 0.4); cursor: pointer; } .visuallyhidden { -webkit-transform: translate3d(100%, 0, 0); -ms-transform: translate3d(100%, 0, 0); transform: translate3d(100%, 0, 0); opacity: 1; } .js-module-hide { display: none; opacity: 0; } .modal-dark { background: rgba(0, 0, 0, 0.8); position: absolute; left: 0; top: 0; width: 100%; height: 100%; z-index: 9; } .modal.js-module-hide { -webkit-transform: translate3d(0, 0, 0); -ms-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } .visuallyhidden { -webkit-transform: translate3d(100%, 0, 0); -ms-transform: translate3d(100%, 0, 0); transform: translate3d(100%, 0, 0); opacity: 1; } .modal { height: 600px; background: #fff; position: absolute; top: 0; margin-top: 120px; padding: 20px 0; left: 0; width: 100%; z-index: 10; -webkit-transition: -webkit-transform 0.3s ease-out; transition: transform 0.3s ease-out; will-change: top; } .base { width: 100%; margin: 0 auto; position: relative; } .close-modal { cursor: pointer; position: absolute; right: 0; font-size: 30px; border-radius: 100%; -webkit-transition: all ease .3s; transition: all ease .3s; } .project-gallerey { float: left; width: 60%; position: relative; } .project-info { float: left; width: 32%; margin-top: 50px; margin-left: 35px; padding-left: 15px; position: relative; z-index: 2; background: rgba(255, 255, 255, 0.8); }

Show me


Ответ

Возможно, я не до конца понял вашу логику. Но мне показалось, что вы слегка намудрили с классами и напрасно использовали конструкцию
var box = $('.modal-dark, .modal');
Таким образом, вы выбрали два элемента, родителя и потомка и работали с ним как с одним: проверяли наличие класса, добавляли и убирали классы (одновременно обоим элементам). Когда я навел в этой части порядок, т.е. разделил функции родителя и потомка (родитель просто скрывается, а потомок исполняет анимацию) - все встало на свои места.
$(document).on("click", ".project__discr--active", function () { // $(' .modal-dark').removeClass('js-module-hide').show(600, 'swing'); module(); }); $(document).on("click", ".js-close-modal", function () { // $(' .modal-dark').addClass('js-module-hide').hide(600, 'swing'); module(); }); var box = $('.modal-dark'), modal = $('.modal'); function module () { if (box.hasClass('js-module-hide')) { box.removeClass('js-module-hide'); setTimeout(function () { modal.removeClass('visuallyhidden'); }, 20); } else { modal.addClass('visuallyhidden'); modal.one('transitionend', function(e) { box.addClass('js-module-hide'); }); } }; body { overflow: hidden; } .project__discr--active { display: inline-block; background: rgba(0, 2, 45, 0.4); cursor: pointer; } .visuallyhidden { -webkit-transform: translate3d(100%, 0, 0); -ms-transform: translate3d(100%, 0, 0); transform: translate3d(100%, 0, 0); opacity: 1; } .js-module-hide { display: none; opacity: 0; } .modal-dark { background: rgba(0, 0, 0, 0.8); position: absolute; left: 0; top: 0; width: 100%; height: 100%; z-index: 9; } .modal.js-module-hide { -webkit-transform: translate3d(0, 0, 0); -ms-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } .visuallyhidden { -webkit-transform: translate3d(100%, 0, 0); -ms-transform: translate3d(100%, 0, 0); transform: translate3d(100%, 0, 0); opacity: 1; } .modal { height: 600px; background: #fff; position: absolute; top: 0; margin-top: 120px; padding: 20px 0; left: 0; width: 100%; z-index: 10; -webkit-transition: -webkit-transform 0.3s ease-out; transition: transform 0.3s ease-out; will-change: top; } .base { width: 100%; margin: 0 auto; position: relative; } .close-modal { cursor: pointer; position: absolute; right: 0; font-size: 30px; border-radius: 100%; -webkit-transition: all ease .3s; transition: all ease .3s; } .project-gallerey { float: left; width: 60%; position: relative; } .project-info { float: left; width: 32%; margin-top: 50px; margin-left: 35px; padding-left: 15px; position: relative; z-index: 2; background: rgba(255, 255, 255, 0.8); }

Show me