Страницы

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

суббота, 13 октября 2018 г.

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

На эти размышления меня натолкнула следующая статья
В ней приведен классический для принципа Лисков пример с прямоугольник и квадратом. В коде это можно выразить так:
class Rectangle {
private int width; private int height;
public int getWidth() { return width; }
public void setWidth(int width) { this.width = width; }
public int getHeight() { return height; }
public void setHeight(int height) { this.height = height; }
public int area() { return width * height; }
}
class Square extends Rectangle{
@Override public void setWidth(int width){ super.setWidth(width); super.setHeight(width); }
@Override public void setHeight(int height){ super.setHeight(height); super.setWidth(height); }
}
public class Use {
public static void main(String[] args) { Rectangle sq = new Square(); LSPTest(sq); }
public static void LSPTest(Rectangle rec) { rec.setWidth(5); rec.setHeight(4);
if (rec.area() == 20) { // делать что то полезное } }
}
Если в метод LSPTest подставить объект Square вместо Recatangle поведение программы изменится. Это противоречит принципу Лисков.
Автор вышеупомянутой статьи делает такое заявление:
Квадрат перестает быть нормальным прямоугольником, ТОЛЬКО если квадрат и прямоугольник являются изменяемыми! Так, если мы сделаем их неизменяемыми (immutable), то проблема с контрактами, принципом подстановки и нарушением поведения клиентского кода при замене прямоугольников квадратами пропадет. Если клиент не может изменить ширину и высоту, то его поведение будет одинаковым как для квадратов, так и для прямоугольников!
Я не понимаю почему. Может это от того что я не хорошо понимаю сам LSP или immutable. Я переписал пример:
Добавил конструктор в Rectangle:
public Rectangle(int width, int height) { this.width = width; this.height = height; }
И изменил методы установки длины и ширины.
public Rectangle setWidth(int width) { return new Rectangle(width, this.height); }
public Rectangle setHeight(int height) { return new Rectangle(this.width, height); }
Вот как изменился класс Square:
public Square() {
}
public Square(int width, int height) { super(width, height); }
@Override public Rectangle setWidth(int width) { return new Rectangle(width, width); }
@Override public Rectangle setHeight(int height) { return new Rectangle(height, height); }
}
И клиентский код:
public class Use {
public static void main(String[] args) { Rectangle sq = new Square(4, 4); LSPTest(sq); }
public static void LSPTest(Rectangle rec) { rec = rec.setHeight(5);
if (rec.area() == 20) { System.out.println("yes"); } }
}
Все те же проблемы остались. Какая разница, изменяется ли сам объект или возвращается новый объект? Программа то ведет себя по-разному для базового класса и его подкласса.


Ответ

Призвали бы в пост, ответил бы раньше:)
Можно рассматривать разные варианты неизменяемости. С одной стороны, объект может быть неизменяемым, но при этом предоставлять методы withNewValue или setValue, которые вернут новый экземпляр объекта. А с другой стороны, тип может не предоставлять даже этих возможностей.
В первом случае объект неизменяемый, но мы можем огрести проблемы с LSP, как и проблемы с многопоточностью (это, на самом же деле, в некоторой мере один из мифов, что неизменыемые объекты безопасны в многопоточной среде; они менее опасны, но наличие методов setXXX может привести к гонкам). В случае "полной неизменяемости" (да, такого термина нет), этих проблем не будет.
Еще раз приведу приведенную в вопросе цитату:
Квадрат перестает быть нормальным прямоугольником, ТОЛЬКО если квадрат и прямоугольник являются изменяемыми! Так, если мы сделаем их неизменяемыми (immutable), то проблема с контрактами, принципом подстановки и нарушением поведения клиентского кода при замене прямоугольников квадратами пропадет. Если клиент не может изменить ширину и высоту, то его поведение будет одинаковым как для квадратов, так и для прямоугольников!
Я зря сделал акцент на неизменямость. Главная мысль выделена мною сейчас жирным: даже при наличии setWidth методов, возвращающие новый экземпляр, нарушение LSP возможно, вы правы. Если же у клиента этой возможности нет совсем (просто такого API не существует), то тогда нарушение невовзможно.
З.Ы. Приведенный пример уважаемого @VladD будет нарушать LSP;), поскольку трюк с final противоречит следующему неформальному, но вполне вменяемому контракту: вызов метод withXXX не меняет тип объекта:
public class Use {
public static void main(String[] args) { Rectangle sq = new Square(3); LSPTest(sq); }
public static void LSPTest(Rectangle rec) { Rectangle oldRec = rec; rec = rec.withWidth(4).withHeight(5);
// Первое из следующих утрвеждений будет нарушено! assert(oldRec.getClass().equals(rec.getClass()), "Неявный контракт: метод withWidth/withHeight не должны поменять тип объекта"); assert(rec.getWith() == 4); assert(rec.getHeight() == 5);
if (rec.area() == 20) { // делать что то полезное } }
}

Как добавить новые ветки из репозитория git

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


Ответ

Чтобы они просто появились в локальном репозитории:
git fetch # если вдруг удалённых репозиториев несколько, можно указать имя git fetch origin
При выполнении git fetch с удалённого репозитория в ваш локальный выкачиваются все имеющиеся в удалённом коммиты, которых у вас пока нет, а также все ветки. Локально создаются специальные ветки, которые повторяют содержание удалённых веток. Эти ветки имеют формат имени <имя удалённого репозитория>/<имя ветки>, например origin/master. Они отличаются тем, что в них вы не можете делать коммиты (тогда они перестанут быть копиями удалённых). Они предназначены для того, чтобы:
получать информацию о структуре веток на удалённом репозитории делать из них соответствующие локальные ветки иным образом забирать из них коммиты в локальные ветки
Узнать, из чего можно выбрать (варианты равнозначны):
git branch -a git branch --all
Переключиться на ветку просто чтобы посмотреть
git checkout
Посмотреть, чем отличаются между собой две ветки (cпасибо KoVadim за идею):
git diff ..
Создать свою локальную ветку из удалённой, чтобы потом делать коммиты в локальную и сразу настроить, чтобы пушить в эту удалённую. Это нужно только если вы хотите продолжать разработку в этой ветке
git checkout -b <имя ветки>
Подробнее в Pro Git - 3.5 Ветвление в Git - Удалённые ветки

Подгрузка файла в память

Есть большой файл с двумерным массивом. Весь массив целиком загружать в память, я думаю, не стоит (ну очень большой массив). Периодически нужны кусочки данных из разных частей массива. Как это лучше организовать?
Есть вариант держать fstream все время открытым и выбирать данные используя seekg(). Будет ли в таком случае весь файл загружен в память?


Ответ

Файл нужно отобразить на оперативную память (mmap в unix, CreateFileMapping в Windows). Тогда при обращении к нему, ОС будет сама подтягивать с диска нужные куски (причем самым оптимальным образом). В том случае, если физической памяти будет недоставать, ОС выбросит эти страницы из нее (что не займет практически никакого времени), и не будет их долго и мучительно сливать в файл подкачки.

Как в C# обходились, когда не было Dynamic?

Например, из вне приходит какой-то объект неизвестного типа.
Известно, что объекты могут быть разными(разные поля), но одно поле всегда есть у данного объекта.
Через Dynamic- это тривиальная задача, а как это делалось, когда он не был введен в C#?
UPD
Пример кода работы с Dapper, где руками мапятся колонки
var codes = conn.Query(...sql and params here...) .Select(s=>new Code{Id = s.Id, Type = s.Type, Value = s.code, Description = s.Description});


Ответ

Если говорить в целом, то до появления dynamic работа с логикой объектов неизвестного типа (а знание о том, что у объекта есть определенный атрибут и, тем более, операции с ним - это, хочешь не хочешь, а работа с логикой) в языке программирования со строгой типизацией считалось дурным тоном и bad practice. Некоторые олдфаги, типа меня, считают так до сих пор.
Но если очень надо, то есть два варианта: наследование и Reflection.
Наследование применяется в тех случаях, когда у вас есть контроль над моделью данных - тогда можно сделать либо базовый класс, либо (еще лучше) интерфейс с нужным полем, отнаследоваться, в нужном месте скастовать и далее работать уже как с обычным объектом.
Вариант с reflection применяется, если наследование делать нельзя или не хочется - например, мы используем модель данных из внешней библиотеки. В этом случае, мы просто лезем внутрь объекта и при помощи reflection'а выдираем нужное поле.
Оформить этот процесс в реализацию можно множеством способов. Можно использовать какой-нибудь фреймворк, который обернет несколько команд в одну типа GetPropertyValue. Можно сделать класс с нужными полями и, используя автомаппер (которых есть великое множество), скопировать поля неизвестного объекта в наш объект. Можно все поля неизвестного объекта скинуть в Dictionary и работать уже с ним.

поиск позиции многострочного текста

имеется большой текстовый файл1. например:
a b c d e
имеется другой текстовый файл2 с несколькими строками. например:
b c d
как с помощью posix-утилит (или хотя бы gnu-утилит, а в крайнем случае — на максимально платформо-неспецифичном си) найти номер строки в первом файле, начиная с которой эти файлы совпадают? для приведённого примера — это будет 2 (начиная со второй строки в первом файле содержатся точно такие же строки, как и во втором).

на данный момент нашёл лишь способ узнать, входит ли второй файл в первый:
$ grep -qzP "$(sed ':a;N;$!ba;s/
/\
/g' файл2)" файл1 && echo входит
но он не позволяет узнать номер строки, с которой началось совпадение.
пояснение по поводу программы для sed: она заменяет каждый перевод строки в файле2 на два символа
(обратный слэш и n), чтобы получилось регулярное выражение для grep-а. позаимстовавана отсюда: How can I replace a newline (
) using sed?


Ответ

C помощью patch
if line=$(diff -U0 файл2 /dev/null | patch -f --dry-run файл1 - | sed -rn 's/^Hunk #1 succeeded at ([0-9]+) .*/\1/p; /FAILED/ q1') then echo строка ${line:-1} else echo фрагмент не найден fi
Создаём патч удаляющий из файла-образца все строки и пытаемся его применить ко второму файлу в режиме проверки (dry-run). Если это возможно, patch сообщает найденное смещение, если оно не нулевое. Если нет - сообщает об ошибке.
С помощью diff.
Это был мой первый вариант, оставил его на всякий случай. Вроде работает, но как поведёт себя с очень большими файлами, не знаю:
diff -U0 файл2 файл1 | sed -rn '1!{/^-/q1}; 3{s/@@ -0,0 \+(1,([0-9]+)|(1)).*/\2\3/p}; /^@@ -[1-9]/ {G; h; /@@
@@/ q1 }'
Только строки нумеруются с 0.
Возможно будет неоправданно долго работать с большим файлом, так как diff будет выводить весь файл1 несовпадающий с файл2
Если совпадений нет и при частичном совпадении возвращает статус 1, текст при этом стоит игнорировать. Если файлы совпадают с самого начала, ничего не выводится, статус=0.
Пояснения по программе.
diff -U0 выдаёт патч в унифицированном формате без контекстных строк.
Первая группа отлавливает строки начинающиеся с минуса, кроме первой строки. Если такие строки присутствуют, значит diff не нашёл какой-то строки из файл2, программа завершается с кодом ошибки 1.
Вторая группа отлавливает начало фрагмента который diff считает, как добавленное перед строками из файл2. Отсюда берётся число строк этого фрагмента. Заголовок этого фрагмента должен выглядеть как @@ -0,0 +1,n @@, где n - количество его строк. n равное 1 опускается.
Если в файл1 есть все строки из файл2, но между ними есть ещё другие, в этом случае diff выдаст больше двух срок начинающихся с @@ и ни одного минуса, последняя группа команд отслеживает это.

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

Допустим, есть класс, который вызывает в методе конструктор и создает тип.
Можно ли неявно в конструкторе класса получить ссылку на класс без явной передачи this в конструктор?
Пример:
public class A { public void MethodA() { var b = new B(); } }
public class B { public B() { // каким-то образом неявно получаем ссылку на класс, который вызвал конструктор. // Т.е в данном случае ссылка на экземпляр A } }
Если не ошибаюсь, то в IL в качестве первого аргумента всегда неявно передается ссылка на вызывающий код.
P.S Задач никаких нету. Интереса ради.


Ответ

Нет, вы не можете получить экземпляр вызывающего класса. Этой информации нету даже на уровне IL. Конструктор B, декомпилированный в ILDasm, выглядит так:
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // Размер кода: 9 (0x9) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: nop IL_0007: nop IL_0008: ret } // end of method B::.ctor
У него нету объявления параметров, так что скрытых параметров нету.

То, что вы можете выяснить — это какой конкретно метод вас вызывает, без указания на экземпляр класса. Это делается так:
[MethodImpl(MethodImplOptions.NoInlining)] public B() { MethodBase callingMethod = new StackFrame(1).GetMethod(); Console.WriteLine($"Called from type: {callingMethod.DeclaringType.FullName}, " + $"calling method name: {callingMethod.Name}"); }
У меня выводит:
Called from type: Test.A, calling method name: MethodA
Вы создаёте stack frame, начинающийся на 1 выше вашего текущего фрейма, и запрашиваете метод. Имея reflection-дескриптор метода, вы можете получить информацию из него.
Заметьте, что я применил атрибут MethodImplOptions.NoInlining, чтобы запретить встраивать этот метод в точку вызова, в противном случае в stack trace могла бы попасть не та информация.
Ещё один немаловажный момент: запрос StackFrame — затратная, дорогостоящая операция, поэтому не стоит применять это решение в production-коде. Если вы хотите информацию о том. кто вас вызвал, в production-коде, стоит доверить это компилятору и воспользоваться атрибутом [CallerMemberName], доступным начиная с .NET 4.5:
public B([CallerMemberName] string callerName = null, [CallerFilePath] string callerFile = null, [CallerLineNumber] int callerLineNumber = -1) { Console.WriteLine($"Called from method: {callerName}, " + $"located {callerFile}@{callerLineNumber}"); }
Выводит:
Called from method: MethodA, located D:\full path here\Test\Program.cs@42

Длина штриха в border-style: dashed. Возможно ли регулировать?

Нужно сделать блок с такой обводкой

Но если использовать border: 2px dashed #15acd3, то получается так:

Возможно ли через CSS задавать как длину штриха и отступы между штриками?


Ответ

background-image с SVG. Регулировать расстояния между черточкам нужно в свойстве stroke-dasharray
Источник: stroke-dasharray
.block { width: 200px; height: 100px; background-color: #999; background-image: url("data:image/svg+xml;utf8,"); }


Инициализация класса с индексатором

Задали вопрос на собеседовании. Возможно ли инициализировать экземпляр класса с индексатором блоком инициализатора?
class MyClass { private int[] array = new int[5];
public int this[int index] { get { return array[index]; } set { array[index] = value; } } }
class Program { static void Main() { // Допустима ли чисто теоретически такая инициализация? MyClass my = new MyClass(){1,2,3,4,5};
//my[0] = 1; //my[1] = 2; //my[2] = 3; //my[3] = 4; //my[4] = 5;
Console.ReadKey(); } }
Если реализовать два интерфейса iEnumerable и IEnumerator:
class MyClass : IEnumerable, IEnumerator { private int[] array = new int[5]; int index;
// Индексатор. public int this[int index] { get // Аксессор. { return array[index]; } set // Мутатор. { array[index] = value; } }
public IEnumerator GetEnumerator() { return this; }
public bool MoveNext() { if(index == array.Length - 1) { Reset(); return false; }
index++; return true; }
public void Reset() { index = -1; }
public object Current { get { return array[index]; } } }
В блоке инициализатора VS на каждое число ругается:
CS1061 'MyClass' does not contain a definition for 'Add' and no extension method 'Add' accepting a first argument of type 'MyClass' could be found (are you missing a using directive or an assembly reference?
Как можно реализовать метод Add в классе, чтобы конструкция инициализатора работала? Или же это недопустимо?


Ответ

Если не нужно использовать foreach loop, а нужна только инициализация значений блоком инициализатора, то достаточно просто унаследоваться от IEnumerable, по сути не реализуя сам метод GetEnumerator() и добавить метод Add()
public class MyClass : IEnumerable { private List array = new List();
public int this[int index] { get { return array[index]; } set { array[index] = value; } }
public IEnumerator GetEnumerator() { throw new NotImplementedException(); }
public void Add(int value) { this.array.Add(value); } }
Такой класс можно инициализировать следующим образом:
MyClass instance = new MyClass { 1, 2, 6, 7, 8, 9, 10 }

Разбиение строк в формате с фиксированной шириной полей и необязательными значениями

Есть большой массив данных.
Пример строки из массива:
20046 2005 27.0 44.3 9.0 15.9 3.6 9.2 9.2 37.5 18.3 18.6 24.4 26.0
Где первые два значения - номер метеостанции и год, остальные - температуры воздуха, начиная с января. Значения разделяются пробелами, при этом количество пробелов варьируется от 1 до 3. Значения температур, которые не были зафиксированы метеостанцией заменяется пробелами, т.е. в массиве допускается строка вида:
20667 2014 5.5 2.4 7.9 8.1 42.7 10.1
Необходима регулярка, которая бы разбивала эту строку на массив вида:
['20667','2014','5.5','2.4','7.9','8.1','','','42.7','','','10.1','','']


Ответ

По описанию ваших входных данных, похоже что это fixed-width файл.
В этом случае будет очень удобно воспользоваться Pandas модулем
import pandas as pd
cols = ['id', 'year'] + ['m{}'.format(i) for i in range(1, 13)] df = pd.read_fwf(r'D:\temp\.data\655212.txt', header=None, names=cols) print(df)
Результат:
In [136]: df Out[136]: id year m1 m2 m3 m4 m5 m6 m7 m8 m9 m10 m11 m12 0 20046 2005 27.0 44.3 9.0 15.9 3.6 9.2 9.2 37.5 18.3 18.6 24.4 26.0 1 20047 2005 26.5 NaN 7.5 17.3 NaN NaN 10.2 39.9 19.7 NaN 20.4 20.0
Также можно воспользоваться идеей от @jfs для того чтобы назвать столбцы по именам месяцев:
import calendar
cols = ['id', 'year'] + list(calendar.month_abbr)[1:]
df = pd.read_fwf(r'D:\temp\.data\655212.txt', header=None, names=cols)
Результат:
In [139]: df Out[139]: id year Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec 0 20046 2005 27.0 44.3 9.0 15.9 3.6 9.2 9.2 37.5 18.3 18.6 24.4 26.0 1 20047 2005 26.5 NaN 7.5 17.3 NaN NaN 10.2 39.9 19.7 NaN 20.4 20.0
Исходный файл:
20046 2005 27.0 44.3 9.0 15.9 3.6 9.2 9.2 37.5 18.3 18.6 24.4 26.0 20047 2005 26.5 7.5 17.3 10.2 39.9 19.7 20.4 20.0

Зачем нужны Nothing, Null, Nil и None

Судя по именам все типы означают одно и тоже. В каких случаях в scala нужно применять: Nothing, Null, Nil и None, чем они отличаются?


Ответ

Хорошо расписано тут. Кое-что добавлю, кое-что подрезюмирую.
Тип Nothing - это самый нижний тип. Это значит что переменные с таким типом можно присвоить к абсолютно любому другому типу.
Пример 1:
def isTen(number: Int): Boolean = if (10 == number) true else throw new Exception("Number is not ten")
true имеет тип Boolean, кидание исключения имеет тип Nothing и так как Nothing в иерархии типов наследник Boolean, то в результате получается тип Boolean
Пример 2:
def genericIsTen[T](value: T): T = if (10 == value) value else throw new Exception("Generic is not ten")
Так как Nothing самый нижний тип, значит в иерархии типов наследник любого типа - вместо Boolean может быть и дженерик.
Пример 3:
trait Box[+T]
case class Full[T](value: T) extends Box[T] object Empty extends Box[Nothing]
def boxedIsTen(value: Int): Box[Int] = if (10 == value) Full(value) else Empty
Аналогично примерам выше объект с типом Box[Nothing] спокойно присваивается к типу Box[Int] (благодаря ковариантности, т.е. тому плюсику у трейта).
Вывод, как видишь тип Nothing используется тогда, когда нужно чтоб тип был принят другим типом. "Перетёрт" другим типом.
Тип Null - это почти самый нижний тип. В иерархии типов - он наследник всех объектов, но не наследник всех примитивов. А значит он будет работать для объектов точно также как и Nothing.
isTen(null) // НЕ будет работать так как функция хочет примитив genericIsTen((null) // будет работать boxedIsTen(null) // НЕ будет работать так как функция хочет Int
Nil - это не тип, это объект Nil. Тип у этого объекта Nil.type. Объект Nil - один из двух наследников класса List и используется он там, где нужен пустой список типа List. Ну и так как он наследник List-а, у него доступны все его методы.
sealed abstract class List[+A] { /* ... */ }
case object Nil extends List[Nothing] { /* ... */ } final case class ::[B]( /* ... */ ) extends List[B] { /* ... */}
def listIsTen(number: Int): List[Int] = if (10 == number) List(number) else Nil
None - это тоже не тип, а объект None. Тип у этого объекта None.type. Объект None - один из двух наследников класса Option и используется как пустой вариант Option.
sealed abstract class Option[+A]
case object None extends Option[Nothing] { /* ... */ } final case class Some[+A](x: A) extends Option[A] { /* ... */ }
def optionIsTen(number: Int): Option[Int] = if (10 == number) Some(number) else None

WPF Создание кастомного стиля окна с тенью

Задачей является создание кастомного стиля окна обладающего следующими свойствами:
Тень в четыре направления (left, top, right, bottom) Наличие хрома или, иначе, области за которую можно окно перетаскивать Возможность изменения размера окна мышью Тень приравнивается к областям, которые не имеют цвета на прозрачных окнах: это означает, что мы можем не только наблюдать за элементами других окон, которые находятся за тенью, но и работать с ними прямо сквозь тень (точно таким же свойством обладают окна с установленным в True свойством AllowsTransporency и не имеющего никакого цвета фона). Анимации сворачивания и разворачивания окон в Windows

Проблематика:
Хром окна всегда расположен сверху. Мы можем лишь задать его высоту (WindowChrome.CaptureHeight). Отсюда вытекает невозможность создания верхней тени, ведь она будет лишь фоном хрома и за неё можно будет потянуть окно. Решением может быть либо отрисовка тени на более низком уровне (WinApi; понятия не имею как), либо отказ от WindowChrome и использование Border, у которого есть обработчик MouseLeftButtonDown с вызовом в нём Window.DragMove метода. Пункт 4 их списка выше. Вот тут и идей я даже не имею. Разве что, опять же, рисовка тени окна на более низком чем WPF уровне... Анимацию сворачивания и разворачивания окна при WindowStyle в None не работают. Но можно сделать следующим образом: при сворачивании поменять стиль окна с None на любой другом, и, соответственно, при разворачивании делать наоборот. Но уж как-то совершенно в лоб. WindowChrome.ResizeBorderThickness позволяет задать толщину бордюра для ресайза окна. Но он и понятия никакого не имеет об отступах - там где у нас тень, там и будет расположен.


Ответ

У меня вот такой стиль убирает Chrome и оставляет тени:

Вот два окна, которые получаются в результате:

Жёлтое окно — стандартное, зелёное — стилизованное.
Обратите внимание, что белый прямоугольник в зелёном окне — часть стиля, его можно увидеть в шаблоне:

и убрать при желании.

Решение проблемы с максимизацией у меня выглядит так: добавляем имя:

и в триггеры:

Такое нужно потому, что окно в максимизированном состоянии размещается по координатам (-7, -7). (Информация из этого ответа.) Откуда взять константу 7 «цивилизованным путём», я пока не знаю. (Кажется, информация есть здесь.)

Как оптимизировать деплой через docker-compose?

Мы реализовали деплой через GitLab CI и docker-compose. В процессе деплоя на удалённый сервер копируется файл docker-compose.yml и файлы Dockerfile и пр. для создания "вспомогательных" контейнеров типа nginx и mysql
Всё работает как нужно. Беспокоят 2 момента: даунтайм и "мусорные" образы docker (те, что с в колонке TAG в docker images)
Вот кусок файла .gitlab-ci.yml, ответственный собственно на деплой на удалённый сервер:
.template-secure-copy: &secure-copy stage: deploy image: covex/alpine-git:1.0 before_script: - eval $(ssh-agent -s) - ssh-add <(echo "$SSH_PRIVATE_KEY") script: - ssh -p 22 $DEPLOY_USER@$DEPLOY_HOST 'set -e ; rm -rf '"$DEPLOY_DIRECTORY"'_tmp ; mkdir -p '"$DEPLOY_DIRECTORY"'_tmp' - scp -P 22 -r build/* ''"$DEPLOY_USER"'@'"$DEPLOY_HOST"':'"$DEPLOY_DIRECTORY"'_tmp' # */ <-- в оригинале строка не закоментирована =) - ssh -p 22 $DEPLOY_USER@$DEPLOY_HOST 'set -e ; cd '"$DEPLOY_DIRECTORY"'_tmp ; docker login -u gitlab-ci-token -p '"$CI_JOB_TOKEN"' '"$CI_REGISTRY"' ; docker-compose pull ; if [ -d '"$DEPLOY_DIRECTORY"' ]; then cd '"$DEPLOY_DIRECTORY"' && docker-compose down --rmi local && rm -rf '"$DEPLOY_DIRECTORY"'; fi ; cp -r '"$DEPLOY_DIRECTORY"'_tmp '"$DEPLOY_DIRECTORY"' ; cd '"$DEPLOY_DIRECTORY"' ; docker-compose up -d --remove-orphans ; docker-compose exec -T php phing app-deploy -Dsymfony.env=prod ; rm -rf '"$DEPLOY_DIRECTORY"'_tmp' tags: - executor-docker
Даунтайм сейчас - это 1-2-3 минуты. Начинается он с docker-compose down ... и до конца выполнения скрипта. Хочется его уменьшить.
А как сделать так, чтобы "мусорные" образы docker не появлялись - я вообще не понял. Про docker image prune знаю, хочется не очищать, а не захламлять.
UPD1:
Файл docker-compose.yml создаётся следующей конструкцией:
.template-docker-compose: &docker-compose stage: build image: covex/docker-compose:1.0 script: - for name in `env | awk -F= '{if($1 ~ /'"$ENV_SUFFIX"'$/) print $1}'`; do eval 'export '`echo $name|awk -F''"$ENV_SUFFIX"'$' '{print $1}'`'='$"$name"''; done - mkdir build - docker-compose -f docker-compose-deploy.yml config > build/docker-compose.yml - sed -i 's/\/builds\/'"$CI_PROJECT_NAMESPACE"'\/'"$CI_PROJECT_NAME"'/\./g' build/docker-compose.yml - cp -R docker build artifacts: untracked: true name: "$CI_COMMIT_REF_NAME" paths: - build/ tags: - executor-docker
В результате этой процедуры получается такой docker-compose.yml
networks: nw_external: external: name: graynetwork nw_internal: {} services: mysql: build: context: ./docker/mysql environment: MYSQL_DATABASE: project MYSQL_PASSWORD: project MYSQL_ROOT_PASSWORD: root MYSQL_USER: project expose: - '3306' networks: nw_internal: null restart: always volumes: - database:/var/lib/mysql:rw nginx: build: args: app_php: app server_name: project-dev1.ru context: ./docker/nginx depends_on: php: condition: service_started networks: nw_external: ipv4_address: 192.168.10.13 nw_internal: null ports: - 80/tcp restart: always volumes_from: - service:php:ro php: depends_on: mysql: condition: service_healthy environment: ENV_database_host: mysql ENV_database_name: project ENV_database_password: project ENV_database_port: '3306' ENV_database_user: project ENV_mailer_from: andrey@mindubaev.ru ENV_mailer_host: 127.0.0.1 ENV_mailer_password: 'null' ENV_mailer_transport: smtp ENV_mailer_user: 'null' ENV_secret: ThisTokenIsNotSoSecretChangeIt expose: - '9000' image: gitlab.site.ru:5005/dev1-projects/symfony:master networks: nw_internal: null restart: always volumes: - /composer/vendor - /srv version: '2.1' volumes: database: {}
Dockerfile для сервиса nginx
FROM nginx:alpine ARG server_name=docker.local ARG app_php=app_dev
COPY ./default.conf /etc/nginx/conf.d/default.conf
RUN sed -i 's/@SERVER_NAME@/'"$server_name"'/g' /etc/nginx/conf.d/default.conf \ && sed -i 's/@APP@/'"$app_php"'/g' /etc/nginx/conf.d/default.conf
Dockerfile для сервиса mysql
FROM mysql:5.7
HEALTHCHECK CMD mysqladmin ping --silent


Ответ

Нужно минимум два контейнера, которые будет zero downtime. Дальше процесс (хорошо описан тут): остановить один старый, запустиить один новый и так по очереди.
Но я буквально пару недель назад все это проходил и docker swarm это ОЧЕНЬ ПРОСТО, там пару команд, рецепт по ссылке в несколько раз сложнее. Для своего решения нужно настраивать балансировщик, а в docker swarm уже все есть и ставиться, ещё раз скажу, ОЧЕНЬ ПРОСТО.
Переходите сразу на docker swarm. Он очень быстро настраивается и нулевой downtime из коробки.
Просто docker service отличный инструмент, а docker stack вообще бомба (как раз поднимает все оружение из docker-compose подобного файла).

В чём разница между using и on в join-запросах?

Сабж в заголовке, т.е. равносильны ли запросы (если mysql рассматривать)
SELECT * FROM `tab1` RIGHT JOIN `tab` ON `table2`.`id` = `table1`.`id`
и
SELECT * FROM `tab1` RIGHT JOIN `tab2` USING(`id`)
если нет, то какой лучше и в чём различие?


Ответ

USING (column_name(s)), по сути, является синтаксическим сахарочком над ON. Согласно докам — служит для указания списка столбцов, которые должны существовать в обеих таблицах.
Такое выражение USING, как:
A LEFT JOIN B USING (C1, C2, C3, ...)
семантически идентично выражению ON
A.C1 = B.C1 AND A.C2 = B.C2 AND A.C3 = B.C3,...
В то время как ON можно "склеить" столбцы с различными именами.
Но с ON можно проделать операций чуть больше, например можно присоединить не только колонку, но и набор колонок или даже целое условие, пример:
SELECT * FROM world.City JOIN world.Country ON (City.CountryCode = Country.Code) WHERE ...

Дополнительно
USING — при перечислении полей в запросе не обязательно указывать префикс:
SELECT film.title, film_id // # film_id указан без префикса FROM film JOIN film_actor USING (film_id) WHERE ...
Тоже самое с ON
SELECT film.title, film.film_id // # film.film_id обязателен префикс FROM film JOIN film_actor ON (film.film_id = film_actor.film_id) WHERE ...
Если не перечислять поля явно, а использовать select * для соединения столбцов, то в результирующем наборе при ON колонка "всплывёт" дважды, в то время как с USING — только раз:
mysql> create table t(i int); insert t select 1; create table t2 select*from t;
Query OK, 0 rows affected (0.11 sec)
Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0
Query OK, 1 row affected (0.19 sec) Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from t join t2 on t.i = t2.i; +------+------+ | i | i | +------+------+ | 1 | 1 | +------+------+ 1 row in set (0.00 sec)
mysql> select * from t join t2 using(i); +------+ | i | +------+ | 1 | +------+ 1 row in set (0.00 sec)
mysql>

инфа позаимствована на enSO MySQL ON vs USING?

Ошибка lvalue required as left operand of assignment

Есть три (независимые) строчки кода:
1) *a++ = 5; 2) *(a++) = 5; 3) (*a)++ = 5;
Первая и вторая строчки работают одинаково. На третью компилятор (minGW, GCC) ругается:
lvalue required as left operand of assignment (*a)++=5;
Не могу понять почему. Теоретически она не должна отличаться от первых двух: разыменовываем указатель a, присваиваем новое значение, выполняем постфиксный инкремент указателя. Расстановка скобок в левой части не должна влиять на порядок выполнения, но такое впечатление, что в третьем случае влияет, и код выглядит так:
((*a) + 1) = 5;
Только в таком случае действительно не выполняется условие lvalue
Объясните, пожалуйста, почему на самом деле я получаю ошибку компиляции, и какая разница между первыми двумя строчками кода и третьей, а так же что является операндом для постфиксного инкремента (указатель или разлинованная область).


Ответ

*a++ = 5;
Сначала применение ++ к a, возврат старого указателя, разыменование, присвоение.
*(a++) = 5;
Сначала инкремент, который возвращает старый указатель, который разыменовывается, и по этому адресу выполняется присваивание (все, как в первой строке).
(*a)++ = 5;
Разыменование, получаем значение, к которому применяем ++... к чему? К разыменованному значению указателя? OK, но что при этом вернуть? Просто старое значение в памяти по этому адресу?
Ссылок в C нет, это не C++. Значит, вернуть просто старое значение 5? Но это не lvalue! на что, сообственно, и указывает компилятор....
По-моему, так (с) Пух

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

В одной статье наткнулась на следующие строки:
Элементы enum Season (WINTER, SPRING и т.д.) - это статически доступные экземпляры enum-класса Season. Их статическая доступность позволяет нам выполнять сравнение с помощью оператора сравнения ссылок ==.
А каким образом статическая доступность позволяет выполнять сравнение с помощью оператора сравнения ссылок ==? Почему нестатические объекты сравнивать через == нельзя, а статические можно?


Ответ

При сравнению через == сравниваются указатели, а статические поля класса одинаковы для всех экземпляров класса - указатели на них определяются в момент запуска программы. Если поле финальное, то оно не изменяется на протяжении всей работы программы. А элементы enum как раз финальные (в вашей ссылке далее по тексту приводится пример декомпиляции enum-а - это класс с public static final полями).
Почему нестатические объекты сравнивать через == нельзя, а статические можно?
Неизменяемость указателей статических полей и позволяет их сравнивать.
Примерным аналогом enum может служить следующий класс ("примерным", т.к. для полноты соответствия нужно также реализовать методы valueOf, values):
public class Season { public static final Season WINTER = new Season(); public static final Season SPRING = new Season(); public static final Season SUMMER = new Season(); public static final Season AUTUMN = new Season();
private Season() {} } Season a = Season.AUTUMN; Season b = Season.AUTUMN; System.out.println(a == b); //true

Git. Работа с заначкой (Stash)

Добрый день!
Я сделал часть работы в ветке(условно old_branch). Далее мне понадобилось перенести эту работу в другую ветку(условно new_branch). Так как работа не закончена, я не стал комитить изменения, а воспользовался заначкой(stash)
$ git stash $ git stash branch new_branch
У меня создалась новая ветка new_branch, в которую перенеслись мои незакомиченные изменения. Все ОК.
Далее я вернулся на старую ветку и восстановил ее состояние до моих изменений
$ git checkout old_branch $ git checkout -- .
Изменения откатились не только в старой ветке, но и в новой тоже (WTF?). Понимаю что незакомиченные изменения потеряны навсегда, но есть ли способ восстановить заначку из новой ветки?


Ответ

У меня создалась новая ветка new_branch, в которую перенеслись мои незакомиченные изменения.
нет, они не «перенеслись». просто была создана новая ветка, копия той, в которой была создана «заначка» (stash), т.е., создан новый указатель на тот же самый коммит, который был текущим во время создания «заначки», затем эта новая ветка была назначена текущей, к рабочему каталогу (working directory) были применены сохранённые в «заначке» изменения, а сама «заначка» была удалена.
раз вы сразу после этого выполнили команду checkout (с аргументом ), то изменения в рабочем каталоге были удалены

восстановить удалённую «заначку» теоретически можно (до проведения «сборки мусора»). пример:
$ git fsck --no-reflog Checking object directories: 100% (256/256), done. dangling commit 424c2946da3bfe5cbc719f808c1a006612e5cab7
найденный «подвисший» (dangling) коммит и является удалённой (мною) «заначкой». с этим хэшем можно манипулировать как с «обычной заначкой»:
$ git show 424c294 commit 424c2946da3bfe5cbc719f808c1a006612e5cab7 Merge: 3330f58 8a98560 Author: aleksandr barakin Date: Fri Oct 6 12:46:55 2017 +0300
WIP on master: 3330f58 20171006124552
diff --cc file index abf3108,abf3108..e1743f8 --- a/file +++ b/file @@@ -1,1 -1,1 +1,2 @@@ 2017-10-06 12:45 ++2017-10-06 12:46
$ git stash show -p 424c294 diff --git a/file b/file index abf3108..e1743f8 100644 --- a/file +++ b/file @@ -1 +1,2 @@ 2017-10-06 12:45 +2017-10-06 12:46
$ git stash apply 424c29 On branch new Changes not staged for commit: (use "git add ..." to update what will be committed) (use "git checkout -- ..." to discard changes in working directory)
modified: file
no changes added to commit (use "git add" and/or "git commit -a")

Переопределение ToString в собственном классе

Есть класс Polynom. В нем многочлен задается массивом коэффициентов. нужно вывести многочлен в консоль в виде, например, 3x^4+2x^3+1, используя String.format
Класс выглядит так:
public class Polynom { public int[] coefficients; public int polynomDegree; public string x; public int[] powers;
// задать полином при помощи коэффициентов public Polynom(params int[] coefficients) { this.coefficients = coefficients; }
//свойство степени многочлена public int PolynomDegree { get { for (int i = 0; i < coefficients.Length; i++) { powers[i] = i; } return powers.Length - 1; } }

public override string ToString() { object[] args = new object[] { this.coefficients, this.powers }; return string.Format("Polynom {0}" + "x^{1}", string.Join("" + "x^", args));
}
//индексатор на чтение и запись public int this[int index] { set { this.coefficients[index] = value; }
get { return this.coefficients[index]; } }


Ответ

Так просто через string.Format() здесь не получится, он не работает с переменным количеством аргументов.
Мой вариант с использованием StringBuilder
class Polynom { //int[] coefficients = new int[] { 1, 2, -6, 2, 3 }; ...
public override string ToString() { var sb = new StringBuilder(); for (int i = coefficients.Length - 1; i >= 0; --i) { if (coefficients[i] == 0) continue; if (coefficients[i] > 0 && sb.Length > 0) sb.Append('+'); if (coefficients[i] < 0) sb.Append('-'); var abs = Math.Abs(coefficients[i]); if (abs != 1 || i == 0) sb.Append(abs); if (i > 0) sb.Append('x'); if (i > 1) sb.Append('^').Append(i); } if (sb.Length == 0) return "0"; return sb.ToString(); } }
Учтено: 1. Члены с нулевым коэффициентом не выводятся. 2. Корректно отображается знак +/- перед коэффициентом, если старший коэффициент положительный — + перед ним не отображается. 3. Не отображается степень при x^1 4. Не отображается x^0 при свободном члене. 5. Если все коэффициенты равны 0 — отображается 0 6. Коэффициент 1/-1 отображается только для свободного члена
Пример вывода: 3x^4+2x^3-6x^2+2x+1

Clean Project входит в Rebuild Project?

Или нет?
Т.е. делаем Rebuild, Clean выполнится тоже?


Ответ

Да, rebuild project не только удаляет все артефакты, но и перестраивает проект.
Здесь можно посмотреть подробные логи clean и rebuild

Как задать background тексту в виде изображения? [дубликат]

На данный вопрос уже ответили: Наложение background только на текст 2 ответа Всем привет!
Подскажите, как реализовать (css/html/js) данный эффект текста так, чтобы фоном текста было изображение?

Спасибо!


Ответ

Товарищ user202854 указал верное направление для 'раскопок', в итоге задуманное получилось реализовать:

var canvas = document.getElementById('canvas'); var ctx = canvas.getContext("2d"); var img = document.createElement('img'); img.onload = function() { ctx.fillStyle = ctx.createPattern(img, 'repeat'); ctx.font = 'bold 80px sans-serif'; ctx.fillText("Image text", 20, 80); }; img.src = 'https://s1.1zoom.ru/big3/81/Russia_Mountains_Lake_469922.jpg';

Как получить список всех вызываемых методов в коде C# Roslyn

Как получить список всех используемых. Например
using System; using System.Collections.Generic; using System.Text;
namespace HelloWorld { class Program { static void Main(string[] args) { String s = "sasdad"; s.ToString(); Console.WriteLine(""Hello, World!""); } } }
Получить ToString.


Ответ

Делаем вот как. Для начала создадим анализатор, как описано в этом вопросе
Нам нужно получить все вызовы методов, и вывести их. Это делается напрямую так:
var workspace = MSBuildWorkspace.Create(); // подставьте путь к вашему проекту var solution = await workspace.OpenSolutionAsync(@"D:\HelloWorld.sln"); var project = solution.Projects.Single(); var compilation = await project.GetCompilationAsync();
// обходим все деревья (то есть, все файлы) foreach (var syntaxTree in compilation.SyntaxTrees) { var root = await syntaxTree.GetRootAsync(); var model = compilation.GetSemanticModel(syntaxTree); // получаем всё, что выглядеит как вызов метода var invocations = root.DescendantNodes().OfType(); foreach (var invocation in invocations) { var expression = invocation.Expression; // спрашиваем у семантического анализатора о типе выражения var symbol = model.GetSymbolInfo(expression).Symbol; if (symbol.Kind != SymbolKind.Method) continue; // выясняем дополнительнуыю информацию bool isStatic = symbol.IsStatic; var name = symbol.Name; var containingTypeName = symbol.ContainingType.ToDisplayString(); var location = invocation.GetLocation().GetLineSpan(); // и выводим Console.WriteLine($"{(isStatic ? "Static" : "Non-static")} call," + $" type = {containingTypeName}, method = {name}, location = {location}"); } }
Например, для вот такого тестового кода:
using System;
namespace HelloWorld { class Program { static string g = string.Empty; static void Main(string[] args) { string[] strings = { "Hello ", "world" }; foreach (var s in strings) Console.Write(s.ToString() + s?.ToString()); for (int i = 0; i < strings.Length; i++) Console.Write(strings[i].ToUpper()); Console.WriteLine(); } } }
получаем результат:
Static call, type = System.Console, method = Write, location = Program.cs: (11,16)-(11,59) Non-static call, type = string, method = ToString, location = Program.cs: (11,30)-(11,42) Non-static call, type = string, method = ToString, location = Program.cs: (11,47)-(11,58) Static call, type = System.Console, method = Write, location = Program.cs: (13,16)-(13,41) Non-static call, type = string, method = ToUpper, location = Program.cs: (13,30)-(13,50) Static call, type = System.Console, method = WriteLine, location = Program.cs: (14,12)-(14,31)

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

При исполнении кода #include #include
int main() { char *first = "first"; char *second = "second"; char *third = strcat(first, second); } происходит ошибка сегментирования.


Ответ

Проблема в том, что функция strcat не выделяет память, а копирует из одной строки в другую. Поскольку длина первой строки меньше, чем длина второй, то память перетирается. Нужно изменить код, например, так. #include #include
int main() { char first[7] = "first"; char second[7] = "second"; char *third = strcat(first, second); }

Ошибка кодировки в Python: readline() при чтении utf-8 файла ругается: 'charmap' codec can't decode byte

Пытаюсь читать файл портов от IANA. Он сохранен в кодировке UTF-8 w/o BOM. Но на одной из строк функция readline() ругается вот таким вот образом
'charmap' codec can't decode byte 0x98 in position 7938: character maps to <"undefined">
Строка в файле выглядит следующим образом:
# Jim Harlan <"jimh&infowest.com">
Какой костыль придумать для этого? Или есть прямой путь решения?
UPD
Ибо костыль в виде удаления данной строки пойдет (причем она, почему-то вот такая одна), но только на время отладки, ибо потом вдруг что, партнеры будут рвать волосы на моей голове. Так же выложу код, которым пользуюсь для данной операции:
try: file = open(path, 'r') while True: line = file.readline() if(not line): break print(line) finally: file.close()


Ответ

попробуйте использовать встроенную библиотеку codecs: import codecs fileObj = codecs.open( "someFilePath", "r", "utf_8_sig" ) text = fileObj.read() # или читайте по строке fileObj.close()

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

Как по мне, то в С есть передача аргументов в функцию только по значению, а в С++ по факту тоже только передача по значению. То есть, передачи по указателю не может быть, потому что указатель содержит адрес, а это тоже значение. Так что правильней говорить, что передача по значению. Ну а насчет ссылок, то это те же указатели с константным адресом и которые неявно преобразуются к указателю, так что тоже передача по значению. То есть, есть только передача по значению. А когда говорят о передаче по указателю и ссылке, то это скорей для того, чтобы внести ясность о том, будет ли переменная копирована или взят её адрес или так же неявно взят адрес с невозможностью заменить его на другой адрес. В общем, условно(для упрощения понимания) есть 2 способа передачи аргументов в функцию в Си : по значению, по указателю. И 3 способа в C++: по значению, по указателю, по ссылке. А по факту везде передается по значению и только. В тесте по Си были 2 ответа : по значению, и по указателю. Но вопрос там был другой "Какими способами можно передавать параметры в функцию?". То есть, не аргументы, а параметры. Не совсем понимаю этот момент, но если предположить, что аргументы передаются в параметры, а потом параметры в тело функции, то параметры вполне могут передаваться по значению или указателю или по ссылке( в C++). И будет выглядеть как - void func1 ( int arg ); void func2 ( int * arg ); void func3 ( int & arg ); Из кода видно, что сами параметры могут быть и ссылкой и указателем, но тем не менее во всех трех случаях инициализированы они будут аргументами, которые передаются только по значению. Что-то мне кажется, что скорей всего не правильно был сформулирован вопрос теста и параметры не передаются в функцию, так как они и так в её сигнатуре, а передаются аргументы, ну а параметры просто инициализируются где-то между сигнатурой и телом в области видимости под которую попадает тело функции.


Ответ

Насколько я понимаю, в C ровно один способ передачи аргументов: по значению. Передаёте ли вы по значению число или указатель, вы получаете с той стороны копию этого числа/указателя: если вы меняете число внутри функции, с его «внешним прообразом» (который может, кстати, быть и выражением) ничего не случается; если внешний прообраз меняется в течение выполнения функции, на значении аргумента это никак не отражается. Иногда говорят, что передавая указатель на объект в функцию, вы как бы тем самым неявно передаёте сам объект в функцию «по указателю». Это на самом деле не вполне верный подход. Давайте я приведу пример: представьте себе, что вам передали число. Вы использовали это число как индекс в глобальном массиве, и изменили элемент этого массива. Можно ли сказать, что вам был передан этот элемент? Нет, вы получили лишь число. Точно так же можно смотреть на указатель как на индекс в памяти, рассматриваемой как массив байт. Доступ к объекту через указатель ничем не лучше и не хуже доступа к ячейке массива по индексу. В C++ появился новый вид передачи параметров: по ссылке. По существу, передача «по ссылке» ничем не отличается от передачи указателя кроме того, что (1) ссылка не может соответствовать NULL-указателю в корректной программе, (2) ссылка синтаксически ведёт себя как разыменованный указатель. Однако, разработчики C++ советуют всё же видеть в передачу по ссылке другую семантику: ссылка является «алиасом», другими именем объекта. Хотя такая семантика и более привлекательна с точки зрения ясности программ, всё же ссылка на объект и сам объект — не одно и то же. В частности, ссылка может пережить объект, и вы получите при попытке обратиться к ней undefined behaviour. Если бы ссылка была самим объектом (как это часто пытаются подать), такого произойти бы не смогло. Следовать ли совету разработчиков или думать о передаче по ссылке как о синтаксическом сахаре для передачи по указателю — личное дело каждого. Я бы всё же советовал думать так, как советуют разработчики, но не упускать из виду, что эта абстракция «протекает». ЗЫ: Пример кода без явных ошибок (наподобие возврата ссылки на локальную переменную), в котором ссылка на объект переживает сам объект: class X { struct C { int x; }; C* pc;
void f(int& x) { g(); cout << x << endl; } void g() { delete pc; }
public: X() : pc(new C()) {} void run() { f(pc->x); } };

Пробрасывание исключений

Скажите, пожалуйста, пробрасывание исключений на верх это нормальная практика?
Просто сейчас в проекте своем учебном попробовал это сделать (точнее сделал это во все узких места, особенно там, где идет работа с БД), и мне показалось это удобным в плане поиска ошибок и отладке.
Пример (на логику не обращайте внимания, интересует только проброс исключений):
// Получение какого-либо значения из базы данных в виде object private object GetData_AsObject() { try { //тут идет получение данных из бд } catch (Exception e) { throw new Exception("Получение данных из " + tableName + "." + column); } }
// Получение какого-либо значения из базы данных в виде string public string GetData_AsString() { try { if (GetData_AsObject() != null) return GetData_AsObject().ToString(); else return ""; } catch (Exception e) { throw new Exception(e.Message + " as string"); } }
// Получение какого-либо значения из базы данных в виде int public int GetData_AsInt() { try { if (GetData_AsObject() != null) return int.Parse(GetData_AsObject().ToString()); else return 0; } catch (Exception e) { throw new Exception(e.Message + " as int"); } }
И так исключение поднимается выше. Если где-то выше в коде есть обработка исключения, то она выполняется и не беспокоит пользователя. Если обработки нет, то пользователь получает полное сообщение об ошибке.
Но в коде получается очень много конструкций try-catch. Не считается ли это захламлением?


Ответ

Да, это вполне нормальная практика. Чаще всего код не должен заниматься обработкой исключений - у него обычно на это нет соответствующих полномочий. Иными словами, это не его дело. Он должен либо выполнить некие действия, либо, получив исключение, пробросить его вызывающему коду, которому можно доверить эту самую обработку (что само по себе является отдельной задачей, а согласно Single responsibility, первому из принципов SOLID, объект не должен брать на себя более одной обязанности) Бывают, конечно, ситуации, когда исключение является одним из видов "штатной ситуации", и сгенерировавший его код способен корректно его обработать, но это довольно нечастые случаи (и честно говоря, примеры таких ситуаций у меня в голове как-то сразу не всплывают). Более того, тут возникает вопрос - стоит ли в такую ситуацию рассматривать как исключение.
Если говорить о вашем примере, то в любом случае логика реакции на исключение должна находиться вне сферы ответственности кода, работающего с БД . Вряд ли этот код должен брать на себя еще и задачу записи в лог или формирования человекопонятного сообщения об ошибке для конечного пользователя.
З.Ы. несмотря на ваши слова про "на логику не обращайте внимания", я всё не удержусь и добавлю: искренне надеюсь, следующий кусок не из реального кода?
if (GetData_AsObject() != null) return GetData_AsObject().ToString(); else return "";
З.Ы. вы же вроде задавали несколько месяцев тому назад очень похожий вопрос

Как разделить/склеить старый комит?

Задачка из области синтетических, нужно для понимания как это делать правильно.
Есть история из 3 коммитов
git log --oneline cccccc change c.txt bbccaa add new two file (b.txt, c.txt) and change a.txt aaaaaa add new file a.txt
Задача 1: разделить bbccaa на два, чтобы результат был
git log --oneline cccccc change c.txt aaa111 change a.txt bbbccc add two file (b.txt, c.txt) aaaaaa add new file a.txt
Задача 2: склеить частично bbbccc с aaaaaa, чтобы вышло
git log --oneline cccccc change c.txt aaa111 change a.txt ccc111 add file c.txt aaabbb add files a.txt b.txt


Ответ

И то, и другое делается с помощью rebase (самой страшной командой в гите:) ).
Начнем с второго, как более простого.
git rebase -i HEAD~3
-i - интерактивный режим, HEAD~3 - три последних коммита.
Откроется редактор по умолчанию, где будет список коммитов. Вверху более старые, внизу более свежие (обратно выводу git log!) На против каждого будет написано pick (то есть, "взять"). Находим коммиты, которые нужно слить и напротив верхнего с пары пишем s или squash. Сохраняемся. Git сам откатит указанные коммиты, а потом накатит по новому. Коммит-сообщение возьмет с парного коммита. Если нужно его поправить, то напротив него пишем edit - при накатывании коммита будет открыто стандартное окно редактора для ввода сообщения коммита.
С разделением чуть сложнее. Для этого выбираем коммит, пишем напротив него edit и сохраняем. Гит откатит коммиты (не только тот, который выбран, и все до самого свежего - это нужно понимать!). И начнет накатывать их по новой. Когда дойдет до того, который помечен edit - вывалится в консоль. В этот момент с помощью git add/git reset (я люблю использовать git add -i, если нужно добавить "кусочками") исправить коммит, можно сделать ещё один-другой, а потом дать комманду git rebase --continue и гит продолжит накатывать коммиты. Важно понимать, что sha хэши новых коммитов поменяются.
За дополнительными инструкциями как всегда читайте справку

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

