Страницы

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

суббота, 4 января 2020 г.

Как писать unit тесты для DAL?

#c_sharp #юнит_тесты


К примеру есть классы с такими extension методами:

IQueryable ToViewDto(this IQueryable query)


Или элементарный Linq запрос (в другом классе):

_repository.Query
                .Where(x => x.Id == id)
                .Where(x=>x.Type == UserType.Oldfag)
                .ToViewDto()
                .ToList();


Каждый раз в тестовом методе заполнять список с UserEntity делать AsQueryable() уж
очень долго. 

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

Подскажите как правильно поступить? Или я иду в направлении интеграционных тестов
и DAL вообще не стоит трогать? 
    


Ответы

Ответ 1



Каждый раз в тестовом методе заполнять список с UserEntity делать AsQueryable() уж очень долго. Именно так и надо делать. В результате вы получите юнит-тесты в чистом виде, без сторонней зависимости в виде БД. И это не должно быть долго, поскольку набор входных данных должен получаться небольшой, если тестовые методы у вас достаточно хорошо разбиты по соответствуют отдельным кейсам. Или я иду в направлении интеграционных тестов и DAL вообще не стоит трогать? Тесты всякие нужны, тесты всякие важны. И на DAL в т.ч. Просто если у вас нет в БД никакой логики, то тогда вы сможете замокать ее, и получить чистые юнит-тесты. Если же в БД есть логика, то придется делать и интеграционные тесты (тут, впрочем, можно подискутировать на тему того, стоит ли тестировать БДшный код из тестов приложения или иметь отдельные тесты для процедур).

Ответ 2



Мне кажется, тут нужно разделять тесты DAL-а, от тестов пользователей DAL-а. Вот, например, как протестировать приведенный фрагмент?: _repository.Query .Where(x => x.Id == id) .Where(x=>x.Type == UserType.Oldfag) .ToViewDto() .ToList(); Для этого нужно проверить: (1) что DAL реализован корректно и (2) что связка DAL_Client -> DAL -> Data Store работают корректно. Разбиваем этот процесс на две части: Тесты реализации DAL-а Парсинг деревьев выражений Применение предикатов для фильтрации содержимого SQL-генератор Работу методов Select и других методов IQueriable Корректность работы метода ToViewDto Данные тесты могут (и должны) использовать классы, отличные от UserEntity: для этого подойдут дата-объекты. Тесты связки DAL_Client -> DAL -> DataStore Теперь нужно проверить, что использование репозитория в приведенном виде приводит к корректным результатам. При этом нет никакого смысла проверить парсинг выражений и работу предикатов. Эту связку нужно уже интеграционными тестами, поскольку важно, чтобы end-to-end сценарий использования репозитория приводил к нужным результатам. Подобные вызовы можно завернуть в фасадные классы, а можно оставить прямо в контроллерах, сервисах. Это зависит от их числа и сложности. Сложно сказать сейчас, есть ли смысл мокать репозиторий с UserEntity, поскольку не ясно, будет ли при этом проверяться что-то, что еще не было покрыто в первом разделе юнит-тестами, которые работали с произвольными дата-объектами. Я бы начал с интеграционных тестов, ведь они все равно нужны. Потом, если будет понятно, что нужны более низкоуровневые тесты, то уже бы добавлял их по мере необходимости.

Ответ 3



Все зависит от того насколько изменчив список с UserEntity. Если редко, или один список на все тесты - положить данные в файл/json и грузить данные в каждом тесте. Если каждый тест - свой список - использовать много файлов или использовать аналог approvaltests

Объединить два массива с объединением полей объектов

#javascript #массивы


Подскажите плиз как объединить несколько массивов в один.
Допустим у меня есть массивы следующего вида

var first = [
    { id: 1, name: 'first' },
    { id: 2, name: 'second' },
    { id: 3, name: 'third' }
]

var second = [
    { id: 2, filed: 'foo2' },
    { id: 3, field: 'foo3' },
    { id: 4, field: 'foo4' }
]

var third = [
    { id: 2, data: 'some2' },
    { id: 4, data: 'some4' },
    { id: 6, data: 'some6' }
]


Я хотел бы объединить их чтобы получить такой результат:

var result = [
    { id: 1, name: 'first',   field: undefined, data: undefined },
    { id: 2, name: 'second',  field: 'foo2',    data: 'some2' },
    { id: 3, name: 'third',   field: 'foo3',    data: undefined },
    { id: 4, name: undefined, field: 'foo4',    data: 'some4' },
    { id: 5, name: undefined, field: undefined, data: undefined },
    { id: 6, name: undefined, field: undefined, data: 'some6' }
]


Как это можно сделать? Заранее спасибо
    


Ответы

Ответ 1



