Страницы

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

четверг, 5 марта 2020 г.

Страница доступная по IP адресу сервера

#linux #apache #nginx


Есть VPS с установленной на нём Plesk панелью (хотя панель, вероятно, значения не имеет).
На сервере висит несколько сайтов, если перейти не по одному из доменов, а по IP-адресу
сервера, то открывается по-умолчанию тот сайт, который был добавлен на сервер последним.

Как установить сайт/страницу открываемую по-умолчанию при переходе напрямую по IP-адресу
сервера? Сервер Linux (Apache + Nginx)
    


Ответы

Ответ 1



В общем-то ответ в случае с Plesk прост: Необходимо зайти в "Инструменты и настройки" (Tools & Setting) Перейти в "IP-адреса" (вкладка "Инструменты и ресурсы") Открыть нужный IP-адрес Выбрать подписку по-умолчанию. При попытке изменить конфигурацию Nginx сервер выдаст ошибку (так как в Plesk эта настройка уже существует).

Ответ 2



Указываете конфигурацию Nginx по умолчанию для 80 порта: server { listen 80 default; root /default/site/path; ... location site_1 { ... } location site_2 { ... } } Если идет проксирование на Apache, то там ничего менять не надо, просто определяем директории на которые идут запросы с Nginx.

Как узнать, применяется ли схемы оформления (Vcl.Styles)?

#delphi #vcl


D 10.1 starter. Стандартное приложение. В опциях включены схемы оформления.
Вопрос: Как программно узнать, применяется ли сейчас какая-то схема оформления или
стиль оформления стандартный?

если схема применяется, то в файле проекта видим (например):

...
TStyleManager.TrySetStyle('Amethyst Kamri'); *
...


если в опциях проекта схемы выбраны, но дефолтное оформление выбрано "Windows", то
в проекте ничего (*) такого нет 

Нужна функция примерно такая

Function IsAppThemed:boolean;
begin
 Result := <..?..>
end;

    


Ответы

Ответ 1



Нашел: function IsAppThemed: Boolean; begin Result := TStyleManager.Enabled and TStyleManager.IsCustomStyleActive; end;

Реализация чата на rxjava+retrofit

#java #android


Сервер при запросе возвращает json схему чата(дата, время, id пользователя, его сообщение
и т.д), c помощью retrofit я создал метод запроса чата.
Вопрос, как с помощью rxjava реализовать отправку запроса на сервер скажем раз в
x секунд? И вообще как вам такая архитектура чата? Мб лучше было бы через сокеты реализовать?
Нужно ли использовать ORM при реализации чата?
    


Ответы

Ответ 1



Конечно чат нужно через сокеты. Вы такими периодическими запросами весь заряд батареи в фоне скушаете. При чем тут ORM? Если Вы храните сообщения в базе, то тут уже выбор за Вами, использовать для доступа к базе ORM или руками писать все необходимое. Я бы конечно использовал, но и без ORM надо уметь творить.

Нисходящая сортировка слиянием. Метод абстрактного обменного слияния

#cpp #алгоритм #сортировка


Нужно реализовать нисходящую сортировку слиянием методом абстрактного обменного слияния.
Вот функция абстрактного обменного слияния:

template 
void merge(Item a[], int l, int m, int r) {
    int i, j;
    static Item aux[maxN];
    for (i = m + 1; i > l; i--)
        aux[i - 1] = a[i - 1];
    for (j = m; j < r; j++)
        aux[r + m - j] = a[j + 1];
    for (int k = l; k <= r; k++)
        if (aux[j] < aux[i])
            a[k] = aux[j--];
        else
            a[k] = aux[i++];
}


Как сделать эту сортировку нисходящей, то есть рекурсивной?
    


Ответы

Ответ 1



Я немного изменил вашу функцию. Среднее значение вычисляется внутри. Принцип работы алгоритма таков, что сначала исходный массив разбивается на два других. Каждый из них также разобьется ещё на два. Это будет продолжаться до тех пор, пока длина каждого подмассива будет равна 1. template void merge(Item a[], int l, int r) { if (abs(r - l) <= 1) return; //конец рекурсивных вызовов int i, j; int m = (l + r) / 2; merge(a, l, m); //вызов для левой части merge(a, m+1, r); //вызов для правой части static Item aux[1000]; for (i = m + 1; i > l; i--) aux[i - 1] = a[i - 1]; for (j = m; j < r; j++) aux[r + m - j] = a[j + 1]; for (int k = l; k <= r; k++) { if (aux[j] < aux[i]) a[k] = aux[j--]; else a[k] = aux[i++]; } } Замечание: при вызове функции необходимо указывать длину массива - 1. То есть: int main() { int a[N]; merge(a, 0, N-1); }

не отправляется Notification

#android #android_notification #pendingintent


Есть сервис, по расписанию качает новости, после загрузки отправляет уведомление
- Notification. В последнее время начал замечать что сервис отрабатывает, однако уведомление
не отправляет. Повесил логи в аналитику, метод отправки сообщения вызывается - однако
сообщение не доходит (Причем может через раз отправлять, может день не отправлять а
потом день все нормально). Что может быть не так, код прилагается.

public void sendMessage(int countNews){
    Resources resources = getResources();
    Intent i = NewsListActivity.newIntent(this);
    PendingIntent pi = PendingIntent.getActivity(this, 1, i, 0);

    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
            .setTicker(resources.getString(R.string.get_new_news))
            .setSmallIcon(R.drawable.ic_notif_logo)
            .setLargeIcon(BitmapFactory.decodeResource(res, R.mipmap.ic_launcher))
            .setNumber(countNews)
            .setContentTitle(resources.getString(R.string.get_new_news))
            .setContentText(resources.getQuantityString(R.plurals.news_plurals, countNews,
countNews))
            .setContentIntent(pi)
            .setAutoCancel(true);

    NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
    notificationManager.notify(1, mBuilder.build());
}


Не может это быть из-за того что PendingIntent у Notification по requestCode совпадает
с PendingIntent сервиса - последний для периодического запуска через AlarmManager.

чтобы не пересекались ID у PendingIntent исправил код:

public void sendMessage(int countNews){
    Resources resources = getResources();
    Intent i = NewsListActivity.newIntent(this);
    PendingIntent pi = PendingIntent.getActivity(this, NOTIFICATION_INTENT_ID, i,
PendingIntent.FLAG_CANCEL_CURRENT);

    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
            .setTicker(resources.getString(R.string.get_new_news))
            .setSmallIcon(R.drawable.ic_notif_logo)
            .setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))
            .setNumber(countNews)
            .setContentTitle(resources.getString(R.string.get_new_news))
            .setContentText(resources.getQuantityString(R.plurals.news_plurals, countNews,
countNews))
            .setContentIntent(pi)
            .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
            .setAutoCancel(true);

    NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
    notificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}


сутки сообщения отправлялись отлично, все работало, ночью новости скачались - сообщения
нет, днем еще подгрузились - опять сообщение не пришло. Как будто аппарат очень крепко
"уснул" и не принимает уведомления...
Причем на втором аппарате с Android 5.1 уведомления приходят - на Android 6.0 вышеописанная
картина.
    


Ответы

Ответ 1



С 6 андроида из-за Doze для точных уведомлений следует использовать методы: If you need to set alarms that fire while in Doze, use setAndAllowWhileIdle() or setExactAndAllowWhileIdle(). https://developer.android.com/training/monitoring-device-state/doze-standby.html

Ответ 2



Очень похоже, что проблема из-за режима Doze (как раз появился в 6.0). Примерно происходит так: Телефон лежит неподвижно без подзарядки Система переходит в режим Doze Отрабатывает сервис, но Doze игнорирует wake lock и нотификация не срабатывает. То есть в окошко, которое дает для работы Doze сервис успевает отработать, а все дальше уже нет (примерно так, не видя весь код сложно сказать точнее). Проверить можно внеся приложение в "белый список" (Настройки -> Батарея -> меню -> Экономия зараяда батареи -> все приложения -> клик и выбрать не экономить батарею) и проверив повторяется ли описанное в вопросе поведение.

Строгое сравнение в min-width и max-width

#css #media_queries


Если одновременно использовать @media (max-width: 1000px) и @media (min-width: 1000px),
то при ширине ровно 1000px будут выполняться оба правила

Если использовать @media (max-width: 1000px) и @media (min-width: 1001px), то при
масштабе в 1,25 и ширине 1251px не будет выполняться ни одно из этих правил (т.к. 1251/1,25=1000,8)

Вопрос: как сделать так, чтобы одно правило выполнялось при ширине меньшей либо равной
1000px, а другое выполнялось при ширине строго большей 1000px?
    


Ответы

Ответ 1



Задачу решает использование оператора отрицания для второго медиа-запроса. @media not all and (max-width: 1000px) { /* ... */ }

Странности при работе с двумерным массивом в си

#c


#include "stdio.h"

int main(void)
{
    int a[3][2] = {{10,2}, {2,3}, {3,4}};
    printf("%p\n", a[0]);
    printf("%p\n", (int *)a);
    printf("%p\n", *a);
    printf("%p\n", a); 
    printf("%p\n", &(a[0][0]));
    return 0;
}


Код выдает одно и то же число...
Особенно поражает то, что равны a и *a.
Что происходит?
И еще когда смотрю на *(int *)a, то получаю 10...
    


Ответы

Ответ 1



