Страницы

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

четверг, 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] -- нулевой элемент в этом массиве и его адрес это адрес начала всего массива.