Если объединение идет по свойству id, то можно использовать следующий код: function merge() { var hash = {}; // временный хэш объектов по свойству id for (var l = 0; l < arguments.length; l++) { var arr = arguments[l]; if (!arr.length) continue; for (var i = 0; i < arr.length; i++) { var el = arr[i]; if (!('id' in el)) continue; var id = el.id; if (!hash[id]) hash[id] = {}; for (var key in el) { if (el.hasOwnProperty(key)) hash[id][key] = el[key]; } } } var result = []; for (var id in hash) { if (hash.hasOwnProperty(id)) result.push(hash[id]); } return result; } var result = merge(first, second, third);

Ответ 2



function merge(){ var result = []; Array.prototype.forEach.call(arguments, function(arr){ // Проходимся по переданным агрументам, функция принимает неограниченное количество аргументов if(Array.isArray(arr)){ for(e in arr){ // Проходимся по всем e = arr[e]; // переданным объектам var tmp = {}, isAdd = true; result.some(function(i){ if(i.id == e.id){ tmp = i; // Если в массиве уже был объект с данным id, то берём его isAdd = false; // и запрещаем добавлять его в результат return true; } }); for(prop in e){ tmp[prop] = e[prop]; // Изменяем/добавляем свойства из переданного объекта } if(isAdd) result.push(tmp); } } }); return result; } var first = [ { id: 1, name: 'first' }, { id: 2, name: 'second' }, { id: 3, name: 'third' } ]; var second = [ { id: 2, filed: 'foo2' }, { id: 3, field: 'foo3' }, { id: 4, field: 'foo4' } ]; var third = [ { id: 2, data: 'some2' }, { id: 4, data: 'some4' }, { id: 6, data: 'some6' } ]; var res = merge(first, second, third); console.info(res); /* => [ { "id": 1, "name": "first" }, { "id": 2, "name": "second", "filed": "foo2", "data": "some2" }, { "id": 3, "name": "third", "field": "foo3" }, { "id": 4, "field": "foo4", "data": "some4" }, { "id": 6, "data": "some6" }, length: 5 ] */

Ответ 3



Если вы планируете работать с коллекциями, объединять их, сортировать и производить прочие подобные операции, то я бы порекомендовал вам использовать для этого специальную библиотеку: Lodash или Underscore

Ответ 4



Для выполнения запросов удобно работать с LINQ.js. // Приводим массивы к удобному виду — словарю "индентификатор-значение" var names = Enumerable.From(first) .ToObject("$.id", "$.name"); var fields = Enumerable.From(second).ToObject("$.id", "$.field"); var datas = Enumerable.From(third) .ToObject("$.id", "$.data"); // Получаем общий список ключей — объединение списков ключей из трёх словарей выше var keys = Enumerable.From(Object.keys(names)) .Union(Object.keys(fields)) .Union(Object.keys(datas)); // Объединяем в общее перечисление var joined = keys.Select(function (id) { return { id: id, name: names[id], field: fields[id], data: datas[id] }; }); // Преобразуем перечисление к стандартному массиву console.log(joined.ToArray()); var first = [ { id: 1, name: 'first' }, { id: 2, name: 'second' }, { id: 3, name: 'third' } ]; var second = [ { id: 2, filed: 'foo2' }, { id: 3, field: 'foo3' }, { id: 4, field: 'foo4' } ]; var third = [ { id: 2, data: 'some2' }, { id: 4, data: 'some4' }, { id: 6, data: 'some6' } ]; var names = Enumerable.From(first).ToObject("$.id", "$.name"); var fields = Enumerable.From(second).ToObject("$.id", "$.field"); var datas = Enumerable.From(third).ToObject("$.id", "$.data"); var keys = Enumerable.From(Object.keys(names)) .Union(Object.keys(fields)) .Union(Object.keys(datas)); var joined = keys.Select(function (id) { return { id: id, name: names[id], field: fields[id], data: datas[id] }; }); document.write(joined.ToJSON());

Ответ 5



function smartMerge(mainProp, arrays) { /* Более универсальная версия, но требуется оптимизация mainProp - общее свойство для всех элементов, всех массивов: число arrays = массив массивов ( простите за тавтологию ) */ var mergedArray = []; // конечный массив for(var arrayIndex in arrays) { var array = arrays[arrayIndex]; for( var elementIndex in array) { var element = array[elementIndex]; if (!mergedArray[element[mainProp]]) mergedArray[element[mainProp]]={}; for( var prop in element) { mergedArray[element[mainProp]][prop] = element[prop]; } } } return mergedArray.filter(function (el) { return el;}); } // используем var arr = smartMerge('id', [first, second, third]); Живой пример( ответ в консоли )

Ответ 6



Все можно сделать намного легче с помощью concat var result = first.concat(second, third);

При нажатии комбинации клавиш раздаётся звук и ввода нет

#windows_7


Например, не работают сочетания
Space + → + ←
d + f + 3
d + f + 5

Но при этом работают
d + f + 4
d + f + 6

Система начинает издавать сигналы, как при залипании клавиш.

Если открою стандартный windows блокнот, и зажму d + f + 6, то в блокнот будет записываться
6666666666666666666...

Если зажму d + f + 5, то ничего записываться не будет, будет сигнал звуковой через
каждые 0.8 секунды. Залипание клавиш отключено.

Как узнать из-за чего подобное? 
    


Ответы

Ответ 1



Это называется Key jamming and ghosting. Сама по себе технология изготовления дешевых клавиатур - две пленки с пересекающимися дорожками - накладывает ограничение на количество одновременных нажатий. Но при этом экономит материалы - не надо вести два провода к каждой кнопке! Т.е. из матрицы n + m проводов получается сделать аж n * m кнопок. Но это вызывает проблему определения одновременных нажатий: Например, кнопки A, B, C, D могут быть реализованы двумя парами дорожек: A1, A2, B1, B2: A замыкает A1, B1 B замыкает A1, B2 C замыкает A2, B1 D замыкает A2, B2 и вот при нажатии одновременно на A+B+C получаются замкнуты еще и A2, B2, хотя D не нажата. Это эффект Keyboard Ghosting. D - кнопка-призрак. Это не так страшно при наборе текста - но вот в играх это вызывает неприятный эффект. Пытался подпрыгнуть и повернуть одновременно - и бросил себе под ноги гранату. Производители клавиатур решают эту следующими хаками: делают разводку, которая учитывает стандартные раскладки в играх (WASD) для того же WASD впаивают isolation diodes (что удорожает клавиатуру) для всех остальных проблемных комбинаций - тупо игнорируют их и выдают ошибку Последнее называется Keyboard Jamming, и вот именно его вы и наблюдаете. Для дешевых клавиатур это срабатывает примерно на 5% трехбуквенных комбинаций. Объяснение проблемы и тулза для теста на сайте MS Applied Sciences Статья в вики на эту тему

Ответ 2



Варианты: 1) Нестандартный драйвер (многие производители предоставляют свое ПО для тонкой настройки) на клавиатуру. 2) Слиплись (перемыкают) дорожки на самой клавиатуре.

Автогенерируемые конструкторы и операторы присваивания rvalue

#cpp #cpp11


Читаю Прата С++ 2015 стр 1072.

В одном абзаце он пишет 


  Если вы не определили конструктор переноса или операцию
  присваивания с переносом, компилятор не будет автоматически
  предоставлять конструктор копирования или операцию присваивания с
  копированием


, а в другом 


  Например, если определен конструктор переноса, то конструктор по
  умолчанию, конструктор копирования и операция присваивания с
  копированием не предоставляются


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


Ответы

Ответ 1



ИМХО ошибка перевода. Из оригинала с моим переводом: Конструктор по умолчанию: те же правила, что и в C++98. Генерируется только если класс не содержит определенных пользователем конструкторов. Деструктор: практически те же правила, что и в C++98; единственное отличие - в том, что по умолчанию деструкторы объявляются как noexcept. Как и в C++98, виртуальный если деструктор базового класса также виртуальный. Копирующий конструктор: то же поведение, что и в C++98: вызов копирующего конструктора для всех нестатических членов. Генерируется только если в классе нет определенного пользователем копирующего конструктора. Удаляется, если класс определяет операцию перемещения. Генерация этой функции в классе с определенным пользователем копирующим оператором присваивания или деструктором считается устаревшей (deprecated). Копирующее присваивание: то же поведение, что и в C++98: копирующее присваивание всех нестатических членов. Генерируется только если в классе нет определенного пользователем копирующего присваивания. Удаляется, если в классе присутствует определенная пользователем операция перемещения. Генерация в случае, если в классе есть определенный пользователем копирующий конструктор или деструктор, считается устаревшей (deprecated). Перемещающий конструктор и перемещающее присваивание: перемещают нестатические члены (соответственно конструктором или присваиванием - прим. АА). Генерируются только если класс не содержит определенных пользователем операций копирования, перемещения, или деструкторов. Примечание: шаблонные методы не участвуют в этих правилах, то есть не предотвращают генерацию специальных функций, даже если их специализации могут иметь подходящую форму (переформулировал - АА). UPD: только это, кажется, из другой книги - Effective Modern C++.

Ответ 2



Думаю нашел что Вы хотели с примером. If a class has no explicitly defined constructors, the compiler will implicitly declare and define a default constructor for it. This implicitly defined default constructor is equivalent to an explicitly defined one with an empty body. For example: class MyClass { int x; // no constructor, so the compiler produces an (implicit) default constructor }; int main() { MyClass m; // no error at runtime: the (implicit) default constructor is called } If constructors are explicitly defined for a class, but they are all non-default, the compiler will not implicitly define a default constructor, leading to a situation where the class does not have a default constructor. This is the reason for a typical error, demonstrated by the following example. class MyClass { public: MyClass (int y); // declaration a non-default constructor private: int x; }; MyClass :: MyClass (int y) { x = y; } int main() { MyClass m(100); // the non-default constructor is called MyClass * p; // for pointer declarations, the compiler does not need to know about constructors p = new MyClass(); // error at compilation: no default constructor return 0; } Since neither the programmer nor the compiler has defined a default constructor, the creation of the objected pointed to by p leads to an error. Вы были правы. Если нет Конструктора по умолчанию. Он не создается и дает ошибку при использовании. А Выражение "Если вы не определили конструктор переноса или операцию присваивания с переносом, компилятор не будет автоматически предоставлять конструктор копирования или операцию присваивания с копированием", говорит что не будут созданы конструкторы копирования и присваивания. Значит создатся конструктор по умолчанию. от http://en.wikipedia.org/wiki/Default_constructor

Инициализация значимых типов в C#

#c_sharp #net #clr


Читаю книгу, написанную Дж. Рихтером, CLR via C#. К сожалению, в самом начале у меня
возникают вопросы. Надеюсь, вы поможете мне разобраться.

Джеффри пишет, что различие между значимыми и ссылочными типами заключается в том,
что значимые типы хранятся в стеке потока, в то время как ссылочные типы хранятся по
принципу: объект типа лежит в управляемой куче, а ссылка на этот объект находится в
стеке. Далее он говорит, что ссылка на объект ссылочного типа возвращается оператором
'new'. А для значимых типов возвращать ссылку не нужно, поэтому можно не писать оператор
'new'. 

Дж. Рихтер приводит пример:

struct SomeVal { public Int32 x; } // здесь он объявляет структуру
SomeVal v1 = new SomeVal();


Потом он добавляет, что строку выше можно записать иначе:

SomeVal v1;


Дословно:


  Здесь тоже создается IL-код, который помещает экземпляр SomeVal в стек
  потока и обнуляет все его поля.


Подскажите, правда ли это? Ведь мы же не можем обратиться к какому-нибудь полю структуры
до тех пор, пока не выполним его инициализацию. А по словам Джеффри выходит, что ничего
инициализировать не нужно, ведь все поля сами обнуляются.
    


Ответы

Ответ 1



Это правда. Вся выделенная память просто инициализируется нулями. Ведь мы же не можем обратиться к какому-нибудь полю структуры до тех пор, пока не выполним его инициализацию. Это проверка C# компилятора, CLR же не накладывает таких ограничений. Книга Рихтера -- она же в первую очередь о CLR, поэтому он не врет.

Замена символов в строке

#cpp #парсер #символы #замена


У меня есть строка: "''Start''".
После всех действий над ней, должно получиться: "Start". Т.е удаляются все символы
",  а затем все пары символов '' заменяются на ".
Удаляю из нее все символы ":
result.erase(std::remove(result.begin(), result.end(), '"' ), result.end());

Затем нужно заменить все пары символов '' на ":
replace(result.begin(), result.end(), "\'\'", "\"");

Выдает ошибку следующую ошибку: 

tools/data_parser.cpp: In function ‘int main(int, const char**)’:
tools/data_parser.cpp:21:52: error: no matching function for call to ‘replace(std::__cxx11::basic_string::iterator,
std::__cxx11::basic_string::iterator, const char [3], const char [2])’
  replace(result.begin(), result.end(), "\'\'", "\"");
                                                    ^
In file included from /usr/include/c++/5/algorithm:62:0,
                 from tools/data_parser.cpp:7:
/usr/include/c++/5/bits/stl_algo.h:4233:5: note: candidate: template void std::replace(_FIter, _FIter, const _Tp&, const _Tp&)
     replace(_ForwardIterator __first, _ForwardIterator __last,
     ^
/usr/include/c++/5/bits/stl_algo.h:4233:5: note:   template argument deduction/substitution
failed:
tools/data_parser.cpp:21:52: note:   deduced conflicting types for parameter ‘const
_Tp’ (‘char [3]’ and ‘char [2]’)
  replace(result.begin(), result.end(), "\'\'", "\"");


Я так понимаю, что std::replace заменяет только один символ на другой. Как заменить
пару символов? Компилирую так: g++-5 -std=c++11 cfg_parser.cpp -o cfg_parser
    


Ответы

Ответ 1



Если я вас правильно понял, то вы можете выполнить задачу следующим образом #include #include #include int main() { std::string s( "\"''Start''\"" ); std::cout << '[' << s << ']' << std::endl; s.erase( std::remove( s.begin(), s.end(), '"' ), s.end() ); for ( std::string::size_type n = 0; ( n = s.find( "''", n ) ) != std::string::npos; ++n ) { s.replace( n, 2, 1, '"' ); } std::cout << '[' << s << ']' << std::endl; } Программа имеем следующий вывод на консоль: ["''Start''"] ["Start"]

Ответ 2



Просто, быстро и (надеюсь) надежно #include #include char * replq (char *str) { int i, j; for (i = j = 0; str[i]; i++) if (str[i] != '"') { if (str[i] == '\'' && str[i + 1] == '\'') { str[j++] = '"'; i++; } else str[j++] = str[i]; } str[j] = 0; return str; } int main (int ac, char *av[]) { char str[1000]; while (fgets(str, 1000, stdin)) puts(replq(str)); return puts("End") == EOF; } По поводу Си -- конечно это Си (но g++ признает код своим, т.е. крестовым).

Ответ 3



std::replace действительно заменяет лишь символы. Вам нужно воспользоваться string::replace. string haystack = "''text''"; string needle = "''"; size_t pos; while ((pos = haystack.find(needle)) != haystack.npos) haystack.replace(pos, pos + needle.length(), "\""); Проверка: http://ideone.com/zxa0Rn Впрочем, это по сути не отличается от варианта @Vlad from Moscow

Ответ 4



/*********************************************************** * Method: fn_Replace * Description Замена одного символа в строке на один символ или строку * Returns: void * Parameter: wstring & ws - исходная строка * Parameter: const wchar_t wchF - один заменяемый символ * Parameter: LPCTSTR wchR - замена, символ или строка символов ************************************************************/ void fn_Replace(wstring& ws, const wchar_t wchF, LPCTSTR wchR) { size_t sz = ws.size(); for(size_t i = 0; i < sz; ++i) { if(ws[i] != wchF) continue; else ws.replace(i,1,wchR); } }

Как найти символы из кортежа ('!',',','?') в строке и удалить их?

#python #python_3x


Есть кортеж:

a= ('!',',','?')


И строка

dasd,sadarg!ada


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


Ответы

Ответ 1



Например, так: >>> a=('!',',','?') >>> s='dasd,sadarg!ada' >>> ''.join(filter(lambda x: x not in a, s)) 'dasdsadargada' или >>> ''.join(x for x in s if x not in a) 'dasdsadargada' И в том и в другом случае не удаляем символы из старой строки, а создаем новую строку, в которую входят только те символы старой строки, которые удовлетворяют условию "символ x не входит в кортеж а" (x not in a).

Ответ 2



Best way to strip punctuation from a string in Python показывает как можно удалить пунктуацию, используя разные подходы такие как: регулярные выражения, str.replace(), bytes.translate(), listcomp/genexpr, а также сравнивает их производительность. Похожий вопрос Deleting consonants from a string in Python проводит сравнение для Питона 3. Remove punctuation from Unicode formatted strings демонстрирует решения с акцентом на не-ascii пунктуацию. Наиболее простое для понимания решение это использовать genexpr как показано в ответе @insolor. Идентичное решение, которое использует listcomp, является более производительным на CPython: punct = ('!',',','?') no_punct = ''.join([c for c in text if c not in punct]) Если входной текст содержит только ascii, то .translate() метод быстрее в 10-20 раз: translation_table = dict.fromkeys(map(ord, punct)) def remove_punctuation(text): # Python 3.5+ improves performance otherwise use bytes.translate return text.translate(translation_table) Чтобы удалить все возможные Юникодные символы пунктуации из текста: #!/usr/bin/env python3 import regex # $ pip install regex def remove_punctuation(text): return regex.sub(r"\p{P}+", "", text) Производительность решения с .replace() ухудшается с увеличением длины punct и text (необходимо сравнение с другими подходами для каждого случая): from functools import reduce no_punct = reduce(lambda text, p: text.replace(p, ''), punct, text) Для коротких кортежей .replace() уступает (незначительно) только bytes.translate().

Видео из YouTube в андроид приложении

#android #youtube


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


Ответы

Ответ 1



[http://www.sitepoint.com/using-the-youtube-api-to-embed-video-in-an-android-app/ ] Тут ты найдёшь пример использования такого окна ютуба. Там же найдёшь ссылку на целый проект. Ссылка называется download the completed project here. Чтоб проект заработал, тебе нужен api ключ, который ты должен создать в console.developers.google.com, тебе только гугл аккаунт нужен. Там создай виртуальный проект, перейди по кнопке Enable APIs and get credentials like keys YouTube Data API - Enable кажется, кнопка сверху. Нажми её, далее слева вкладка Credentials, далее на синюю кнопку credentials, выйдет подменю, там android key package name - имя твоего проекта, типа com.example.zaynulabid.myprojectname . SHA-1 у меня такой 39:A2:AB:DF:C9:A4:24:BB:19:0F:73:40:FC:99:08:4E:36:6B:FC:6D, у тебя будет другой. Как тебе его достать: В андроид студио внизу есть окошко терминала, напиши там команду для Mac OS X keytool -list -v -keystore ~/.android/debug.keystore или keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android для Windows7: keytool -list -v -keystore "%USERPROFILE%\.android\debug.keystore -alias androiddebugkey -storepass android -keypass android НО! это DEBUG CERTIFICATE Он для тестирования. Для выгрузки на маркет, он не подойдёт. Для выгрузки на маркет нужен, кажется, "RELEASE CERTIFICATE". Если выйдет строка Enter keystore password:, впиши android Выйдет куча строк. Найди "SHA1:" и содержимое скопируй и вставь в поле при создании апи ключа. Когда создашь этот апи ключ, засунь его в тот проект, в класс Config.java P.S. Browser API нужен для отображения списка видео, а Youtube API нужен для самого плеера в приложении, он и должен считывать количество просмотров. В общем, браузер апи используем при подгрузке данных о списке видео, ютуб апи при воспроизведении через плеер. Ещё, последнее. Надо скачать библиотеки ютуба. Отсюда [https://developers.google.com/youtube/android/player/downloads/ ] Распакуй архив в папку lib твоего проекта и в build.gradle в блок dependencies впиши строку compile files('libs/YouTubeAndroidPlayerApi.jar') Чтоб расширить функционал, я поискал и добавил ещё парочку файлов. Тебе они по идее не должны понадобиться для этого проекта. Но если что, поищи в инете и скачай, тоже с офф сайта google compile files('libs/google-api-client-1.21.0.jar') compile files('libs/google-api-client-android-1.21.0.jar') compile files('libs/google-http-client-1.21.0.jar') compile files('libs/google-http-client-android-1.21.0.jar') compile files('libs/google-http-client-jackson2-1.21.0.jar') compile files('libs/google-oauth-client-1.21.0.jar') compile files('libs/jackson-core-2.1.3.jar') compile files('libs/jsr305-1.3.9.jar') Если будете работать с каналом youtube, то нужен будет browser api, можно также создать в Credentials, где создавали youtube api ключ. При создании ключа, поля адреса для доступа пока оставить пустым(это ограничители для ключа). Вот пример адреса к видео https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&playlistId=[ID плейлиста]&key=[ключ browser api] У меня так: https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&playlistId=UUIQ6UDqSoWIEoGZ5tLJd1QA&key=AIzaSyDLMSSM79_......................BQ Если будете работать с проектом, на который я ссылался, то там будет класс плеера, в котором будет строка кода youTubeView.initialize(Config.YOUTUBE_API_KEY, this); Вот в YOUTUBE_API_KEY класса Config и надо вставить свой ютуб-апи ключ

Ответ 2



Можно попробовать через VideoView: VideoView videoView = (VideoView)findViewById(R.id.video_view); String pathToVide = "https://archive.org/download/ksnn_compilation_master_the_internet/ksnn_compilation_master_the_internet_512kb.mp4"; Uri videoUri = Uri.parse(pathToVide); videoView.setVideoURI(videoUri); videoView.start(); Разметка: Еще, как вариант, можно использовать MediaPlayer. Скорее всего вам он предпочтительнее в использовании. По ссылке можете посмотреть реализацию. Пример взят отсюда.

Как удалить .NET Framework 4.6?

#net #windows_8 #windows_server


Вместе с Visual Studio 2015 RTM установил .NET Framework 4.6, в связи с чем получил
кучу багов, связанных с Tail Call Optimization, отключение RyuJIT их не лечит - как
мне удалить .NET Framework 4.6 и RyuJIT с машины полностью?

Два кейса - удалить с девелоперской машины (Windows 8.1) и удалить с билд-серверов
(Windows Server 2012R2).
    


Ответы

Ответ 1



Можно просто скачать .NET 4.6 Offline Installer, запустить - и выбрать опцию Remove. Если без инсталлера - то откройте Control Panel / Programs / Programs and Features / Installed Updates. Там найдите и удалите: KB3033095 для RC KB3045557 для RTM Не уверен насчет точного номера - он не появляется при апгрейде через RC. Если не найдете KB3045557 - то ищите по дате установки.

Ответ 2



При попытке удалить фреймворк через инсталлер - мне сообщили какой именно апдейт нужно удалить: KB3045563 в моём случае. https://www.microsoft.com/en-us/download/details.aspx?id=48137 On Windows Vista SP2 / Windows 7 SP1/ Windows Server 2008 SP2 / Windows Server 2008 R2 SP1, you will see the Microsoft .NET Framework 4.6 as an installed product under Programs and Features in Control Panel. • On Windows 8 / Windows Server 2012 you can find this as Update for Microsoft Windows (KB3045562) under Installed Updates in Control Panel. • On Windows 8.1 / Windows Server 2012 R2 you can find this as Update for Microsoft Windows (KB3045563) under Installed Updates in Control Panel. В соответствии с этим, удалить нужно один из апдейтов: KB3045562 KB3045563 Для более старых операционных систем .NET Framework 4.6 появится в установленных Programs and Features.

В каком стандарте появилась функция to_string?

#cpp


у меня старенький компилятор (C++98). функция to_string() присутствует в библиотеке
но во время компиляции выдает ошибку.


    


Ответы

Ответ 1



Фкнкция std::to_string была включена в стандарт C++ 2011. В связи с этим, например, в MS VS 2010 она перегружена не для всех целочисленных типов, для которых она должна быть перегружена в соответствии со стандартом, потому что компилятор MS VC++ 2010 вышел до окончательного принятия стандарта. Об этом недостатке MS VC++ 2010 можете почитать в моем сообщении по этой ссылке

Угол между шарами одинаковой массы после столкновения (упругого)

#физика #2d


Симулирую столкновения шаров в 2D, сделал столкновения о стенки, теперь встал перед
проблемой определения угла между ними после нецентрального удара. Пусть векторы скоростей
шаров соответственно равны v1, и v2. Иза за одинаковой массы, как объясняется в матчасти,
следует, что шары после столкновения, в этом случае просто обменяются скоростями, а
угол между ними всегда будет прямым (как я понял, это угол между направляющими линиями(векторами)
шаров после удара). Мне не понятно почему говорится ВСЕГДА этот угол будет прямым ???
Везде даются картинки и пояснения когда этот угол выходит точно в 90 градусов.
Сомневаясь до отчаяния, нашёл таки пример удара когда угол не прямой. Например здесь
можно построить подобный удар. На рисунках показаны результаты до и после удара.

До удара:



после

Так что же тут происходит ?? Какой тут угол будет всегда прямым ?? Я не вижу тут
никаких прямых углов! Что я не понимаю ?? Поясните пожалуйста поподрбней.
    


Ответы

Ответ 1



В моём понимании задачки подобного рода решаются очень просто. На рисунке вверху два изображения. До удара (слева) и после удара (справа). Исходные вектора скоростей взяты произвольно. Кратко разъясню суть. Шары как-то движутся. Шары ударяются. В момент удара шары деформируются в месте контакта. Энергия деформации на все 100% переходит в кинетическую энергию шаров. Работает закон сохранения импульса и закон сохранения энергии. Что касается импульса - это величина векторная. Поэтому её(как и скорость) можно разложить на две составляющие. Ось ОХ совмещается с линией, которая соединяет центры шаров. Ось OY ⊥ OX. Вертикальная(OY) составляющая импульса на удар влияния не оказывает. Поэтому она остается неизменной. А горизонтальными составляющими импульса шары просто обмениваются. Итого: V2OY = V2*OY V1OY = V1*OY V2OX = V1*OX V1OX = V2*OX А под 90 градусов шары разлетятся в случае если один из шаров неподвижен.

Как правильно сделать циклический сдвиг в одномерном массиве?

#java #массивы


Я новичок в java и у меня возник данный вопрос. Опишу ситуацию: есть двумерный массив
типа int 9 на 9, и есть метод, который делает циклический сдвиг в одномерном массиве
на заданное количество элементов. 

Первое что я сделал это инициализировал первую строку двумерного массива числами
от 1 до 9.    

private static final int MAX = 9;
private static int[][] baseTable = new int[MAX][MAX];

for (int b = 0; b < 9; b++) {       

    baseTable[0][b] = b + 1;

}


После чего я, сделав сдвиг на один элемент, записал то что получится в 4-ю строчку
двумерного массива. 

baseTable[3] = CyclicShift.shiftLeft(baseTable[0], 1);


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

Вот код метода shiftLeft:

public static int[] shiftLeft(int[] a, int iter) {
    if (a != null) {
        for (int m = 0; m < iter; m++) {
            int tmp = a[0];
            for (int i = 0; i < a.length - 1; i++) {
                a[i] = a[i + 1];
            }
            a[a.length - 1] = tmp;
        }
        return a;
    } else {
        return null;
    }
}


P.S. Проблема была решена сначала полным заполнением всего двумерного массива, а
затем сортировкой только тех строк, которых мне нужно, и запись в них же. Но интересует
именно механизм работы массива, и то, почему возникает такая ситуация.
    


Ответы

Ответ 1



Тут всё довольно просто. Дело в том, что вы переставляете элементы в том же самом массиве, который и получаете в качестве источника. Нужно определиться, что же все-таки должен делать ваш метод shiftLeft(): Переставлять элементы в том массиве, который получает Или возвращать новый массив, являющийся перестановкой старого. Сейчас он делает и то, и другое. А еще вместо того, чтобы сразу перемещать элементы на N позиций, он делает N итераций — это не очень производительно. Вот вариант, который создает новый массив и записывает в него значения со сдвигом, используя созданный как раз для этих целей метод System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length) Реализация: public class ArrayShift { public static int[] shiftLeft(int[] a, int shift) { if (a != null) { int length = a.length; int[] b = new int[length]; // шаг 1 System.arraycopy(a, shift, b, 0, length - shift); // шаг 2 System.arraycopy(a, 0, b, length - shift, shift); return b; } else { return null; } } } Вот как это работает. Шаг 1: array a: 0 1 2 3 4 5 ↓ ↓ ↓ ↓ array b: _ _ _ _ _ _ Шаг 2: array a: 0 1 2 3 4 5 ↓ ↓ array b: 2 3 4 5 _ _ Несколько юнит-тестов: import org.junit.Assert; import org.junit.Test; public class ArrayShiftTest { int[] source = {0, 1, 2, 3, 4, 5}; @Test public void testValid() { int[] expected = {2, 3, 4, 5, 0, 1}; Assert.assertArrayEquals(expected, ArrayShift.shiftLeft(source, 2)); } public void testZero() { Assert.assertArrayEquals(source, ArrayShift.shiftLeft(source, 0)); } /** * На отрицательных значениях метод сломается * */ @Test(expected = IndexOutOfBoundsException.class) public void testNegative() { ArrayShift.shiftLeft(source, -1); } /** * На значениях выше длины массива — тоже * */ @Test(expected = IndexOutOfBoundsException.class) public void testExceedLength() { ArrayShift.shiftLeft(source, 10); } } Если про юнит-тесты непонятно будет, спрашивайте. Также подскажу вам три пункта, которые вы можете улучшить самостоятельно: Сдвиг влево и вправо — одно и то же, можно задавать направление положительным и отрицательным значением параметра и объединить shiftLeft и shiftRight Если не объединять методы, то нужно что-то делать при отрицательных значениях Необходимо подумать о значениях, превышающих длину массива

Ответ 2



Я совершенно не знаю Java, но попробую объяснить, как это мне представляется.:) Думаю, что данное объявление private static int[][] baseTable = new int[MAX][MAX]; задает не двумерный массив, а массив массивов. Поэтому каждый элемент baseTable[i] - это ссылка на одномерный массив. Похоже функция CyclicShift.shiftLeft(baseTable[0], 1); действительно сдвигает циклически элементы массивы baseTable[0] и возвращает ссылку на этот же массив, то есть на baseTable[0] Эту ссылку вы присваиваете ссылке baseTable[3] baseTable[3] = CyclicShift.shiftLeft(baseTable[0], 1); В результате две ссылки массива baseTable[] ссылаются на один и тот же целочисленный массив.

Что такое constructor в JavaScript и для чего он полезен?

#javascript


Ни как не могу уложить у себя в голове что такое конструктор в JavaScript ?
Для чего мы его изменяем и используем ? 
К примеру:

var Duck = function(name){
  this.name = name;
};

Duck.prototype.quack = function(){
    return this.name + " Duck: Quack-quack!";
};

var TalkingDuck = function(name){
    Duck.call(this, name);
}

TalkingDuck.prototype = Object.create(Duck.prototype);
TalkingDuck.prototype.constructor = TalkingDuck;


Как эффективно мы можем его использовать на практике ?
Обьясните это коротко и понятно, или на оборот :)
    


Ответы

Ответ 1



На практике constructor обычно не используется. Что это такое: У любой функции f() есть свойство f.prototype, являющееся объектом со свойством constructor, равным самой функции. То есть: f.prototype.constructor === f Это означает, что у любого объекта o, сконструированого функцией f, у которой не заменяли prototype, будет выполнено o.constructor /* === (new f()).constructor */ === f Кроме того, constructor определен у встроенных объектов (Number, Boolean, String, RegExp, ...) и, вследствие "boxing", даже у примитивных значений (1, "asdf", /reg[eE]xp/). У последних его не имеет смысла менять, т.к. изменение касается временно созданного объекта-оболочки над примитивом, и фактически не имеет эффекта. Некоторые пытаются использовать это свойство, чтобы в методе объекта использовать this.constructor чтобы определить функцию, с помощью которой можно построить такой же объект (пример). Однако, если заменять prototype, как в вашем примере: TalkingDuck.prototype = Object.create(Duck.prototype); ..то TalkingDuck.prototype.constructor уже равен Duck, что означает, что new TalkingDuck() уже будет не будет иметь ожидаемый constructor (=== Duck, а не TalkingDuck). Это лечится дополнительным финтом: TalkingDuck.prototype.constructor = TalkingDuck; ...но чтобы опираться на то что constructor "правильно" установлен для всех объектов, нужно чтобы для каждого из них был проделан этот финт. Ну а дальше решайте сами - нужен вам такой constructor или нет.

Ответ 2



Если в двух словах, constructor возвращает ссылку на функцию, которая создала прототип экземпляра. По сути, constructor позволяет динамически управлять созданием объекта. Тем самым обеспечивается большая гибкость. Однако это не работает для примитивных значений (таких как true, 1, "text").

Ответ 3



Дополню: Свойство конструктор не является перечисляемым. Object.getOwnPropertyDescriptor(Duck.prototype, 'constructor') Вот пример.

Ответ 4



Напишите код в Typescript и посмотрите, как он это перевёл в Javascript. Всё станет понятно! Ссылка. Под стандартным ООП я подразумеваю ООП, которое используется в C++/Java/C# ... В Javascript используется прототипное программирования - стиль объектно-ориентированного программирования, при котором отсутствует понятие класса, а наследование производится путём клонирования существующего экземпляра объекта — прототипа.

Настройка и интеграция Jenkins и Gradle с нуля

#java #git #юнит_тесты #gradle #jenkins


Туториалов много, но каждый охватывает только часть процесса, не могу найти простой
и понятный для новичка, охватывающий весь процесс.

Что я хочу: 


Есть Java приложение (причем, это может быть как web приложение, запускаемое в том
же Tomcat, либо обычное консольное приложение или библиотека, собираемая в jar  )
Написаны Unit и интеграционные тесты
Приложение собирается gradle-ом.
Развернут Artifactory с репозиторием, куда я хочу деплоить сборки. 


Собственно процесс, который я хочу настроить:


При каждом пуше на сервере прогоняются unit-тесты, интеграционные тесты, анализируется
покрытие кода тестами, codestyle и т.д. 
Если все хорошо, сборка деплоится в Artifactory, а также (если приложение - веб),
обновляется и перезапускается на dev сервере.
Либо иметь некоторую страничку, представляющее собой таблицу: ссылка на скачивание
- commit message (для примера: http://abrok.eu/stockfish/)
Если что-то пошло не так, ответ с описанием приходит на почту (например)


Было бы здорово посмотреть туториал с самого нуля, когда создается helloWorld Java
проект, как настраивается Jenkins, что происходит, когда делается commit и т.д. Т.е.
туториал, где одновременно с настройкой Jenkins пишется и изменяется java код. 

Может быть не обязательно полностью описанный мной процесс, но какой-нибудь туториал,
который показывает упрощенно процесс разработки (изменение, написание тестов, коммиты)
java приложение при работающем jenkins. 
    


Ответы

Ответ 1



Если сфокусироваться на организации процесса сборки средствами Jenkins, получится примерно следующее: При каждом пуше на сервере прогоняются unit-тесты, интеграционные тесты, анализируется покрытие кода тестами, codestyle и т.д. Для проекта (job) задается триггер сборки "Опрашивать SCM об изменениях" и расписание проверки Git-а на наличие свежих коммитов, например раз в 10 минут. Расписание задается в формате crontab: H/10 * * * *. Другой вариант - выбрать триггер "Trigger builds remotely (e.g., from scripts)" и настроить post-commit hook в репозитории, который будет уведомлять Jenkins о наличии новых коммитов. Для этого достаточно дернуть curl-ом адрес http:///job//build. Прогон тестов реализуется вызовом gradle. Установите на билдсервер Gradle Plugin и в качестве основного шага сборки вызывайте gradle, как если бы вы запускали его на локальной машине. Если сборка будет включать в себя прогон тестов, jenkins сохранит информацию о результатах. Если все хорошо, сборка деплоится в Artifactory, а также (если приложение - веб), обновляется и перезапускается на dev сервере. Ставите Artifactory Plugin и добавляете послесборочный шаг "Deploy artifacts to Artifactory". Редеплой приложение лучше вынести в отдельный проект, который будет вызываться после основной сборки через Послесборочную операцию "Build other project". Чтобы "дотянуться" из проекта деплоя до артефактов основной сборки, установите Copy Artifacts Plugin. Вам будет доступен шаг сборки "Copy artifacts from another project", который скопирует нужные файлы из исходной (upstream) сборки. Саму процедуру деплоя можно реализовать средствами Jenkins (например, Deploy Plugin), средствами gradle (например, gradle-cargo-plugin) или просто shell-скриптом. Если что-то пошло не так, ответ с описанием приходит на почту (например) Это Jenkins умеет "из коробки", достаточно включить в настройках проекта флажок "E-mail Notification". Но я рекомендую поставить Email-ext plugin - он позволяет гибче настраивать события для письма и содержимое.

Reflections: анализ модификаторов метода

#java


Мне необходимо выделить из класса protected-методы. Я получаю массив Method[] из
метода Class.getDeclaredMethods(), затем анализирую объекты массива. Есть метод Method.getModifiers(),
который возвращает, как я понимаю, одну из статических констант класса Modifier. Прикол
в том, что у метода модификаторов может быть несколько (типа public static), а у меня
в распоряжении только один. Как так то?
    


Ответы

Ответ 1



Метод getModifiers() возвращает битовую маску — самый простой способ представления множества значений (эдакий EnumSet для бедных). Каждый отдельный модификатор в этой битовой маске — это отдельный бит. Например, public — самый младший (нулевой) бит, private — следующий за ним (первый) и так далее. Чтобы проверять, установлен ли i-й бит в битовой маске, надо проверить на ноль результат операции (modifiers & (1 << n)), где n — это номер бита. Для упрощения обычно для возможных значений (1 << n) заводят подходящие константы, которые как раз есть в классе Modifier: Modifier.PUBLIC = 1 << 0 = 1 Modifier.PRIVATE = 1 << 1 = 2 Modifier.PROTECTED = 1 << 2 = 4 И так далее. Соответственно, чтобы узнать, например, объявлен ли метод protected, надо проверить условие method.getModifiers() & Modifier.PROTECTED != 0. Именно это и делают вспомогательные статические методы в классе Modifier, поэтому можно писать ещё проще: Modifier.isProtected(method.getModifiers()).

Ответ 2



Ой, тьфу, там есть булевы методы типа Modifier.isProtected() и т.п.

Обработка ошибок в Rust

#rust


Есть программа на rust, взятая отсюда: Учебник по Rust

Захотелось мне, чтобы программа постоянно выводила собственный префикс ("guess_game>>
"). По-этому немного пришлось подкорректировать строки перед запросом ввода.

В оригинале было так

println!("Пожалуйста, введите предположение.");


Если просто заменить println! на print!, у меня вывод сбрасывался на терминал слишком
поздно. Выход был найден в принудительном вызове stdout().flush(). Но, когда я добавил
обработку ошибок, как приведена ниже, при запуске программы стали бесконечно рисоваться
строки "guess_game>> try: ". Прошу объяснить, почему так и какова логика?

extern crate rand;

use std::io::stdin;
use std::io::Write;
use std::io::stdout;
use rand::Rng;
use std::cmp::Ordering;

fn main() {
    let snum = rand::thread_rng().gen_range(1, 101);
    println!("guess_game>> rnd: {}", snum);

    loop {
        let mut guess = String::new();

        print!("guess_game>> try: ");
        match stdout().flush() {
            Ok(_)  => continue,
            Err(_) => continue,
        };

        stdin().read_line(&mut guess)
               .ok()
               .expect("Fail read line");

        let guess: u32 = match guess.trim().parse() {
            Ok(num) => num,
            Err(_)  => continue,
        };

        match guess.cmp(&snum) {
            Ordering::Less    => println!("guess_game>> Less"),
            Ordering::Equal   => {
                println!("guess_game>> Equal");
                break;
            }
            Ordering::Greater => println!("guess_game>> Greater"),
        }
    }
}


UPD:
Решение:

print!("guess_game>> try: ");
match stdout().flush() {
    Ok(_)  => (),
    Err(_) => (),
};

    


Ответы

Ответ 1



У вас бесконечно выводится guess_game>> try: по тому, что у вас получился бесконечный цикл.

Ответ 2



Более удобный способ проигнорировать ошибку в Result - превратить его в Option: stdout().flush().ok(); Однако, с точки зрения надежности, игнорировать ошибки вывода все же не стоит. Чтобы получить панику с информацией об ошибке, можно воспользоваться методом unwrap: stdout().flush().unwrap();

Фильтрация textbox

#c_sharp




1 - входные данные 2 - выход 

Суть программы в том чтобы убрать из textbox все повторы, но по какой-то причине
 у меня повторяется первый  убранный элемент
Код: https://gist.github.com/anonymous/82420aad4fd453ebabd6

Прошу не бить тапком, так как программирую на C# первый раз.
    


Ответы

Ответ 1



Так изначальная строка по всей видимости имеет вид "Андрей Соловьев 10,\nАндрей Соловьев 10,\nАндрей Соловьев 10..." и при попытке ее разбить .Split(new Char[] { ',' }); получаем что "Андрей Соловьев 10" != "\nАндрей Соловьев 10"

Анимация svg в Firefox

#svg #анимация


По непонятной причине не работает анимация в Firefox: http://codepen.io/SelenIT/pen/mHpDG/












Здесь следом за анимацией круга должна включаться анимация прямоугольника.
    


Ответы

Ответ 1



Похоже, Firefox неверно интерпретирует выражение в атрибуте begin, если в id анимации, на которую это выражение ссылается, присутствует дефис. Скорее всего, Firefox интерпретирует дефис как минус и пытается вычислить выражение circ-anim.begin + 1s, но не может, так как не знает, что такое circ и anim. Переименуйте анимацию в circAnim, и всё заработает: http://codepen.io/anon/pen/gawXJZ

Ответ 2



Скорее всего, Firefox интерпретирует дефис как минус и пытается вычислить выражение circ-anim.begin + 1s, но не может, так как не знает, что такое circ и anim. Переименуйте анимацию в circAnim, и всё заработает: Да, совершенно верно, этот баг Firefox давно замечен, но прошло три года со времени ответа @fori1ton а он до сих пор присутствует. Переименовал orange-cicle в id="orange_circle" и все остальные id тоже переименованы. Анимация начинается после клика по оранжевому кругу

2D игры на Андроид [закрыт]

#java #android #разработка_игр


        
             
                
                    
                        
                            Закрыт. На этот вопрос невозможно дать объективный ответ.
Ответы на него в данный момент не принимаются.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Хотите улучшить этот вопрос? Переформулируйте вопрос,
чтобы на него можно было дать ответ, основанный на фактах и цитатах, отредактировав его.
                        
                        Закрыт 3 года назад.
                                                                                
           
                
        
Хочу выучить Android и, как описано тут, мне, во-первых, надо знать JAVA. 
Я не против JAVA и понимаю что этот язык стоит на вершине как C# , C++ и т.д. 
Но особо хочу написать 2D-игру (типа этой) на Андроид.
Скачал Андроид Студио но, как понимаю, с ним создать игру не так уж легко, как программу.
Жду советы професионалов в этой сфере:
1. Какие библиотеки и 2D движки мне надо знать?
2. Какие языки предпочетаемы для Андроид кроме JAVA  
    


Ответы

Ответ 1



Для создания игр у вас 2 пути: 1 - Использовать какой-то игровой движок/framework. 2 - Изучать openGL. Идею о том чтобы пытаться рисовать объекты используя canvas.drawBitmap() отбрасывайте сразу - потому что это тупиковый путь на который просто можно убить время и не получить достойного результата. Путь 1 Движки. Одни из самых популярных - Unity - по нему куча уроков + сообщество + бесплатные и платные плагины ассеты. Минусы - немного громоздкий, но бесспорно мощный и лидирующий в отрасли. Если хочется больше классического программирования и небольших приложений, я бы советовал обратить внимание на framework/движок libgdx, подключается к проекту элементарно, весит мало, большое сообщество, много уроков, легко начать делать простенькие спрайтовые игрушки. вот уроки по быстрому старту от Survitruf (кстати сам Survitruf сейчас пересел на Unity). http://suvitruf.ru/libgdx/ Обзорно по другим движкам можно посмотреть тут: http://4pda.ru/forum/index.php?showtopic=315915 Путь 2. Изучать openGL самому не сказать чтоб очень легкий путь. Во первых сложно найти рускоязычный материал, а если и находится, то он очень устаревший годов 2005,2006 и так сейчас уже никто не делает работает. Можно попробовать с уроков usnavii на 4pda они актуальны, есть примеры спрайтовой анимации, работы с текстурными атласами, системами частиц. http://4pda.ru/forum/index.php?showtopic=418429 Путь долгий, сложный, но если происходит просветление и понимание что к чему, вы становитесь независимы от движков, можете легко делать простые 2d и 3d игры не загромождая их ненужными возможностями движков, делать более легкие и более быстрые приложения.

Ответ 2



по поводу 2D я не знаю, но кроме java есть технологии Embarcadero® RAD Studio™ котором можно программировать на Pascal/Delphi и C++ Ionic создание мобильных приложения на HTML/CSS/JS PhoneGap создание мобильных приложения на HTML/CSS/JS

Реализация чисел Фибоначчи с помощью хвостовой рекурсии в Haskell

#функции #рекурсия #haskell #функциональное_программирование


Решаю задачу с рядом фибоначчи (+ отрицательные). Приблизительно так:

fibonacci 0 = 0
fibonacci 1 = 1
fibonacci n | n == 0 = 1
                 | n > 0 = fibonacci (n - 1) + fibonacci (n - 2)
                 | n < 0 = fibonacci (n + 2) - fibonacci (n + 1)


нужно увеличить скорость просчета. для этого естественно нужен аккумулятор.

Как это сделать?
    


Ответы

Ответ 1



Правильнее всего, конечно, использовать готовую формулу n-ого члена :) Но для случая, когда нужно находить программным путём, подходит следующая идея (пишу алгоритм, не знаю синтаксис Хаскеля): fib n = helper 0 1 n where helper curr prev n | n == 0 = curr | n > 0 = helper (curr+prev) curr (n-1) | n < 0 = helper prev (curr-prev) (n+1) Это вычисляет последовательность за линейное время с хвостовой рекурсией.

Регулярное выражение. Поиск повторяющихся цифр

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


Есть вот такая строка:

---011110000-----


Нужно найти 3 повторяющиеся цифры если нет 4-ёх повторяющихся цифр.

Например:


---011110000----- не должно быть совпадений
---01110000------ должно совпасть только с 111
-----0111000----- должно совпасть и с 000 и с 111


Помогите составить регулярку для JavaScript.

P.S. ((?=(\d{1}))\2{3}) это выражение даст совпадение в каждом примере...
    


Ответы

Ответ 1



А как на счёт двух регулярок? '---011110000-----'.replace(/(\d)\1{3}/g,'-').match(/(\d)\1{2}/g) → null '---011110000-----'.replace(/(\d)\1{3}/g,'-').match(/(\d)\1{2}/g) → ["111"] '-----0111000-----'.replace(/(\d)\1{3}/g,'-').match(/(\d)\1{2}/g) → ["111", "000"] С одной регуляркой удалось только захватить символ, после которого идёт тройка: '---011110000-----'.match(/(.)(?=(\d)\2{2}(?!\2))(?!\1)/g) → null '---01110000------'.match(/(.)(?=(\d)\2{2}(?!\2))(?!\1)/g) → ["0"] '-----0111000-----'.match(/(.)(?=(\d)\2{2}(?!\2))(?!\1)/g) → ["0", "1"]

Ответ 2



Частный случай, который подходит под нужды ТС довольно прост: (?=.(\d))(?!\1)(?=.(\1{3})(?!\1)) https://regex101.com/r/yT5sD9/1 Гораздо интереснее сформулировать задачу так: Найти непрерывную последовательность, состоящую из литерала, повторенного N раз. Здесь уже решение будет весьма нетривиальным за счет слишком малого функционала регулярных выражений в JavaScript. Решение выглядит так: (?:(?=((?=([^]))(?=\2{0,2}(?!\2)|\2{4,}(?!\2))\2+(?!\2)))\1)*(([^])\4{2}(?!\4)) Кратко его можно описать так: Сымитировав атомарную группировку захватываем все непрерывные последовательности длиной, отличной от N, а после этого захватываем непрерывную последовательность длиной N. Результат в четвертой группе (результатом считается любой символ повторенный подряд ровно 3 раза, не только цифры) Посмотреть можно здесь: https://regex101.com/r/yT5sD9/2 Общий вид в зависимости от N: (?:(?=((?=([^]))(?=\2{0,[N-1]}(?!\2)|\2{[N+1],}(?!\2))\2+(?!\2)))\1)*(([^])\4{[N-1]}(?!\4))

Перегрузка оператор присвоения

#cpp



Изучаю язык. Написал простенький класс:

class Point{
public:
  Point();
  Point(int x, int y);      
private:
  int _x;
  int _y;
}


Захотел преобразовать его в другой тип. По не знанию и паскалевской привычки
написал такой оператор:

int operator=(const Point& src);


Скомпилировал класс вместе с оператором и все нормально скомпилировалось.
Решил проверить на коде:

int main(int argc, char *argv[])
{
  Point pt(1, 2);    
  int i;
  i = pt;
}


Компиляция не удалась:   

main.cpp:14: ошибка: cannot convert 'Point' to 'int' in assignment


Потом я нашел как преобразовать тип через другой оператор. Но мне интересно, раз
компилятор дал мне скомпилировать этот оператор, значит наверно его, как то можно применить. 

Вопрос: Что это оператор делает и как его можно использовать?
    


Ответы

Ответ 1



Надо различать оператор присвоения и функцию преобразования. Оператор присвоения не меняет тип объекта, которому присваивается выражение. В вашем примере class Point{ public: //... int operator=(const Point& src); //... }; оператор присваивания присваивает выражение объекту класса Point. Причем присваиваемое выражение имеет также ссылочный тип класса Point. Вы можете использовать возвращаемое значение выражения с данным оператором присваивания, чтобы присвоить его переменной типа int. Например, int main(int argc, char *argv[]) { Point pt(1, 2); int i; i = pt = pt; } Так как операторы присваивания выполняются справа налево, то сначала бы выполнилось присваивание pt = pt результатом которого было бы значение типа int, и только во втором присваивании это значение было бы занесено в переменную i Если же вы хотите написать оператор преобразования, то он может выглядеть следующим образом: operator int() const; И тогда вы можете записать i = pt; Имейте в виду, что для не пользовательских типов вы не можете переопределить оператор присваивания. И в этом предложении i = pt; используется стандартное присваивание для целых чисел. Но так как pt не имеет целочисленный тип, то компилятор пытается его преобразовать к объекту целочисленного типа и вызывает для pt оператор operator int() const; если вы его определили. Иначе компилятор выдаст сообщение об ошибке.

Ответ 2



Когда вы пишете a = b, это транслируется как a.operator=(b). То есть, для вашего случая (i = pt) вам нужно бы перегрузить оператор присваивания у i, в типе данных int. Это, очевидно, невозможно. Правильный путь — оператор преобразования типов operator int() const. Заметьте, что другие, сложные операторы присваивания вполне можно перегрузить и вне класса-получателя. Например, operator += (пример): class Point { public: Point() : _x(), _y() {} Point(int x, int y) : _x(x), _y(y) {} friend int& operator += (int& i, const Point& pt) { i += pt._x; i += pt._y; return i; } private: int _x; int _y; };

Ответ 3



Интересно то, что никто так и не показал как реализовать оператор присваивания... class Point { public: Point(); Point( int x, int y ); Point & operator = ( const Point & rhs ) { if ( &rhs != this ) { _x = rhs._x; _y = rhs._y; } return *this; } private: int _x; int _y; };

Ответ 4



Выше все ответили правильно. Забавно, что если использовать Ваше описание класса Point, то можно написать следующее: Point x(1, 2); Point y(3, 4); int i = y = x; И в i останется то, что Вы хотели получить. class A { public: A(int v) {this->v = v;} A(const A &a) { v = a.v; } int operator= (const A &a) { this->v = a.v; return v; } private: int v; }; int main(int argc, char *argv[]) { A x(1); A y(2); int i = y = x; cout << i; } выводит как раз 1

Как правильно открыть COM порт

#c_sharp #com_порт


На столе лежит Gsm модуль RX 101 от "Телеофис", хочу пообщаться с ним из кода, но
не получается.

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

А теперь что происходит когда я пытаюсь обратиться к модулю из кода - ничего!
То есть лампочка RX мигает, но ответа нет. При чем после закрытия программы которая
успешно общалась с модулем, я могу из кода обращаться и модуль отвечает. Вот такая
магия. Я полагаю что программы открывают порт с какими-то параметрами которые я не
указываю в коде, но понятия не имею какие.

Вот код который пытается связаться с модулем:

using System;
using System.IO.Ports;
using System.Threading;

namespace ConsoleApplication
{
    internal class Program
    {
        private static void Main( string[] args )
        {
            var comPort = new SerialPort( "COM4", 115200, Parity.None, 8, StopBits.One );

            comPort.Open();

            if ( !comPort.IsOpen ) throw new Exception();

            comPort.DataReceived += ComPortOnDataReceived; //событие, кстати, тоже
не генерируется

            comPort.WriteLine( "AT \r\n" );

            Thread.Sleep( 3000 );

            var response = comPort.ReadExisting();

            Console.WriteLine( string.IsNullOrWhiteSpace( response ) ? "null" : response );

            comPort.DataReceived -= ComPortOnDataReceived;
            comPort.Close();
        }

        private static void ComPortOnDataReceived( object sender,
            SerialDataReceivedEventArgs serialDataReceivedEventArgs )
        {
            Console.WriteLine( "received" );
        }
    }
}

    


Ответы

Ответ 1



В данном случае необходимо установить кроме основных параметров инициализации СОМ порта еще и дополнительные comPort.Handshake = Handshake.XOnXOff; так как по умолчанию этот параметр установлен в None. Более детально про этот параметр можно посмотреть здесь. Так же иногда могут возникать ситуации когда устройство долго отвечает на запрос(дольше стандартных значений). В таких случаях нужно изменять время ответа (искать в документации или экспериментировать с увеличением значений) comPort.ReadTimeout = 500; Я встречал устройства у которых время ответа по умолчанию равнялось 10с. А вообще, в подобных ситуациях, когда не получается опросить устройство по СОМ порту и у вас есть родная программа опроса, запускать снифер СОМ-порта и смотреть какие основные и дополнительные параметры порта устанавливает эта программа.

Обновление фоновых изображений на странице без перезагрузки

#javascript #html #css


Еще раз подчеркну: задача не стоит вывести рандомное изображение. Набор изображений
и их адреса на сервере строго заданы.

Задача: обновлять картинки на сайте, т.к. содержимое файлов с изображениями может
измениться. 
Физически файл с изображением остается лежать по тому же адресу, но т.к. содержимое
файла может измениться, необходимо заставить браузер обновлять отображаемое изображение
принудительно.
Для этого по таймеру добавляю параметр к адресу картинки

setInterval(function(){
       var arr = $(".image-responsive");
       for (var i = 0; i < arr.length; i++ ){
           arr[i].style.backgroundImage = 'url(' + arr[i].style.backgroundImage.slice(4,
-1).replace(/"/g, "").split("?")[0] +  "?" +  Math.random() + ')';
       }
}, 1000);


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

Обновление 2:
Попытался использовать предзагрузчик - невидимый контейнер, в который подгружаются
изображения, прежде чем установить их в качестве фоновых изображений для нужных блоков
на странице.
С одной картинкой убрать дерганье получилось
http://jsfiddle.net/rGkww/36/
Однако дергается скроллинг. 
С несколькими http://jsfiddle.net/rGkww/41/ меняется только одна картинка, дерганье
картинки по-прежнему, и скроллинг дергается

Обновление 3:
Вроде дерганье убрал, пример кода со множеством изображений
http://jsfiddle.net/rGkww/57/
Осталось дерганье скролла, ну и не совсем уверен в корректности самого решения. Страница
должна быть рассчитана на длительную работу.

Обновление 4:
Убрал дерганье скроллинга
http://jsfiddle.net/rGkww/61/

Обновление 5:

Доработал немного код, чтобы в случае обрыва соединения с сервером не возникало переполнение
памяти, и после восстановления обновление возобновлялось.
http://jsfiddle.net/rGkww/64/
Обновление происходит без проблем.
Однако Iceweasel/Firefox через пару часов падает. Т.к. необходима длительная работа,
это критично. Неясно, проблема в коде или в браузере. Chrome/Chromium спокойно работает
несколько дней. 
    


Ответы

Ответ 1



Вот переделка вашего скрипта без дерганий. Изображения появляются только когда полностью загрузились. Вот что добавилось (прошу обратить внимание на то, что порядок строк очень важен): var i = new Image(); i.onload = function(){alert(i.width);} i.src = 'image.jpg'; // существующее изображение Для демо версии так же прописал счетчик (увеличивающееся число), который показывает рассинхронизацию появления нового числа и изображения. Ну, вы же понимаете да, что для загрузки картинки браузеру нужно время. п.с. я повторю еще раз - вы что-то не то делаете. Загружать ещё раз изображение, которое уже лежит в кеше браузера - не правильно. Никто так не делает. Наоборот пытаются предзагрузить все изображения, чтобы потом показывать их без дерганий ОДНОВРЕМЕННО с текстом. п.п.с. если у вас задача выбрать 1 из миллиона изображений (то есть вы реально не знаете какое изображение к вам придет и именно это вы изображаете в данном вопросе с помощью random()), то тогда нужно в интервале сделать "шаг назад", то есть загружать БУДУЩЕЕ изображение (которое покажется в следующую итерацию). Пример давать сложно, потому что не известно каким образом в реальном проекте у вас контент обновляется. ajax? $(window).load(function() { var num = 0; var randomImages = ['344291068_HdnTo', '344290962_h6JjS', '344291168_nErcq']; setInterval(function() { var rndNum = Math.floor(Math.random() * randomImages.length); var url = 'http://photos.smugmug.com/photos/' + randomImages[rndNum] + '-XL.jpg' + '?random=' + Math.random(); var i = new Image(); i.onload = function() { $(document.body).css({ 'background': 'url(' + url + ')' + ' no-repeat center center fixed', '-webkit-background-size': 'cover', '-moz-background-size': 'cover', '-o-background-size': 'cover', 'background-size': 'cover' }); } i.src = url; num++; $('#home').html(num); }, 3000); }); #home { height: 150px; width: 150px; }


Ответ 2



Таймер одноразовый, что бы между сменой изображений всегда было заданное время таймера (+время на загрузку изображения). var url = 'http://photos.smugmug.com/photos' var images = ['344291068_HdnTo-XL.jpg', '344290962_h6JjS-XL.jpg', '344291168_nErcq-XL.jpg'] new updateBackgroundTimer('real', url, images, 1000) function updateBackgroundTimer(node_id, url, images, timer) { // init node_id = String(node_id) var node = document.getElementById(node_id) if (!node) return false this.node_id = node_id this.node = node url = String(url) if (!images.length) return false for (var i in images) { images[i] = url + '/' + images[i] + '?r=' + Math.random() } shuffleArray(images) // вывод изображний в случайном порядке this.images = images timer = parseInt(timer) if (isNaN(timer) || timer < 1) return false this.timer = timer // model this.start = function() { initTimer() } this.stop = function() { if (this.timer_id) { clearInterval(this.timer_id) this.timer_id = null } } initTimer = function(_this) { return function() { if (_this.timer_id) { clearTimeout(_this.timer_id) _this.timer_id = null } _this.timer_id = setTimeout( function(_this) { return function() { _this.updateImage() } }(_this), _this.timer) } }(this) this.updateImage = function() { var url = this.getImageNext() var image = new Image() image.onload = function(_this, url) { return function() { _this.setImage(url) if (!_this.images_loaded) _this.images_loaded = {} _this.images_loaded[url] = true _this.start() } }(this, url) image.src = url } this.setImage = function(url) { url = String(url) this.node.style.backgroundImage = 'url(' + url + ')' } this.getImageNext = function() { var images = this.images var images_qty = images.length var index = parseInt(this.index) if (isNaN(index) || index < 0 || index >= images_qty) { index = 0 } else { index++ if (index >= images_qty) index = 0 } this.index = index var image = images[index] return image } function shuffleArray(array) { for (var j, x, i = array.length; i; j = parseInt(Math.random() * i), x = array[--i], array[i] = array[j], array[j] = x); } // run this.start() } #real { width: 300px; height: 300px; border: 2px solid red; }


Ответ 3



Обновление 2: .... С одной картинкой убрать дерганье получилось Однако дергается скроллинг. Немного переписали Ваш код, убрали дерганье скролла, таким же образом код меняется и для нескольких картинок: $(window).load(function() { var randomImages = ['344291068_HdnTo', '344290962_h6JjS', '344291168_nErcq']; setInterval(function() { var rndNum = Math.floor(Math.random() * randomImages.length); var src = 'http://photos.smugmug.com/photos/' + randomImages[rndNum] + '-XL.jpg' + '?random=' + Math.random(); $(".preload_hidden").html(""); $(".preload_hidden img").load(function() { var img = src; $("#real").css({ "background": "url(" + img + ")" }); }); }, 1000); }); .preload { width: 300px; height: 300px; #width: 1px; #height: 1px; background-repeat: none; #background-position: -1000px -1000px; #position: absolute; #opacity: 0; border: 2px solid blue; } #real { width: 300px; height: 300px; border: 2px solid red; } .preload_hidden { display: none; } }
Пример на JsFiddle UPDATE написали решение по вопросу автора setInterval(function() { $(".real").each(function(index) { var obj = $(this); d = new Date(); var bg = obj.css("background-image").match(/((http|https):\/\/.*(jpg|png|gif)).*/i)[1] + '?random=' + d.getTime(); console.log(bg); $('').attr('src', bg).load(function() { $(this).remove(); // чтобы избежать утечки памяти obj.css('background-image', 'url(' + bg + ')'); }); }); }, 2000); .real { width: 350px; height: 350px; border: 2px solid red; float: left; } .preload_hidden { display: none; }
Example on Jsfiddle

Пустой блок catch

#c_sharp


Здраствуйте! Так как я студент, и студент такой себе, то я не знаю, можна ли оставлять
блок catch пустым? Мне просто-напросто надо, чтобы в случае возникновения Exception`а
ничего не делалось, а просто продолжалась работа программы. Меня интересует, есть ли
какие-то правила или нормы, которые такого не разрешают?
    


Ответы

Ответ 1



На уровне языка — можно, точно так же как и пустой цикл while. Программа откомпилируется и не будет ворчать во время выполнения. Но с точки зрения хорошего дизайна, игнорировать исключения нужно довольно редко. Если вы игнорируете исключения, никто (в том числе и вы) не узнает, что что-то в программе идёт не по плану. Обычно в случае, если произошло исключение, вам должно захотеться известить об этом как-нибудь вышестоящую логику программы, чтобы она не тыкалась в это место постоянно. Если вам действительно хочется подавить исключение, хотя бы залогируйте проблему. Ну и во взрослых проектах имеет смысл оставить комментарий для других разработчиков, объясняющий, почему вы можете/должны проигнорировать исключение в этом месте.

Ответ 2



Пустые блоки catch ничем не запрещены. Можете смело использовать их, но учтите, что при возникновении exception в коде блока try, выполнение закончится на этом месте и перейдет в catch. В таком случае какой-то код в try может остаться невыполненным, поэтому будьте осторожны.

Как передать данные из Form2 в Form1 не закрывая формы?

#c_sharp #net #winforms


Есть Form1. На ней размещены richTextBox1 и Button1. Button1 вызывает Form2. 

На Form2 есть textBox1 и Button1.

ВОПРОС:
Как при нажатии на Form2.Button1 пеердать текстовое сообщение из Form2.textBox1 в
Form1.richTextBox1? При этом не закрывая ни одну из форм?

Есть подозрение, что лучший и самый универсальный способ это сделать — это использовать
делегаты. Но что-то я никак не соображу, как это правильно сделать?
    


Ответы

Ответ 1



Аргументы события public class MyEventArgs : EventArgs { private readonly string _text; public string Text { get { return _text; } } public MyEventArgs(string text) { _text = text; } } форма 2: public partial class Form2 : Form { public Form2() { InitializeComponent(); } public delegate void MyEventHandler(object sender, MyEventArgs args); public event MyEventHandler MyEvent; protected virtual void MyEventRaise() { if(MyEvent != null) MyEvent(this, new MyEventArgs(textBox1.Text)); } private void button1_Click(object sender, EventArgs e) { MyEventRaise(); } } на первой фоме подписываемся на событие var form2 = new Form2(); form2.MyEvent += Form2_MyEvent; разбираем что у нас там пришло private void Form2_MyEvent(object sender, MyEventArgs args) { // Текст из текстбокса, вставляем куда нам надо richTextBox1.Text += args.Text; }

Ответ 2



Есть несколько путей решения это задачи: Передать в Form2 ссылку на Form1 - это можно сделать классическими тремя путями: конструктор, свойство, контекст; Конструктор: форма 1 var form_2 = new Form2(this); форма 2 private Form1 form_1; public Form2(Form1 obj) { this.form_1 = obj; } private void f() { this.form_1.RichTextBox1.Lines[0] = "Hello"; } Свойство: форма 1: var form_2 = new Form2(); form_2.UpForm = this; форма 2: public class Form2 : Form { public Form1 UpForm { get; set; } private void f() { this.UpForm.RichTextBox1.Lines[0] = "Hello"; } } Контекст: Делается через статический объект. Объект: static internal class GLOBAL { static public Form1 CONTEXT_FORM; } форма 1: GLOBAL.CONTEXT_FORM = this; var form_2 = new Form2(); форма 2: private void f() { GLOBAL.CONTEXT_FORM.RichTextBox1.Lines[0] = "Hello"; } Через событие: описать в Form2 event, а в Form1 на него подписаться. (Вам уже описал Dmitry)

рамка с треугольником

#css #css3


Насколько реально сделать вот такую рамку на css



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

border: 20px solid transparent; 
border-left: 20px solid green; 
border-top: 20px solid green;


В треугольнике часть картинки находится а не просто цвет. Вообщем как сделать такую
рамку на css?
    


Ответы

Ответ 1



Подсмотрев одну идею в интернете, я немного попробовал помудрил и получилось вот что: html:
css: /* photo original width: 604px; photo original height: 592px; */ .tooltip-wrap { position: relative; width: 450px; } .tooltip-content { position: relative; height: 200px; border: 3px solid blue; border-radius: 20px; overflow: hidden; } .tooltip-triangle { position: absolute; overflow: hidden; margin: 0 auto; width: 300px; height: 156px; border-left: 3px solid blue; bottom: -153px; left: 78px; } .tooltip-triangle-wrap { width: 604px; height: 592px; } .tooltip-triangle-wrap { overflow: hidden; position: absolute; transform: skewX(-55.98deg); border-right: 3px solid blue; } .tooltip-triangle-wrap:first-child { transform-origin: 100% 0; position: absolute; bottom: -234px; left: -78px; } .tooltip-triangle-wrap:last-child { right: -.25em; transform-origin: 0 100%; } .tooltip-triangle-wrap img, .tooltip-triangle-wrap:after { transform: skewX(55.98deg); transform-origin: inherit; } Пример Вам придется немного адаптировать величины ширины высоты и позиций для себя. По идее, немного поманипулировав шириной и высотой тултипа, и треугольника, а также расположением треугольника и картинки внутри как вам надо - можно будет просто скриптом менять картинки как вам надо. Если хотите, то можете попробовать оттолкнуться от этого примера: jsfiddle.net

Сессии и DAO классы в Hibernate

#java #база_данных #hibernate #orm


Здравствуйте.

Есть маленький проектик работающий с БД. В качестве ORM решения выбран Hibernate 4. 

Попутно обуздывая фреймворк, создал классы сущностей, связал аннотациями, использовал
DAO pattern. Но: в имплементации ДАО классов в каждом изменяющем БД методе сессия открывалась
и закрывалась прямо в методе (как и в этой туториал ссылочке http://javaxblog.ru/article/java-hibernate-1/).
Пример

Session session = null;
        try {
            session = HibernateUtil.getSessionFactory().openSession();
            session.beginTransaction();
            // Здесь добавляю, обновляю или удаляю
            // ...
            session.getTransaction().commit();
        } catch (Exception e) {
            // Обрабатываю
            // rollback()
        } finally {
            // Закрываю
            if (session != null && session.isOpen()) {
                session.close();
            }
        }


Но что-то подсказывает, что это как-то, мягко говоря, не правильно. 
Порыв немного интернет, наткнулся на статейку (https://developer.jboss.org/wiki/GenericDataAccessObjects),
где говорится, что ДАО имплементации не должны создавать сессию внутри, а на неё нужно
лишь ссылаться. Если я правильно понял, ДАО имплементаций не должно волновать создание
сессий. 


  You could also use constructor injection. How you set the Session and what scope
this Session has is of no concern to the actual DAO implementation. A DAO should not
control transactions or the Session scope.


Интересует вопрос опытных разработчиков: 
создавать ли сессию один раз на всё приложение и просто в сеттере давать ссылочку
ДАО классам (при этом сессию не закрывать), или же в каждом методе ДАО класса создавать
и закрывать сессию? 
    


Ответы

Ответ 1



Жаль, что автор не нашёл время сам ответить на свой вопрос. Хоть я ни разу не опытный разработчик, попробую ответить на основании информации, которую нашёл в сети на текущий день. На многих ресурсах рекомендуют использовать Hibernate в связке со Spring. Мне не нравится этот совет тем, что вводится лишняя "сущность". Человек учится пользоваться отвёрткой, а ему хотят всучить шуруповёрт. Да, вроде бы шуруповёрт круче, но и отвёрткой уметь пользоваться тоже не будет лишним. Ручное открытие/закрытие сессии. В первую очередь напрашивается такая структура взаимодействия: слой DAO содержит только основные (CRUD - create, read, update, delete) операции взаимодействия с базой данных; в бизнес-слой выносятся операции, которые можно (и нужно) объединять в транзакции. Выглядит DAO-класс примерно так: public class ItemDAOImpl implements ItemDAO { private Session session; public ItemDAOImpl(Session session) { this.session = session; } @Override public Item get(long id) { return session.get(Item.class, id, LockMode.PESSIMISTIC_READ); } @Override public long create(Item item) { return (Long) session.save(item); } @Override public void update(Item item) { session.update(item); } @Override public Item delete(long id) { Item item = session.byId(Item.class).load(id); session.delete(item); return item; } } Сессия session создаётся в бизнес-слое и передаётся в конструктор DAO: public class AdminServiceImpl extends PersonServiceImpl implements AdminService { SessionFactory sessionFactory; public AdminServiceImpl(SessionFactory sessionFactory){ this.sessionFactory = sessionFactory; } @Override public long createItem(Item item) throws DBException { try (Session session = sessionFactory.openSession()){ Transaction transaction = session.beginTransaction(); ItemDAO dao = new ItemDAOImpl(session); long id = dao.create(item); transaction.commit(); return id; } catch (HibernateException | NoResultException e) { throw new DBException(e); } } @Override public void updateItem(Item item) throws DBException { try (Session session = sessionFactory.openSession()){ Transaction transaction = session.beginTransaction(); ItemDAO dao = new ItemDAOImpl(session); dao.update(item); transaction.commit(); } catch (HibernateException | NoResultException e) { throw new DBException(e); } } @Override public void deleteItem(long id) throws DBException { try (Session session = sessionFactory.openSession()){ Transaction transaction = session.beginTransaction(); ItemDAO dao = new ItemDAOImpl(session); Item item = dao.delete(id); transaction.commit(); } catch (HibernateException | NoResultException | IllegalArgumentException e) { throw new DBException(e); } } } Недостаток метода очевиден - при большой нагрузке должен активно работать сборщик мусора, чтобы освобождать память от DAO- и сервисных объектов. Это осталось за кадром, но подразумевается, что также должен создаваться объект сервисного класса AdminServiceImpl. В конструкторе этот объект получает ссылку на объект типа SessionFactory. Стратегия открытия сессии Чтобы избавиться от постоянного создания dao - и сервисных объектов, нужен механизм создания сессии или получения текущей сессии в каждом из этих объектов независимо друг от друга. И тут на помощь приходят стратегии открытия-закрытия сессии. Рекомендую эту статью к прочтению. Допустим, что выбираем стратегию ManagedSessionContext - каждому потоку по отдельной сессии. Тогда для получения сессии можно будет использовать Session session = sessionFactory.getCurrentSession(); Увы, сразу это не заработает. Чтобы заработало, нужно в hibernate.cfg.xml прописать thread. Или второй способ - в конфигурацию hibernate добавить свойство configuration.setProperty("hibernate.current_session_context_class", "thread"); Уже знакомый DAO-класс будет теперь выглядеть так: public class ItemDAOImpl implements ItemDAO { ItemDAOImpl() { } @Override public Item get(long id) { return DBService.getSessionFactory() .getCurrentSession() .get(Item.class, id, LockMode.PESSIMISTIC_READ); } @Override public long create(Item item) { return (Long) DBService.getSessionFactory() .getCurrentSession() .save(item); } @Override public void update(Item item) { DBService.getSessionFactory().getCurrentSession() .update(item); } @Override public Item delete(long id) { Session session = DBService.getSessionFactory().getCurrentSession(); Item item = session.byId(Item.class).load(id); session.delete(item); return item; } } Здесь DBService - абстрактный класс, содержащий ссылку на объект SessionFactory. Так выглядит функция getSessionFactory(): public static SessionFactory getSessionFactory(){ return sessionFactory; } А вот и переделанный сервисный класс: public class AdminServiceImpl extends PersonServiceImpl implements AdminService { AdminServiceImpl() { } @Override public long createItem(Item item) throws DBException { Transaction transaction = DBService.getTransaction(); try { ItemDAO dao = DaoFactory.getItemDAO(); long id = dao.create(item); transaction.commit(); return id; } catch (HibernateException | NoResultException e) { DBService.transactionRollback(transaction); throw new DBException(e); } } @Override public void updateItem(Item item) throws DBException { Transaction transaction = DBService.getTransaction(); try { ItemDAO dao = DaoFactory.getItemDAO(); dao.update(item); transaction.commit(); } catch (HibernateException | NoResultException e) { DBService.transactionRollback(transaction); throw new DBException(e); } } @Override public void deleteItem(long id) throws DBException { Transaction transaction = DBService.getTransaction(); try { ItemDAO dao = DaoFactory.getItemDAO(); Item item = dao.delete(id); transaction.commit(); } catch (HibernateException | NoResultException | IllegalArgumentException | IllegalStateException e) { DBService.transactionRollback(transaction); throw new DBException(e); } } } Вот используемые функции из DBService: public static Transaction getTransaction(){ Session session = DBService.getSessionFactory().getCurrentSession(); Transaction transaction = DBService.getSessionFactory().getCurrentSession().getTransaction(); if (!transaction.isActive()) { transaction = session.beginTransaction(); } return transaction; } public static void transactionRollback(Transaction transaction){ if (transaction.getStatus() == TransactionStatus.ACTIVE || transaction.getStatus() == TransactionStatus.MARKED_ROLLBACK) { transaction.rollback(); } } А вот класс DaoFactory для получения инстанса ItemDAO: public abstract class DaoFactory { private static ItemDAO itemDAO = new ItemDAOImpl(); public static ItemDAO getItemDAO() { return itemDAO; } } Собственно, на этом, думаю, всё. Для тех, кто хочет пощупать код, вот ссылки на github: - ручное управление сессией; - управление при помощи ManagedSessionContext.

Ответ 2



когда слишком много операций на вставку или обновление необходимо делать, то кадрый раз открытие и закрытие сесии отнимет много времени в совокупности. По этой причине данные действия можно позволить решить выше. private Session currentSession; private Transaction currentTransaction; public Session openCurrentSession() { currentSession = HibernateUtil.HibernateUtil.getSessionFactory().openSession(); return currentSession; } public Session openCurrentSessionwithTransaction() { currentSession = HibernateUtil.getSessionFactory().openSession(); currentTransaction = currentSession.beginTransaction(); return currentSession; } public void closeCurrentSession() { currentSession.close(); } public void closeCurrentSessionwithTransaction() { currentTransaction.commit(); currentSession.close(); } public void update(Object o) { this.currentSession.update(o); } таким образом, Вы сами решаете, когда открывать сессию и когда закрывать.

Ответ 3



Использование ссылки на SessionFactory внутри реализации DAO и создание сессии на каждый вызов дао методов. Для массивных изменений рекомендуется batch update.

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

#c_sharp


Дефолтное значение - это хорошо. Но что, когда дефолтное значение - это длинная строка,
а у нее надо изменить 1 символ? Не хотелось бы набирать его вручную полностью (тем
более это повышает шанс допустить опечатку)

Есть ли возможность сделать ввод через Console.ReadLine так, чтобы уже было введено
какое то значение?
    


Ответы

Ответ 1



Вариант без SendKeys, из аналогичного вопроса на английском // write the initial buffer char[] buffer = "Initial text".ToCharArray(); Console.WriteLine(buffer); // ensure the cursor starts off on the line of the text by moving it up one line Console.SetCursorPosition(Console.CursorLeft + buffer.Length, Console.CursorTop - 1); // process the key presses in a loop until the user presses enter // (this might need to be a bit more sophisticated - what about escape?) ConsoleKeyInfo keyInfo = Console.ReadKey(true); while (keyInfo.Key != ConsoleKey.Enter) { switch (keyInfo.Key) { case ConsoleKey.LeftArrow: ... // process the left key by moving the cursor position // need to keep track of the position in the buffer // if the user presses another key then update the text in our buffer // and draw the character on the screen // there are lots of cases that would need to be processed (backspace, delete etc) } keyInfo = Console.ReadKey(true); }

Ответ 2



static void Main(string[] args) { Console.Write("Your editable text:"); SendKeys.SendWait("hello"); //hello текст будет редактируемым Console.ReadLine(); }

Необходимо ли папки 'packages' в C# проекте хранить в git-репозитории проекта?

#c_sharp #visual_studio #nuget


У меня есть два два проекта HelloWorld и HelloWorld.UnitTests. Во втором применив
nuget я установил NUnit, в результате чего создана папка packages. Использую Visual
Studio 2013.

Сейчас репозиторий выглядит так:

.\HelloWorld\
.\HelloWorld.UnitTests\
.\HelloWorld.UnitTests\packages.config
.\packages\
.\HelloWorld.sln


Папка packages появилась после того как сделал активным проект HelloWorld.UnitTests
и применил команду Install-Package NUget в консоли.

В Python-е, есть так называемые файлы зависимостей и можно применить команду pip
install -r requirements.txt. Но в C# такого решения не нашел. Меня смущает, что видимо
придется хранить множество dll-файлов, хотя логичнее было бы в репозитории хранить
файл зависимостей, аналогичный python-овскому решению с requirements.txt файлом.

Правильно ли я понимаю, что мне все-таки придется эту папку хранить в репозитории
проекта?
    


Ответы

Ответ 1



Основной способ подключения/удаления зависимостей в проект является nuget. В папке проекта у вас должен быть файл packages.config. В нем хранятся данные об используемых в проекте nuget-пакетах. Добавлять в VCS нужно именно его. На основании содержащихся в нем данных будут скачаны необходимые пакеты. Dll'ки же включать необязательно. Пример:

Ответ 2



Для.Net проектов есть nuget. Он создает файл, подобный питоновскому requirements.txt с зависимостями, и умеет их самостоятельно востанавливать.