Вас не должно удивлять равенство a и *a в данном контексте. Нечего удивительного в этом нет. В языке С "двумерный массив" - это просто обычный одномерный массив, элементами которого тоже являются одномерные массивы. Одномерный массив, скажем, double d[10] - это просто плоский непрерывный компактный блок памяти, размера 10 * sizeof(double), состоящий из десяти плотно лежащих друг за другом элементов типа double. При этом адрес всего массива &d численно совпадает с адресом его нулевого элемента &d[0], ибо "начинаются" они в одной и той же точке памяти. Ситуация полностью аналогична равенству указателей вот в таком вот примере struct S { int a; } s; printf("%p %p\n", (void *) &s, (void *) &s.a); // Оба указателя совпадают численно Адрес всего объекта struct-типа численно совпадает с адресом самого первого поля внутри этого объекта. Совершенно аналогичным образом адрес всего массива численно совпадает с адресом самого первого (нулевого) элемента этого массива. При этом в языке С выражение d типа "массив double [10]" в большинстве контекстов (не во всех) неявно приводится к типу double * - указателю, указывающему на нулевой элемент массива. Т.е. в большинстве контекстов выражение d ведет себя эквивалентно выражению &d[0], т.е. массив внешне ведет себя как указатель. Это явление называют array type decay. (Именно по этой причине массивы в С часто путают с указателями, хотя на самом деле это разные типы и никаких указателей в массивах нет.) Все это немедленно применимо и к двумерным массивам (и многомерным массивам), ибо, как сказано выше, в языке С "двумерный массив" - это рекурсивная по своему устройству структура: это просто одномерный массив, элементами которого являются одномерные массивы. Вышеупомянутое явление array type decay работает неизменным образом на любом уровне этой рекурсии. Выше выражение a изначально имеет тип int [3][2], но в данном контексте неявно приводится к типу "указатель на нулевой элемент массива a". Этот указатель имеет тип int (*)[2] и указывает на подмассив a[0] типа int [2] в составе a. Выражение *a изначально имеет тип int [2] - это подмассив a[0] в составе a, но в данном контексте *a неявно приводится к типу "указатель на нулевой элемент массива a[0]". Это указатель типа int *, который указывает на самый первый int в составе подмассива a[0], т.е. на a[0][0]. И сам a, и a[0], и a[0][0] начинаются в одной и той же точке памяти, по каковой причине числовые представления этих указателей совпадают printf("%p %p %p\n", (void *) &a, (void *) a, (void *) *a); // Все три указателя совпадают численно

Ответ 2



Возьмем тип int равный четырем байтам Давайте представим массив в памяти: +------------+----------+----------+----------+----------+ | Переменная | a[0][0] | a[0][1] | a[1][0] | a[1][1] | +------------+----------+----------+----------+----------+ | Адрес | 0x61fe98 | 0x61fe9c | 0x61fea0 | 0x61fea4 | +------------+----------+----------+----------+----------+ | Значение | 10 | 2 | 2 | 3 | +------------+----------+----------+----------+----------+ В отладчике можно увидеть: print &a => (int (*)[3][2]) 0x61fe98 // указатель на двумерный массив print a => {{10, 2}, {2, 3}, {3, 4}} print &(*a) => (int (*)[2]) 0x61fe98 // указатель на одномерный массив print *a => {10, 2} print &(**a) => (int *) 0x61fe98 // указатель на целое число print **a => 10 Как видим, адреса двумерного массива a, одномерного подмассива a[0] ({10, 2}) и первого элемента подмассива a[0][0] (10) равны. То есть: &a == &(*a) == &(**a) ^ ^ ^ | | | a[0][0] (первое значение первого подмассива двумерного массива) | | | | a[0][] (первый подмассив двумерного массива) | | a[][] (весь двумерный массив) Итак: printf("%p\n", a[0]); // 1. адрес первого подмассива двумерного массива (int (*)[2]) 0x61fe98 printf("%p\n", (int *)a); // 2. адрес двумерного массива, просто // приведенный к указателю, имеет тип (int*), // если разыменовать его получим 10 printf("%p\n", *a); // 3. то же самое, что и 1 printf("%p\n", a); // 4. не то же самое, что и 2! Имеет тот же // адрес, но тип (int (*)[3][2]) printf("%p\n", &(a[0][0])); // 5. Указатель на первый элемент подмассива // двумерного массива, то же самое что и 2

Ответ 3



printf("%p\n", a[0]); // <- 1 printf("%p\n", (int *)a); // <- 2 printf("%p\n", *a); // <- 3 printf("%p\n", a); // <- 4 printf("%p\n", &(a[0][0])); // <- 5 Для того, чтобы понять, что происходит полезно понимать, что такое на самом деле массив. В С/C++ массив это обычный указатель на начало массива. Значения в массиве хранятся последовательно. Также на указателях есть арифметика. То есть если прибавить к указателю 1, то получим уаказатель на следующий элемент данного типа. Итак что же такое запись a[i] на самом деле эта запись эквивалентна следующей: *(a+i) то есть берём значение, которое хранится в i-ой ячейке после той, на которую указывает a. И на самом деле такая запись тоже допустима: i[a] (попробуйте, например вывести ещё 0[a]). Итак a[0] = *(a+0) = *a. Таким образом равенство 1 и 3 установили. Теперь разберём, почему a и *a совпадают. На самом деле потому, что они указывают ровно в одно и тоже место. В памяти эти 6 чисел будут храниться последовательно: {10, 2, 2, 3, 3, 4}. Таким образом a указывающее на весь этот массив и a[0] указывающее на кусок {10, 2} будут указывать в одно и тоже место, так как их начала совпадают. Также a будет иметь тип int (*)[2]. Таким образом несмотря на то, что a и *a совпадают, но a+1 и *a+1 совпадать уже не будут, так как указывают на типы разных размеров. И сдвиг на 1 для этих указателей будет отличаться. Теперь про оставшееся: a -- указатель, поэтому при конвертиации в указатель на int ((int *)a) указывать он продолжит на туже ячейку. И последнее: &(a[0][0]) = &(*(a[0]+0)) = a[0]+0 = a[0] так как a[0][0] -- нулевой элемент в этом массиве и его адрес это адрес начала всего массива.

Добавить хеш git в исходный код

#cpp #git #visual_cpp


Как заставить Visual Studio автоматом при сборке присваивать макросу GIT_HASH значение
хеша git, без использования дополнительных утилит/установки поддержки дополнительных
языков. Чтобы на чистой машине, с установленным Visual Studio и git можно было собрать
такой код: 

std::cout << "git hash: " << GIT_HASH << std::endl;

    


Ответы

Ответ 1



Используйте Pre-Build Event, в нем выполняйте echo и git rev-parse: echo | set /p _=#define GIT_HASH > rev.h git rev-parse --short=12 HEAD >> rev.h В свойствах проекта можно задать сразу несколько команд отдельными строчками. Конструкция echo | set /p _= позволяет убрать перевод строки. Пример использования rev.h : #include "rev.h" #define STRINGIFY_(x) #x #define STRINGIFY(x) STRINGIFY_(x) #define GIT_HASH_STR STRINGIFY(GIT_HASH) int main() { std::cout << GIT_HASH_STR << '\n'; }

Ответ 2



Альтернативный вариант с использованием for /f (так же в Pre-Build Event - Command Line) for /f "delims=" %%a in ('"git rev-parse --short=12 HEAD"') do @echo #define GIT_HASH "%%a" > git_hash.h Перед сборкой будет создаваться файл git_hash.h содержащий строку: #define GIT_HASH "325f66c2c290" Использование: #include #include "git_hash.h" int main() { std::cout << GIT_HASH << std::endl; }

Можно ли в Delphi, вызвать функцию по имени, которое хранится в строке?

#delphi


Есть строка, которая может принимать разные значения, 

можно ли вызвать функцию, имя которой, равно значению строки,

а если, допустим, такой функции нет, то ничего не произойдет

Что бы не использовать много раз if str = 'myfunc' then myfunc(a);
    


Ответы

Ответ 1



как следует из комментариев, от того, что у вас используется классовая функция, ничего особо не меняется (при использовании RTTI для решения задачи) type TTest = class(TObject) public class function myFunc(x : integer): integer; end; class function TTest.myFunc(x: integer): integer; begin result := x*100; end; метод TRttiMethod.invoke() имеет несколько перегруженных вараинтов, и может принимать как экземпляр класса так и мета-класс (class of ..). function invokeClassFunction(cls: TClass; funcName: string; args: array of TValue): TValue; var ctx: TRttiContext; t: TRttiType; m: TRttiMethod; begin ctx := TRttiContext.Create(); try t := ctx.GetType(cls); m := t.GetMethod(funcName); if (m = nil) then raise Exception.Create('Method not found'); result := m.Invoke(cls, args); finally ctx.Free(); end; end; Поэтому при вызове вы просто указываете нужный класс: var r : TValue; try r := invokeClassFunction(TTest, 'myFunc', [1]); writeln('result: ', r.AsInteger); except on e: Exception do writeln('ничего не проиозошло'); end;

Снятие галочек с других checkbox-ов по условию

#javascript #html #jquery


Есть три чекбокса.
Нужно сделать так, чтобы если активен первый чекбокс, то убирались галочки со второго
и третьего, а если второй или третий активный - убиралась галочка с первого.

Вот что у меня получилось:



$('.food_in_tour input:checkbox').change(function() {
  if ($('#eat_all').prop('checked')) {
    if ($('#not_meat').prop('checked') || $('#not_sugar').prop('checked')) {
      $('.food_in_tour input:checkbox:not(#eat_all)').prop('checked', false);
    }
  } else if ($('#not_meat').prop('checked') || $('#not_sugar').prop('checked')) {
    if ($('#eat_all').prop('checked')) {
      $('#eat_all').prop('checked', false);
     }
  }
});
В чем ошибка, и как это можно реализовать?


Ответы

Ответ 1



Нужно проверять какой checkbox был нажат, а не состояние checkbox-ов после нажатия. Если нажали на #eat_all, то убираем выделение с других checkbox-ов. Если нажали на какой-то другой - убираем с #eat_all. Проверку можно делать, например, с помощью ID checkbox-a: $('.food_in_tour :checkbox').change(function() { if (this.id == "eat_all") { $('.food_in_tour :checkbox:not(#eat_all)').prop("checked", false); } else { $("#eat_all").prop("checked", false); } });


Провайдинг зависимостей “перепрыгивая” через компонент

#java #android #dagger2


Имеется три пакета: a, b и c. Каждый из этих пакетов включает в себя интерфейс с
буквой, реализацию интерфейса, компонент, модуль и Scope (не знаю, как правильно переводится).
В результате, выходит вот такая структура проекта:

