Страницы

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

пятница, 12 октября 2018 г.

Недостатки использования Qt для Android

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


Ответ

Qt - это всё-таки C++. Разрабатывать на нём существенно сложнее, чем на Java. То есть дольше и с большим количеством ошибок. Инструментарий разработки для C++ однозначно хуже такового для Java в силу, опять-таки, особенностей языка. Java - родная платформа для Android. Отсюда потенциальные проблемы с совместимостью у Qt.
Если вы опытный С++ разработчик, то вам, наверное, будет удобнее использовать Qt. В противном случае - не вижу преимуществ перед Java (касательно разработки под андроид).
Если вы планируете разрабатывать для ряда мобильных платформ, то qt хороший выбор. Если сугубо для андроида, то я на стороне Java.

Переопределение GetHashCode

Троелсен в своей книге, советует переопределить метод ToString() у класса(переопределенная версия возвращает строку из полей всего класса через пробел), а потом в методе GetHashCode вызывать this.ToString().GetHashCode()
Где-то читал критику такой реализации, например, вызов ToString() будет порождать мусор.
Правда ли, что она не очень хороша.
Какие могут быть альтернативы?


Ответ

Проблема со строкой состоит в том, что GetHashCode() может вызываться очень часто, много тысяч раз в секунду. Например, при поиске элемента в HashSet или поиске ключа в Dictionary у каждого искомого элемента берётся хэшкод. Если при этом будет каждый раз создаваться временная, никому за пределами метода не нужная строка, их потом должен будет очистить сборщик мусора.
Поэтому функция GetHashCode должна быть по возможности быстрой и не создавать дополнительных объектов.
По поводу того, как же лучше считать хэшкод, я бы посоветовал немного переделанный код из ответа @Umed:
public override int GetHashCode() { unchecked { int hash = 17; hash = hash * 23 + field1.GetHashCode(); // для поля типа-значения, например int hash = hash * 23 + field2.GetHashCode(); // то же самое if (field3 != null) // а это для поля ссылочного типа hash = hash * 23 + field3.GetHashCode(); return hash; } }
Вместо 17 и 23 можно взять другие разные простые числа.

Ещё по теме: Почему при переопределении Equals советуют также переопределять GetHashCode

Команда using()

using(var variable) {
}
Правильно ли я понял, что данная конструкция создает область видимости(работы) переменной variable. И после закрытия скобки вызывает Dispose() переменной?


Ответ

Правильно ли я понял, что данная конструкция создает область видимости(работы) переменной variable.
Да. Если переменная объявлена (и проинициализирована) в блоке, то ее область видимости ограничена только блоком using
Также возможно использовать блок using c уже объявленной и проинициализированной переменной. Для чего это может понадобиться, см. ниже.
И после закрытия скобки вызывает Dispose() переменной?
Да. Такой участок:
using (var x = ...) { x.Foo(); }
Преобразовывается компилятором в следующий код:
var x = ...; try { x.Foo(); } finally { if (x != null) { ((IDisposable)x).Dispose(); } }
Обратите внимание, что инициализация находится вне блока try
Соответственно, использование в using уже проинициализированной переменной является более компактным способом записи try/finally с вызовом Dispose()

Как сериализовать List в xml

Есть класс DB, который я хочу сериализовать в xml
public class DB { [XmlElement("Nomer")] public string Nomer { get; set; }
[XmlElement("Raspolojenie")] public string Raspolojenie { get; set; }
[XmlElement("Whois")] public string Whois { get; set; }
[XmlElement("Start")] public string Start { get; set; }
[XmlElement("End")] public string End { get; set; } }
Пробовал такой вариант, но выдает ошибку.
List listDB = new List();
XmlSerializer xmlSerializer = new XmlSerializer(typeof(DB)); StringWriter stringWriter = new StringWriter(); xmlSerializer.Serialize(stringWriter, listDB); string xml = stringWriter.ToString();


Ответ

Вы объявляете сериализатор с типом вашего класса
new XmlSerializer(typeof(DB));
И передаете список объектов вашего класса:
xmlSerializer.Serialize(stringWriter, listDB);
Попробуйте объявить сериализатор с типом списка вашего класса
new XmlSerializer(typeof(List));
Проверить!

В разных enum нельзя применять одинаковые имена

Есть два enum: enum OBJECT_PULSES и enum OBJECT_SENSOR_MODE_RD имена в перечислениях одинаковые RD_CH..., но их числовые значения разные. При компиляции ошибка: redeclaration. Это особенность языка или что не так с настройками компилятора, как это побороть кроме как переименования?
enum OBJECT_PULSES { RD_CH1 = 14, // Счетчик импульсов, канал 1 // ... RD_CH32 = 45 // Счетчик импульсов, канал 32 };
enum OBJECT_SENSOR_MODE_RD { RD_CH1 = 46, // RD. Режим датчика, канал 1 // ... RD_CH32 = 77, // RD. Режим датчика, канал 32 };


Ответ

Константы enum'ов не имеют собственной области видимости, поэтому у приведённых двух енумов всё оказывается в одной области видимости. Естественно, в одной области видимости одинаковые имена недопустимы.
Как вариант, можно использовать enum class, которые создают свой скоуп. Либо использовать более старую идею с обёртыванием enum'а в пространство имён.

Статические методы у не статических классов

Есть классы, которые наследуются от одного абстрактного класса, у которого есть не виртуальная функция для работы со строкой:
protected string NormalizeString(string s) { return s.Trim().ToUpper(); }
Нужно ли эту функцию делать статической? Когда функции нужно делать статическими, а когда обычными, если они не используют поля объекта?


Ответ

Да, я бы сделал эту функцию статической. Принцип очень простой.
Если функция относится к конкретному объекту, она должна быть нестатической. Пример: получение температуры с конкретного термометра — явно нестатическая фукция. Если функция относится ко всем объектам данного типа, то она скорее всего должна быть статической. Пример: получение диапазона температур для класса термометров — явно статическая функция. Если функция не относится ни к какому объекту, то есть является по существу утилитой (как у вас), и не сильно связана с функциональностью класса, её надо бы вынести в отдельный статический класс. Но часто, конечно, лень. Пример: перевод температуры из градусов Фаренгейта в градусы Цельсия — явная функция-утилита.
(Существуют и пограничные случаи, когда не так очевидно, к какому из случаев относится функция. В этих случаях полагайтесь на интуицию или совет более опытных коллег.)

Как удалить знаки пунктуации (препинания) из конца строки?

Задача: Из строки Ха-ха!? получить Ха-ха. Т.е. удалить только последние символы !?. Мой пример делает лишнего и на выходе Хаха
import re valids = re.sub(r"[^A-Za-zА-Яа-я]+", '', 'Ха-ха!?') print(valids)
Помогите, пожалуйста, направить регулярку на правильный путь..
UPD: Вместо !? может быть любая комбинация символов (!!!, ?), :) ). Важно то, что она в конце.


Ответ

Можно и без регулярок обойтись:
print('Ха-ха!?'.rstrip('!?')) # 'Ха-ха'
Или взять набор символов из модуля string
import string print('Ха-ха!?'.rstrip(string.punctuation)) # 'Ха-ха'
rstrip удаляет справа, lstrip удаляет слева, а strip слева и справа

Или с такой регуляркой:
print(re.sub(r"[!?]+$", '', 'Ха-ха!?')) # 'Ха-ха'
@jfs предложил такой вариант:
# pip install regex import regex as re print(re.sub(r'\p{P}+$', '', 'Ха-ха!?')) # Ха-ха

Сортировка по DayOfWeek, неделя начинается с понедельника

Есть табличка с расписанием (день недели + где), в основе лежит enum DayOfWeek
public class Schedule { public int Id { get; set; }
public DayOfWeek DayOfWeek { get; set; }
public int? PlaceId { get; set; }
public Place Place { get; set; }
[Required] [MaxLength(50)] public string Notes { get; set; } }
И мне для людей приходится делать сортировку по возрастанию дней недели, например:
return await this.ApplicationDbContext.Schedule .Where(x => x.PlaceId != null) .OrderBy(x => x.DayOfWeek) .AsNoTracking() .ToListAsync();
И всё было бы прекрасно, но сайт делается для тех стран, где неделя начинается с понедельника (Россия), а не с воскресенья.
А DayOfWeek начинается с воскресенья:
public enum DayOfWeek { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, }
Есть ли какой-то простой способ указать сортировку "первый день недели - понедельник"?


Ответ

Попробуйте "магию" (на самом деле это просто циклический сдвиг дней внутри недели):
.OrderBy(x => ((int)x.DayOfWeek + 6) % 7)
В дерево выражений эта лямбда раскладывается нормально, думаю, EF сумеет транслировать это дерево в SQL-запрос (сам не проверял).
Метод хорош тем, что простой сменой константы 6 можно сменить и требуемое начало недели.
Как спрятать формулу и привести запрос в более читабельный вид можно посмотреть в этом топике: Как составить дерево выражения для лямбды?

Дополнение. Действительно, подобный запрос транслируется вполне нормально.
Исходный запрос был:
SELECT [t0].[Id], [t0].[DayOfWeek], [t0].[Notes], [t0].[PlaceId] FROM [Schedule] AS [t0] WHERE [t0].[PlaceId] IS NOT NULL ORDER BY [t0].[DayOfWeek]
Со сдвигом дня недели получается такой:
-- Region Parameters DECLARE @p0 Int = 6 DECLARE @p1 Int = 7 -- EndRegion SELECT [t0].[Id], [t0].[DayOfWeek], [t0].[Notes], [t0].[PlaceId] FROM [Schedule] AS [t0] WHERE [t0].[PlaceId] IS NOT NULL ORDER BY ([t0].[DayOfWeek] + @p0) % @p1

Почему компиляторы не сообщают о неопределенном поведении

Неопределенное поведение, мягко говоря, неоднозначное решение в дизайне языка. Тем не менее с этим злом приходится жить миллионам программистам. В стандарте, ситуации в которых возникает неопределенное поведение, описаны очень тяжелым техно языком. Неудивительно что большое количество программистов, да что там основная масса, просто не читали стандарт, а если и читали то одну половину не поняли, а вторую забыли.
Самое страшное не столько в том, что неопредленное поведение вообще допускается стандартом или что оно достаточно широко распространено. А в том, что в жизни рядовой программист плохо понимает когда оно вообще возникает. Тем более разочаровывает то, что разработчики компиляторов не стремятся помочь своему клиенту рядовому программисту хотя могли бы, христоматийный пример:
int i = 0; i = ++i + i++;
Вот этот код мой MSVC съедает молча. Есть еще не мало ситуаций когда компилятор мог бы предупредить программиста.


Ответ

Почему не сообщают? Потому что не обязаны. Тем не менее некоторые компиляторы могут сообщать о некоторых ситуациях, которые могут приводить к неопределённому поведению. Так, если собрать код из вопроса с помощью GCC или clang, Вы получите предупреждение. Есть и другие ситуации, которые покрыты компиляторами, но не все.
Для других ситуаций существуют всевозможные статические анализаторы, типа того же PVS Studio, clang-tidy (встроен в CLion & Resharper++) и прочих.

Регулярное выражение \W+ не находит символ “_” в строке

Согласно документации языка С#
\W - Соответствует любому символу, который не является буквенно-цифровым знаком.
Мне казалось логичным предположить, что символ нижнего подчеркивания - "_" попадает под данное определение.
Но на практике оказалось, что регулярное выражение - @"\W+" не находит символ нижнего подчеркивания в строке - @"@$^&#№_\|/*-+=~%{}()[];:,.!?'"""`
Объясните пожалуйста, почему регулярное выражение, не находит символ нижнего подчеркивания -"_"?


Ответ

Под \W попадают все символы, кроме тех, что попадают под \w
В C# под \w попадают буквы (не A-Za-z, а все символы, из определенных категорий Unicode, включая кириллицу), цифры, и спецсимволы из категории Punctuation, Connector.
Символ _ входит в категорию Punctuation, Connector (там кроме него еще десяток символов, вроде ﹍ и ⁀).
Если проблема только с _ - явно добавьте его в список символов: [\W_]+.
Если хотите захватить все Punctuation, Connector - добавляйте весь класс все не-бувкы и не-цифры - добавляйте весь класс: [\W\p{Pc}]+

Как сохранить и восстановить базу данных PostgreSQL?

Например, имеется пользователь postgres, база base и доступ trust


Ответ

Для сохранения кластера базы данных: pg_dumpall -U postgres -w > backup Для восстановления кластера базы данных: psql -U postgres -w -f backup postgres

Кросс-компиляция из Windows под Linux. Получение бинарных файлов под Linux

Мне поставили задачу - разобраться с кросскомпиляцией C и C++ приложений из под Windows для Linux. Я попробовал использовать Cygwin для этих целей. Установил эту оболочку, запустил её. Установил компилятор cygwin-gcc-3.3.6-glibc-2.3.2-linux (старый правда). И попробовал из него скомпилировать обычный HelloWorld и запустить его под Linux всё получилось. Но задача стоит чтобы из нашего Windows-приложения запускать кросс-компилятор, который будет компилировать некоторые файлы. Как вообще это можно реализовать? Просто в данном случае приходится запускать Cygwin, а уже из него gcc-linux или g++-linux. Пока не вижу путей запуска из нашего приложения Windows Cygwin и далее уже в нём запуска компилятора. Может быть какие-то есть другие выходы из ситуации? Как-то можно настроить вообще отдельный компилятор по Windows, который будет компилить бинарники под Linux?


Ответ

Установить cygwin. Создать скрипт запускающий сборку. Вызвать скрипт из приложения. В скрипте (cmd-файл) set CYGWIN_BIN=c:\cygwin\bin
CYGWIN_BIN\gcc.exe ... В приложении CreateProcess(...) А еще есть такое средство для кросс-компиляций: crosstool-ng

Ключевое слово final

В исходниках LibGDX, в классе Vector2 есть метод dst, который определяет расстояние между векторами. Vector2.java Вот он: public float dst (float x, float y) { final float x_d = x - this.x; final float y_d = y - this.y; return (float)Math.sqrt(x_d * x_d + y_d * y_d); } В нем промежуточные переменные x_d, y_d объявлены как final. Зачем? Чем бы это отличалось от этого: public float dst (float x, float y) { float x_d = x - this.x; float y_d = y - this.y; return (float)Math.sqrt(x_d * x_d + y_d * y_d); } В этом есть какая то особая магия?


Ответ

final — прежде всего защита от самого себя Дело в том, что хорошие компиляторы «умнее» людей. Компилятор может легко пробежаться по коду и выяснить, изменяется ли переменная в методе, и сам применить нужные оптимизации, если считает нужным. Время «подсказок компилятору» на нормальных платформах прошло. А вот защититься от собственных глупых ошибок — например, чтобы случайно не изменить переменную, которую вовсе не нужно менять — хорошая идея. Если вы случайно измените final-переменную, компилятор немедленно подскажет вам об этом. Вы можете смотреть на final как на часть декларации типа. Можно было бы в принципе отказаться от type safety и использовать только тип Object в программе. Когда вы говорите, что переменная имеет тип String, вы намеренно ограничиваете себя: теперь вы можете присваивать объекту только String-значения, при попытке присвоить int компилятор укажет вам на ваш просчёт. Точно так же декларация final позволяет вам ограничить себя, запретить самому себе менять значение, чтобы защититься от ошибок. Мне кажется, указывать наиболее сильное ограничение переменной по типу — хорошая привычка. Действительно, в данном конкретном коде константность переменной очевидна и без final и не приносит дополнительных дивидендов. Тем не менее, имеет смысл не задумываясь ставить final везде, где переменная не должна меняться, не отвлекаясь на то, как в данный момент реализован метод.

Что за тип size_t?

Что представляет из себя тип size_t, похожий на тип int? И для чего его используют?


Ответ

Открываем cplusplus.com - size_t и читаем size_t Unsigned integral type беззнаковое целое. То есть, это не int, он знаковый. Alias of one of the fundamental unsigned integer types. Псевдоним для одного из фундаментальных без знаковых типов. (то есть, скорее всего 4 или 8 байтового). It is a type able to represent the size of any object in bytes: size_t is the type returned by the sizeof operator and is widely used in the standard library to represent sizes and counts. Предназначен для отображения размера любого объекта в байтах: это возвращает size_of и много функций стандартной библиотеки - всякие length и count.

Определение 2-х одинаковых классов не даёт ошибки

//Файл A.cpp class A { public: int func( int i ) { return i*i; } };
//Файл Test.cpp #include using namespace std;
class A { public: int func( int i ) { return i*i*i; } };
int main() { A a; cout<Вопрос в том, почему нет ошибки времени компиляции? Ведь имеется два определения класса с именем А. Программа работает - выводит 8.
Дополню вопрос. Если переписать файл "A.cpp" так:
class A { public: int func( int i ); };
int A::func( int i ) { return i*i; }
То ошибка будет!!!
С функциями аналогичная ситуация. Приведённый ниже код работать не будет.
//A.cpp int func( int i ) { return i*i; }
//Test.cpp #include using namespace std;
int func( int i ) { return i*i*i; }
int main() { cout<Всё это меня как-то запутывает.


Ответ

Согласно стандарту языка (правилу ODR) классы с external linkage (внешним связыванием), определенные в нескольких единицах трансляции, должны быть определены одинаково во всех этих единицах трансляции. Но диагностики этого не требуется.
Точно так же, по ODR, inline-функции с external linkage, определенные в нескольких единицах трансляции, должны быть определены одинаково во всех этих единицах трансляции. Но диагностики этого не требуется.
В вашем исходном примере наличествуют как раз две таких сущности - класс с external linkage и inline-функция с external linkage.
Т.е. спецификация языка требует, чтобы эти сущности были определены одинаково во всех единицах трансляции, но следить за этой одинаковостью - в общем случае ваша задача. Продвинутый компилятор может помочь вам ловить такие ошибки, но это просто вопрос качества реализации.
Как только ваша функция перестала быть inline, диагностика для нарушений ODR для такой функции сразу же формально потребовалась и компилятор ее успешно вам предоставил.

Как использовать несколько view в RecyclerView

Мне нужно в зависимости от типа объекта(записи), заполнить RecyclerView разными view, раньше когда я делал это с помощью ListView у меня получалось, а тут я даже не знаю как это организовать, в onCreateViewHolder сразу создается view но без учета текущей позиции, следовательно я не могу несколько разных view там создать.
Как это можно организовать?


Ответ

Для создания айтемов разного вида необходимо переопределить метод адаптера getItemViewType(), который будет в зависимости от условия определять, айтем какого вида требуется в данной позиции. В RecyclerView этот механизм был улучшен и метод onCreateViewHolder() возвращает значение ViewType - какой тип айтема требуется в данной позиции:
class MyAdapter extends RecyclerView.Adapter {
private final int TYPE_ITEM1 = 0; private final int TYPE_ITEM2 = 1;
public MyAdapter () { // конструктор адаптера }
@Override public ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v;
switch (viewType) { // инфлейтим нужную разметку в зависимости от того, // какой тип айтема нужен в данной позиции
case TYPE_ITEM1: v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item1, parent, false); break; case TYPE_ITEM2: v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item2, parent, false); } return new ItemHolder(v); }
@Override public void onBindViewHolder( ItemHolder holder, int position) {
// Получаем тип айтема в данной позиции для заполнения его данными int type = getItemViewType(position);
switch (type) { case TYPE_ITEM1: holder.mText1.setText("биндим данные в айтем типа 1"); break; case TYPE_ITEM2: holder.mText2.setText("биндим данные в айтем типа 2"); break; } }
@Override public int getItemViewType(int position) { // условие для определения айтем какого типа выводить в конкретной позиции if (position == <условие>) return TYPE_ITEM1; return TYPE_ITEM2; }
public static class ItemHolder extends RecyclerView.ViewHolder{
TextView mText1; TextView mText2;
public ItemHolder(View v) { super(v);
mText1 = (TextView) v.findViewById(R.id.text1); mText2 = (TextView) v.findViewById(R.id.text2); } }

Напечатать символ N раз подряд

Нужно напечатать в bash символ N раз подряд - максимально короткой командой.


Ответ

Думаю, что короче не получится:
printf '=%.s' {1..100}
P.S. Украдено отсюда

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

Когда я только знакомился с программированием, мне брат подкинул exe самописной программы. Исходники он потерял, а я хочу воссоздать эту программу.
Её суть такова:
Даётся три столбца с рандомными цифрами. Ты загадываешь одну цифру и вводишь номер столбца в котором она находится. Потом появляются ещё три столбца, с этими же номерами, но разбросанными по другому. Опять выбираешь столбец в котором твой номер. И так ещё раз. А дальше программа угадывает цифру которую ты загадал. В общем я не представляю как это реализовать. Я знаю что это абсолютно примитивная консольная программа, но я ещё учусь :)
Дайте хоть какие-нибудь зацепки: алгоритм, пример кода, ссылки. Всему буду благодарен.


Ответ

Дано 3 столбца и 3 итерации. Вариантов размещения одного числа так, что бы можно было по размещению определить число - девять: 000 (число всегда на месте), 001, 002, 010, 011, 012, 020, 021, 022.
Берем по 9 чисел для каждой колонки. Можем заполнить массив из 27 элементов случайными, уникальными числами. Далее в описании алгоритма под число будем понимать его позицию в этом массиве, начиная с 0. Колонки "на экране" будем нумеровать 0, 1, 2. На первой итерации первые 9 чисел заносим в 0 колонку, вторые - в 1ю, третьи в 2ю. При размещении на второй итерации берем остаток до деления числа на 9 (по сути это номер числа в своей группе первой итерации). Делим этот остаток нацело на 3 - это на сколько колонок надо сдвинуть число на второй итерации относительно изначального положения (смещение = (X % 9) / 3). Если номер первоначальной колонки + смещение больше 2, то начинаем отсчет с начала (т.е. делаем 2-(K1+смещение)) На третьей итерации берем остаток от деления на 3 (смещение=X % 3). При таком походе мы для каждого числа получим расстановки указанные в самом начале поста.
Отгадывание: Номер колонки первой итерации умножаем на 9, прибавляем номер колонки второй итерации умноженный на 3, прибавляем номер колонки третьей итерации (K1*9+K2*3+K3). Все, получили число (ну т.е. его позицию в начальном массиве).
Пример:
1я итерация 2я итерация 3я итерация 0 1 2 0 1 2 0 1 2
0 9 18 0 3 6 0 1 2 1 10 19 1 4 7 3 4 5 2 11 20 2 5 8 6 7 8 3 12 21 9 12 15 9 10 11 4 13 22 10 13 16 12 13 14 5 14 23 11 14 17 15 16 17 6 15 24 18 21 24 18 19 20 7 16 25 19 22 25 21 22 23 8 17 26 20 23 26 24 25 26

Пользователь ввел: 2-я, 1-я, 0-я: 2*9+1*3+0=21, ввел 1-я, 2-я, 1-я: 1*9+2*3+1=16
Содержимое колонок на каждой итерации можно перемешать, что бы не было видно закономерностей в распределении.
Прямая печать индексов исходного массива на php (формулы пересмотрены для случая печати всех трех итераций в строку, как на примере выше):
for($i=0;$i<9;$i++) { // Строка for($j=0;$j<3;$j++) { // Итерация for($k=0;$k<3;$k++) { // Колонка if($j==0) $m=$i+9*$k; elseif($j==1) $m=(int)($i/3)*9+$i%3+$k*3; else $m=$i*3+$k; printf("%3d",$m); } print " "; } print "
"; }

Как компилятор С++ узнает по заголовочному файлу, что нужно подключить .cpp файл?

есть 2 файла: Element.cpp и Element.h
в main.cpp я подключаю Element.h. Но как компилятор узнает, когда и куда нужно подключить файл Element.cpp, в котором хранится реализация? Ведь его я нигде не прописываю.


Ответ

Компилятор и не знает. При компиляции ему указываются какие именно .срр файлы компилировать, например
g++ file1.cpp file2.cpp
а во всех .cpp файлах нужно указывать необходимые заголовочные файлы. Если вы работаете в IDE, то компилятору будут автоматически передаваться файлы исходного кода те, которые включены в проект.

Где располагается файл деобфускации Android Studio

Написал проект. Залил в Google Play, поймал первую ANR, но без файла деобфускации не могу понять причину сбоя. Где его можно найти ?


Ответ

Самостоятельно нашел ответ на свой вопрос.
Файл деобфускации проекта Android Studio располагается здесь:
\app\build\outputs\mapping
elease\mapping.txt

Что такое Context?

Кто-нибудь объясните по-человечески что такое Context в Android. Имею опыт использования, но чувствую неудовлетворенность, так как четкий его смысл ускользает.
UPD. Хотелось бы узнать, исходя из вашей практики, как он меняется или не меняется в ходе работы приложения, меняется ли он от активности к активности, от активности к сервису...или он разный у каждого компонента приложения, имеет разные возможности в разных ситуациях...


Ответ

Context - интерфейс предоставляющий глобальную информацию о среде приложения. Является абстрактным классом, реализация которого происходит с помощью Android системы. Context позволяет получить доступ к ресурсам приложения и его классам, а также осуществлять вызовы операций на уровне приложения, к примеру: Запуск Activity, Service, Broadcasting and Receiving intents, и тд.
Источник Context
Диаграмма:

Для чего используется статический интерфейс?

В примере фрагмента определялся статический интерфейс для того, чтобы уведомлять активность о нажатиях:
static interface WorkoutListListener { void itemClicked(long id); };
Почему интерфейс статический? К примеру, если переменная статическая — она используется в единственном экземпляре для всех экземпляров класса, но что делают статические интерфейсы?


Ответ

Согласно JLS 8.5.1. Static Member Type Declarations:
A member interface is implicitly static (§9.1.1). It is permitted for the declaration of a member interface to redundantly specify the static modifier.

Интерфейс - член класса, неявно является статическим. При объявлении интерфейса - члена класса допускается избыточное указание модификатора static
Конструкции
public class SomeClass { abstract static interface Interface { public abstract void foo(); } }
и
public class SomeClass { interface Interface { void foo(); } }
эквивалентны, т.к. интерфейс всегда abstract, вложенный интерфейс всегда static, а методы интерфейса всегда public. До java 8 методы интерфейса всегда были abstract, в восьмой версии метод интерфеса может быть static или default, в отсутствие этих модификаторов abstract подразумевается. Явное указание модификаторов допустимо, но не приветствуется с точки зрения стиля.
Поля в интерфейсе всегда public, static и final, избыточное указание этих модификаторов так же допустимо.

Преобразование скалярных типов при сравнении JavaScript

Объясните, пожалуйста, почему из трех алертов ниже исполняется только последний? Вроде как во всех трёх случаях идет мягкое сравнение на равенство к true
if (true == "0") alert('Тру равно нулю!');
if ("0" == true) alert('Ноль равен тру');
if ("0") alert('Как бы тоже тру, или как?');
https://jsfiddle.net/z1xbshmk/


Ответ

Стоит обратиться к спецификации При вычислении равенства EqualityExpression == RelationalExpression получаются значения левой и правой части, и к ним применяется Abstract Equality Comparison
Сравнение x == y, где x и y - значения, возвращает true or false. Такое сравнения производится следующим образом: Если Type(x) тот же самый, что и Type(y), тогда возвращается результат выполнения Strict Equality Comparison x === y. Если x является null и y является undefined, вернуть true Если x является undefined и y является null, вернуть true Если Type(x) - это Number и Type(y) - это String, вернуть результат выражения x == ToNumber(y) Если Type(x) - это String и Type(y) - это Number, вернуть результат выражения ToNumber(x) == y Если Type(x) - это Boolean, вернуть результат выражения ToNumber(x) == y Если Type(y) - это Boolean, вернуть результат выражения x == ToNumber(y) Если Type(x) один из следующих: String, Number, или Symbol и Type(y) это Object, вернуть значение выражения x == ToPrimitive(y) Если Type(x) - это Object и Type(y) один из следующих: String, Number, или Symbol, вернуть значение выражения ToPrimitive(x) == y Вернуть false
Рассмотрим первый пример:
true == "0"
Это выражении соответствует ветке
Если Type(x) - это Boolean, вернуть результат выражения ToNumber(x) == y
При приведении к числу получаем выражение: 1 == "0" попадаем в ветку
Если Type(x) - это Number и Type(y) - это String, вернуть результат выражения x == ToNumber(y).
При приведении к числу получаем выражение: 1 == 0 и как результат: false
Со вторым случаем происходит аналогичное.
Теперь рассмотрим третий случай.
Обратимся опять к спецификации
К выражению внутри скобок применяется функция ToBoolean, которая в случае строки возвращает false если строка пустая(длина строки 0), и true - в противном случае.
Так как "0" - не пустая(длина строки 1), то условие считается выполненным.

Чем, и как проверить что нагружает систему?

Я новичок в разработке под Android. Сейчас я пишу приложение для управления роботом по BLE. В приложении я добавил виртуальный джойстик и пару кнопок, на моем Meizu M2 mini все работает замечательно, но когда я тестирую приложения на других устройствах оно жутко лагает и тормозит. Я вынес функции с большим количеством вычислений в отдельные потоки, и всячески пытался оптимизировать приложение, стало немного лучше, но все равно не юзабельно. Есть ли какие нибудь средства, что бы определить какой фрагмент программы нагружает систему сильнее всего? Если нет, то прошу поделиться опытом, как вы определяете какие фрагменты программы нагружают систему?


Ответ

Для профилирования приложения в Android Studio используются следующие инструменты:
Memory Monitor - показывает использование оперативной памяти профилируемым приложением. Позволяет принудительно вызвать GC (сборщик мусора), получить содержимое "кучи" (HPROF Viewer) и распределение занимаемой памяти (Allocation Tracer). HPROF Viewer - показывает объекты, хранящиеся в "куче" с подробным содержимым. Allocation Tracker - показывает какие объекты находятся в оперативной памяти, включает инструменты анализа, используется для поиска утечек. CPU Monitor - показывает загрузку процессоров профилируемым приложением, включает инструмент Method Tracer для контроля за временем. Method Tracer - показывает вызов методов и время, затраченное на их выполнение. System Information - формирует дампы по нескольким состояниям системы. Network Monitor - показывает нагрузку сети профилируемым приложением. Android Device Monitor - мощное средство профилирования и отладки, включающее несколько инструментов DDMS, Hierarchy Viewer, Systrace, TraceView, OpenGL Trace DDMS - многофункциональный профилировщик. Использовался до появления в Android Studio инструментов, перечисленных выше и в основном дублирует их. Удобен тем, что все находится в одном месте. Hierarhy Viewer - используется для оптимизации разметки и загрузки экранов приложения. С Android Studio 2.2 включен в саму IDE и называется Layout Inspector (настройка Hierarhy Viewer) Три трассировщика из ADM : Systrace, TraceView, OpenGL Trace для контроля за выполнением приложения
C помощью этих инструментов можно полностью оценить, как выполняется приложение и оптмизировать его. Замечу, что по работе с каждым из них нужно писать отдельную статью (есть и книги по профилированию, ибо тема очень сложная), чтобы использовать их эффективно и понимать их вывод. К счастью эти статьи уже написаны и гугл знает где искать их все.

std::hash vs crc32

Какая функция используется для создания хэша в std::hash и насколько она предпочтительнее, чем обычный crc32? Предпочтениями являются меньшее число коллизий, более быстрый расчет. Основа - 32-х битная система. Выдержки из стандарта в качестве ответа не приветствуются.


Ответ

Основа - 32-х битная система.
Вы понимаете, что crc32 и разрядность вашей системы никак не соотносятся? crc32 использовался и в 16-битных ОС типа MS-DOS. И 32 - это просто размер итогового хэша в битах.
Какая функция используется для создания хэша в std::hash
std::hash это не функция, а шаблон, поэтому для хэширования различных типов он будет использовать разные алгоритмы хэширования, например, std::hash для int 1 вернет 1, поскольку хэш для числа - это само число.
Кроме того, вы не сказали, какую именно реализацию стандартной библиотеки C++ вы используете. В теории можно представить себе библиотеку, которая для всего хэширования использует crc32 (и работает очень плохо).
crc32 используется для небольших данных, зато быстрый. md5 в медленней, зато гораздо труднее нарваться на коллизию (32 бита < 128 бит в md5)
ответ на комментарии:
Я соотносил crc32 с хэшем c++11, а он в свою очередь зависит от битности оси. И для корректного сравнения они должны быть одной разрядности
зависит от стандарта ISO, потом от разработчика компилятора. как он реализует хэширование - его собственное дело, если не прописано в стандарте, и да, именно std::hash зависит от разрядности системы, вы правы.
The actual hash functions are implementation-dependent а это значит что и clang и msvc и gcc и все остальные могут реализовать их по-разному. Разве я спрашивал про md5 и его скорость? Он устарел. И там где мне необходимы хэши с минимальными коллизиями я его не буду использовать.
вот это новость. md5 уязвим к намеренным атакам (вы можете создать коллизию специально), поэтому он устарел как криптографический хэш (спасибо @D-side за правку) , но как функция хэширования - нет. (хорошее сравнение md5/sha1)
дефолтная функция для хэширования строк в gcc - MurmurHashUnaligned2
и вот вам абсолютно прекрасное сравнение различных алгоритмов хэширования

Почему один индекс Sphinx возвращает атрибуты вместе со значениями, другой - нет?

В моем конфиге настроены 2 индекса на индексацию 2-х таблиц MySQL:
#medicalfacilities source medicalfacilities : lsParentSource {
sql_query_range = SELECT MIN(idMedicalFacilities), MAX(idMedicalFacilities) FROM
medicalfacilities sql_range_step = 128
sql_query = SELECT idMedicalFacilities * 10 + 1 as id, 2000 as type,
idmedicalfacilities, MedicalFacilitiesName, medicalfacilitiesiduser, medicalfacilitiessite,
medicalfacilitiesemail, medicalfacilitiesphoto FROM medicalfacilities WHERE
idMedicalFacilities>=$start AND idMedicalFacilities<=$end
sql_attr_uint = idmedicalfacilities sql_attr_uint = type sql_attr_uint = MedicalFacilitiesIdUser sql_field_string = MedicalFacilitiesSite sql_field_string = MedicalFacilitiesName sql_field_string = MedicalFacilitiesPhoto sql_field_string = MedicalFacilitiesEmail sql_query_info = SELECT MedicalFacilitiesName, MedicalFacilitiesDescription \ FROM medicalfacilities WHERE idMedicalFacilities = ($id - 1) / 10
# Время засыпания в миллисекундах (sleep) перед отправкой запросов серверу (может быть
полезно для разгрузки сервера базы данных) sql_ranged_throttle = 0 }

#users source users : lsParentSource {
sql_query_range = SELECT MIN(idDetailToUsers), MAX(idDetailToUsers) FROM detailtousers sql_query = SELECT idDetailToUsers as id, 1000 as type, UsersTypeAccount,
idDetailToUsers, SpecializationName, DetailToUsersName, DetailToUsersPhoto, city, country FROM
detailtousers join users ON users.idUsers = detailtousers.idDetailToUsers left join
usersspecialization ON usersspecialization.UsersSpecializationIdUser =
detailtousers.idDetailToUsers left join specializationtousers ON
specializationtousers.idSpecialization = usersspecialization.UsersSpecializationIdSpecialization
WHERE idDetailToUsers >= $start AND idDetailToUsers <= $end GROUP BY idDetailToUsers
sql_attr_uint = type sql_attr_uint = idDetailToUsers sql_attr_uint = UsersTypeAccount sql_field_string = SpecializationName sql_field_string = DetailToUsersName sql_field_string = DetailToUsersPhoto sql_attr_uint = city sql_attr_uint = country
sql_query_info = SELECT idDetailToUsers, DetailToUsersName, UsersTypeAccount,
SpecializationName, DetailToUsersPhoto, city, country \ FROM detailtousers WHERE idDetailToUsers = $id sql_ranged_throttle = 0 }
Индексы:
index medicalfacilities { source = medicalfacilities path = /var/data/sphinx/medicalfacilities #enable_star = 1 charset_type = utf-8 html_strip = 1 #morphology = stem_ru min_word_len = 3 min_prefix_len = 3 #min_infix_len = 3 }
index users_index { docinfo = extern source = users path = /var/data/sphinx/users charset_type = utf-8 html_strip = 1 morphology = stem_enru min_word_len = 1 min_prefix_len = 0 min_infix_len = 1 enable_star = 1 }
Для индекса users возвращаются атрибуты со значениями, а для medicalfacilities - без.


Ответ

На первый взгляд проблема в этой части
sql_query_info = SELECT MedicalFacilitiesName, MedicalFacilitiesDescription \ FROM medicalfacilities WHERE idMedicalFacilities = ($id - 1) / 10
Зачем нужно выражение ($id - 1) / 10 ? Может заменить его на $id?
Кроме того у сфинкса есть SphinxQL. Т.е. можно писать запросы в него как в MySQL. Работает по протоколу mysql(т.е. можно присоединиться обычным mysql клиентом по указанному порту).
http://sphinxsearch.com/docs/latest/sphinxql.html

Динамическое программирование, алгоритм

Задача такая:
Дано положительное число n, целые числа в порядке возрастания p1 < p2 < ... < pk, и c1, c2, ..., ck (0 < k < 10^5; 0 <= n, pi < 10^9, 0 < ci < 10^9). pi - координаты точек на оси, ci - их веса. Нужно выбрать точки так, чтобы сумма их весов была максимальной, но расстояние между любой парой точек было не меньше n (n - расстояние на оси).
Я делал так - на i-м шаге для каждой точки запоминал число, равное максимальной допустимой сумме совокупности i точек с учётом их весов, расположенных по возрастанию, и оканчивающейся данной точкой.
В общем случае не работает (неверный ответ), но я не смог найти примеров с ошибкой. Помогите, пожалуйста, разобраться.

Тестовый пример (на обоих программа работает верно):
Ввод
4 10 5 10 15 20 100 50 100 300
Вывод
400 Ввод
5 15 2 14 25 31 37 8 19 20 11 25
Вывод
44

#include #include #include
std::vector f(const std::vector &first, const std::vector &v1, const std::vector &v2, int n1, int n2) { int a = -1000000000; std::vector ans(n1); for (int i = 0; i != n1; ++i) { if (v1[i] <= n2) { ans[i] = a; } else { std::vector A(n1); int j = 0; while (abs(v1[i] - v1[j]) > n2) { A[j] = first[j]; ++j; } int m = *std::max_element(A.begin(), A.end()); if (m == 0) { ans[i] = a; } else { ans[i] = m + v2[i]; } } } return ans; }
int main() { int n1, n2; std::cin >> n1 >> n2; std::vector v1(n1); for (size_t i = 0; i != n1; ++i) { std::cin >> v1[i]; } std::vector v2(n1); for (size_t i = 0; i != n1; ++i) { std::cin >> v2[i]; } std::vector ans; std::vector c = f(v2, v1, v2, n1, n2); ans.push_back(*std::max_element(c.begin(), c.end())); for (int i = 0; i != n1; ++i) { std::vector x = f(c, v1, v2, n1, n2); ans.push_back(*std::max_element(x.begin(), x.end())) c = x; } std::cout << *std::max_element(ans.begin(), ans.end()); return 0; }


Ответ

Учитывая, что все веса положительные, все точки удовлетворяющие вашему условию |P[i] - P[j]| < n, i # j и будут решением. Это очевидно.

Gitlab CI / Получить только apk

При сборке проекта можно скачать архив, но apk лежит в:
Artifact/app/build/outputs/apk/debug/
Как можно получать сразу apk?
Мой файл .gitlab-ci.yml
# This file is a template, and might need editing before it works on your project. # Read more about this script on this blog post https://about.gitlab.com/2016/11/30/setting-up-gitlab-ci-for-android-projects/, by Greyson Parrelli image: openjdk:8-jdk
variables: ANDROID_COMPILE_SDK: "25" ANDROID_BUILD_TOOLS: "24.0.0" ANDROID_SDK_TOOLS: "24.4.1"
before_script: - apt-get --quiet update --yes - apt-get --quiet install --yes wget tar unzip lib32stdc++6 lib32z1 - wget --quiet --output-document=android-sdk.tgz https://dl.google.com/android/android-sdk_r${ANDROID_SDK_TOOLS}-linux.tgz - tar --extract --gzip --file=android-sdk.tgz - echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter android-${ANDROID_COMPILE_SDK} - echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter platform-tools - echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter build-tools-${ANDROID_BUILD_TOOLS} - echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter extra-android-m2repository - echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter extra-google-google_play_services - echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter extra-google-m2repository - export ANDROID_HOME=$PWD/android-sdk-linux - export PATH=$PATH:$PWD/android-sdk-linux/platform-tools/ - chmod +x ./gradlew - mkdir -p $ANDROID_HOME/licenses/ && cp sdk-licenses/* $ANDROID_HOME/licenses/
stages: - build
build: stage: build script: - ./gradlew assembleDebug artifacts: paths: - app/build/outputs/
Строкой - app/build/outputs/apk/debug/app-debug.apk я получаю zip архив с единственным файлом app-debug.apk. Но мне нужно только apk без /app/build/outputs/apk/debug/ можно в архиве или только apk.


Ответ

Вы можете просто скопировать его - описав скрипт с копированием. В вашем случае так например:
script: ./gradlew assembleDebug; mv app/build/outputs/apk/app-debug.apk [ожидаемое_расположение]
, где [ожидаемое_расположение] - тот путь где вы хотите сохранить app-debug.apk после сборки.

Как обучить нейронную сеть с несколькими выходящими нейронами?

Всем привет.
Визуализация нейронной сети, которую я пытаюсь создать:
Вот что получилось:
private static final int LAYERS = 5;
private static final int INPUT_NEURONS = 3; private static final int HIDDEN_NEURONS = 4; private static final int OUTPUT_NEURONS = 3;
private static final Random random = new Random();
// inputNeurons
private static final float[][] weights1 = new float[INPUT_NEURONS][HIDDEN_NEURONS]; private static final float[] hiddenNeurons1 = new float[HIDDEN_NEURONS];
private static final float[][] weights2 = new float[HIDDEN_NEURONS][HIDDEN_NEURONS]; private static final float[] hiddenNeurons2 = new float[HIDDEN_NEURONS];
private static final float[][] weights3 = new float[HIDDEN_NEURONS][HIDDEN_NEURONS]; private static final float[] hiddenNeurons3 = new float[HIDDEN_NEURONS];
private static final float[][] weights4 = new float[HIDDEN_NEURONS][OUTPUT_NEURONS]; private static final float[] outputNeurons = new float[OUTPUT_NEURONS];
// Каждый bias нейрон равен 1, поэтому мы учитываем только вес при подсчете private static final float[][] biasWeights = new float[LAYERS - 1][];
private static final int MAX_EPOCH = 10000; private static final float LEARNING_RATE = 0.7F;
public static void main(String[] args) { initWeights(weights1); initWeights(weights2); initWeights(weights3); initWeights(weights4); initWeights(biasWeights);
}
private static void initWeights(float[][] weights) { for (int i = 0; i < weights.length; i++) { for (int j = 0; j < weights[i].length; j++) { weights[i][j] = randFloat(0.1F, 0.5F); } } }
public static float randFloat(float min, float max) { return random.nextFloat() * (max - min) + min; }
private static void train(float[][] inputs, float[][] outputs) { for (int i = 0; i < MAX_EPOCH; i++) { for (int j = 0; j < inputs.length; j++) { float[] result = getResult(inputs[j]);
float[] errors = new float[result.length];
for (int k = 0; k < result.length; k++) { float actual = result[k]; float expected = outputs[j][k]; errors[k] = expected - actual; }
} } }
private static float[] getResult(float[] inputNeurons) { if (inputNeurons.length != INPUT_NEURONS) { throw new IllegalArgumentException(); }
calculate(inputNeurons, weights1, hiddenNeurons1, biasWeights[0]); calculate(hiddenNeurons1, weights2, hiddenNeurons2, biasWeights[1]); calculate(hiddenNeurons2, weights3, hiddenNeurons3, biasWeights[2]); calculate(hiddenNeurons3, weights4, outputNeurons, biasWeights[3]);
return outputNeurons.clone(); }
private static void calculate(float[] neurons, float[][] weights, float[] nextNeurons, float[] biasWeights) { for (int i = 0; i < neurons.length; i++) { for (int w = 0; w < weights[i].length; w++) { nextNeurons[w] = nextNeurons[w] + neurons[i] * weights[i][w]; } }
for (int i = 0; i < nextNeurons.length; i++) { nextNeurons[i] = sigmoid(nextNeurons[i] + biasWeights[i]); } }
private static float sigmoid(float value) { return (float) (1 / (1 + Math.exp(-value))); }
Моя проблема заключается в том, что я не могу понять как ее правильно обучить используя метод обратного распространения ошибки. Я не нашел понятной мне информации о том как использовать этот метод на нескольких выходящих нейронах, в большинстве случаев все примеры и объяснения показываются на одном выходящем нейроне.
Основываясь на полученной информации об обучении на одном выходящем нейроне, я предположил, что формулы для меня будут выглядеть так:
После вычисления ошибок составлю формулы получения нового веса:
Правильно ли я сделал формулы? Так же я не уверен в правильности текущего кода.
Спасибо!


Ответ

Вообщем, не долго думая я решил перенести мои предположения в код. На мое удивление все начало работать замечательно, я проверил нейронную сеть на нескольких простых задача и результаты не стали себя долго ждать!
Спасибо всем, кто пытался помочь!

На чем сделать систему автополива и открытия/закрытия теплицы?

В общем-то, задача, которая стоит передо мной, описана в заголовке, сейчас опишу, как вижу процесс: 1. Компьютер - на данный момент обычный, в идеале Arduino. 2. Электроклапан (для отключения/включения подачи воды). 3. Электропривод стекла (для открывания форточек теплицы), думаю взять простой автомобильный. 4. Аккумулятор - тут вообще не знаю, что взять под это дело, не знаю, подойдет ли автомобильный. 5. Как-то воткнуть в это дело gsm модуль (3g модем как вариант).
Ну вот, в общем-то и все, то есть схема работы отправили смс с одним кодом, вода полилась, с другим остановилась и т.д. Потом можно будет датчики температуры воткнуть и тому подобные приколюхи! Но вот хотелось бы получить инфу от опытных людей, как все это организовать. Заранее спасибо!


Ответ

Raspberry PI2 и Arduino +gsm модуль + powerRalayPad (если ток большой).
По простому- микрокомпьютер Rasperry Pi2 (он с ардуиной вяжется, есть много всяких примеров в открытом доступе), ваша ардуино (достаточно просто в части написания кода под нее). gsm модуль для ардуины тоже есть, и есть примеры работы с ним и работы по командам принятым. PowerRelyaPad не что иное как управление силывами реле. Если меня не подводит память, то это на случай работы с 220в. Допускаю что мои познания в части плат управления выходами несколько устарели, но помнится мне есть плата управления выходами т.е. по сути подача питания на ваши подъемники.
И еще сразу решите задачу актуации положения окна т.к. вероятность того что сломается ЭСП существует. Посмотрите в сторону герконов или чего-то подобного сигнализациям на окна.
Почему пока что лучше использовать ардуино - простота в написании и доступность как примеров, так и компонентов. То, что у вас получится в итоге будет прототипом, на основе которого вы сможете исполнить реализацию на более правильных, с точки зрения отказоустойчивости, компонентов.

обтекание изображения текстом в EditText

Справа от ImageView в EditText должен вводиться текст. Если вдруг окажется что текст заполнил все пространство справа от ImageView, нужно чтобы текст продолжал вводиться под ImageView начиная от самого (левого) края экрана устройства. Схематически это представлено на прикрепленном рисунке.
Сразу скажу что подобный вариант чудесно работает с TextView, но не хочет сотрудничать с EditText. Прошу не оставаться равнодушными и подсказать хотя бы направление решения моей проблемы.


Ответ

После нескольких экспериментов и изучения EditText/TextView оказалось, что в TextView (в котором собственно и задано все необходимое для редактирования текста) есть ошибки (или недоделки) из-за которых он при отрисовке курсора и выделения не принимает во внимание span текста.
В результате текст в EditText при использовании LeadingMarginSpan отрисовывается правильно, а выделение и курсор ведут себя так, как будто текст занимает прямоугольник (за исключением первой строки).
Чтобы это реализовать надо делать свой кастомный TextView и править в нем баги доделывать недоделки. Учитывая, что TextView содержит порядка 10000 строк кода это будет непросто.

Сделать приоритет для маски телефона используя jquery.inputmask

Для телефона написал такую маску:
$("#phone").inputmask("(8 999 999 99 99)|(+7 999 999 99 99)|(+7 99999 9 99 99)|(8 99999 9 99 99)|(+7 9999 99 99 99)|(8 9999 99 99 99)");
Как можно сделать, чтобы именно первая маска (мобильного телефона) была в приоритете и подставлялась первой при заполнении поля?


Ответ

Самым гибким вариантом будет для вас, повесить слушатель события keyup и менять маски в зависимости от введенного значения. Приведу пример смены маски для номеров с 8 или +7. При таком подходе вы сможете полностью контролировать приоритет маск и кейсы их применения относительно введенного значения.
let $phone = $('#phone'); //Маска по умолчанию $phone.inputmask("9 999 9999-999"); $phone.on("keyup", function(event) { //Получаем значение поле без маски var value = $(event.target).inputmask("unmaskedvalue"); //Далее могут быть любые проверки, чтобы изменить маску на нужную.. //Например:сделаем для номеров +7 if (value.length === 2 && value === "+7") { $phone.inputmask("+7 (999) 999-99-99"); } //Если поле очистили, уберем маску и значение, можем еще вернуть маску по умолчанию при необходимости if (value === "") $phone.inputmask('remove').val(""); });

Обработка текстовых файлов

Есть задача по обработке и преобразованию файлов. Все файлы представляют собой аналог CSV(текст с разделителями)
дано два или более файлов. Необходимо "склеить" их по некоторым полям и выдать уже один, обработанный файл дан один файл. Необходимо выполнить преобразование полей, склейку из нескольких строк в одну и т.д. и тоже выдать один, обработанный файл.
Проблема в том, что единой структуры файлов нет. Т.е. файлы/пары файлов могут быть различны по полям/структуре
На данный момент идея по такой обработке таких файлов только одна:
Грузим файл/файлы в некую БД(in-memory, к примеру), предварительно в runtime прочитав структуру файла - создаем таблицы по структуре Выполняем некий SQL скрипт, на основании результатов которого формируем выходной файл
Вопрос: может есть какие-то наработанные алгоритмы/библиотеки по подобному преобразованию/обработке, чтобы не городить "велосипед"?
UPD: чтобы избежать привязки к структуре, конечно можно использовать некую NoSql, но тогда лишимся полноценной силы SQL


Ответ

Можно записать файл построчно в таблицу, например c колонками DOC_NAME, ROW_NUMBER, ROW_CONTENT
в DOC_NAME - имя файла в ROW_NUMBER - номер строки в ROW_CONTENT - считываем строку из файла, например, Имя;Фамилия;Год_Рождения;Место_рождения - Петр;Семенов;12.12.1980;г. Москва
Далее это строчку можно распарсить с помощью sql по столбцам и вставить в заранее подготовленную таблицу:
INSERT INTO PARSED_TABLE1 SELECT TRIM(SUBSTR(CON,0,INSTR(CON,CHR(59))-1)) NAME, TRIM(SUBSTR(CON,INSTR(CON,CHR(59),1,1)+1,INSTR(CON,CHR(59),1,2)- INSTR(CON,CHR(59),1,1)-1)) SURNAME, TRIM(SUBSTR(CON,INSTR(CON,CHR(59),1,2)+1,INSTR(CON,CHR(59),1,3)- INSTR(CON,CHR(59),1,2)-1)) BIRTHDAYDATE, TRIM(SUBSTR(CON,INSTR(CON,CHR(59),1,3)+1)) BIRTHPLACE FROM ( SELECT ROW_CONTENT CON FROM CONTENT_TABLE WHERE DOC_NAME="doc.csv")
По аналогии делаем запрос для заполнения PARSED_TABLE2, из 2-х таблиц склеиваешь новую как пожелаешь, можно сразу и без PARSED_TABLE склеивать. CHR(59) - это символ ; в ANSII
Вот также хорошая статья на тему чтения из .csv в Oraсle БД http://torofimofu.blogspot.ru/2015/10/oracle-csv.html

Аналог конфигурации object_parallel_to_source для moc_ файлов

Нашел, по слухам, недокументированную, конфигурацию qmake, позволяющую размещать объектные файлы в отдельных папках в соответствии со структурой самого проекта.
CONFIG += object_parallel_to_source
Это нужно, когда вы держите несколько классов с одинаковыми именами в разных неймспейсах, чтобы иметь одинаковые именна файлов для этих классов в разных директориях (действительно, глупо каждый раз создавать еще и разные имена файлов).
Если это классы не унаследованны от QObject все работает прекрасно, однако в обратном случает qmake создает moc_ClassName (.cpp .h) файлы, для которых правило для объектных файлов не действует, то есть все кидается в одну директорию.
Допустим мы создали два класса ActionDouble в двух разных неймспейсах и папках:
namespace Concept002 {
class ActionDouble : public Action { Q_OBJECT public: ActionDouble(QObject *parent = 0);
... };
}
и
namespace Concept003 {
class ActionDouble : public Action { Q_OBJECT public: explicit ActionDouble(QObject *parent = 0);
... signals:
public slots: };
}
получаем предупреждения и ошибки:
warning: overriding recipe for target 'moc_ActionDouble.cpp' warning: ignoring old recipe for target 'moc_ActionDouble.cpp'
и как следствие:
error: undefined reference to `vtable for Concept002::ActionDouble'

Собственно, в этом и состоит вопрос, может кто знает флаг конфигурации qmake (или же другой способ разрешения вышеописанной проблемы - иметь несколько классов в разных папках и разных неймспейсах с одним и тем же именем, и унаследованных от QObject), позволящий генерировать moc_ файлы в разных папках в соотвествии со струкурой проекта. Или, например, может быть можно сформировать моки как moc_Namespace_ClassName?


Ответ

Приложения делю на статик либы(ей же присваивается неймспейс). В одной либе нет дублирующихся имен. Причем использую подпроекты и руками указываю диру сборки по умолчанию объявляю ./build/[TARGET_ARCH] TARGET_ARCH добавляю через mkspec или в IDE Проекты -> сборка -> qmake -> Доп. параметры.
isEmpty(TARGET_ARCH){ TARGET_ARCH=x86 } BASE_PATH=$$PWD/$$TARGET_ARCH OBJECTSDIR = $$BASE_PATH/obj/$${MODULE_NAME}/$${BUILD_TYPE} DESTDIR = $$BASE_PATH/lib
Структура проекта
Module1 Module (namespace Module1) ClassA.cpp (Module1::ClassA) Test ClassA.cpp (тут unit test Fixture|Mocks) Module2 Module (namespace Module2) ClassA.cpp (Module2::ClassA) Test ClassA.cpp (тут unit test Fixture|Mocks)
Так заборол дублирующиеся имена объектников.

Одна переменная на несколько процессов в Python

По совету @andreymal из моего предыдущего вопроса:
Если разными частями приложения являются разные процессы, то для этого надо организовывать межпроцессное взаимодействие, чтобы один процесс работал с соединениями, а другие процессы отправляли этому процессу сообщения. Можно для этого написать свой велосипед на сокетах, можно для этого использовать готовые решения вроде RabbitMQ и Redis.
Пытаюсь реализовать межпроцессное взаимодействие при помощи celery.
Исходные данные и какую задачу нужно решить: К серверу по вебсокетам должны подключаться клиенты (люди, использующие браузер) и ожидать сообщений от сервера. На сервере время от времени срабатывает процесс, генерирующий это самое сообщение. Это сообщение (которое нужно отдать клиенту) можно попросить у процесса передать в указанный скрипт.
Что для этого сделано:
Обработчик сокет-соединений на Python tornado; .py скрипт, которому на stdin подается сообщение от процесса, который генерирует само сообщение; функция-таск для celery, которая должна отправить сообщение в браузер.
То есть, процесс генерирует сообщение -> вызывает скрипт, передавая ему сообщение на stdin -> скрипт вызывает celery таск -> таск берет массив соединений и рассылает им сообщение.
Суть проблемы: Сокет сервер складывает все соединения в массив, но этот массив оказывается пустым для celery таска.
Собственно, вопрос: как завести один массив на несколько процессов, или где я налажал, и как это делать правильно?
UPD добавил упрощенный код для понимания того, как и что есть. Сокет-сервер на tornado:
class SocketHandler(tornado.websocket.WebSocketHandler): connections = []
def open(self): self.__class__.connections.append(self)
@classmethod def get_connections(cls): return cls.connections
и celery таск, который должен отправлять сообщения клиентам:
from handlers import SocketHandler
@celery.task def send_msg(msg): for conn in SocketHandler.get_connections(): conn.write_message(msg)
Но список полученный путем SocketHandler.get_connections() в файле с celery тасками оказывается пустым. Запускаю все это в разных терминалах так:
(venv)$ python app.py # это торнадо апп, импортирующий приведенный handlers (venv)$ celery -A tasks worker


Ответ

Из описания проблемы и документации Celery я так понимаю, что таски выполняются в отдельных воркерах, которые может запускать сам Celery, но суть в том, что таск должен выполняться в одном процессе с сокет-сервером, тогда массив с сокетами ему будет виден. Пробежавшсь по диагонали по документации Celery, я подобного не нашёл; если это на нём и правда невозможно, то, видимо, стоит взять что-то попроще.
Вообще я представляю это как-то так (несколько кривенько, но, думаю, суть должна быть понятна):
def queue_thread(): while thread_should_work(): msg = redis.blpop("websocket_queue", timeout=5) if not msg: continue data = pickle.loads(msg[1]) send_message_to_all_sockets(data)
Threading.thread(target=queue_thread).start()

Как закрасить сектора картинки приведенной ниже?

Рисую примерно так:
canvas.drawCircle(0, 0, 100, paint); canvas.drawCircle(20, 20, 50, paint); canvas.drawLine(0,50,100,50, paint); canvas.drawLine(50,0,50,100, paint);
Как раскрасить сектора программно?


Ответ

Раз вы решили рисовать линиями (drawLine), то надо так и продолжать. Для начала у вас должна быть логика, определяющая все ваши границы, а потом уже приступать к рисованию. Я взял центр окружности и закрасил левую четверть зеленым цветом.
public class MyView extends View { Paint paint;
public MyView(Context context) { super(context); init(); } private void init(){ // значения по умолчанию paint = new Paint(); paint.setColor(Color.BLUE); paint.setStrokeWidth(5); paint.setStyle(Paint.Style.STROKE); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawLine(100,100,200,100, paint); // startX, startY, stopX, stopY линии диаметра canvas.drawLine(150,50,150,150, paint); canvas.drawLine(143,98,143,52, initGreen()); //закраска зеленым canvas.drawLine(135,98,135,55, initGreen()); //двигаем закраску по оси Х canvas.drawLine(127,98,127,58, initGreen()); //двигаем закраску по оси Х canvas.drawLine(120,98,120,61, initGreen()); //двигаем закраску по оси Х canvas.drawLine(113,98,113,61, initGreen()); //двигаем закраску по оси Х canvas.drawLine(105,98,105,63, initGreen()); //двигаем закраску по оси Х canvas.drawCircle(150, 100, 50, initBlue()); } private Paint initGreen(){ paint.setStrokeWidth(10); paint.setColor(Color.GREEN); return paint; } private Paint initBlue(){ paint.setStrokeWidth(5); paint.setColor(Color.BLUE); return paint; } }

Как реализовать обязательный вызов метода базового класса?

Столкнулся с интересной проблемой при написании программы на с++, есть класс родитель, есть его наследник, в наследнике я переопределяю какую-то функцию, но хочу вызвать и функцию базового класса, решение очевидное и простое
class A { public: virtual void Func() { //do something } }
class B : A { public: void Func() override { A::Func(); //aditional logic } }
Все работает и все классно, только меня смущает дублирование кода я должен вызывать метод базового класса во всех наследниках, а что страшнее теоретически могу забыть этот вызов и будут странные ошибки. Решение тоже пришло быстро, решил сделать вот так
class A { public: virtual void Func() final { //do something FuncInternal(); } protected: virtual void FuncInternal() = 0; }
class B : A { void FuncInternal() override { //aditional logic } }
Теперь всегда отработает сначала метод базового класса, потом наследника, но понял что если уровень наследования будет больше 2 то мне будет нужно вводить FuncInternal1, FuncInternal2 и т.д. И вот тут я завис, как мне решить задачу по избавлению от дублирования вызова базовой функции во всех потомках таким образом, чтоб реализация не отличалась в зависимости от количества наследников.
Думаю что я что-то упускаю из общих знаний ООП, привязка к языку не обязательна. Спасибо
UPDATE1
Источник проблемы в задумке сделать абстрактный класс-интерфейс, к примеру, IRenderable, и если есть объект который наследуется от такого класса Monster : IRenderable, то я уверен что у Monster будет функция рендер и что при обращению к этой функции будет проведен некий единый набор действий описанных в IRenderable.


Ответ

Поскольку вы пишете, что конкретный язык вам безразличен, вот вам пример с честной рефлексией на C#.
Идея: вызывать «родительскую» имплементацию не нужно, вместо этого каждый из порождённых классов может, если захочет, добавить свою имплементацию метода. Базовый метод вызывает все имплементации по очереди.
Классы выглядят при этом так:
class C1 { public void F(int x) { // вызываем в цикле все имплементации foreach (var impl in Util.GetAllImplementations>(this, "FImpl")) impl(x); }
// имплементация в C1 private void FImpl(int x) => Console.WriteLine($"From C1::F({x})"); }
class C2 : C1 { // тут нету имплементации }
class C3 : C2 { // имплементация в C1 private void FImpl(int x) => Console.WriteLine($"From C3::F({x})"); }
Класс-утилита (ужасы рефлексии):
static class Util { static public IEnumerable

GetAllImplementations
(object obj, string name) { Type[] argTypes = GetArgTypes(typeof(DT)); for (Type curr = obj.GetType(); curr != null; curr = curr.BaseType) { var method = curr.GetMethod( name, BindingFlags.NonPublic | BindingFlags.Instance, null, argTypes, null); if (method == null) continue; yield return (DT)(object)Delegate.CreateDelegate(typeof(DT), obj, method); } }
static Type[] GetArgTypes(Type delegateType) { if (delegateType == typeof(Action)) return new Type[0]; if (!delegateType.IsGenericType) throw new ArgumentException("Expected delegate type"); var typedef = delegateType.GetGenericTypeDefinition(); var isFunc = (typedef.Name.StartsWith("Func`")); var isAction = (typedef.Name.StartsWith("Action`")); if ((!isFunc && !isAction) || typedef.Namespace != "System") throw new ArgumentException("Expected delegate type"); var argTypes = delegateType.GetGenericArguments(); if (isFunc) Array.Resize(ref argTypes, argTypes.Length - 1); return argTypes; } }
Запускаем, получаем результат:
class Program { static void Main(string[] args) { new C3().F(1); } }
From C3::F(1) From C1::F(1)

Уверен, что на C++ можно получить такой же результат при помощи какой-нибудь шаблонной магии.

Как использовать Sphinx в Yii2 + PostgreSQL?

Не до конца понимаю, возможно ли использование Sphinxsearch в Yii2 в качестве поискового движка в связке с PostgreSQL? В экстеншене: Yii2-sphinx говорится про MySQL, но про PgSQL ни слова. Сам экстеншен устанавливается, и конфиг вида:
'components' => [ 'sphinx' => [ 'class' => 'yii\sphinx\Connection', 'dsn' => 'pgsql:host=localhost;port=5432;dbname=testdb', 'username' => 'yii', 'password' => '********', ], ]
ошибок не вызывает, даже при отсутствии Sphinx на сервере. В связи с вышеизложенным возникает ряд вопросов:
Подходит ли данный экстеншен для использования его с PgSQL. Если да, где про это можно почитать, или посмотреть реальные примеры (Yii2 + PgSQL + Sphinx)? Стоит ли использовать его, или лучше что-то другое, вроде: pg-sphinx? Стоит ли вообще его использовать, быть может есть решения быстрее и проще?
Стэк: Debian, Nginx, FPM, PHP7, Yii2, PgSQL
UPD Вопрос всё ещё актуален! :)


Ответ

Первая фраза по ссылке yii2-sphinx в блоке Configuration, говорит о том, что используется только протокол MySQL:
This extension interacts with Sphinx search daemon using MySQL protocol and SphinxQL query language.
По идее, Вы можете попробовать добавить 'pgsql' => 'yii\sphinx\Schema' в массив $schemaMap, в файле Connection.php (в основной директории модуля), и, скорее всего простые запросы даже будут отрабатывать, но, как только будет более-менее сложный запрос, гарантирую, что Вы получите ошибку.
Лучшим вариантом будет использование расширения pg-sphinx или похожее, если Вам действительно нужен Sphinx. В противном случае, попробуйте обычный полнотекстовый поиск, возможно, для ваших целей хватит и его.

{} + [] + {} = [object Object][object Object]?

Пытаюсь разобраться в некоторых тонкостях js. {} + [] = 0 , потому что {} будет восприниматься как пустой блок кода, а + [] приведется к числу, т.е. к 0, окей.
А почему {} + [] + {} = "[object Object][object Object]" ? Ну т.е. я ожидал, что тут будет 0 + {} и выдаст что-то типа "0[object Object]". Почему так?


Ответ

Вообще, это от браузера зависит. Как я понимаю, вы это проверяете в Хроме, а там оборачивается всё, что начинается с { и заканчивается }
В Firefox выводится ожидаемое "0[object Object]"

Java. Поиск в многострочном тексте при помощи регулярного выражения

Доброго времени суток, в Java я новичок, поэтому тапками не кидайте, если спрашиваю очевидную вещь. Однако, гугл мне в моём вопросе не смог помочь. Есть текст вида:
"Белеет парус одинокой В тумане моря голубом!.. Что ищет он в стране далекой? Что кинул он в краю родном?..."
И тут у меня возникает два вопрос: 1) Как поместить этот текст в одну переменную. 2) Если это невозможно (размещение многострочного текста в переменной), то как реализовать поиск по регулярке, если, к примеру мне требуется данный отрывок:
голубом!.. Что
Т.е. должно срабатывать регулярное выражение вида:
[а-я]+[!.]+
[а-яА-Я]+


Ответ

Массивы текстовых данных, в т. ч. состоящие из отдельных строк, могут существовать в Java как в виде наборов строковых элементов (массив, ArrayList и т.п.), так и в виде отдельной строки, содержащей символы перенеоса строк ("
" или "
", в зависимости от системы). Если данные читаются из файла, то, как правило, они читаются методом readLine() одного из классов-потомков Reader , по одной строке за раз, и в этом случае со строками можно поступать как с элементами массива.
Если текст хранится в виде набора строк, то все эти строки можно объединить используя StringBuilder (последовательно в цикле добавляя к нему строку за строкой) или методом String.join(). Второй вариант может быть чуть удобнее, но он может оказаться дороже в смысле памяти и быстродействия.
Когда строки объединены тем или иным способом, можно использовать регулярку для поиска в объединенной строке. Пример кода ниже показывает объедининие строк обоими методами и описание единой строки, содержащей символы переноса строк.
import java.util.regex.Matcher; import java.util.regex.Pattern;
public class Ru_So_756552 {
public static String[][] testData = {
{ "Белеет парус одинокой
" + // array of 1 string "В тумане моря голубом!..
" + "Что ищет он в стране далекой?
" + "Что кинул он в краю родном?..." },
{ "Мой дядя самых честных правил,
" + "Когда не в шутку занемог,
" + "Он уважать себя заставил
" + "И лучше выдумать не мог" },
{ "Белеет парус одинокой", // Array of 4 strings "В тумане моря голубом!..", "Что ищет он в стране далекой?", "Что кинул он в краю родном?..." },
};
public static void main(String[] args) { Pattern pattern = Pattern.compile("([\\wА-Яа-я]+!\\.{2}\
[\\wА-Яа-я]+)"); for (String[] data: testData) {
System.out.println("*** Data:"); StringBuilder sb = new StringBuilder(); for (String s: data) { System.out.println(s); sb.append(s + "
"); // Concatenate using StringBuilder }
String joint = String.join("
", data); // Concatenate using join() System.out.println("*** Joint data:
" + joint);
Matcher m = pattern.matcher(sb); System.out.println("*** Found:
" + (m.find()? m.group(1) : "nothing... :(")); m = pattern.matcher(joint); System.out.println("*** Found in joint:
" + (m.find()? m.group(1) : "nothing... :(") + "
");
} // for (String[] data: testData) { } // public static void main(String[] args) {
} // public class Ru_So_756552

websocket выключается из-за простоя PHP

Возникли проблемы с веб-сокетом. Работает отлично, все супер, но если сокетом никто не пользуется больше 1 минуты, он выключается. Спустя минуту простоя я получаю "CloseEvent" c кодом "1000" на любой запрос. Когда подключен хотя бы один пользователь проблема решается пинг-понгом, но когда нет ни одного пользователя сокет висит без дела. Вроде уже указал все конфигурации связанные с timeout-ом, но не помогло.
Сокет реализован с помощью библиотеки: https://github.com/pmill/php-chat
Проверял на Open Server. Используется Apache в связке с Nginx.


Ответ

Кто бы мог подумать что проблема будет в конфигах MySQL.
Спустя минуту бездействия база автоматически прерывает соединение с ней, а у меня при любом запросе происходила проверка прав пользователя.
Для решения проблемы в mysql.ini нужно установить свойство wait_timeout в секундах сколько вам необходимо, у меня стояло по умолчанию 60
Так же прошу заметить что есть вариант "Б", если его таковым можно назвать.
Для обхода проблемы можно воспользоваться "Supervisor", он в таких случаях решает следствие, а не причину.
Он автоматически запускает или перезапускает сервер когда тот упал или недоступен. Для примера можно воспользоваться этим туториалом для установки и настройки Supervisor.

Программируемые игры [закрыт]

Хотелось бы попробовать поиграть в программируемые игры. Что-то типа "CeeBot", но немного посложнее.
Желательно язык С++/Java/C# или свой, но похожий на них. Так же желательно наличие графической составляющей, а не консольной.
Если Вы знакомы с такими играми, буду очень рад получить их названия или даже полезные ссылочки.


Ответ

Linux-овский Robocode - весьма интересный проект, предлагающий программировать танк на уничтожение себе подобных. Программирование на Java.

Почему (не)стоит использовать шаблонизатор?

Собственно сабж. Часто попадаю в конфликтные ситуации по этому поводу, которые часто заканчиваются совокуплением с мамой чьей-либо стороны.
Многие "выбирают" шаблонизаторы из-за того, что php отдельно, html отдельно... Но чем плох такой вариант:
PHP:
$title = "Some Title"; $text = "Some Text"; $images = array( 0 => "img1", 1 => "img2", 2 => "img3" );
require "template.html";
HTML:


По сути же: шаблонизатор — это php, написанный на php... Или я что-то упускаю?
Ссылаться на популярность Smarty среди верстальщиков не катит
Ответ аля это стандарт де-факто меня тоже не устраивает


Ответ

Однозначного ответа тут нет. Самый главные вопросы: Как вам удобнее с ним или без? Вы делаете для себя или для людей? Мне удобнее работать со Smarty. {$aaa}

{foreach $images AS $img} {/foreach} Только не стоит забывать о том, что помимо тупой передачи чего-то в шаблон, шаблонизатор имеет массу других полезных фич. Если делаете для себя, то делайте как удобнее. Если для других, то возможно шаблонизатор будет удобнее.

Как сверстать шестиугольные ячейки с картинками и ховером?

Задача сверстать блоки, с изображением и ховером (цвет случайный), блок является ссылкой.

сначала попробовал с css3, подсмотрел http://kizu.ru/fun/polygons/ , но возникла сложность с закруглением граней фигуры, плюс еще внутренняя граница позже подумал насчет canvas, но опять же углы плюс не разу с canvas не работал.
после прочтения документации по canvas словил пятничный ступор мозга, подскажите в каком направлении стоит продолжать?


Ответ

Найдено на англоязычном stackoverflow, добавьте border-radius и будет то, что вам нужно. https://stackoverflow.com/questions/10062887/generate-repeating-hexagonal-pattern-with-css3 Сразу демо
body { background-color: white; } .hexrow { white-space: nowrap; /*right/left margin set at (( width of child div x sin(30) ) / 2) makes a fairly tight fit; a 3px bottom seems to match*/ margin: 0 25px 3px; } .hexrow > div:hover > span { opacity: 1; z-index: 3; color: white; } .hexrow > div:hover { background-color: rgb(199, 155, 101); background-image: none !important; z-index: 2; } .hexrow > div:hover > div:first-of-type { background-color: rgb(199, 155, 101); background-image: none; z-index: 2; } .hexrow > div:hover > div:last-of-type { background-color: rgb(199, 155, 101); background-image: none; z-index: 2; } .hexrow > div { border-radius: 10px; width: 104px; height: 173.2px; /* ( width x cos(30) ) x 2 */ /* For margin: right/left = ( width x sin(30) ) makes no overlap right/left = (( width x sin(30) ) / 2) leaves a narrow separation */ margin: 0 25px; position: relative; background-image: url(http://i1166.photobucket.com/albums/q605/Artem_Lebedev/dog-training-collars.jpg); background-position: -50px 0; /* -left position -1 x width x sin(30) */ background-repeat: no-repeat; background-size: auto 120%; color: #000000; text-align: center; line-height: 173.2px; /*equals height*/ display: inline-block; } .hexrow > div:nth-child(odd) { top: 43.3px; /* ( width x cos(30) / 2 ) */ } .hexrow > div:nth-child(even) { top: -44.8px; /* -1 x( ( width x cos(30) / 2) + (hexrow bottom margin / 2)) */ } .hexrow > div > div:first-of-type { border-radius: 10px; position: absolute; width: 100%; height: 100%; top: 0; left: 0; z-index: -1; overflow: hidden; background-image: inherit; -ms-transform: rotate(60deg); /* IE 9 */ -moz-transform: rotate(60deg); /* Firefox */ -webkit-transform: rotate(60deg); /* Safari and Chrome */ -o-transform: rotate(60deg); /* Opera */ transform: rotate(60deg); } .hexrow > div > div:first-of-type:before { content: ''; position: absolute; width: 206px; /* width of main + margin sizing */ height: 100%; background-image: inherit; background-position: 0 0; background-repeat: no-repeat; background-size: auto 120%; bottom: 0; left: 0; z-index: 1; -ms-transform: rotate(-60deg) translate(-150px, 0); /* IE 9 */ -moz-transform: rotate(-60deg) translate(-150px, 0); /* Firefox */ -webkit-transform: rotate(-60deg) translate(-150px, 0); /* Safari and Chrome */ -o-transform: rotate(-60deg) translate(-150px, 0); /* Opera */ transform: rotate(-60deg) translate(-150px, 0); -ms-transform-origin: 0 0; /* IE 9 */ -webkit-transform-origin: 0 0; /* Safari and Chrome */ -moz-transform-origin: 0 0; /* Firefox */ -o-transform-origin: 0 0; /* Opera */ transform-origin: 0 0; } .hexrow > div > div:last-of-type { content: ''; position: absolute; border-radius: 10px; width: 100%; height: 100%; top: 0; left: 0; z-index: -2; overflow: hidden; background-image: inherit; -ms-transform: rotate(-60deg); /* IE 9 */ -moz-transform: rotate(-60deg); /* Firefox */ -webkit-transform: rotate(-60deg); /* Safari and Chrome */ -o-transform: rotate(-60deg); /* Opera */ transform: rotate(-60deg); } .hexrow > div > div:last-of-type:before { content: ''; position: absolute; width: 206px; /* starting width + margin sizing */ height: 100%; background-image: inherit; background-position: 0 0; background-repeat: no-repeat; background-size: auto 120%; bottom: 0; left: 0; z-index: 1; /*translate properties are initial width (100px) and half height (173.2 / 2 = 86.6) */ -ms-transform: rotate(60deg) translate(100px, 86.6px); /* IE 9 */ -moz-transform: rotate(60deg) translate(100px, 86.6px); /* Firefox */ -webkit-transform: rotate(60deg) translate(100px, 86.6px); /* Safari and Chrome */ -o-transform: rotate(60deg) translate(100px, 86.6px); /* Opera */ transform: rotate(60deg) translate(100px, 86.6px); -ms-transform-origin: 100% 0; /* IE 9 */ -webkit-transform-origin: 100% 0; /* Safari and Chrome */ -moz-transform-origin: 100% 0; /* Firefox */ -o-transform-origin: 100% 0; /* Opera */ transform-origin: 100% 0; } .hexrow > div > span { display: inline-block; margin: 0 -30px; line-height: 1.1; vertical-align: middle; white-space: normal; opacity: 0; position: relative; } .hexrow:nth-child(2) > div:nth-child(1) { background-image: url(http://i724.photobucket.com/albums/ww244/NBAchikk1995/flowers.jpg); } .hexrow:nth-child(2) > div:nth-child(1) > span { /*change some other settings*/ margin: 0 -20px; color: black; font-size: .8em; font-weight: bold; } .hexrow:nth-child(2) > div:nth-child(2) { background-image: url(http://i197.photobucket.com/albums/aa231/sterling_red/landscape.jpg); color: #ffffff; } .hexrow:nth-child(2) > div:nth-child(3) { background-image: url(http://i257.photobucket.com/albums/hh204/h22prld98/2157781306_7a7a8e4cf7.jpg); opacity: .3; color: #ffffff; } .hexrow:nth-child(2) > div:nth-child(3) > div:before { /* nothing special needed here */ } .hexrow:nth-child(2) > div:nth-child(4) { background-image: url(http://i916.photobucket.com/albums/ad8/paulak100/Obraz395.jpg); /*you can shift a large background image, but it can get complicated best to keep the image as the total width (200px) and height (174px) that the hex would be. */ background-position: -150px -20px; } .hexrow:nth-child(2) > div:nth-child(4) > div:before { background-position: -100px -20px; /* the left shift is always less in the pseudo elements by the amount of the base shift */ }

Any text you would like (that fits).
Really, change the text to say what you want!
I'm not kidding here.
Okay?
Did I mention you can change images? I mean, really, these are just rectangular images "cropped" to a hex shape (well, more complicated than just a crop, but the result is the same).
See, another image!
Testing opacity.
Satisfied?

Imgproc.FindContours не заполняет List контуров Opencv Android

Использую OpenCV4Android версии 2.4.11 (разработка ведется под Xamarin.Android). Я пытаюсь найти Границы прямоугольного объекта(лист бумаги формата А4) посредством OpenCV. Пытаюсь реализовать следующий алгоритм: Canny edge -> Largest contour -> largest rectangle -> find corners -> perspective change.
Вот мой код:
using(Bitmap _img = BitmapFactory.DecodeFile(App._file.Path)) { if (_img != null) { m = new Mat(); grayM = new Mat();
Utils.BitmapToMat(_img, m); //apply filter Imgproc.Canny(m, m, 100, 100, 3, true); //gaus Blur Imgproc.GaussianBlur(m, m, new Org.Opencv.Core.Size(5, 5), 5); //list for contours List < MatOfPoint > Contours = new List < MatOfPoint > (); Mat hierarcy = new Mat(); //our method to find contours,via filling List(Contours) Imgproc.FindContours(m, Contours, hierarcy, Imgproc.RetrList, Imgproc.ChainApproxSimple);
System.Console.WriteLine(Contours.Count + " Contours founded"); //Dont know why,but Contours list is always empty(no values) if (Contours.Count != 0) { MatOfPoint temp = Contours[0]; } }
И тут я застрял, потому что не понимаю, почему FindContours не заполняет значениями мой список List(всегда пустой). Перепробовал наверное все,все равно не хочет. В чем же может быть проблема?
Так же,довольно странная проблема: Исходное изображение #1 если я использую только такие методы, как Imgproc.Canny и Imgproc.GaussianBlur , то тогда результат выглядит примерно так(контуры обведены отлично):
В противном случае,а именно когда я использую метод Imgproc.FindContours,то результат выглядит гораздо хуже,ежели без использования самого метода(нахождения контуров),к тому же List он не заполняет,т.е. лист остается пустым,после инициализации:
Другое исходное изображение #2: без использования метода Imgproc.FindContours(только Imgproc.Canny вместе с Imgproc.GaussianBlur) : а здесь уже применяется FindContours метод :
Все же не могу понять,где моя ошибка. Может кто то подсказать\объяснить что я делаю не так,а так же как мне достичь моей цели? Заранее благодарю!
PPS позже выложу результаты альтернативных алгоритмов(к примеру,через HoughLinesP или FeatureDetector.Fast)


Ответ

После того как было потрачено куча времени,я пришел к выводу,что это просто напросто Баг, т.к. скорей всего не корректно спортировался этот метод(а что именно не так встало,не понятно). Решением проблемы может быть:
Установка новой версии(к примеру OpenCV 3.0.0). Заимплементить Java Wrapper класс,который можно будет подключить к проекту и успешно юзать(через мир Java'ы).
Такие вот дела.
PS в нативной форме все работает как часы.

Как правильно обфусцировать код используя ProGuard?

Решил сделать обфускацию кода своего Android проекта. В интеренете прочитал что от хакеров можно защитить приложение используя ProGuard или DexGuard. Как правильно нужно настроить проект чтобы заработал ProGuard (я использую Gradle)? Как потом убедиться что он работает и что он поменял имена классов и методов? Может есть какие нибудь другие обфускаторы которые справляются с задачей лучше чем ProGuard? Спасибо за ответ.


Ответ

В Gradle --> build.gradle
buildTypes { release { minifyEnabled true //обфускация shrinkResources true //удаление мусора proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }
Для надежности можете перевести программу на модульный режим/подгружать dex, который у вас будет полность обфусцирован и уже в самой программе, перед прогрузом, будет проводиться деобфускация

Сенсорный ScrollBar

Для активации сенсорной прокрутки ScrollViewer достаточно установить PanningMode в Both. Однако, это не даёт возможности использовать Thumb ScrollBar'а при сенсорном взаимодействии. Как включить возможность сенсорной прокрутки за счёт захвата thumb'а?


Ответ

Предлагаю следующее решение:
double thumbHeight, startPos = 0;
private void ScrollViewer_PreviewStylusDown(object sender, StylusDownEventArgs e) { ScrollViewer scrollViewer = sender as ScrollViewer; DependencyObject parent = VisualTreeHelper.GetParent(scrollViewer.InputHitTest(e.GetPosition(scrollViewer)) as DependencyObject);
if (parent is System.Windows.Controls.Primitives.Thumb) { thumbHeight = (parent as System.Windows.Controls.Primitives.Thumb).ActualHeight; startPos = e.GetPosition(parent as IInputElement).Y; scrollViewer.PanningMode = PanningMode.None; Mouse.Capture(scrollViewer); } }
private void ScrollViewer_PreviewStylusUp(object sender, StylusEventArgs e) { Mouse.Capture(null); (sender as ScrollViewer).PanningMode = PanningMode.Both; }
private void ScrollViewer_PreviewStylusMove(object sender, StylusEventArgs e) { ScrollViewer scrollViewer = sender as ScrollViewer; if (Mouse.Captured != scrollViewer) return;
scrollViewer.ScrollToVerticalOffset(scrollViewer.ScrollableHeight / (scrollViewer.ActualHeight - thumbHeight) * (e.GetPosition(scrollViewer).Y - startPos)); }

3D модели в Android

Здравствуйте! Столкнулся с проблемой в имплантации 3D(Например .max (Можно и другой))в Android app

Задача состоит в: - В обычный layer-layout (слой-макет) внедрить довольно сложную модель (Это не куб, а допустим Ветвистое Дерево) - Проиграть некую анимацию (Допустим Содрогание листьев)

Есть некие ограничения, которые не позволяют сделать это через тот же Unity Перелистал уже все ресурсы (на разных языках) - ничего схожего не нашел...кроме
7-летней статьи про "Конвертацию 3D моделей в XAML" 5-летней статьи на Хабре - которую я перечитывал 20 раз и ничего кроме глобальной логики не понял
Подмогните/подскажите - может кто-то сталкивался с таким... может у кого мысли какие есть - Буду очень признателен!


Ответ

Я бы посоветовал использовать libGDX для загрузки и рендеринга 3d объектов. Движок легко импортировать в свой проект и довольно просто с ним работать. LibGDX имеет умеет работать с форматом .obj, а так же имеет собственный формат 3d моделей g3db, в который можно сконвертировать файл .fbx с помощью утилиты fbx-converter. Можно и так .max -> .fbx -> .g3db. Есть хороший туториал по 3d https://xoppa.github.io/blog/loading-models-using-libgdx/ Так же движок умеет проигрывать и сводить анимации.
LibGDX можно встроить в проект как отдельное представление - SurfaceView. Не обязательно писать весть проект на нем.

Как называется и работает такое динамическое выделение памяти?

#include
class T { int x; public: T() { std::cout << "constr
"; } ~T() { std::cout << "destr
"; } };
int main (void) { char *buf = new char[sizeof(T)]; //13 line T *t = new(buf) T;
t->~T(); } Что это за выделение памяти такое new(buf)? То есть память выделяется в строчке 13, а потом в строчке 14 не выделяется новая память под объект типа T, а берется уже выделенная память из той, на которую указывает buf. То есть такой способ занимает меньше действий, потому как можно раз выделить много памяти и потом использовать её с помощью new(buf) при динамическом выделении объектов. Если это так, то указатель будет указывать на следующий свободную ячейку памяти выделенного участка, когда будет к примеру ещё одно выделение T *t2 = new(buf) T;, то есть buf указывает на участок памяти размером с размер класса T и по этому перезапишет память, на которую указывает *t. И ещё не понятно как это реализовано. Так как new - это оператор, то наверное есть его перегруженная версия, которая принимает указатель на уже выделенную память и вторым параметром объект, который нужно выделить в ней. Вообщем это все догадки и возможно я кардинально не прав по этому поводу. Так что лучше всего было бы, если бы вы написали как это называется, что бы можно было хоть почитать где нибудь об этом способе или объяснили так, как вы считаете нужным.


Ответ

@mzarb, на самом деле никакой магии тут нет. Все довольно просто. Это Вы наделяете язык/компилятор какими-то особыми свойствами. Разберите пример Вашей (немного измененной) программы. avp@avp-xub11:~/hashcode$ cat mzarb.cpp #include #include
class T { int x; public: T() { std::cout << "constr
"; } ~T() { std::cout << "destr
"; } void setX(int v) { x = v; } };
int main (void) { struct { char f1[2]; char f2[10]; } s; strcpy (s.f2,(char *)"1234"); std::cout << "f2 before: " << s.f2 << '
';
T *t = new(s.f1) T;
std::cout << "f2 after: " << s.f2 << '
'; t->setX('z'); std::cout << "f2 again: " << s.f2 << '
';
std::cout << "f2 offset: " << s.f2+2 << '
';
t->~T(); } avp@avp-xub11:~/hashcode$ g++ mzarb.cpp avp@avp-xub11:~/hashcode$ ./a.out f2 before: 1234 constr f2 after: 1234 f2 again: f2 offset: 34 destr avp@avp-xub11:~/hashcode$ Видите, все предельно прозрачно. Никто ничего не проверяет. А рассуждения о надежности и безопасности это в реальности "развод лохов". Да, крестовый компилятор делает много проверок и для них язык заставляет Вас писать (и изучать) кучу лишнего.