Как правильно уменьшить размер стека для .NET приложения? Возможно есть какие либо директивы или опции в Visual Studio.


Ответ

Вы можете, например, воспользоваться конструктором Thread с указанием максимального размера стека.

Если вы планируете запускать Task на этом потоке, имеет смысл реализовать TaskScheduler, который перекинет Task в этот поток.
Или можно воспользоваться готовым scheduler'ом, например, WPF.

Пример кода:
При помощи этого метода можно «перебросить» async-метод в поток, на котором бежит данный WPF-диспетчер:
static class AsyncHelper { public static DispatcherRedirector RedirectTo(Dispatcher d) { return new DispatcherRedirector(d); } }
// http://blogs.msdn.com/b/pfxteam/archive/2011/01/13/10115642.aspx public struct DispatcherRedirector : INotifyCompletion { public DispatcherRedirector(Dispatcher dispatcher) { this.dispatcher = dispatcher; }
#region awaiter public DispatcherRedirector GetAwaiter() { // combined awaiter and awaitable return this; } #endregion
#region awaitable public bool IsCompleted { get { // true means execute continuation inline return dispatcher.CheckAccess(); } }
public void OnCompleted(Action continuation) { dispatcher.BeginInvoke(continuation); }
public void GetResult() { } #endregion
Dispatcher dispatcher; }
Теперь вам нужен поток, в котором бежит диспетчер.
public class DispatcherThread : IDisposable { public Dispatcher Dispatcher { get; private set; } public TaskScheduler TaskScheduler { get; private set; }
Thread thread;
public DispatcherThread(int maxStackSize) { using (var barrier = new AutoResetEvent(false)) { thread = new Thread(() => { Dispatcher = Dispatcher.CurrentDispatcher; barrier.Set(); Dispatcher.Run(); }, maxStackSize);
thread.SetApartmentState(ApartmentState.STA); thread.Start(); barrier.WaitOne(); }
TaskScheduler = Get(() => TaskScheduler.FromCurrentSynchronizationContext()); }
// --------------------------------------------- // остальные функции вам не нужны для вашей задачи, но могут пригодиться впоследствии public void Execute(Action a) { if (Dispatcher.CheckAccess()) a(); else Dispatcher.Invoke(a); }
public void FireAndForget(Action a) { Dispatcher.BeginInvoke(a); }
public T Get(Func getter) { if (Dispatcher.CheckAccess()) return getter(); else { T t = default(T); Dispatcher.Invoke((Action)(() => { t = getter(); })); return t; } }
public Task GetAsync(Func getter) { return Dispatcher.InvokeAsync(getter).Task; }
public Task StartNewTask(Action action) { return Task.Factory.StartNew( action: action, cancellationToken: CancellationToken.None, creationOptions: TaskCreationOptions.None, scheduler: TaskScheduler); }
public Task StartNewTask(Func function) { return Task.Factory.StartNew( function: function, cancellationToken: CancellationToken.None, creationOptions: TaskCreationOptions.None, scheduler: TaskScheduler); }
public void Dispose() { Dispatcher.InvokeShutdown(); if (thread != Thread.CurrentThread) thread.Join(); } }
Этим можно пользоваться, например, так:
using (var t = new DispatcherThread(maxStackSize)) { await AsyncHelper.RedirectTo(t.Dispatcher); // остаток метода }

Обновление: совсем забыл, надо же по идее сбежать из умирающего потока! Например, в thread pool.
static class AsyncHelper { public static ThreadPoolRedirector RedirectToThreadPool() { return new ThreadPoolRedirector(); } }
public struct ThreadPoolRedirector : INotifyCompletion { #region awaiter public ThreadPoolRedirector GetAwaiter() { // combined awaiter and awaitable return this; } #endregion
#region awaitable public bool IsCompleted { get { // true means execute continuation inline return Thread.CurrentThread.IsThreadPoolThread; } }
public void OnCompleted(Action continuation) { ThreadPool.QueueUserWorkItem(o => continuation()); }
public void GetResult() { } #endregion }
и использовать как
using (var t = new DispatcherThread(maxStackSize)) { await AsyncHelper.RedirectTo(t.Dispatcher); // остаток метода await AsyncHelper.RedirectToThreadPool(); }

Хотя может быть это и не нужно, InvokeShutdown не убивает поток немедленно. Но тем не менее.

Более современная версия DispatcherThread — в этом ответе

Что должно быть в gitignore для Visual Studio?

Создаю проект в Visual Studio, к корневую директорию проекта копирую .gitignore взятый отсюда
Под контроль версий я добавляю следующие файлы:
Классы, Интерфейсы .gitignore
Собственно вопрос необходимо ли добавлять в систему контроля версий прочие файлы?
Например:
Properties\AssemblyInfo.cs Проект.csproj Имя_решения.sln Прочие файлы


Ответ

Не нужно добавлять *.sln в .gitignore. В файлах sln студия хранит структуру проекта и связи между элементами. Если вы будете потом откатываться к более раннему коммиту, то этим немало озадачите студию, ей придется заново выстраивать связи. Поэтому их нужно коммитить вместе с другими файлами.
На всякий случай оставлю тут копию текущего состояния .gitignore с гитхаба
## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons.
# User-specific files *.suo *.user *.userosscache *.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio) *.userprefs
# Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ build/ bld/ [Bb]in/ [Oo]bj/
# Visual Studio 2015 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/
# MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.*
# NUNIT *.VisualState.xml TestResult.xml
# Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c
# DNX project.lock.json artifacts/
*_i.c *_p.c *_i.h *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc
# Chutzpah Test files _Chutzpah*
# Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile
# Visual Studio profiler *.psess *.vsp *.vspx *.sap
# TFS 2012 Local Workspace $tf/
# Guidance Automation Toolkit *.gpState
# ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user
# JustCode is a .NET coding add-in .JustCode
# TeamCity is a build add-in _TeamCity*
# DotCover is a Code Coverage Tool *.dotCover
# NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_*
# MightyMoose *.mm.* AutoTest.Net/
# Web workbench (sass) .sass-cache/
# Installshield output folder [Ee]xpress/
# DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html
# Click-Once directory publish/
# Publish Web Output *.[Pp]ublish.xml *.azurePubxml # TODO: Comment the next line if you want to checkin your web deploy settings # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj
# NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore **/packages/* # except build/, which is used as an MSBuild target. !**/packages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/packages/repositories.config
# Windows Azure Build Output csx/ *.build.csdef
# Windows Azure Emulator ecf/ rcf/
# Windows Store app package directory AppPackages/
# Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/
# Others ClientBin/ [Ss]tyle[Cc]op.* ~$* *~ *.dbmdl *.dbproj.schemaview *.pfx *.publishsettings node_modules/ orleans.codegen.cs
# RIA/Silverlight projects Generated_Code/
# Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm
# SQL Server files *.mdf *.ldf
# Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings
# Microsoft Fakes FakesAssemblies/
# GhostDoc plugin setting file *.GhostDoc.xml
# Node.js Tools for Visual Studio .ntvs_analysis.dat
# Visual Studio 6 build log *.plg
# Visual Studio 6 workspace options file *.opt
# Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions
# Paket dependency manager .paket/paket.exe
# FAKE - F# Make .fake/

Почему блок при применении `padding` увеличивает свои размеры?

В заглавии блоки multi-accordion-title и находящийся в нём catalog-title почему-то увеличивают с размер, когда применяется padding хотя их родительский блок шириной 240px. Как это исправить?
$('.multi-accordion li > a').next().parent().addClass('has-children') $('.multi-accordion .has-children > a').click(function(e) { var li = $(this).parent(); li.parent('ul').find('.open').add(li).toggleClass('has-children open').children('ul'); e.preventDefault(); }); .body { } .col-left-first { display: block; position: relative; width: 240px; margin-left: 240px; box-sizing: border-box; } .multi-accordion-catalog { display: block; position: relative; width: 100%; } .multi-accordion { line-height: 40px; margin: 0; color: #646464; padding: 0; font-family: "Helvetica Neue", Arial, sans-serif; font-weight: normal; font-size: 16px; text-transform: none; } .multi-accordion ul { display: none; list-style: none; padding: 0px; } .multi-accordion li { list-style: none; } .multi-accordion > li > a{ } .multi-accordion > li > ul { padding-left: 8px; } .multi-accordion > li > ul > li > ul { padding-left: 8px; } .multi-accordion a, .multi-accordion a:link, .multi-accordion a:visited { display: block; text-decoration: none; padding: 0 24px 0 10px; color: #646464; position: relative; } .multi-accordion a:hover { } .multi-accordion > a:only-child:link, .multi-accordion > a:only-child:visited { color: blue; } .multi-accordion > a:only-child:hover { text-decoration: underline; background: transparent; } .multi-accordion-title { display: inline-block; position: relative; width: 100%; padding-right: 40px; margin-bottom: 12px; } .multi-accordion-title:after { content: ''; position: absolute; width: 0; height: 0; border-style: solid; top: 100%; left: -12px; border-width: 0 12px 12px 0; border-color: transparent #cccccc transparent transparent; } .catalog-title { display: inline-block; position: relative; height: 40px; width: 100%; font-family: "Helvetica Neue", Arial, sans-serif; font-weight: 600; font-size: 16px; text-transform: uppercase; background-color: #e1e1e1; padding: 9px 0 0 10px; box-shadow: -4px 4px 4px rgba(0, 0, 0, 0.2); } .catalog-title:before { content: ''; position: absolute; top: 0; left: -12px; height: 100%; width: 12px; background-color: #e1e1e1; } .catalog-title:after { content: ''; position: absolute; top: 0; left: 100%; border-style: solid; border-width: 0 0 40px 40px; border-color: transparent transparent transparent #e1e1e1; } .has-children, .open { position: relative; } .has-children > a:before , .open > a:before { content: ''; position: absolute; height: 24px; width: 24px; top: 8px; right: 4px; } .has-children > a:before { background: url(https://cdn2.iconfinder.com/data/icons/ios-7-icons/50/down4-16.png) no-repeat; } .open > a:before { background: url(https://cdn1.iconfinder.com/data/icons/mayssam/512/Top_2-16.png) no-repeat; } .multi-accordion .open > ul { display: block; }



Ответ

По умолчанию значение padding не включается в высоту и ширину блока. Либо отнимайте от размеров высоты и ширины значения padding, либо задавайте целевому блоку свойство box-sizing:border-box;, которое включит внутренние отступы и границы в значения ширины и высоты элемента
.multi-accordion-title { box-sizing: border-box; ... }

Получение пути текущего проекта C++

Как в консольном приложении на C++ получить путь к текущему проекту ? Можно ли как-то использовать для этого переменные IDE, такие как $(TargetDir), например ?


Ответ

Идём в настройки проекта. Далее: Configuration Properties->Debugging->Command Arguments. Жмём Edit... в этом поле, после чего появляется диалог. Выбираем Macros>>, далее выбираем нужный нам макрос и нажимаем Insert. Вам нужен $(ProjectDir). После этого, в коде, получить нужный нам параметр очень просто:
#include using namespace std;
int main(int argc, char** argv) { cout << argv[1] << "
"; }

что такое барьер? (структуры данных)

По предмету "Алгоритмы и структуры данных" дали задание создать:
Структуру данных для организации линейного односвязного списка Структура данных: очередь (FIFO) с барьером. Представление памяти - динам. память.
Все, в принципе понятно, кроме барьера
Кто то может простым языком объяснить, что это, и с чем его едят?


Ответ

У вас имеется линейный неупорядоченный список элементов, а именно, в данном случае - FIFO (не будем заморачиваться с тем, что такая структура хранения данных - это очередь, будем называть списком).
Однажды вам понадобится выполнить поиск в этом списке элемента по значению, но так как элементы в нем не упорядочены, то и вариант поиска всего один: полный обход списка поэлементно (если без непосредственного применения сортировки перед поиском, конечно же).
На каждом шаге поиска вам придется проверять не выходите ли вы за границы вашего списка, а лишь затем сравнивать текущий элемент списка с искомым. Существует несколько способов проверки этого факта: один из них - установить в конец списка уникальный элемент, натыкаясь на который вы будете уверены, что достигли конца списка. При этом необходимо обеспечить уникальность данного элемента. Вот именно этот элемент и будет называться барьером (т.е. дальше него искать не стоит - вы обошли весь список).
В вашем же случае с FIFO (First In, First Out) придется добавлять барьерный элемент в список самым последним в связи с порядком обхода данного списка, а затем при обходе списка проверять не является ли текущий элемент барьером, т.е. вы должны заранее знать значение барьера.

Особенности использования scanner.nextLine()

У меня есть такой код.
String anun=sc.nextLine(); System.out.println("age:"); int tar=sc.nextInt(); System.out.println("email:"); String mail=sc.nextLine(); System.out.println(mail); System.out.println("email:" + mail);
И всегда, когда наступает время для String mail=sc.nextLine();, просто пропускается шаг. В чем заключается проблема?


Ответ

В этой строке вы считали только число (не учитывая всё, что может идти дальше, включая конец строки):
sc.nextInt();
Далее при вызове
sc.nextLine();
Происходит считывание конца строки (начиная от ранее введенного числа и заканчивая переводом строки). Можете добавить дополнительный вызов sc.nextLine(); после каждого вызова nextInt();

selector c VectorDrawables падает на Resources$NotFoundException

Еще не так сильно запылилась новость, про возможность использования векторов в ресурсах, как 7 апреля вышло обновление для Android Studio и иже с ним. Обновление подсосало новую версию Gradle (2.0). В результате у меня приложение падает с воплями на Resources$NotFoundException на PRE-Lollipop версиях, но только на тех ресурсах, где вектор использовался в виде стейта в selector

Это кастомный чекбокс, ресурс устанавливаю программно через setButtonDrawable() и при запуске на PRE-Lollipop версиях получаю большой стейк на выходе. Если в setButtonDrawable() подать просто обычный вектор, то все прекрассно работает, за исключением того, что мне это не нужно, так как более нет стейтов на чебкоксе. Естественно для работы в векторами в gradle файле я указывал необходимые параметры. С начало по стейку грешил на сам векторный файл, но при установке ресурса ic_like_stroke_24dp на прямую в виджет, креш не вызывается. Вот сами векторы для экспериментов.
ic_like_stroke_24dp.xml



и
ic_like_solid_red_24dp


До того, как я обновился у меня в gradle были следующие параметры (для Gradle 1.5)
android { defaultConfig { generatedDensities = [] } aaptOptions { additionalParameters "--no-version-vectors" } }
После обновления Android Studio и Gradle (2.0) я заменил выше описанное на
android { defaultConfig { vectorDrawables.useSupportLibrary = true } }
И отсюда вопрос, куда копать? После обновления ушла возможность использовать вектор в selector. Откатить студию до прошлой версии можно, но не выход. Стейк:
Fatal Exception: android.content.res.Resources$NotFoundException: File res/drawable/check_box_like.xml from drawable resource ID #0x7f02004d at android.content.res.Resources.loadDrawable(Resources.java:1953) at android.content.res.Resources.getDrawable(Resources.java:660) at android.support.v7.widget.ResourcesWrapper.getDrawable(ResourcesWrapper.java:128) at android.support.v7.widget.TintResources.getDrawable(TintResources.java:45) at android.support.v4.content.ContextCompat.getDrawable(ContextCompat.java:323) at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:201) at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:191) at android.support.v7.widget.AppCompatCheckBox.setButtonDrawable(AppCompatCheckBox.java:74) at view.catalogs.CatalogListAdapter$ViewHolder.(CatalogListAdapter.java:126) at view.catalogs.CatalogListAdapter.getItemView(CatalogListAdapter.java:61) at com.culiu.mhvp.core.tabs.GridViewWithHeaderBaseAdapter.createItemRow(GridViewWithHeaderBaseAdapter.java:114) at com.culiu.mhvp.core.tabs.GridViewWithHeaderBaseAdapter.getView(GridViewWithHeaderBaseAdapter.java:95) at com.culiu.mhvp.core.InnerListView$InflateFirstItemIfNeededAdapter.getView(InnerListView.java:557) at android.widget.HeaderViewListAdapter.getView(HeaderViewListAdapter.java:220) at android.widget.AbsListView.obtainView(AbsListView.java:2159) at android.widget.ListView.makeAndAddView(ListView.java:1831) at android.widget.ListView.fillDown(ListView.java:674) at android.widget.ListView.fillSpecific(ListView.java:1332) at android.widget.ListView.layoutChildren(ListView.java:1642) at android.widget.AbsListView.onLayout(AbsListView.java:1994) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.support.v4.view.ViewPager.onLayout(ViewPager.java:1695) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1663) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1521) at android.widget.LinearLayout.onLayout(LinearLayout.java:1434) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.support.v4.view.ViewPager.onLayout(ViewPager.java:1695) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1663) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1521) at android.widget.LinearLayout.onLayout(LinearLayout.java:1434) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.support.design.widget.CoordinatorLayout.layoutChild(CoordinatorLayout.java:1091) at android.support.design.widget.CoordinatorLayout.onLayoutChild(CoordinatorLayout.java:801) at android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:815) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.support.v4.widget.DrawerLayout.onLayout(DrawerLayout.java:1187) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1663) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1521) at android.widget.LinearLayout.onLayout(LinearLayout.java:1434) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1663) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1521) at android.widget.LinearLayout.onLayout(LinearLayout.java:1434) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:1892) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1711) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:989) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4351) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749) at android.view.Choreographer.doCallbacks(Choreographer.java:562) at android.view.Choreographer.doFrame(Choreographer.java:532) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735) at android.os.Handler.handleCallback(Handler.java:725) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:5041) at java.lang.reflect.Method.invokeNative(Method.java) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) at dalvik.system.NativeStart.main(NativeStart.java) Caused by android.content.res.Resources$NotFoundException: File res/drawable/ic_like_stroke_24dp.xml from drawable resource ID #0x7f02009d at android.content.res.Resources.loadDrawable(Resources.java:1953) at android.content.res.Resources.getDrawable(Resources.java:660) at android.graphics.drawable.StateListDrawable.inflate(StateListDrawable.java:173) at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:885) at android.graphics.drawable.Drawable.createFromXml(Drawable.java:822) at android.content.res.Resources.loadDrawable(Resources.java:1950) at android.content.res.Resources.getDrawable(Resources.java:660) at android.support.v7.widget.ResourcesWrapper.getDrawable(ResourcesWrapper.java:128) at android.support.v7.widget.TintResources.getDrawable(TintResources.java:45) at android.support.v4.content.ContextCompat.getDrawable(ContextCompat.java:323) at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:201) at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:191) at android.support.v7.widget.AppCompatCheckBox.setButtonDrawable(AppCompatCheckBox.java:74) at view.catalogs.CatalogListAdapter$ViewHolder.(CatalogListAdapter.java:126) at view.catalogs.CatalogListAdapter.getItemView(CatalogListAdapter.java:61) at com.culiu.mhvp.core.tabs.GridViewWithHeaderBaseAdapter.createItemRow(GridViewWithHeaderBaseAdapter.java:114) at com.culiu.mhvp.core.tabs.GridViewWithHeaderBaseAdapter.getView(GridViewWithHeaderBaseAdapter.java:95) at com.culiu.mhvp.core.InnerListView$InflateFirstItemIfNeededAdapter.getView(InnerListView.java:557) at android.widget.HeaderViewListAdapter.getView(HeaderViewListAdapter.java:220) at android.widget.AbsListView.obtainView(AbsListView.java:2159) at android.widget.ListView.makeAndAddView(ListView.java:1831) at android.widget.ListView.fillDown(ListView.java:674) at android.widget.ListView.fillSpecific(ListView.java:1332) at android.widget.ListView.layoutChildren(ListView.java:1642) at android.widget.AbsListView.onLayout(AbsListView.java:1994) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.support.v4.view.ViewPager.onLayout(ViewPager.java:1695) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1663) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1521) at android.widget.LinearLayout.onLayout(LinearLayout.java:1434) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.support.v4.view.ViewPager.onLayout(ViewPager.java:1695) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1663) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1521) at android.widget.LinearLayout.onLayout(LinearLayout.java:1434) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.support.design.widget.CoordinatorLayout.layoutChild(CoordinatorLayout.java:1091) at android.support.design.widget.CoordinatorLayout.onLayoutChild(CoordinatorLayout.java:801) at android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:815) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.support.v4.widget.DrawerLayout.onLayout(DrawerLayout.java:1187) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1663) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1521) at android.widget.LinearLayout.onLayout(LinearLayout.java:1434) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1663) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1521) at android.widget.LinearLayout.onLayout(LinearLayout.java:1434) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:1892) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1711) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:989) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4351) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749) at android.view.Choreographer.doCallbacks(Choreographer.java:562) at android.view.Choreographer.doFrame(Choreographer.java:532) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735) at android.os.Handler.handleCallback(Handler.java:725) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:5041) at java.lang.reflect.Method.invokeNative(Method.java) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) at dalvik.system.NativeStart.main(NativeStart.java) Caused by org.xmlpull.v1.XmlPullParserException: Binary XML file line #2: invalid drawable tag vector at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:881) at android.graphics.drawable.Drawable.createFromXml(Drawable.java:822) at android.content.res.Resources.loadDrawable(Resources.java:1950) at android.content.res.Resources.getDrawable(Resources.java:660) at android.graphics.drawable.StateListDrawable.inflate(StateListDrawable.java:173) at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:885) at android.graphics.drawable.Drawable.createFromXml(Drawable.java:822) at android.content.res.Resources.loadDrawable(Resources.java:1950) at android.content.res.Resources.getDrawable(Resources.java:660) at android.support.v7.widget.ResourcesWrapper.getDrawable(ResourcesWrapper.java:128) at android.support.v7.widget.TintResources.getDrawable(TintResources.java:45) at android.support.v4.content.ContextCompat.getDrawable(ContextCompat.java:323) at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:201) at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:191) at android.support.v7.widget.AppCompatCheckBox.setButtonDrawable(AppCompatCheckBox.java:74) at view.catalogs.CatalogListAdapter$ViewHolder.(CatalogListAdapter.java:126) at view.catalogs.CatalogListAdapter.getItemView(CatalogListAdapter.java:61) at com.culiu.mhvp.core.tabs.GridViewWithHeaderBaseAdapter.createItemRow(GridViewWithHeaderBaseAdapter.java:114) at com.culiu.mhvp.core.tabs.GridViewWithHeaderBaseAdapter.getView(GridViewWithHeaderBaseAdapter.java:95) at com.culiu.mhvp.core.InnerListView$InflateFirstItemIfNeededAdapter.getView(InnerListView.java:557) at android.widget.HeaderViewListAdapter.getView(HeaderViewListAdapter.java:220) at android.widget.AbsListView.obtainView(AbsListView.java:2159) at android.widget.ListView.makeAndAddView(ListView.java:1831) at android.widget.ListView.fillDown(ListView.java:674) at android.widget.ListView.fillSpecific(ListView.java:1332) at android.widget.ListView.layoutChildren(ListView.java:1642) at android.widget.AbsListView.onLayout(AbsListView.java:1994) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.support.v4.view.ViewPager.onLayout(ViewPager.java:1695) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1663) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1521) at android.widget.LinearLayout.onLayout(LinearLayout.java:1434) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.support.v4.view.ViewPager.onLayout(ViewPager.java:1695) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1663) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1521) at android.widget.LinearLayout.onLayout(LinearLayout.java:1434) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.support.design.widget.CoordinatorLayout.layoutChild(CoordinatorLayout.java:1091) at android.support.design.widget.CoordinatorLayout.onLayoutChild(CoordinatorLayout.java:801) at android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:815) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.support.v4.widget.DrawerLayout.onLayout(DrawerLayout.java:1187) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1663) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1521) at android.widget.LinearLayout.onLayout(LinearLayout.java:1434) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1663) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1521) at android.widget.LinearLayout.onLayout(LinearLayout.java:1434) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:1892) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1711) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:989) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4351) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749) at android.view.Choreographer.doCallbacks(Choreographer.java:562) at android.view.Choreographer.doFrame(Choreographer.java:532) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735) at android.os.Handler.handleCallback(Handler.java:725) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:5041) at java.lang.reflect.Method.invokeNative(Method.java) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) at dalvik.system.NativeStart.main(NativeStart.java)


Ответ

Нарвался на новость - https://plus.google.com/+AndroidDevelopers/posts/iTDmFiGrVne частично на время пока можно забыть про векторы. Проблема решается удалением строки в gradle
android { defaultConfig { vectorDrawables.useSupportLibrary = true } }
Это приведет к увеличению объему апк, за счет конвертации векторов в png.