│   
│
├───a   A.java
│       AComponent.java
│       AImpl.java
│       AModule.java
│       AScope.java
│
├───b   B.java
│       BComponent.java
│       BImpl.java
│       BModule.java
│       BScope.java
│
└───c   C.java
        CComponent.java
        CImpl.java
        CModule.java
        CScope.java

Application.java


CComponent имеет зависимость (dependencies) на BComponent, а BComponent - на CComponent. 

BModule требует класс A для создания класса B, а CModule требует классы A и B для
создания класса C:

@AScope
@Component(modules = AModule.class)
public interface AComponent {
    A a();
}

@Module
public class AModule {
    @Provides
    @AScope
    public A provideA() {
        return new AImpl();
    }
}



@BScope
@Component(modules = BModule.class, dependencies = AComponent.class)
public interface BComponent {
    B b();
}

@Module
public class BModule {
    @Provides
    @BScope
    public B provideB(A a) {
        return new BImpl(a);
    }
}



@CScope
@Component(modules = CModule.class, dependencies = BComponent.class)
public interface CComponent {
    C c();
}


@Module
public class CModule {
    @Provides
    @CScope
    public C provideC(A a, B b) {
        return new CImpl(b, a);
    }
}




При попытке собрать проект, Dagger 2 начинает ругаться, что CComponent не может найти
провайдера класса A:

Error:(9, 7) java: com.dugin.rostislav.a.A cannot be provided without an @Provides-annotated
method.
      com.dugin.rostislav.a.A is injected at
          com.dugin.rostislav.c.CModule.provideC(a, …)
      com.dugin.rostislav.c.C is provided at
          com.dugin.rostislav.c.CComponent.c()




Почему компонент не может получить доступ к Provide-методам модулей компонентов,
который находятся ниже по иерархической цепочке зависимостей (более одного компонента)?
    


Ответы

Ответ 1



Проблема была в том, что компонент BComponent должен был явно указать компонентам, имеющим на него зависимости, какие реализации он может провайдить из нижестоящих компонентов. То есть он должен указать, что может дать класс A: @BScope @Component(modules = BModule.class, dependencies = AComponent.class) public interface BComponent { A a(); B b(); } Для того, чтобы пробрасывать зависимости неявно — можно использовать Subcomponent. Очень хорошая статья на хабре про Component Dependencies и Subcomponents, где раскрывается данный вопрос - Dagger 2. Часть вторая. Custom scopes, Component dependencies, Subcomponents.

Вызов диалога “Обзор папок”

#delphi #delphi_7


Как вызвать точно такое же окно выбора папки?

Использовал эту функцию:

var
  chosenDirectory: string;

SelectDirectory('Выберите папку', '', chosenDirectory);


Как сюда добавить кнопку создания папки?


    


Ответы

Ответ 1



Для Delphi 7 находится вот такое (не очень красивое) решение: uses ShlObj, ActiveX; //global variables var lg_StartFolder: String; //functions //no need to declare these anywhere at the top of the unit function BrowseForFolderCallBack(Wnd: HWND; uMsg: UINT; lParam, lpData: LPARAM): Integer stdcall; begin if uMsg = BFFM_INITIALIZED then SendMessage(Wnd,BFFM_SETSELECTION, 1, Integer(@lg_StartFolder[1])); result := 0; end; function BrowseForFolder(const browseTitle: String; const initialFolder: String =''): String; var browse_info: TBrowseInfo; folder: array[0..MAX_PATH] of char; find_context: PItemIDList; begin FillChar(browse_info, SizeOf(browse_info), #0); lg_StartFolder := initialFolder; browse_info.pszDisplayName := @folder[0]; browse_info.lpszTitle := PChar(browseTitle); browse_info.ulFlags := BIF_RETURNONLYFSDIRS or BIF_EDITBOX or $40; browse_info.hwndOwner := Application.Handle; if initialFolder <> '' then browse_info.lpfn := BrowseForFolderCallBack; find_context := SHBrowseForFolder(browse_info); if Assigned(find_context) then begin if SHGetPathFromIDList(find_context,folder) then result := folder else result := ''; GlobalFreePtr(find_context); end else result := ''; end; Пример использования: procedure TForm4.Button3Click(Sender: TObject); begin BrowseForFolder('Select Dir', 'C:\'); end;

Ответ 2



не уверен на счет Delphi-7, но в более поздних версиях можно было использовать класс StdActns.TBrowseForFolder: procedure TForm1.ChooseDirButtonClick(Sender: TObject); var bff : TBrowseForFolder; begin bff := TBrowseForFolder.create(nil); try bff.Caption := 'Выберите папку'; bff.BrowseOptions := [bifNewDialogStyle]; if bff.Execute() then begin if bff.Folder <> '' then showMessage(bff.Folder); end; finally bff.Free(); end; end;

Ответ 3



Как минимум, начиная с Delphi 2007 (про Delphi 7 не уверен), в юните FileCtrl есть функция SelectDirectory, которая имеет вот такое описание: function SelectDirectory( const Caption: string; const Root: WideString; var Directory: string; Options: TSelectDirExtOpts = [sdNewUI]; Parent: TWinControl = nil ): Boolean; overload; Соответственно, передав опцию sdNewFolder в параметре Options можно добиться того, что вам нужно: uses FileCtrl; ... if SelectDirectory('Выберите папку', '', chosenDirectory, [sdNewFolder, sdNewUI, sdShowEdit, sdShowShares]) then begin ... end;

Как вызвать функцию класса внутри js класса [закрыт]

#javascript #классы #ecmascript_6


        
             
                
                    
                        
                            Закрыт. Этот вопрос не по теме. Ответы на него в данный
момент не принимаются.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Хотите улучшить этот вопрос? Переформулируйте вопрос,
чтобы он соответствовал тематике «Stack Overflow на русском».
                        
                        Закрыт 2 года назад.
                                                                                
           
                
        
Например: 

 class Car(){
    weight(){
      alert('100kg');
    }
    getWeight(){
      this.weight()   //не работает
   }
}


Как это сделать правильно?
    


Ответы

Ответ 1



Этот вопрос следует закрыть, т.к. проблема вызвана опечаткой class Car { weight(){ alert('100kg'); } getWeight(){ this.weight() //не работает } } (new Car()).getWeight();

Ответ 2



class Car { weight() { console.log('100kg'); } getWeight(){ this.weight(); } } var car = new Car; car.getWeight();

Как правильно реализовать морфинг Hamburger'а в back button?

#android #архитектура


Я хочу использовать подход: "каждому фрагменту свой Toolbar".
Как в этом случае правильно реализовывать анимацию морфинга
Hamburger -> BackButton
при переходах между фрагментами?
    


Ответы

Ответ 1



У вас получается такая ситуация: Toolbar принадлежит фрагменту, а иконка внутри Toolbar отображает состояние стека фрагментов внутри активити. Если вам действительно нужна эта анимация перехода от гамбургера к стрелке, то есть два варианта: 1) Делаете глобальный Toolbar в активити. Но тогда будут все вытекающие кейсы с инфлейтом разных меню и заголовков из конкретных фрагментов. 2) Делаете в активити метод, который синхронизирует переданный Toolbar с состоянием стека. Но надо не забывать отсоединять Toolbar, когда фрагмент уходит с экрана (логично использовать методы старт/стоп) fun attachToolbarNavigationIcon(toolbar: Toolbar) {} fun dettachToolbarNavigationIcon() {} ЗЫ: Есть более простой вариант. Скорее всего анимация из "гамбургера" в кнопку "назад" вам нужна только при переходе с первого фрагмента на следующий. В остальных случаях там висит только кнопка "назад". Поэтому можно это обработать только в рамках первого фрагмента и все: перед переходом вперед - превращаем в кнопку назад и только тогда переходим. При возврате превращаем обратно в гамбургер.

Ответ 2



Не могу дать Вам готового решения, но в общем случае в support library есть готовый класс DrawerArrowDrawable, который как раз реализует эту морфирущую иконку. Вы всегда можете попробовать добавить её на Ваш Toolbar и запустить анимацию после того, как тулбар нового фрагмента добавится на экран. Пример запуска анимации вот тут. Если Вы используете Navigation Drawer, то иконка должна работать "из коробки". Вот здесь есть схожий вопрос с ответами, как при этом использовать разные тулбары (обратите внимание не только на принятый ответ, но и на ответ с большинством голосов).

C++ std::thread. Как обратить и завершить поток

#cpp #многопоточность


Всем привет, 

Как обратиться к потоку по id и попросить его "завершиться"?

Использую стандарт С++11 и библиотеку  

Спасибо)
    


Ответы

Ответ 1



Никак. std::thread такое не предусматривает. Используйте atomic, [shared_]future::wait_for или другие примитивы чтобы просигнализировать коду внутри потока о том что он должен завершиться.

Отключение отображения шкал значений осей в OxyPlot WPF

#c_sharp #wpf #oxyplot


Хотелось бы узнать, каким образом можно отключить шкалы (помечены в красном круге
на изображении) на графике. Требуется, чтобы контур графика имел форму прямоугольника,
без каких либо подписей, так как в моем случае требуется отразить в графике лишь динамику
и числа совсем не важны. Спасибо.


    


Ответы

Ответ 1



Видимостью осей можно управлять через установку свойства IsAxisVisible. Если вы настраиваете отображение графика в XAML то разметка может выглядеть так Отображение

Как сделать анимацию SVG текста вокруг многоугольника

#css #анимация #svg


Допустим необходимо равномерно разместить текст вокруг многоугольника, таким образом,
чтобы вне зависимости от  длины слов и их количества, а также  размера шрифта,- вся
фраза размещалась вдоль сторон многоугольника без перекрытия символов.  

Конечно такие условия невозможно выполнить при большом количестве слов и размере
шрифта, но в определенных рамках это возможно? 

Например, чтобы такие разные фразы, как:


Текст шестиугольника
Текст вокруг шестиугольника 
Весь текст целиком вокруг шестиугольника


Одинаково равномерно размещались вокруг сторон шестиугольника без перекрытия начала
и конца фразы.  

Далее, необходимо сделать анимацию текста вокруг шестиугольника. 










    


Ответы

Ответ 1



Чтобы разместить текст целиком вокруг фигуры необходимо узнать длину пути, то есть длину периметра сторон многоугольника. Для нашего примера длина периметра многоугольника будет равна 760px Чтобы конец текстовой фразы не перекрывал символы начала и был гарантированный промежуток между ними,- установим textLength="700" Теперь для текста применим атрибут lengthAdjust="spacingAndGlyphs", который выполняет согласование между установленной длиной textLength="700" и расчетной длиной текстовой фразы, которая может иметь различные длины в зависимости от количества слов и размера шрифта. Другими словами она уплотняет текстовую фразу до заданных размеров textLength="700" за счет уменьшения ширины отдельных символов Анимация текста вдоль сторон многоугольника достигается изменением атрибута attributeName="startOffset" Ниже пример, который работает и в Chrome, FireFox, Opera, IE11 (кроме анимации) Начало анимации - клик на кнопке "Старт" Весь очень длинный текст целиком вокруг шестиугольника Старт

Навесить на поле класса анонимную функцию

#c_sharp


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

Есть класс Process, в нём есть поле Name и Duration. Есть класс ProcessQueue, в котором
есть поле Items и ItemIndex. Так вот, я имитирую какие-либо процессы, указываю их название
и продолжительность. Затем засовываю Process с заданными полями в очередь в поле ProcessQueue.Items.
По окончанию процесса, должна сработать заданная пользователем функция. Я хочу засунуть
эту функцию, скажем, в поле Process.Callback.

Как засунуть туда функцию и как её потом вызвать?
    


Ответы

Ответ 1



Для того, чтобы записать в поле класса функцию, всё равно анонимную или нет, вы должны создать поле делегатного типа. Для этого есть два основных пути: определение собственного делегата, или использование готового, имеющегося в системе. Предпочтительным методом является использование готового делегата. Например, если ваш callback должен принимать один аргумент типа int и не возвращать никакого значения, вам подойдёт тип Action: Action callback; Присваивание выглядит просто: callback = n => Console.WriteLine($"работа окончена, результат: {n}"); Вызов тоже очевиден: callback(5);

В каком стандарте Си разрешили обьявлять переменные в любом месте функции?

#c #language_lawyer


В каком стандарте Си разрешили объявлять переменные в любом месте функции?
    


Ответы

Ответ 1



В любом месте - начиная с С99. Не совсем понятна, правда, привязка к функции. В классическом ANSI C (C89/90) тоже можно было делать локальные объявления "в любом месте функции", если это "место" являлось началом блока. Такая возможность появилась еще в достандартные времена - она присутствует уже в первом издании K&R C. Начиная же с С99 разрешается делать локальные объявления в любом месте блока. Требование выноса локальных объявлений в начало именно функции существовало только уж в совсем архаичных версиях языка, типа описанной в C Reference Manual.

Буфер — это обязательно Heap?

#winapi #ассемблер #указатели


Здравствуйте, скажите пожалуйста, вот во многих (по крайне мере которые я встречал)
строковых-winapi'шных функциях следует передавать указатель на некий буфер, буфер обязательно
должен быть заранее выделенной кучей (Heap)? Можно отправить указатель например на
заранее зарезервированный массив байт?
    


Ответы

Ответ 1



Лишь бы эта память была корректна во время работы с ней (ну и, конечно же, доступна для записи-чтения :)). Например, при выделении памяти в стеке следует не забывать, что она будет корректна только до окончания вызова функции. А так - что выделите, то и годится :)

Как в ASP.Net Core работать с PostgreSQL?

#c_sharp #postgresql #aspnet_core


С помощью каких библиотек Вы работаете в ASP.Net Core с PostgreSQL?
    


Ответы

Ответ 1



Можете использовать Entity Framework. Чистый ADO.NET. Dapper (методы расширения для ADO.NET). Рабочий пример.

maven & IntelliJ IDEA & no main manifest attribute

#java #intellij_idea #maven


Нашёл в google не десяток аналогичных вопросов, и везде (практически) советуют одно
и тоже - добавить код ниже в pom.xml:


    
        com.petersamokhin.Main
    



Однако, не у одного меня IDEA выдаёт ошибку - Element archive is not allowed here,
и в результате всё равно no main manifest attribute:


В чём проблема и как лечить? mvn установлен, во время компиляции ошибок тоже нет.
    


Ответы

Ответ 1



Добавил ещё один тег plugin: maven-assembly-plugin com.mypackage.MainClass jar-with-dependencies Полностью теперь тег build выглядит так: maven-assembly-plugin com.mypackage.MainClass jar-with-dependencies org.apache.maven.plugins maven-compiler-plugin 3.1 1.8 1.8 Затем: mvn clean compile assembly:single

Синхронизировать канвас с анимацией

#javascript #css3 #анимация #canvas #css_animation


В каждом фрейме отрисовки (requestAnimationFrame) в центре канваса рисуется круг.
Размер канваса анимируется. В Хроме и FF круг немного дрожит, а в IE он заметно толстеет
перед перерисовкой - т. е. браузер сначала растягивает имеющуюся картинку, а потом
заменяет её новой. Почему так происходит и как исправить?



Насколько я представляю, если я делаю что-то в requestAnimationFrame, то содержимое
страницы вообще не должно перерисовываться, пока я не закончу. Соответственно, на момент
отрисовки должна отрисоваться сразу новая версия. Но в IE сценарий не такой?

https://jsfiddle.net/3wLroppt/



function draw() {
  var canvas = document.querySelector('canvas');
  
  var width = canvas.clientWidth, height = canvas.clientHeight;
  
  canvas.width = width * 2;
  canvas.height = height * 2;
  
  var ctx = canvas.getContext('2d');
  
  var cx = width, cy = height, r = height;
  
  ctx.beginPath();
  ctx.arc(cx, cy, r, 0, 2 * Math.PI, false);
  ctx.fill();
}

requestAnimationFrame(function frame() {
  draw();
  requestAnimationFrame(frame);
});
canvas {
  outline: 1px dotted red;
  height: 200px;
  width: 200px;
  display: block;
  margin: auto;
  animation: w-100-200 .5s linear infinite;
}

@keyframes w-100-200 {
    0% { width: 200px; }
   50% { width: 400px; }
  100% { width: 200px; }
}




    


Ответы

Ответ 1



Нашел ответ, правда на IE пока не тестировал, у меня linux))) Как я и подозревал дело было в том что анимация с высотой и шириной по умолчанию происходит так: Например у вас ширина должна с 200px расшириться до 400px в определенном промежутке времени ($t), и расчет происходит так - к ширине добавляется один пиксель в (400-200) / $t времени.И кода размер ширины контейнера нечетное количество пикселей то центр круга рисуется на один пиксель вправо (по оси x) (201/2 пиксель шириной для него будет 101px), и это приводит к непредусмотренной анимации (дрожанию) круга внутри контейнера. Эту проблему я решил свойством animation-timing-function, у него есть значение steps. там можно задать шаг анимации и у нас поскольку от 200 - 400 будет 100 2-пиксельных шагов прописываем в нем 100 animation-timing-function: steps(100); И вот что у меня получилось: А это пример от автора но время я поставил 5s что бы наглядно было видно непредусмотренная анимация черного круга.

Ответ 2



Вы же сами написали - браузер сначала рисует кружок с помощью js,а css его тем временем растягивает. let start = Date.now(); const canvas = document.querySelector('canvas'); const ctx = canvas.getContext('2d'); const height = canvas.clientHeight; function draw() { let dt = Date.now() - start; var side = Math.pow(-1, ~~(dt/500)); var delta_width = 200 * (dt%500)/500; width = canvas.width = ((side>0)?200:400) + side * delta_width; prev = Date.now(); var cx = width/2, cy = height, r = height; ctx.beginPath(); ctx.arc(cx, 100, 100, 0, 2 * Math.PI, false); ctx.fill(); } setInterval(draw, 54); canvas { outline: 1px dotted red; height: 200px; display: block; margin: auto; }

Как сделать чтобы AutoIncrement в dataGridView увеличивался только при добавлении строки

#c_sharp #winforms #datagridview #datatable


Код

   // *** создаю DataTable
dt_028 = new DataTable();

// *** Добавляю поля в DataTable
// поле Автоинкремент
workColumn = dt_028.Columns.Add("ID", typeof(Int32));
workColumn.AutoIncrement = true;
workColumn.AutoIncrementSeed = 1;
workColumn.AutoIncrementStep = 1;

// поля DataTable
dt_028.Columns.Add("pole_name_1", typeof(String));
dt_028.Columns.Add("pole_name_2", typeof(String));
dt_028.Columns.Add("pole_name_3", typeof(String));

// *** Отображаю DataTable в dataGridView
dataGridView1.DataSource = dt_028;


Когда перемещаю курсор в dataGridView с предпоследней строки на последнюю, увеличивается
значение AutoIncrement в поле "ID".
Т.е. переместил курсор на последнюю строку, но строку не добавил, а AutoIncrement
увеличился.

ВОПРОС
Как сделать чтобы автоинкремент увеличивался только при добавлении строки dataGridView,
а не просто при нахождении курсора на последней строке?

СКРИН


    


Ответы

Ответ 1



На самом деле, перемещение на последнюю строку в DataGridView а потом обратно, приводит к тому, что в DataTable, который указан в качестве источника данных, вставляется новая строка. Вставка новой строки приводит к инкременту поля ID, но т.к. строка на самом деле вставлена не была, происходит отклонение последних изменений - DataTable.RejectChanges(), т.е. тех изменений, которые произошли с момента последнего вызова DataTable.AcceptChanges(), при этом значение инкремента не сбрасывается, в связи с чем при новом перемещении на последную строку в DataGridView значение ID не то, которое вы ожидали увидеть. Что можно сделать? Решение № 1 Инкрементировать вручную, т.е. отключить workColumn.AutoIncrement на колонке ID и выставлять значение самостоятельно. private void FormLoad(object sender, EventArgs e) { _dt = new DataTable(); // Подписываемся на событие вставки новой строки. _dt.TableNewRow += DataTableNewRow; _dt.Columns.Add("ID", typeof(int)); _dt.Columns.Add("pole_name_1", typeof(string)); _dt.Columns.Add("pole_name_2", typeof(string)); _dt.Columns.Add("pole_name_3", typeof(string)); _dataGridView.DataSource = _dt; } private void DataTableNewRow(object sender, DataTableNewRowEventArgs dataTableNewRowEventArgs) { // Инкрементируем ID. dataTableNewRowEventArgs.Row["ID"] = _dt.Rows.Count + 1; } Решение № 2 Возложить задачу по генерации ID на вашу БД, что на мой взгляд более правильно. Решение № 3 Вместо типа int использовать тип Guid, при условии необходимости генерации ID на клиенте.

Ответ 2



Убрать автоинкремент у данного столбца. Остаётся лишь: workColumn = dt_028.Columns.Add("ID", typeof(Int32)); Подписать DataTable на событие добавления новой строки: dt_028.TableNewRow += Dt_028_TableNewRow; В обработчике события вставляем нужное значение: private void Dt_028_TableNewRow(object sender, DataTableNewRowEventArgs e) { e.Row["ID"] = dt_028.Rows.Count; } Ещё лучше вообще убрать эту колонку (вариант - сделать её скрытой). А номера строкам давать при сохранении данных в БД/файл. Собственно, а нужны ли вообще эти номера? В БД айдишник должен быть свой. А в файле он не нужен.

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

#javascript #html #jquery #css


Если заполняется один из блоков, то оба блока принимают наибольшую высоту.
Вариант с фиксированной высотой не подойдет.
будет ли правильно сделать блокам display:table или всё же есть более правильный способ?
    


Ответы

Ответ 1



Вот Вариант с flexbox։ .list { width: 400px; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-flex-wrap: wrap; -ms-flex-wrap: wrap; flex-wrap: wrap; } .list__item { width: 40%; background: #3e3e3b; display: -webkit-flex; display: -ms-flexbox; display: flex; padding: 2%; margin: 0 3%; color: #FFFFFF; }
  • Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
  • Lorem Ipsum is simply dummy text of the printing and typesetting industry.


Как скрыть текст (разного цвета!) под фоном до клика на него мышкой?

#javascript #html #jquery


Добрый день!

Хочу скрыть цветной текст под прямоугольником такого же цвета. Пример поправил, возможно
ли это сделать для текста разных цветов?



div.myHiddenBlock {
  color: green;
  background: green;
}

span.myVIPText
{
  color: red;
}

span.myVisibleBlock {
  color: green;
}
Текст, который нужно скрыть до клика мышкой


Ответы

Ответ 1



Вот пример: body { backround-color: #ffffff; } Текст, который нужно скрыть до клика мышкой Текст, который нужно скрыть до клика мышкой Простой текст

Ответ 2



body { color: green; } Текст, который нужно скрыть до клика мышкой

В чем разница между методом val jquery и свойством value в javascript?

#javascript #jquery


Когда перебираю массив из инпутов, то метод val() jquery выдает ошибку, а вот свойство
value javascript выводит значение атрибута value. В чем тут подвох?
    


Ответы

Ответ 1



Разница между методом val и свойством value довольно большая: Свойство находится непосредственно в элементе, и получает значение как есть. Если посмотреть реализацию метода val и опустить проверку на то, передали в метод параметр или нет и сразу перейти к получению значения можно отметить, что сначала проверяется наличие хуков: if ( hooks && "get" in hooks && ( ret = hooks.get( elem, "value" ) ) !== undefined ) { return ret; } И если они есть, то выполняется соответствующая функция. Если хуков нет, то получается значение, с помощью свойства value, и если полученное значение является строкой - перед возвратом из функции из строки будут удалены символы \r с помощью замены по регулярному выражению rreturn Ошибку при вызове метода val можно получить, если пытаться вызвать этот метод у нативного html элемента, а не у объекта jQuery. Для решения, достаточно обернуть имеющийся элемент, в объект: $(element).val();

Ответ 2



.val() - метод, применяемый к объекту JQ. Использование объекта jQuery начинается с вызова одноименной функции - $("селектор")..value - применяется к элементу DOM. Работа с элементом DOM начинается с document.getElementByТипСелектора("егоНазвание"). Для наглядности примера - ссылка, нужно открыть консоль в браузере! И кликнуть единственную кнопку.

Проверка, чтобы все числа номера телефона были не одинаковые

#javascript #jquery


В продолжение своего вопроса о маске телефона возник еще один вопрос.

Как можно усовершенствовать код ( регулярное выражение), чтобы НЕ было возможности
ввести все цифры одинаковыми? Т.е. Если пользователь вводит номер +7(111)111-1111 должна
появляться ошибка, но если например так: +7(111)111-1112, то все отлично. 



$('form').validate();
$('.js-phone').mask("+7(999)999-9999", {autoclear: false});

jQuery.validator.addMethod("checkMask", function(value, element) {
  return /\+\d{1}\(\d{3}\)\d{3}-\d{4}/g.test(value); 
});
label {
  display: block;
  margin: 10px 0;
}

.error {
  color: red;
}



  


Ответы

Ответ 1



Не уверен, что можно обойтись одним регулярным выражением, но можно добавить второе регулярное выражение, в котором проверить, что все цифры одинаковые. Для этого можно воспользоваться возможностью проверять уже найденные группы например: /\+\d\((\d){3}\)\1{3}-\1{4}/g Пример: $('form').validate(); $('.js-phone').mask("+7(999)999-9999", { autoclear: false }); jQuery.validator.addMethod("checkMask", function(value, element) { return /\+\d{1}\(\d{3}\)\d{3}-\d{4}/g.test(value) && !/\+\d\((\d){3}\)\1{3}-\1{4}/g.test(value); }); label { display: block; margin: 10px 0; } .error { color: red; }


Поиск описания параметра команды в man

#linux #man


Предположим, что я хочу узнать назначение параметра -s команды curl. 
Я выполняю man curl. 
Далее мне нужно найти секцию параметра -s, она начинается примерно так:

   -s, --silent
          Silent  or  quiet  mode. Don't show progress meter or error messages. 
Makes Curl mute. It will still output the data you ask
          for, potentially even to the terminal/stdout unless you redirect it.


Какой наиболее удобный способ прокрутить справочную страницу до нужной мне секции?



Все способы, которыми я пользуюсь сейчас, основаны на поиске строк вроде -s, -s,
и других. 
Поиск выполняю через /ввожу искомую строкуEnter. Перехожу между найденными вхождениями
с помощью n (следующее вхождение) и N (предыдущее вхождение). 
Вот мои способы:


Поискать -s. Чтобы добраться до искомой секции придётся нажимать n больше 10 раз.
Первый способ с добавлением пробела в конец. Не работает в данном случае, так как
у параметра -s есть длинная версия --silent, поэтому в описании секции после названия
параметра стоит запятая, а не пробел.
Первый способ с добавлением запятой в конец. В данном случае позволяет перейти к
искомой секции всего за одно нажатие n, в общем случае может потребоваться больше нажатий,
также этот способ не работает для параметров без длинной версии.


Видно, что все способы не очень удобны.
    


Ответы

Ответ 1



1. При поиске через / и используя регулярное выражение -s[ ,] можно сделать поиск по обоим вариантам: -s и --silent: -S, --show-error When used with -s, --silent, it makes curl show an error message if it fails. -s, --silent See also -v, --verbose and --stderr. ... 2. При поиске через & и а. -s выводятся все строки, соответствующие поисковому запросу: ... --sasl-ir --service-name Examples: --negotiate --service-name sockd would use sockd/server-name. -S, --show-error When used with -s, --silent, it makes curl show an error message if it fails. -s, --silent See also -v, --verbose and --stderr. --socks4 --socks4a --socks5-gssapi-nec ... б. -s[ ,] уже совсем хорошо: -S, --show-error When used with -s, --silent, it makes curl show an error message if it fails. -s, --silent See also -v, --verbose and -s, --silent. Use -s, --silent to make curl really quiet. Получается, что чем точнее составлено регулярное выражение, тем быстрее найдёте.

Ответ 2



Нужно искать строку " -s" (два пробела, а затем короткое имя команды). Почти всегда нужная секция должна находиться с первого раза, иначе можно увеличить число пробелов.

Почему так не рекомендуется писать?

#java #android #задание_на_собеседовании


Делал тестовое задание на вакансию Junior Android разработчика, в коде была строчка:

ArrayList valNames = new ArrayList();


Мне сказали, что лучше писать так: 

List valNames = new ArrayList(); 


Потом в одной из статей на habrahabr.ru встретилась фраза:


  Подумаешь, большое дело, что человек не понимает почему нужно писать 
  List values = new ArrayList(); вместо ArrayList values = ….; Ну и кому
  же не хочется увидеть названия в стиле ArrayList arrayList = new
  ArrayList(); и улыбнуться. Жаль только, что с применением данного
  антипатерна, все эти, вызывающие улыбку, вещи обычно обнаруживаются
  после приблизительно месяца работы.


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


Ответы

Ответ 1



Обычно это объясняется так: если кодер объявляет переменную типа ArrayList вместо List - он не понимает что все нужные ему методы уже есть в интерфейсе. Тем самым демонстрируется непонимание основных принципов проектирования, ведь ему на самом деле совсем не требуется именно ArrayList, он может использовать любую другую коллекцию! ... с той же асимптотикой операций... упс. На самом деле те, кто так пишет, защищаются от автоматических рефакторингов, способных преобразовать переменную конкретного типа в параметр метода, что проявит их непонимание основных принципов проектирования привыкли к IDE, которые подчеркивают такие места желтым и предлагают исправить тип переменной. Это просто привычка. Для большинства алгоритмов, выдумываемых на ходу, ArrayList<> является единственной коллекцией с адекватными временами выполнения операций и нет никакой разницы какого типа объявлять переменную. А вот за типами параметров методов или возвращаемых значений надо и правда следить внимательнее, выбирая наименьший подходящий интерфейс - это упростит стыковку кода, написанного разными программистами.

Ответ 2



Это носит больше религиозно/стилистический оттенок, нежели формальный. Объявление List шире чем декларация ArrayList, то есть когда человек пишет List он типа демонстрирует свою ООП сущность, как бы понимает, что underlying объект может быть и ArrayList и Vector и Stack и т.д. и декларируя List абстрагируется от конкретной реализации. На самом то деле, насколько это правильно или нет - напоминает дискуссии средневековых схоластов о сущности универсалий

Как найти преобладающий цвет на изображении?

#javascript #jquery




Как получить цвет каждого пикселя, посчитать, и в итоге оставить только тот, который
наиболее часто встречается в изображение?  

Возможно, вы знаете уже готовые библиотеке. Заранее, признателен за помощь.
    


Ответы

Ответ 1



Есть маленькая библиотека RGBaster (briangonzalez/rgbaster.js) Она позволяет сделать ровно то, что вам нужно. Ниже пример ее использования. // Для примера я загружаю изображение по URL, а не из тела документа var img = 'http://briangonzalez.github.io/jquery.adaptive-backgrounds.js/img/main-images/6.jpg'; RGBaster.colors(img, { // Не учитывать белый цвет exclude: ['rgb(255,255,255)'], success: function(payload) { // console.log(payload.dominant); // Преобладающий цвет // console.log(payload.secondary); // Второй по популярности цвет // console.log(payload.palette); // Палитра цветов (по умолчанию 30) // Устанавливаем фоновый цвет равный самому популярному. document.body.style.background = payload.dominant; } }); img { width: 250px; display: block; margin: 0 auto; }

Ответ 2



Библиотека Vibrant.js позволяет реализовать то, что вам нужно. Более подробный пример - тут. var img = document.querySelector('img'); img.setAttribute('src', img.getAttribute('data-src')); img.crossOrigin = "Anonymous"; img.addEventListener('load', function() { var vibrant = new Vibrant(img); var swatches = vibrant.swatches(); for (var swatch in swatches) if (swatches.hasOwnProperty(swatch) && swatches[swatch]) console.log(swatch, swatches[swatch].getHex()) });

Итератор с методами класса

#cpp


У меня есть класс FileSystem, и я хочу хочу сделать, чтобы с итераторов можно было
выполнять некоторые методы самого класса. Для этого в итератор добавил указатель на
класс чтобы методы вызванные с итератора были примерно такими:

int FileSystem::iterator::make_dir(const std::string& name){
    return указатель_на_FileSystem->make_dir(name,указатель_на_Dir );
}


метод в классе FileSystem: 

int FileSystem::make_dir(const std::string& name, Dir* & cur_dir);


Создавать итератор хотел так

iterator(this,указатель_на_Dir);


Проблема в том, что this - константный, соответственно в итераторе можно создавать
можно только константные указатели на FileSystem и выполнять только константные методы.
Вопрос заключается в том, стоит ли делать 

 const_cast<...>(this)


и насколько это плохо. Возможно стоит как-то пересмотреть архитектуру или использовать
что-то другое?
    


Ответы

Ответ 1



this может иметь несколько разных типов: T * const при вызове функции-члена на константном объекте (т.е. нельзя изменять как сам this, так и то, на что он указывает); T * при вызове на изменяемом объекте (по прежнему нельзя изменять this, но можно изменять объект, на который он указывает); ещё пара вариантов с volatile (в данном случае, не рассматриваем). Если создание вашего итератора происходит в константной функции, то и this имеет соответствующий тип. Таким образом, как минимум следует создавать итератор там, где объект, указываемый this может изменяться. Более того, не обязательно создавать итератор именно из функции-члена. Преобразования const_cast, сбрасывающие константность у действительно константных объектов приводят к неопределённому поведению. Поэтому тут надо быть крайне осторожным. В качестве возможного подхода предлагаю рассмотреть ситуацию с итераторами для стандартных контейнеров. Они имеют как const-версию, так и обычную. Т.е. существуют два отдельных класса итераторов. Надеюсь, такое объяснение позволит решить Вашу проблему.

Объясните спецификатор

#c


Использовал в scanf спецификатор " %[^\r\n]" для того, чтобы мог вводить название
из нескольких слов,отделенных пробелами.(посоветовали так же на форуме это спецификатор
использовать), но как его объяснить.Почему в квадратных скобках?
Что означает "^" крышечка? 
Коротко говоря подробно написать саму работу данного спецификатора.
    


Ответы

Ответ 1



Читайте документацию по scanf, там все подробно написано. Спецификатор формата вида %[что-то] означает "читать все символы, пока они принадлежат набору, указанному в квадратных скобках". Спецификатор формата вида %[^что-то] означает "читать все символы, пока они НЕ принадлежат набору, указанному в квадратных скобках" (т.е "читать все символы, пока не наткнешься на один из указанных в квадратных скобках"). В вашем случае " %[^\r\n]" означает: пропустить ведущие пробелы и затем читать все подряд, пока не наткнешься на '\r' или '\n'. Вообще-то, если речь не идет о каких-то тонкостях, связанных с обработкой символа '\r', scanf с форматом " %[^\r\n]" означает просто "пропустить ведущие пробелы и затем читать до конца строки", при этом оставляя символы конца строки непрочитанными. Это примерно то же самое, что и обычный fgets, с той только разницей, что fgets не пропускает ведущие пробелы и вычитывает из потока символы конца строки. Может быть вам лучше подойдет просто fgets и не надо городить огород с этим %[]? Также не ясно, зачем понадобилась отдельная обработка символа '\r'. Если речь идет о чтении текстового потока под Windows, то там никакого '\r' уже не будет. Все маркеры конца строки будут заменены на простое '\n' еще до того, как дело дойдет до scanf. Также имейте в виду, что scanf не умеет читать пустые строки. То есть если этот %[^\r\n] сразу же наткнется на '\r' или '\n', то scanf тут же завершится с ошибкой, не изменив значение принимающего буфера.

Не могу подключить namespace используя autoload

#php #namespace


Класс Autoload.php подключает в проект все имеющиеся .php-файлы. Не могу использовать
пространство имен какого-либо файла, если он подключен через Autoload. 

Ручное подключение файла (используя require/include) и подключение его namespace
работает без ошибок. 

Autoload.php:


Ответы

Ответ 1



У вас $class_name передается как полное имя класса вместе с пространством имен. И вот на этом этапе $path = ROOT . $path . $class_name . '.php'; у вас получается что-то вроде ROOT.'/models/Admin\\Auth.php' А такого файла у вас скорее всего нет

Ответ 2



можно еще так str_replace('\\', '/', __NAMESPACE__); , хотя в вашем случае нужно только короткое имя класса. Интересно что namespace обязательно должен присутствовать в файле класса, а доступ к нему производится или установкой пространства имен или указанием полного имени класса или имени класса относительно установленного пространства имен. Ниже загрузчик, код не мой, но я проверял он вполне рабочий. Нужно только загрузить сам загрузчик, выше него естественно указать желаемое пространство имен, и дальше уже работать непосредственно с классами и их функциями. Загрузчик AutoPSR-4.php test(); Z\Zed::test(); //расположен в models\Z\Zed.php \controllers\Xclass::test(); // расположен вне текущего пространства имен в controllers\Xclass.php Пример класса controllers\Xclass.php класс Xclass'; } }

Ответ 3



Автозагрузчик composer`a. Подключение через композер, предполагает запихивание всего апликейшена в папку, связывание с именем проекта, а следовательно все неймспейсы приобрели дополнительный префикс \Проект, и стал выглядеть подобным образом \Проект\сабнеймспейс\класс, т.е. нужно для нормального функционирования, переименовывать во всех файлах проекта пространство имен, внедряя имя проекта, но чтобы не менять в глубинах кода используемые классы, можно добавить указатель на пространство имен use. Теперь в начале каждого класса пишем используемое пространство имён. У основных классов это:

Как git работает со ссылками

#git #gitlab


Здравствуйте.
Мне нужно завести проект в gitlab. В проекте есть symlink'и как на директории так
и на файлы. Мой вопрос такой, как git работает со ссылками? Имеет ли значение идет
ссылка на файл или директорию? Если я хочу добавить их в .gitignore, мне просто добавлять
их как конкретные файлы?
    


Ответы

Ответ 1



git сохраняет symlink так же как файл в blob. При checkout он создаст его как symlink и не важно есть ли оригинальный файл/директория. Вы можете добавить их в .gitignore как простые файлы по имени.

Какие коды ошибок возвращать в rest?

#java #http #rest


В задании написано вернуть коды ошибок типичные для rest. Какие именно? Какие коды
являются типичными для rest?
    


Ответы

Ответ 1



Типичные для REST это ошибки 200 - успешные 400 - ошибки на стороне клиента 500 - ошибки на стороне сервера

Как изменить цвет поисковой строки в мобильном Google Chrome

#html #google_chrome


Мне надо сделать цветной панель поиска в Google Chrome, например, как у лайфхакера:



Пробовал сделать это с помощью




Но увидел всю ту же белую панель.



Помогла чистка кэша


    


Ответы

Ответ 1



У лайфхакера в коде стоит: Может Вы не туда тег вставили? Это нужно между добавить. Так же, возможно, Вам нужно почистить кэш браузера в телефоне.

перехват исключения производным классом

#cpp #ооп #классы #исключения


Объясните почему при вводе 0  и выбросе исключения Base, оно не отлавливается блоком
Derived1?

int main()
{
    int number = 0;

    for (;;)
    {
        try
        {
            cin >> number;
            cout << number << " ";

            switch (number)
            {
                case 0:
                    throw Base();

                case 1:
                    throw Derived1();

                case 2:
                    throw Derived2();
            }
        }
        catch (Derived1 /*exception*/)
        {
            cout << "Exception of derived class" << endl;
        }
        catch (Base /*exception*/)
        {
            cout << "Exception of Base class" << endl;
        }
    }

    return 0;
}

    


Ответы

Ответ 1



Потому что Base не является Derived, а вот Derived является Base. Вот если бы вы написали (кстати, перехватывайте исключения по ссылке, иначе столкнетесь со срезкой) catch (Base& /*exception*/) { cout << "Exception of Base class" << endl; } catch (Derived1& /*exception*/) { cout << "Exception of derived class" << endl; } то тут и Base, и Derived ловились бы первым блоком - Base.

Создать полоску клеток вверху сайта

#html #css


Как можно сделать полоску клеток вверху сайта? Я пытаюсь делать таким кодом



header {
  background: linear-gradient( #bbb, transparent 1px), linear-gradient( 90deg, #bbb,
transparent 1px);
  background-size: 15px 15px;
  background-position: center center;
  height: 100px;
}
Но тогда остаются зазоры по бокам. Как можно сделать, чтобы клетка прижималась к верхнему и боковым краям без зазора?


Ответы

Ответ 1



Для body надо сбросить margin, body { margin:0px; }

Ответ 2



А если просто добавить бордер?: header { background: linear-gradient( #bbb, transparent 1px), linear-gradient( 90deg, #bbb, transparent 1px); background-size: 15px 15px; background-position: center center; height: 100px; border:1px solid #ddd; } div { background: linear-gradient( #bbb, transparent 1px), linear-gradient( 90deg, #bbb, transparent 1px); background-size: 15px 15px; background-position: 0 0; height: 90px; border-right:1px solid #ddd; border-bottom:1px solid #ddd; }



Преобразование TIMESTAMP WITH TIME ZONE в Oracle 12c

#sql #oracle #timezone


По каким-то причинам не получается правильно преобразовать TIMESTAMP WITH TIMEZONE
из одной временной зоны в другую, пример:

SELECT SYSTIMESTAMP,
       DBTIMEZONE,
       CURRENT_TIMESTAMP
       SESSIONTIMEZONE
  FROM DUAL;




=============================================================================================================================================================================================================
|                   SYSTIMESTAMP                   |                    DBTIMEZONE
                   |                CURRENT_TIMESTAMP                 |           
     SESSIONTIMEZONE                  |
=============================================================================================================================================================================================================
|            20.07.2017 7:15:33 -04:00             |                  Europe/Moscow
                  |            20.07.2017 14:15:33 +03:00            |            
         +03:00                      |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------




Второй пример:

SELECT 
  SYSTIMESTAMP,
  SYSTIMESTAMP AT TIME ZONE 'Europe/Moscow' Moscow,
  SYSTIMESTAMP AT TIME ZONE 'America/New_York' New_York
  FROM DUAL




==========================================================================================================================================================
|                   SYSTIMESTAMP                   |                      MOSCOW
                     |                     NEW_YORK                     |
==========================================================================================================================================================
|            20.07.2017 7:09:25 -04:00             |            20.07.2017 11:09:25
+00:00            |            20.07.2017 11:09:25 +00:00            |
----------------------------------------------------------------------------------------------------------------------------------------------------------


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


Почему в первом примере результат CURRENT_TIMESTAMP отстает на час от реального,
которое должно быть равно 15:15:33, а не 14:15:33?
Почему во втором примере, не смотря на успешное выполнение команды, конвертация не
происходит? Может какие-то параметры базы данных не настроены, или я не понимаю как
AT TIME ZONE работает? Наименования временных зон я брал из V$TIMEZONE_NAMES.


Версия БД: Oracle Database 12c Standard Edition Release 12.2.0.1.0 - 64bit Production

UPD:
Данные из nls_session_parameters

SQL Developer

NLS_LANGUAGE    RUSSIAN
NLS_TERRITORY   RUSSIA
NLS_CURRENCY    ₽
NLS_ISO_CURRENCY    RUSSIA
NLS_NUMERIC_CHARACTERS  , 
NLS_CALENDAR    GREGORIAN
NLS_DATE_FORMAT DD.MM.RR
NLS_DATE_LANGUAGE   RUSSIAN
NLS_SORT    RUSSIAN
NLS_TIME_FORMAT HH24:MI:SSXFF
NLS_TIMESTAMP_FORMAT    DD.MM.RR HH24:MI:SSXFF
NLS_TIME_TZ_FORMAT  HH24:MI:SSXFF TZR
NLS_TIMESTAMP_TZ_FORMAT DD.MM.RR HH24:MI:SSXFF TZR
NLS_DUAL_CURRENCY   ₽
NLS_COMP    BINARY
NLS_LENGTH_SEMANTICS    BYTE
NLS_NCHAR_CONV_EXCP FALSE


dbForge

NLS_LANGUAGE    AMERICAN
NLS_TERRITORY   AMERICA
NLS_CURRENCY    $
NLS_ISO_CURRENCY    AMERICA
NLS_NUMERIC_CHARACTERS  .,
NLS_CALENDAR    GREGORIAN
NLS_DATE_FORMAT DD-MON-RR
NLS_DATE_LANGUAGE   AMERICAN
NLS_SORT    BINARY
NLS_TIME_FORMAT HH.MI.SSXFF AM
NLS_TIMESTAMP_FORMAT    DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_TZ_FORMAT  HH.MI.SSXFF AM TZR
NLS_TIMESTAMP_TZ_FORMAT DD-MON-RR HH.MI.SSXFF AM TZR
NLS_DUAL_CURRENCY   $
NLS_COMP    BINARY
NLS_LENGTH_SEMANTICS    CHAR
NLS_NCHAR_CONV_EXCP FALSE

    


Ответы

Ответ 1



К 1-ой части вопроса SYSTIMESTAMP возвращает текущее время и часовой пояс операционной системы машины на которой установлен сервер БД. CURRENT_TIMESTAMP возвращает эти же данные учитывая часовой пояс сессии на клиенте, который определяется клиентом из окружения (установки региона на ОС, переменные) в котором он запущен и может быть изменён непосредственно: setenv ORA_SDTZ="Europe/Moscow" или alter session set time_zone='+03:00'. Посмотреть часовой пояс сессии можно так: select sessiontimezone from dual; В примере разница между Москвой и Нью-Йорком составляет -4 и +3 = 7 часов, что соответствует действительности. Значит время, которое возвращает SYSTIMESTAMP тоже с отставанием, т.е. системное время установленно не верно. Ко 2-ой части вопроса Преобразование даты и времени производится на стороне клиента и зависит от его NLS настроек, часового пояса (см. выше), которые можно посмотреть: select * from nls_session_parameters; Некоторые клиенты, как в данном примере с dbForge\IDEA "потерялся" часовой пояс, или sqlplus не учитывает изменения часового пояса в России с октября 2014 года, выполняют преобразование не всегда верно. Поэтому при сомнении имеет смысл выполнить запрос на различных клиентах. На заметку не в рамках вопроса Oracle рекомендует устанавливать DBTIMEZONE на UTC, если не используются по каким-то специфическим соображениям тип данных TIMESTAMP WITH LOCAL TIME ZONE.

Анимация на css 3 [закрыт]

#css #css3


        
             
                
                    
                        
                            Закрыт. Этот вопрос необходимо уточнить или дополнить
подробностями. Ответы на него в данный момент не принимаются.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Хотите улучшить этот вопрос? Добавьте больше подробностей
и уточните проблему, отредактировав это сообщение.
                        
                        Закрыт 2 года назад.
                                                                                
           
                
        
Добрый день, подскажите пожалуйста, как сделать бесконечную анимацию на css 3

Нужно, что бы картинки плавно исчезали и появлялись, что бы первая картина быстрее появлялась и исчезала, чем вторая. Без js.


Ответы

Ответ 1



img { position: absolute; animation: blink 5s linear infinite; } img + img { animation-duration: 10s; } @keyframes blink { 0% { opacity: 1 } 50% { opacity: 0 } 100% { opacity: 1 } }

Как получит HWND окна при наведении на него курсора мыши?

#cpp #qt #winapi


Как получить HWND окна при наведении на него курсора мыши С++ WinApi32 или Qt?
    


Ответы

Ответ 1



Функция HWNDWindowFromPoint(POINT Point) поможет вам.

Печать и обновление графика в реальном времени OxyPlot - Windows Form

#c_sharp #net #winforms #oxyplot


Пишу академическую программу - монитор частоты. Для печати графиков использую Nuget
Oxylot. Не могу понять как мне напечатать график в реальном времени. Например изменения
раз в секунду. По оси X должно быть время, по оси Y - значение double, изменяющееся
от 0 до 50.00 единиц (частота в Гц). Взял семпл из документации, а как туда значение
вставить и обновлять по времени не понимаю...
Вот класс графика:

 public class Plotter
{
    private PlotModel model;
    private DateTime startDate = DateTime.Now.AddDays(-10);
    private DateTime endDate = DateTime.Now;

    private readonly List colors = new List
                                        {
                                            OxyColors.Green,
                                            OxyColors.IndianRed,
                                            OxyColors.Coral,
                                            OxyColors.Chartreuse,
                                            OxyColors.Azure
                                        };

    private readonly List markerTypes = new List
                                               {
                                                   MarkerType.Plus,
                                                   MarkerType.Star,
                                                   MarkerType.Diamond,
                                                   MarkerType.Triangle,
                                                   MarkerType.Cross
                                               };



    public Plotter()
    {
        model = new PlotModel { Title = "DateTimeAxis" };
    }


    public PlotModel PrintChart()
    {
        var minValue = DateTimeAxis.ToDouble(startDate);
        var maxValue = DateTimeAxis.ToDouble(endDate);
        model.Axes.Add(new DateTimeAxis { Position = AxisPosition.Bottom, Minimum
= minValue, Maximum = maxValue, StringFormat = "HH:mm" });
        return model;
    }}


В основном окошке:

public void PrintChart()
    {
        Plotter pt = new Plotter();
        frGraph.Model = pt.PrintChart();
    }


По событию кнопки разрешаю печать:

private void startDrawing_Click(object sender, EventArgs e)
    {
       PrintChart();
    }


И по таймеру пытаюсь обновлять (не уверен, что делаю правильно..)

 private void InitializeTimerForChart()
    {
        tickCount.Interval = References.TIMER_INTERVAL; // (1000 мс)
        this.tickCount.Tick += new System.EventHandler(this.tickCount_Tick);
        tickCount.Enabled = true;
    }
private void tickCount_Tick(object sender, EventArgs e)
    {
        if (InvokeRequired)
        {
            Invoke((MethodInvoker)delegate ()
            {
                frGraph.Invalidate();//PrintChart();
            });
        }
    }


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

    


Ответы

Ответ 1



В общем получилось создать линейный график без обновлений. Обновлять буду также через таймер раз в секунду. public PlotModel PrintChart() { var minValue = DateTimeAxis.ToDouble(startDate); var maxValue = DateTimeAxis.ToDouble(endDate); model.Axes.Add(new DateTimeAxis { Position = AxisPosition.Bottom, Minimum = minValue, Maximum = maxValue, StringFormat = "HH:mm" }); var leftAxisY = new LinearAxis { Position = AxisPosition.Left }; model.Axes.Add(leftAxisY); var lineSeries = new LineSeries { Title = "Линейный график", StrokeThickness = 3, LineStyle = LineStyle.Automatic, MarkerType = MarkerType.Circle, MarkerSize = 5, MarkerStroke = OxyColors.White, MarkerFill = OxyColors.Automatic, MarkerStrokeThickness = 1.5, }; for (int i = 0; i < 50; i++) { lineSeries.Points.Add(new DataPoint(minValue, i)); } model.Series.Add(lineSeries); return model; }

Ответ 2



Отвечу, может кому-то понадобится. Когда добавляете серию в график, используйте свойство series.ItemSource private void AddSeries(string Name, OxyColor Color, string AxisKey, List Buffer) { var series = new LineSeries(); series.Title = Name; series.Color = Color; series.YAxisKey = AxisKey; series.ItemsSource = Buffer; Model.Series.Add(series); } Buffer здесь это коллекция данных, в который вы будете складывать собираемые точки. Обновлять следующим образом: Buffer.Add(new DataPoint(x, y)); // здесь можете делать с коллекцией что // хотите: удалять, добавлять, очищать Model.InvalidatePlot(true); Да, тип таймера имеет значение: Threading.Timer каждый обратный вызов запускает в новом потоке, DispatcherTimer в потоке диспетчера (для простых задач наиболее удобен, косяков меньше)

Плиточный дизайн

#html #css


При верстке psd наткнулся на плиточный дизайн. Мне нужно понять что использовать:
flexbox, grid, div или таблицы использовать фреймворки нельзя только чистый css. В
какую сторону копать и если можно привести пример. 
    


Ответы

Ответ 1



Лучше используй Bootstrap Grid:она полностью реализует все твои потребности, если использовать фиксированный маргинг (вот пример) Прочитать подробнее про Bootstrap можно тут. Прочитать подробнее про Bootstrap Grid можно тут.

Ответ 2



Есть такой плагин - isotope. С его помощью можно получить очень похожую верстку в режиме masonry.

preg_replace заменить в строке символы, а цифры оставить

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


Есть строка в php допустим $str = 'z1.z2.z3.z6'
Как привести её к такому виду '[f1][f2][f3][f6]' через регулярку используя preg_replace ???
То есть везде заменить z на f, но соответствующие числа оставить и заключить выражение
в квадратные скобки.
    


Ответы

Ответ 1



$str = 'z1.z2.z3.z6'; echo preg_replace('/z(\d+)(.|$)/i', '[f${1}]', $str);

Ответ 2



Ещё один вариант $string = 'z1.z2.z3.z6'; $symbol = 'f'; // Символ для замены $pattern = ['~\w(\d)~', '~(?<=^|\.)~', '~(?=\.|$)~', '~\.~']; $replace = [$symbol .'$1', '[', ']', '']; echo preg_replace($pattern, $replace, $string); // Результат: [f1][f2][f3][f6]

Entity (сущности) — зачем они нужны?

#java #ооп #java_ee #entity


Всем добрый вечер.

В ходе одного обучающего проекта наткнулся на необходимость использовать Entity (сущность).
В данном случае, существует 3 класса, наследуемые друг от друга:

Entity.java:

public class BaseEntity {
    protected Integer id;

    public BaseEntity() {
    }

    protected BaseEntity(Integer id) {
        this.id = id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getId() {
        return id;
    }

    public boolean isNew() {
        return (this.id == null);
    }

    @Override
    public String toString() {
        return String.format("Entity %s (%s)", getClass().getName(), getId());
    }
}


От него наследуется NamedEntity:

public class NamedEntity extends BaseEntity {

    protected String name;

    public NamedEntity() {
    }

    protected NamedEntity(Integer id, String name) {
        super(id);
        this.name = name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    @Override
    public String toString() {
        return String.format("Entity %s (%s, '%s')", getClass().getName(), id, name);
    }
}


А от него — User:

import java.util.Date;
import java.util.EnumSet;
import java.util.Set;

import static MealsUtil.DEFAULT_CALORIES_PER_DAY;

public class User extends NamedEntity {

    private String email;

    private String password;

    private boolean enabled = true;

    private Date registered = new Date();

    private Set roles;

    private int caloriesPerDay = DEFAULT_CALORIES_PER_DAY;

    public User() {
    }

    public User(Integer id, String name, String email, String password, Role role,
Role... roles) {
        this(id, name, email, password, DEFAULT_CALORIES_PER_DAY, true, EnumSet.of(role,
roles));
    }

    public User(Integer id, String name, String email, String password, int caloriesPerDay,
boolean enabled, Set roles) {
        super(id, name);
        this.email = email;
        this.password = password;
        this.caloriesPerDay = caloriesPerDay;
        this.enabled = enabled;
        this.roles = roles;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Date getRegistered() {
        return registered;
    }

    public void setRegistered(Date registered) {
        this.registered = registered;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    public int getCaloriesPerDay() {
        return caloriesPerDay;
    }

    public void setCaloriesPerDay(int caloriesPerDay) {
        this.caloriesPerDay = caloriesPerDay;
    }

    public boolean isEnabled() {
        return enabled;
    }

    public Set getRoles() {
        return roles;
    }

    public String getPassword() {
        return password;
    }

    @Override
    public String toString() {
        return "User (" +
                "id=" + id +
                ", email=" + email +
                ", name=" + name +
                ", enabled=" + enabled +
                ", roles=" + roles +
                ", caloriesPerDay=" + caloriesPerDay +
                ')';
    }
}


Я не совсем понимаю смысл такой "матрёшки". Внятного объяснения на русском не обнаружил.
Прошу поделиться смыслом сущностей, особенно меня интересует, почему мы пишем отдельно
id, отдельно name, отдельно всё остальное. Объяснение нужно прямо для чайников, а именно,
почему мы не можем без них обойтись или почему лучше их использовать. Также, подойдут
русскоязычные ресурсы, на которых разжёвывают, почему мы должны пользоваться сущностями
и вообще для чего они.
    


Ответы

Ответ 1



Решить каким образом использовать сущности и использовать ли их вообще поможет понимание следующей модели представления даннных. Когда мы говорим о сущностях в абстрактном смысле мы всегда в том или ином виде подразумеваем использование какой-либо модели данных. В частности, в программировании применяется EER-модель (Enhanced Entity-Relationship model). Расширенная модель включает все концепции ER-модели (entity-relationship model) и дополнительно включает понятия подкласса, суперкласса и относящиеся к ним понятия специализации, обобщения и категоризации. Далее рассмотрим базовую ER-модель. "Набор данных, обычно относящихся к какой-либо предметной области или тематической области, и структурированных таким образом, чтобы обеспечить установление отношений между отдельными элементами данных в соответствии с различными потребностями пользователей." G. Knott & N. Waites, Computing 3rd edition ER-модель, модель «сущность — связь» Модель была предложена в в 70-х годах Питером Пин-Шэн Ченом (сайт, статья). Модель "сущность-связь" основывается на некой важной семантической информации о реальном мире и предназначена для логического представления данных. Она определяет значения данных в контексте их взаимосвязи с другими данными. Важным для нас является тот факт, что из модели "сущность-связь" могут быть порождены все существующие модели данных (иерархическая, сетевая, реляционная, объектная), поэтому она является наиболее общей. Сущность фактически представляет из себя множество атрибутов, которые описывают свойства всех членов данного набора сущностей. Например, как у вас в коде. Есть базовая сущность BaseEntity, именованная сущность NamedEntity и конкретная User(пользователь). Таким образом сущность - это объект, который может быть идентифицирован неким способом, отличающим его от других объектов. Преимущества использования ER-модели Высокая гибкость. Обеспечивают: модульность, что позволяет переиспользовать код следуя принципу DRY; простоту рефакторинга Местная автономия. В каждой отдельной части программы можно работать только с нужными нам сущностями. Простота понимания. За счет семантического моделирования данных, при котором отдельная сущность опирается на смысл этих данных. Любую модель легко изобразить в виде диаграммы. Наличие и простота визуализации. Нотация П. Чена, Crow’s Foot, UML, DFD, IDEF0 и IDEF1x, нотация Мартина, нотация Бахмана и др. Недостатки использования ER-модели Сложность. Модель предназначена для высокого уровня абстракции. Увеличивается объем и сложность кодирования. Вам пришлось создать 3 класса со своими полями и методами, хотя можно было бы их оформить в одном классе. Кроме того разработчикам достаточно сложно хранить всю иерархию классов в голове. Безопасность. Трудно контролировать уровни доступности атрибутов сущности. Трудно поддерживать целостность. Такая модель чувствительна к изменению атрбутов.