Страницы

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

вторник, 31 декабря 2019 г.

JSON. Пределы возможного

#json #javascript #aspnet_mvc


Доброго времени суток, ув. сообщество. Перейду сразу к делу:

Какой максимальный объём JSON данных можно забрать с сервера? Неограниченно
Какой максимальный объём JSON данных можно забрать с сервера без вреда для него и
клента? Ограниченно железом
Какой максимальный объём JSON данных можно хранить на клиенте? 
Какой максимальный объём JSON данных можно хранить на клиенте без вреда для системы?
2 Гб ± ...
Как можно оптимизировать загрузку большого объёма данных(кроме Lazy loading)? Параллельная
загрузка
Как можно оптимизировать хранение большого объёма данных на клиенте(кэширование,
может Local Storage)?

Заранее благодарю всех откликнувшихься.
UPD: JSON Compression algorithms - что можете сказать об этом? Чепуха © @karmadro4

@rnd_d, данные я собираюсь рендерить, не все сразу конечно, но чтобы не тратить время
ещё и на загрузку этих данных, они мне нужны ввиде Backbone.Collection на клиенте
@AlexWindHope, на сколько мне известно, кол-во параллельных запросов на один домен
ограничено, в Opere например, по умолчанию стоит 16, но можно увеличить до 128, как
обстоят дела в других браузерах не знаю.    


Ответы

Ответ 1



Знаю что кто-то писал java софтину, где обрабатывали > 2гб json'a( что привело к необходимости фикса JSON парсера 4 java ). Так что юзать можно по полной. С учетом того, что в большинстве браузеров парсинг JSON реализован на нативном уровне - скорость тоже на уровне. Вообще если вы пишите приложение, где удобно было бы использовать json формат данных - стоит посмотреть в сторону noSQL документно-ориентированных бд (mongoDB, couchDB). По поводу хранения большего количества данных - Local storage + запрос вида - не поменялись ли данные(если поменялись, естественно, тянем новые), при желании можно придумать что-то посложнее и поинтереснее, но не думаю что в этом есть смысл, а если и будет - то это уже отдельный вопрос.

Ответ 2



Какой максимальный объём JSON данных можно забрать с сервера? Поскольку json это для начала всего лишь строка, а размер строки в js не ограничен то гипотетически можно передать сколько угодно. Проблема будет именно в парсинге этой строки на стороне клиента, время парсинга зависит от: аппаратной конфигурации, браузера(его рализации js), метода парсинга. То есть на мощной машине можно без проблема забрать 20 mb json'a и превратить их в js объект. На мобильнике эта же операция может запросто повесить браузер. Мне кажется вы прекрасно это понимаете и без меня, но не очень понятно почему у вас такой абстрактный вопрос о максимальном количестве данных на сферическом клиенте в вакууме. Кстати вот тут есть про максимальный размер кэша.

Ответ 3



UPD: JSON Compression algorithms - что можете сказать об этом? Чепуха. Это не алгоритмы и даже не сжатие, а просто представления с уменьшением избыточности. С вполне очевидными последствиями.

Изменить цвет части текста в TextView

#android


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


Ответы

Ответ 1



С помощью span. TextView textView = (TextView)findViewById(R.id.textView); final SpannableStringBuilder text = new SpannableStringBuilder("Text"); final ForegroundColorSpan style = new ForegroundColorSpan(Color.rgb(255, 0, 0)); text.setSpan(style, 0, 1, Spannable.SPAN_INCLUSIVE_INCLUSIVE); textView.setText(text);

Как обратится к приватной переменной из другого класса в Java

#java


Например есть код:

class B {
    private int i = 22;
}

class A {
    // тут код который выводит переменную i
}

Условие:
класс B нельзя менять.
класс А можно менять (т.е наследовать класс B и т.д)    


Ответы

Ответ 1



Через Reflection B b = new B(); Class clazz = B.class; Field iField = clazz.getDeclaredField("i"); iField.setAccessible(true); int fieldValue = iField.getInt(b); System.out.println("i = " + fieldValue);

Ответ 2



Мне кажется, проще в класс А добавить метод public int getI(){ return i; } так называемый, getter.

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

#c #многопоточность #unix #freebsd


Всем добрый день!
 Рассматриваю возможности реализации нового сервера, и пока остановилась на модели
с созданием пула потоков. Однако поступила информация, что при такой работе сервера
на многоядерной системе, определенные потоки будут закреплены за ядрами сразу и перераспределения
их не будет, пока они не будут уничтожены, то есть возможна ситуация, когда часть пула
потоков, которая на данный момент никаких активных действий не производит, будет висеть
на одном ядре, и оно фактически будет простаивать, в то время, как второе ядро будет
загружено несколькими активными потоками. Если кто-то в курсе, подскажите плиз, действительно
ли это так, и есть ли какой-то способ управлять распределением потоков по ядрам, чтобы
загружать их более-менее равномерно? Может кто-то может полезной ссылочкой поделиться
применительно к unix - я ничего толкового пока не нашла по этому вопросу.    


Ответы

Ответ 1



Ручное распределение потоков по ядрам нужно только в очень исключительных случаях. Система будет перераспределять потоки между ядрами, как ей кажется правильно. И может перебросить рабочий тред с одно ядра на другое но в 99% это не нужно. Давайте представим некую виртуальную систему с 16 ядрами и 100 потоками. и 10 из них активно работает, занимая при это 10 ядер. Остальные 90 сидят тихонько на оставшихся 6. Вопрос, есть ли смысл перебрасывать активный поток на другое ядро? Ответ - нет. Только хуже сделаем (накладные расходы на переключение). Поэтому система будет пытаться сохранить поток на своем ядре. Вариант, когда ядер 2 и 100 потоков (из них 10 активных). В этом случае загружены будут точно два ядра. Причем выиграш от того, что есть 10 активных потоков будет отрицательный. Именно по этой причине, когда создают пул потоков, которые нагружены одинаково, не делают их больше кол-ва ядер+1. Потому что при дальнейшем увеличении кол-ва потоков будет только падение производительности (накладные расходы на переключение. Процессор только тем будет и заниматься, что переключать контексты потоков). В случае одного ядра, не рекомендуется создавать более 16 потоков на процесс (это конечно устаревшая информация, данная Борландом в году так 1995-1997 и в век двухядерных процессоров у каждой домохозяйки в ноуте и в планшете она малоактуальна). Но есть вариант, когда много потоков может улучшить задачу - это когда потоки занимаются малоактивной работой. Но преимущество только одно - упрощается логика кода. Но это сильно зависит от задачи. А теперь подсуммируем. Если у вас сервер с 2 ядрами, то на данный момент это не сервер, а домашний компьютер. Будете делать пул потоков - сделайте возможность регулировать кол-во потоков в пуле и проведите замеры. Очень часто, выставив правильное кол-во потоков, можно сильно ускорить задачу. А в некоторых случаях может выяснится, что оптимально будет работать только при одном потоке. Не доверяйте русскоязычному переводу англоязычной документации. В спорных случаях обращайтесь к английскому оригиналу. У меня был случай, когда из за неточностей в одно слово в переводе мана по select смысл очень сильно менялся

Параметры и аргументы функций в Go

#golang


Добрый день!
Подскажите, пожалуйста, по двум вопросам.
1) Можно ли в Go писать функции с необязательными параметрами? Типа как в PHP
function MyFunc($var1, $var2 = 1){}

2) Есть ли в Go возможность передавать значение переменной по ссылке? Опять же, как в PHP
function MyFunc($var1, &$var2){ $var2 = 1;}

После PHP этих приятных мелочей очень не хватает, а гугление что-то в этот раз не
помогло.
Заранее спасибо!    


Ответы

Ответ 1



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

Ответ 2



1) Можно ли в Go писать функции с необязательными параметрами? Типа как в PHP Точно также -- нет. Но есть пути обхода, своего рода костыли: Можно принимать переменное кол-во аргументов(func (params... interface{})), и тогда аргументы будут опциональными. Правда не именованными. Можно передавать словарь map[string]interface{}, немного громоздко, но иногда другого выхода нет. 2) Есть ли в Go возможность передавать значение переменной по ссылке? Опять-же как в PHP В Go нет ссылок, но есть указатели. Передавайте по указателю. UPD: пример использования указателя. package main import "fmt" func f(i *int) { (* i) = 2 } func main() { i := 1 f(&i) fmt.Println(i) } Напечатает 2.

Ответ 3



Мне кажется сделать параметр который не обязательно передавать в функцию не сложно. Значение поумолчанию можно прописать внутри. у меня получилось так: package main import "fmt" func addText(base string, opt ...string) (s string) { if len(opt) > 0 { base += opt[0] } else { base += "-" //хорошее место для обработки параметра поумолчанию } return base } func main() { fmt.Printf("%s\n", addText("info: ")) fmt.Printf("%s\n", addText("info: ", "done")) } Пожалуйста не сильно ругайте, я новичёк на стековерфлоу...

Скрипт в Google Spreadsheets. Как отследить событие изменения в ячейке?

#javascript #события #google_spreadsheet #google_apps_script


Всем добрый день. Составляем файлик, где будем вести семейный бюджет. Столкнулся
со следующей задачей. Есть "направление" и "категория продуктов". В одном направлении
собраны определенные категории продуктов. Также есть форма ввода (типа опроса), что
бы мы могли забивать транзакции через мобильники. Так вот, нужно чтобы скрипт анализировал
категорию продуктов и автоматом проставлял направление. Допустим категория "метро",
автоматом проставляется в соседнем столбце направление "транспорт". Я написал пример
скрипта, который читает содержимое текущей ячейки и проставляет результаты в первой.
Вопрос в том, как это все повесить на событие ввода (нажал enter - скрипт отработал)
function myFunction() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheets()[0];
//  var first = Browser.inputBox("First value");
  if (SpreadsheetApp.getActiveRange().getValue() == "пиво"){
    sheet.getRange("A1").setValue(SpreadsheetApp.getActiveRange().getValue());}
//  sheet.getRange("A1").setValue("First value:");
//  sheet.getRange("B1").setValue(first);
//  var next = Browser.inputBox("Next value"); 
//  sheet.getRange("A2").setValue("Next value:");
//  sheet.getRange("B2").setValue(next);
//  var result = sheet.getRange("B1").getValue() + sheet.getRange("B2").getValue();
//  sheet.getRange("A3").setValue("Result:");
//  sheet.getRange("B3").setValue(result);
//  Browser.msgBox("Summ is: " + result);
  ss.addMenu("Test", [{name: "Test", functionName: "myFunction"}]);
}
    


Ответы

Ответ 1



Вероятно, использовать триггер onEdit(event): onEdit(event) The onEdit function runs automatically when any cell of the spreadsheet is edited. A very simple use case for onEdit is to record the last modified time in a comment on the cell that was edited. The argument e that is passed in to the function contains a single property, source , which is the spreadsheet that is being edited. function onEdit(event) { var ss = event.source.getActiveSheet(); var r = event.source.getActiveRange(); r.setComment("Last modified: " + (new Date())); }

Ответ 2



Все очень просто, используйте функцию onEdit(event) которая реагирует только на изменение данных в таблице. Пример готового решения который при изменение любой строки вносит данные в столбец номер 8, номера строки та которая была изменена Вами function onEdit(event) { var sheet = event.source.getActiveSheet(); var sheetName = event.source.getActiveSheet().getSheetName() // Получаем имя листа который активен var actRng = event.source.getActiveRange(); var index = actRng.getRowIndex(); if (index > 1 && sheetName == "Менеджер") { Logger.log(event.source.parameters); //var user = Session.getEffectiveUser().getEmail(); var user = Session.getActiveUser().getEmail(); Logger.log(index); sheet.getRange(index, 8).setValue(user); } Исходя из Вашей задачи Вам осталось только переписать условие iF.

Исходный код Google Chrome

#google_chrome #opensource


Все знают, что Google Chrome - браузер с открытым исходным кодом, т.е OpenSource.
Корпорация Google даже организовывает конкурсы, в которых участники ищут баги в исходном
коде. Багов с момента выхода самой первой версии браузера было исправлено очень много:
и серьёзных и не особо( Null-Byte в адресной строке, например ).

Так вот, хотелось бы взглянуть на исходный код браузера и попытаться что-либо понять
в нем =). Посмотреть, как бравые разработчики гугла реализовали те или иные вещи...но
исходники браузера я нигде найти не могу, даже на самом сайте разработчика( google.com
) выдается 404 ошибка. Может кто уже скачивал исходники и смотрел? В таком случае хотелось
бы узнать, откуда вы скачивали. 
    


Ответы

Ответ 1



Собственно вот так вот можно получить исходник chromium ( именно на основе chromium, был написан google chrome ). Так-же, не менее интересно, копаться в исходниках webkit и v8

Ответ 2



Идите по этому адресу и изучайте материалы. Сам исходный код в режиме онлайн можно посмотреть тут

Как преобразовать Byte[] в Int32?

#c_sharp


Есть Byte[] buffer большого размера, в который читается значение типа Int32 (из tcp).
Как из этого Byte[] (или его фрагмента) получить Int32?

Можно брать 4 элемента массива и складывать, предварительно сдвинув биты, или есть
какое-то встроенное средство C# для этого?

Может глупый вопрос, но все-таки...    


Ответы

Ответ 1



Для конвертации базовых типов в массивы байт и обратно есть класс BitConverter. using System; public class Example { public static void Main() { // Create an Integer from a 4-byte array. Byte[] bytes1 = { 0xEC, 0x00, 0x00, 0x00 }; Console.WriteLine("{0}--> 0x{1:X4} ({1:N0})", FormatBytes(bytes1), BitConverter.ToInt32(bytes1, 0)); // Create an Integer from the upper four bytes of a byte array. Byte[] bytes2 = BitConverter.GetBytes(Int64.MaxValue / 2); Console.WriteLine("{0}--> 0x{1:X4} ({1:N0})", FormatBytes(bytes2), BitConverter.ToInt32(bytes2, 4)); // Round-trip an integer value. int original = (int) Math.Pow(16, 3); Byte[] bytes3 = BitConverter.GetBytes(original); int restored = BitConverter.ToInt32(bytes3, 0); Console.WriteLine("0x{0:X4} ({0:N0}) --> {1} --> 0x{2:X4} ({2:N0})", original, FormatBytes(bytes3), restored); } private static string FormatBytes(Byte[] bytes) { string value = ""; foreach (var byt in bytes) value += String.Format("{0:X2} ", byt); return value; } } // The example displays the following output: // EC 00 00 00 --> 0x00EC (236) // FF FF FF FF FF FF FF 3F --> 0x3FFFFFFF (1,073,741,823) // 0x1000 (4,096) --> 00 10 00 00 --> 0x1000 (4,096) UPD. И не забывайте про порядок байтов. В случае с TCP/IP, вероятно, придется изменить порядок байтов на обратный. Узнать какой порядок используется в текущей системе можно через свойство того же класса BitConverter.IsLittleEndian

Ответ 2



Вопрос и правда глупый...ведь, как вам, надеюсь, известно, byte отличается от int32 лишь количеством занимаемой памяти в ОЗУ. Так, sizeof(Int32)==4, а sizeof(byte)==1, соответсвенно. Для программиста использование типа BYTE может быть обоснованно лишь в том случае, когда в переменной этого типа нет смысла хранить числа>255. В вашем случае преобразование невозможно по одной простой причине - нельзя преобразовать массив в число =) Как мне кажется, сюда: Byte[] buffer записываются значения байтов( либо 1, либо 0 ) в процессе работы с протоколом TCP. Какие данные - зависит от конкретной задачи. В таком случае можно конкатенировать все байты в одну строку и преобразовать из двоичной системы в десятеричную. Это уже дело техники, как говорится =)

Стат сумма, хеширование, контрольная сумма для сравнения двух текстовых строк.

#алгоритм #хеширование


Есть следующая задача, допустим, есть текстовые строки одинаковой длины. 
Допустим, используются только буквы ABCD. Нужно ввести метрику, способ подсчёта контрольной
суммы и тп. (не знаю как более точно обозвать), чтобы можно было сравнивать строки
между собой по их контрольным суммам. 
То есть:
ABCDABCD и ABCDABCC - очень близкие строки с одной заменой. (1)
ABCDABCD и ABCDDABC - тоже очень близкие строки с одной вставкой "D".
Насколько я представляю, нужно иметь на выходе некоторую постоянную и вариабельную
часть. 
Чтобы в первом примере (1) SUM(ABCDABCD)='wtyy45t'.004 а SUM(ABCDABCC)='wtyy45t'.007
(цифры и буквы условны). 
И в тоже время:  SUM(ABCDABCD)='wtyy45t'.004 а SUM(DDACBADB)='yiejq07'.163
Чтобы можно было потом легко сравнивать похожие строки и откидывать совсем разные. 
Буду благодарен за любые ссылки на алгоритмы, предложения, советы. Спасибо.
UPD
Основной момент - различных строк будет несколько сотен тысяч. Нет возможности их
сравнивать между собой по сложным критериям. Хочется группировать их в кластеры по
общей постоянной части контрольной суммы.    


Ответы

Ответ 1



Как уже отметил margosh, вам следует уточнить требуемое понятие похожести, алгоритма is_strings_similar_like_i_want нет, и подобной функции не найдете даже в пхп. Пока можно рекомендовать полистать Энциклопедический словарь расстояний, в главе 11 приведены все известные метрики на множествах строк.

Ответ 2



Есть некие мысли по поводу алгоритма, не уверена что подобное Вам подойдет, но учитывая все вышесказанное, предложения следующие : Выяснить длину строки и предел количества символов, которые могут быть отличны (судя по Вашим пояснениям - 30%) Поисмвольно вычесть одну строку из другой, если количество "ненулевых" символов в результате превышает предел и данные символы располагаются вразброс - в строке были замены, стока по количеству замен отбрасывается, если же ненулевые символы идут строем - на лицо сдвиг или делеция, и необходимо сохранить позицию первого отличного символа и продолжить анализ. Соответственно при количестве "ненулевых" символов в результате меньше предела - строки похожи. Далее, в случае сдвигов и делеций должен быть цикл, ограниченный пределом количества отличных символов (Nlim), в котором проверяются : сопадение первого несовпавшего символа (позиция m) с одним из символов последующих позиций базовой строки (но не более m + Nlim). В случае совпадения на некоторой позиции r, проверяется совпадение последующих символов строки m+i с символами базовой строки m+r+i,теоретически, можно вынести эти куски в отдельные строки и воспользоваться пунктом 2. Для вставки сверяем символы строки в позиции от m до m+Nlim с символом базовой строки в позиции m. Пример : вставка : ABCDABCD и ABCDCDABСD, рез. - 00001111, m=4,r=6, позиции 4-7 базовой и 6-9 совпадают Как быть со строками разной длины - Вам, как автору темы, виднее. PS: Эти наброски, безусловно, не претендуют на полноту, простоту и быстроту реализации.

Ответ 3



Учитывая то что ваши строки имеют одинаковую длину, то я бы ввел метрику редактирования, то есть сколько замен букв требуется, для получения одного слова из другого. ABCDABCD и ABCDABCC - очень близкие строки с одной заменой. (1) Алгоритм вычисления данной метрики O(LENGTH(str)).

Ответ 4



Если число используемых символов ограничено какой-то разумной величиной N (ну скажем меньше 16), то лучший способ это трансляция строк в некое длинное целое используя в качестве метрики позиционный способ записи N-тиричной системе счисления. Скажем ваш пример с четырьмя символами ABCD - легко ложится под 4-х тиричную систему счисления. Строка: ABCDABCD -> 01230123 ABCDABCC -> 01230122 Ну а дальше сравнение целых это уже просто.

Ответ 5



Вопрос, на самом деле, очень хороший! И пока, решение @Barmaleyя самое лучшее. У меня нет лучшей идеи по этому поводу, разве что только XORить строки с определенной "солью" и опять же снова вычислять номер каждого символа. Это будет надежнее, но гораздо дольше, чем "неХОРеные" строки. А вообще советую вам смотреть в сторону PHP-функции similar_text() . Эта функция вычисляет степень похожести двух строк. Посмотрите её сорцы( они, как мне известно на C++ ), да поймете, как она работает, напишете свою.

Ответ 6



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

Ответ 7



Я думаю, здесь поможет преобразование Барроуза-Уилера.

Как добавить путь в переменную окружения %PATH% на Windows?

#windows #path


Как добавить что-то в путь (PATH или system PATH)? Что такое %PATH% и %что-то%?

Вот примеры:


  
  Add the following string to the PATH, C:\Program Files (x86)\CMake
  2.8\bin.
  Do you have make in your %PATH% environment variable? On my system, I need to add
%MINGW_DIR%\bin to %PATH%.
  Add C:/mingw/bin to the system PATH.
  


Я так понимаю, что надо зайти в Свойства системы → Дополнительно → Переменные среды...

А потом, если говориться про PATH, то добавить в «Переменные среды пользователя такого-то»,
а если system PATH, то «Системные переменные».

Потом нужно нажать «Создать». Что вписывать в «Имя переменной»? В значение переменной
надо записать те строки, которые даны в указании, так?

Qt\_\_directory — это, наверно, путь до папки с Qt. Между двумя % тоже путь до папки?
%PATH% и %MINGW_DIR% — это одно и тоже, если PATH понимают как путь к MinGW?
    


Ответы

Ответ 1



Да, верно, нужно зайти в Свойства системы → Дополнительно → Переменные среды. Там уже будут переменные PATH. Одна для текущего пользователя, вторая — общесистемная. Просто кликаете на них и добавляете нужный путь через точку с запятой. Как вариант, можно написать командный скрипт, в котором будет изменяться переменная окружения. При этом она может менять глобально для всей системы, текущей сессии, так и внутри конкретно той командной оболочки, в которой этот командный скрипт запущен. Смотрите детали в статье «Update Windows Path Environment Variable»[архив].

Парсинг строки при помощи регулярных выражений. Задачка на кавычки и пробелы.

#c_sharp #регулярные_выражения #синтаксический_анализ #powershell


Всю голову сломал себе =) из текстового файла читаются строки. В одной строке может
быть "несколько параметров". Нужно строчку разделить на эти параметры.
Есть несколько условий:


Параметры разделяются пробелами.


Параметр может содержать пробелы, но в это случае он обязательно должен быть заключен
в двойные кавычки ("").


Никто не запрещает заключать параметры без пробелов в кавычки.


Например нужно следующую строку разбить на три.
D:\test "D:\test\Название папки" "D:\test\test"

На выходе из функции должен получить 3 строки содержащие соответственно:
D:\test
D:\test\Название папки
D:\test\test

Подскажите, как бы мне это сделать? Использование string.split() не подходит в этом
случае, потому решил, что это нужно реализовывать при помощи regexp.match()...
Задача еще усложняется тем, что количество параметров может быть не ограничено. Под
концом строки подразумевается \r\n
Очередной раз благодарю Вас за помощь в моей задаче    


Ответы

Ответ 1



Попробуйте ".+?"|[^ ]+ Только надо будет удалять кавычки у параметров, у которых они есть.

Ответ 2



Вот вам ручной парсер (стащил отсюда): public static string[] SplitArguments(string commandLine) { var parmChars = commandLine.ToCharArray(); var inSingleQuote = false; var inDoubleQuote = false; for (var index = 0; index < parmChars.Length; index++) { if (parmChars[index] == '"' && !inSingleQuote) { inDoubleQuote = !inDoubleQuote; parmChars[index] = '\n'; } if (parmChars[index] == '\'' && !inDoubleQuote) { inSingleQuote = !inSingleQuote; parmChars[index] = '\n'; } if (!inSingleQuote && !inDoubleQuote && parmChars[index] == ' ') parmChars[index] = '\n'; } return (new string(parmChars)).Split(new[] {'\n'}, StringSplitOptions.RemoveEmptyEntries); } Поддерживает также и одинарные кавычки. Можно переписать в виде генератора, будет немного поэффективнее.

Защита от частых перезагрузок страницы

#php


Итак. Если например за 1 минуту с одного IP идёт 4 запроса, то мы блокируем доступ
к сайту на 15 минут. Реализовать я это пытался на файлах, то есть записываем каждый
раз в файл:
ip|timestamp|0
Далее проверять, если последний timestamp меньше, чем 3 секунды, то добавлять 

ip|timestamp|1|ip|timestamp|2|ip|timestamp|3

и т.д. Если превысило 5, то блокируем доступ к сайту на 10 минут например. 
Но пришла в голову плохая мысль, ведь пользователей много в онлайне и файл заполнится
до такой степени, что всему придёт конец. Сессии и cookie предлагать не стоит, так
как запрос со стороннего сервера. Или вовсе моё мнение ошибочно?    


Ответы

Ответ 1



А может не изобретать велосипед, а взять готовый и погнуть немного? Называется велосипед fail2ban.

Ответ 2



Для nginx модуль LimitReq, который по дефолту включен при компиляциии. Для Apache не так просто, вопрос на SO. Предлагают mod_evasive и mod_cband, а также в общем случае mod_limitipconn, mod_bw, mod_bwshare.

Ответ 3



Если вЕлик необходим, я тут набросал. Расходы времени и размеров можно сократить, организовав сам файл правильно. К примеру, переводить ip в бинарный вид: function ip2bin($ip) { $ip = explode('.', $ip); return chr($ip[0]).chr($ip[1]).chr($ip[2]).chr($ip[3]); } // и наоборот: function bin2ip($bin) { return ord($bin[0]).'.'.ord($bin[1]).'.'.ord($bin[2]).'.'.ord($bin[3]); } Тогда точно будешь уверен: данные об IP занимают 4 байта. В идеале и всю остальную инфу тоже нужно хранить так же. Но я для примера сделал так: // понадобится для нормирования чисел в «обычном виде»: function norm_len($s, $len = 11, $fill = '0') { if (strlen($s) >= $len) return $s; else { $fill = $fill[0]; return str_repeat($fill, $len - strlen($s)).$s; } } $f = fopen('iptest.bin', "w"); $counter = 0; // заполняем нашу базу случайными значениями: for ($counter = 0; $counter < 200000; $counter++) { // случайный IP: $ip = rand(0,255).'.'.rand(0,255).'.'.rand(0,255).'.'.rand(0,255); // просто, чтоб знать, какой IP найдется — для теста: $count = $counter+1; $timestamp = time(); // приводим к нужному виду: $ip = ip2bin($ip); //$ip = norm_len($ip, 4, ' '); // 4 байта; приводить не требуется $count = norm_len($count, 10, '0'); // 10 байт $timestamp = norm_len($timestamp, 11, '0'); // 11 байт // теперь мы уверены, что размер каждой записи составляет // 4 + 10 + 11 = 25 (байт) fwrite($f, $ip.$count.$timestamp, 25); } fclose($f); die('Filled. Last IP: '.bin2ip($ip)); Файлик заполнен. Пробуем искать: $f = fopen('iptest.bin', "r"); $current_ip = '146.115.156.250'; $ip = NULL; fseek($f, 0); echo 'Searching for "'. $current_ip .'"...'."\n"; $current_ip = ip2bin($current_ip); // приводим к бинарному виду $length = filesize('iptest.bin'); //while (!feof($f)) // не работает почему-то.. while (ftell($f) < $length) { $ip = fread($f, 4); if ($ip === $current_ip) { echo '+ ' . bin2ip($ip).' <- that`s it!'."\n"; $count = intval(fread($f, 10)); $timestamp = intval(fread($f, 11)); echo ' Timestamp: '. $timestamp .' ('. date('Y-m-d H:i:s', $timestamp) .')'."\n"; echo ' Count: '. $count ."\n"; //break; // не будем выходить при первом совпадении } else { //echo '- ' . bin2ip($ip) ."\n"; fseek($f, 21, SEEK_CUR); // всегда точно знаем, на сколько нужно сместиться } } fclose($f); Функцию norm_len нужно доделать еще для отрицательных чисел (ну или учитывать "00000-23464" уже при «распаковке»). Хранилище изобретено. Чтение файла достаточно быстрое, но все же будет сильно нагружать систему при большом количестве клиентов. Этот метод нужно использовать для выявления злоумышленника, после чего информацию о бане записывать в сессию, чтобы не гонять постоянно винт по этому файлу. Я еще подумаю, как сделать асинхронный поиск по файлу (к примеру, составлять список задач, и производить поиск не чаще 1 раза в 10 секунд, после чего сохранять вердикт в самопальную сессию). Это позволит снизить нагрузку при чтении, но может дать плохишу дополнительные 10 секунд. Осталось только придумать, какие данные там лучше всего хранить, чтобы выявлять плохишей. Мой личный вывод: лучше не трогать похапе и прибегнуть к использованию готовых, более продвинутых решений.

Ответ 4



Imho вариант с базой данных гораздо лучше варианта с файлом. Когда 100 потоков начнут писать в файл, то могут возникать коллизии или блокировки на запись. Никаких группировок и сортировок при работе с файлом не удастся нормально сделать. Когда-нибудь файл вырастет до такой степени, что защита сама сайт и положит. Вообще, смысла "Защищаться от частых перезагрузок страницы" нет. Если пользователь хочет перезагружать - пусть перезагружает. Делайте кеширование, если так нужно. Другое дело - защищать свой контент от неопознанных ботов-воришек. Т.е. вы можете сделать такую штуку, чтобы поиграться. Но профита она не даст. Готовое решение уже советовали - fail2ban. Блокировки ip будут на уровне iptables, а не кода приложения. Блокировки на основе лог-файлов сервера.

Инкремент, декремент

#cpp


добрый день, вопрос такой, почему нельзя сделать так:
i++++;
Но можно так:
++++i;    


Ответы

Ответ 1



разница в том, что возвращают постфиксная и префиксная формы инкремента. Префиксная возвращает ссылку на инкрементированную переменную i, а префиксная возвращает не ссылку, а значение некоторой временной переменной, в которой было сохранено предыдущее (до инкремента) значение переменной i. Выглядит это примерно так (для int) : int& operator ++(int& a);​ // префиксная форма ​int operator ++(int& a, int);​ // постфиксная форма В первом случае значение, возвращаемое оператором инкремента является lvalue, во втором - не является

Проблемы с пониманием шаблонов

#cpp #шаблоны_с++


Здравствуйте. Начал изучать шаблоны. Пока всё было просто и понятно, пока не дошёл
до явной специализациии и явного создания экземпляра.
Например, есть такой шаблон
template
void Swap(T&, T&);

Для этого шаблона можно создать явную специализацию для какого-то определённого типа,
например
template<>
void Swap(MyStruct&, MyStruct&);

Это объявление даст команду компилятору создать экземпляр функции Swap для типа MyStruct
и в коде
MyStruct a, b;
Swap(a, b);

Будет вызван именно этот экземпляр функции.
Теперь про явное создание экземпляра. Пусть у нас сеть этот же шаблон. Тогда в этом коде
double a, b;
Swap(a, b);

Либо в этом
double a, b;
template void Swap(double&, double&);
Swap(a, b);

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


Ответы

Ответ 1



Смотрите. Явная специализация — это метод сказать компилятору: когда будешь компилировать Swap для T = MyStruct, пользуйся не обычным определением, а специальным. Специальное поведение нужно, например, если для конкретного типа аргумента вы можете что-то сделать оптимальнее. Например, vector использует особую стратегию хранения, отличную от общего случая, чтобы упаковать значения в bitfield. Теперь о явном создании экземпляра. Начнём с того, что оно, говоря в общем, не нужно. Давайте разберём, что происходит, когда вы определяете template. Компилятор не может скомпилировать шаблон сам по себе. Например, если вы в шаблоне вызываете метод класса-параметра шаблона, компилятор не знает, какие у него аргументы на самом деле и каков возвращаемый тип. Поэтому компилятор может лишь скомпилировать отдельные специализации шаблонного класса. Но в отличие от обычного класса, который существует в единственном раз и навсегда заданном варианте, специализаций шаблонного класса (или функции) существует потенциально бесконечно много: у вас может быть vector, vector, vector, vector и т. д. Вследствие этого компилятор, видя объявление методов шаблонного класса, вовсе не генерирует никакого кода! (Не генерировать же ему и вправду все возможные специализации!) Возникает закономерный вопрос: а когда же генерируется код, и для каких специализаций? Ответ на это таков: в тот момент, когда компилятор видит обращение к шаблонному классу (например, видит vector), он приостанавливает компиляцию и тихонько в уголке компилирует нужную специализацию шаблона. Это значит, кстати, что код для vector будет находиться в каждом объектном файле, использующем vector. Нужна специальная магия компоновщика, чтобы выкинуть дублирующийся код и не получить сообщение об ошибке "multiply defined symbol". Вернёмся к нашей теме: а для чего всё-таки тогда нужно явное создание экземпляра? А вот для чего. Допустим, ваша библиотека предоставляет пользователям шаблонный класс. Если вы нигде в своей библиотеке не пользуетесь этим классом, а лишь определяете его, компилятор, понятно, не сгенерирует вообще никакого кода! Вы, однако, можете сделать явное создание для некоторых специализаций экземпляра в своём коде (то самое явное создание). Таким образом вы заставите компилятор таки сгенерировать код для него — точнее, для выбранных вами специализаций. Для чего это нужно? Этим вы по идее увеличите скорость компиляции для ваших клиентов. Если компилятор увидит, что есть явная специализация, он сможет по идее не отвлекаться на кодогенерацию специализации шаблона каждый раз, видит такую специализацию у клиента. Кроме того, если вы положите имплементацию шаблона не в .h, как принято, а в .cpp, и проведёте там явную специализацию, ваши клиенты смогут пользоваться шаблоном только с типами, для которых вы эту самую специализацию сделали. (Не уверен, однако, что это — хорошее применение.) Кстати, вы можете вызывать вашу функцию Swap и без явного указания шаблонного типа: double a = 2, b = 4; Swap(a, b); Компилятор умный, он догадается сам.

CompareTo и object

#c_sharp #сравнение


Здравствуйте. У меня появился такой вопрос: зачем в C# метод CompareTo интерфейса
IComparable принимает параметр типа object? Не проще ли принимать параметр того же
типа IComparable? Заранее спасибо    


Ответы

Ответ 1



В .NET на самом деле есть оба интерфейса: IComparable и IComparable. Первый сохраняется как наследие со времён .NET 1.x, в котором не было обобщённых типов (генериков). Для старого IComparable каким может быть тип аргумента функции CompareTo? Это должен быть один тип на все возможные случаи использования, для сравнения любого типа с собой, так что единственное, что может в принципе подойти, это object. Для нового IComparable мы можем объявить возможность сравнения с любым типом Т, которым захотим. Разумеется, никто не помешает написать class A : IComparable { ... — но правильное использование интерфейса, конечно, для сравнения с объектами того же самого типа: class A : IComparable<А> { ... К сожалению, система типов .NET на текущий момент недостаточно сильна, чтобы выразить ограничение «тип, сравнимый с самим собой», а не просто «тип, сравнимый с данным типом». Если вам интересны языки с более развитой системой типов, гляньте в сторону функциональных языков.

Ответ 2



Этого достаточно Это намного проще с точки зрения дизайна языка. Например, вы пишите метод сортировки и объявляете его как void Sort(IList list) where T : IComparable тем самым давая возможность сортировать объекты любых сравнимых типов. Единственный способ сделать строготипизированный интерфейс IComparable, это объявить его как interface IComparable { int CompareTo(T obj); } Но тогда никто не запретит вам сделать это class Foo : IComparable, IComparable {...} Что, согласитесь, совсем не логично.

Данные за текущий месяц, текущую неделю, предыдущий месяц

#дата #mysql


Как в mysql вывести 


данные за текущий месяц 

данные за текущую неделю  

данные за предыдущий месяц 

    


Ответы

Ответ 1



Нашел информацию: Данные за текущий месяц ... WHERE MONTH(`date`) = MONTH(NOW()) AND YEAR(`date`) = YEAR(NOW()) Данные за текущую неделю ... WHERE YEAR(`date`) = YEAR(NOW()) AND WEEK(`date`, 1) = WEEK(NOW(), 1) Данные за предыдущий месяц ... WHERE MONTH(`date`) = MONTH(DATE_ADD(NOW(), INTERVAL -1 MONTH)) AND YEAR(`date`) = YEAR(NOW())

Проблема при декомпиляции .NET

#c_sharp #net


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


Ответы

Ответ 1



Если это .NET, то это не значит, что это C#. В стеке языков .NET есть такие, которые позволяют создавать переменные вне всяких классов (VB.NET), или же создавать функции/процедуры вне классов (VB.NET, IronPython), или же полностью функциональные (F#). Такие переменные/функции/процедуры будут находиться в Module. C#, насколько мне известно, не ипользует Module в силу своей ОО. Исключение составляет тот случай, когда код обфусцируют - обфускатор может активно использовать эту часть программы, чтобы запутать код еще больше.

Кастомизация RadioButton

#html #css #вёрстка #svg #css_animation


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


Ответы

Ответ 1



Элементы radio и checkbox кастомизируются с помощью label: label.custom-radio input { display: none; } label.custom-radio input+div { content: "\a"; background: green; width: 20px; height: 20px; } label.custom-radio input:checked+div { background: red; } http://jsfiddle.net/oceog/uYZM2/

Ответ 2



html, body { height: 100%; } body { display: flex; justify-content: center; align-items: center; margin: 0; background-color: #333; } .custom-radios [type='radio'] { position: absolute; right: 100vw; } .custom-radios [type='radio'] + label { display: inline-block; position: relative; margin: 0 4px; border: 2px solid #fff; width: 2.5em; height: 2.5em; border-radius: 50%; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.33); color: transparent; cursor: pointer; } .custom-radios [type='radio'] + label:nth-of-type(1) { background: #2ecc71; } .custom-radios [type='radio'] + label:nth-of-type(2) { background: #3498db; } .custom-radios [type='radio'] + label:nth-of-type(3) { background: #f1c40f; } .custom-radios [type='radio'] + label:nth-of-type(4) { background: #e74c3c; } .custom-radios [type='radio'] + label:before { position: absolute; top: 0; right: 0; bottom: 0; left: 0; opacity: 0; background: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/2017/check-icn.svg") 50%/50% no-repeat; transition: all .3s ease; content: ''; } .custom-radios [type='radio']:checked + label:before { opacity: 1; }
У радио кнопки в активном (checked) состоянии показывается фон, в качестве которого выступает svg файл - галочка.

Разименование итератора в std::set

#cpp


Доброго времени суток! 
Я недавно начал заниматься программированием и сейчас возникла потребность в рассмотрении
контейнера std::set(далее именуемый контейнер). И у меня возникло несколько вопросов,
поискав в интернете не нашел подходящих ответов, решил спросить у знающих людей, которые
могли бы помочь мне. И так суть вопроса, имеется контейнер типа const char* в который
мы добавляем 2 элемента. 
typedef std::tr1::unordered_set unordered_set;
    unordered_set myUnorderedSet;
    myUnorderedSet.insert("testAction");
    myUnorderedSet.insert("testActionTwo");

далее если пробежаться по контейнеру 
for ( unordered_set::iterator it = myUnorderedSet.begin(); it != myUnorderedSet.end();
++it ) {
     std::cout << " " << *it;
     std::cout << std::endl;        
        }

можно вывести значения хранящиеся в данном контейнере. Затем я пытаюсь найти нужное
мне значение используя метод find().
unordered_set::iterator = myUnorderedSet.find("testAction");

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

*iter

я получаю ошибку компиляции: list iterator is not dereferencable.  Не совсем понимаю,
ведь 
for ( unordered_set::iterator it = myUnorderedSet.begin(); it != myUnorderedSet.end();
++it ) {
             std::cout << " " << *it;
             std::cout << std::endl;        
                }

мы можем применить операцию разыменования. Заранее благодарен за ответы!    


Ответы

Ответ 1



смотрим описание метода find() тут(ru) или тут(en) и видим что если find ничего не находит то возвращает итератор на end(), то есть на элемент следующий за последним и он (итератор end()) действительно не разыменуемый (is not dereferencable) то есть имея массив из 5 элементов [0,1,2,3,4] find ненайдя ничего вернёт [5] то есть end() соответственно для проверки "а нашлось ли чего нибудь" сравниваем if(iterator==myUnorderedSet.end()) почему так происходит? в set'e вы храните не строку testAction а указатель на неё и в функции find() сравниваются указатели! когда вы пишите строку в хардкоде то она помещается в специально отведённое место в программе, а вместо неё используется указатель на это место, написав два раза одинаковую строку testAction получаем две строки в специально отведённом месте (НО компиляторы могут с оптимизировать такие строки, в итоге имеем UB) как сравнивать строки? в STL есть тип данных(class) для строк string пихаем строки в стринг и при сравнении будет происходить преобразование string str="hello world";// или string str("hello world"); if(str=="hello world")//TRUE

Кэширование лямбда-выражений C#

#c_sharp #стандарт #оптимизация #linq


Столкнулся со следующим: Написав свою функцию кэширования значений лямбда-выражений(думал
это ускорит работу программы на повторных прогонах со старыми входными данными), я
приступил к тестированию, но заметил, что даже без использования моего кэширования
программа на втором прогоне выражений затрачивает уже значительно меньше тиков процессора(примерно
вдвое меньше). Т.е. есть подозрение, что кэширование для значений лямбда-выражений
уже реализовано в C# по умолчанию, так ли это?    


Ответы

Ответ 1



Лямбда-выражение — не более чем хитро оформленный указатель на функцию, так что кешированием вы не добьётесь ощутимого выигрыша в производительности. Не пытайтесь ускорить программу, не проведя профилирование. По поводу второго прогона — думаю, вы столкнулись с JIT-компиляцией. Каждая функция (не только лямбда) при первом выполнении компилируется в нативный код. Каждое последующее выполнение уже не нуждается в компиляции, а значит, происходит значительно быстрее.

Ответ 2



К ответу @VladD о JIT-компиляции добавлю, что похожее поведение можно наблюдать не только при обращении к обычным IEnumerable (Linq to Objects), но и в случае работы с Entity Framework. Однако в этом случае дело не в JIT-компиляции (хотя и она, разумеется, никуда не девается), а в так называемых "холодных запросах", во время которых "за кулисами" выполняется множество всяческих подготовительных действий по созданию и проверке моделей для дальнейшей работы с базой. После одного холодного запроса выполняются уже "горячие", которые происходят гораздо быстрее

В чем смысл фрагментов (fragment) в Android?

#android_fragment #android


В чем смысл фрагментов (fragment) в Android?    


Ответы

Ответ 1



Что бы понять смысл темплейтов, представьте классическую ситуацию с программой чтения новостей. На телефоне она будет выглядеть как одна активити с списком и одна - собственно новость. На планшете, где экран побольше, можно эти две активити расположить рядом. И что бы не делать дважды одну и ту же работу, можно просто сделать два фрагмента и разместить их на активити. Фрагменты - это "высокоуровневые виджеты". В делфи также есть фрагменты. Они называются "фреймы" (класс TFrame).

Ответ 2



У них есть ещё одна потрясная функция - setRetainInstance(boolean). Это позволяет обойти некоторые ограничения lifecycle activity и сохранять данные/логику прямо во фрагментах. Другими словами при назначении этого флага фрагмент не уничтожается как activity а осатется до выхода из программы. Ну а DialogFragment позволит вам довольно просто добавлять свой собственный View для диалогового окна.

Ответ 3



Фрагмент (Fragment) - является модульной частью активити. Для архитектуры в Android удобно воспринимать, как продолжение основной View, иногда называют SubView. Очень хорошо описаны фрагменты в оф доках: https://developer.android.com/guide/components/fragments.html?hl=ru Смысл фрагментов и их основное преимущество изначально заключалось в том, что вы можете показать 2 фрагмента на 1 Screen. Но вы не можете показать 2 Activity в 1 Screen, это невозможно (кроме мультипроцессов, MultiWindow). Позже данный подход в MaterialDesign получил название, как правильная организация интефрейсов и навигации и название его MasterDetailFlow. Данную концепию, очень удобно организовывать именно через фрагменты. Иначе приходилось бы писать отдельную логику для допольнительной ситуации, и поддерживать обе части, что очень плохо. Сейчас Фрагменты в Android являются неотъемлемой частью разработки полноценных приложений, и они используеются системой с API 3.0. Фрагметны позволяют создавать более удобную декомпозицию View, они лекго заменяемы в Activtiy, и могут лекго переезжать в другие проекты. Только с помощью фрагментов вы можете правильно организовать ViewWidgetы: NavigationView, DrawerLayout, NavigationBottom, BottomSheet, FragmentsDailogs, ViewPagers etc. (кончено можно и без, но порой это сложно или очень сложно) Создать красивые переходы и анимации намого лечге, а порой (Transitions) можно только с помощью фрагментов.

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

#бинарное_дерево #cpp


По заданию требуется реализовать бинарное дерево для хранения и операций с данными
вида: Деталь, Количество, Поставщик(С++). Я составила фрагмент программы нахождения
имени поставщика , который поставляет наибольшее количество деталей
    struct Ttree *Ttree_max (struct Ttree *temp)
    {
        if (temp==NULL)
        return NULL;
        while (temp->right!= NULL) 
        temp= temp-> right;
        return temp;
    }

Однако такой вариант не подходит, необходимо это сделать методом рекурсии, составить
функцию, проверяющую всех поставщиков (Name) методом обхода всего дерева с вызовом
функции подсчета количества деталей (Const) по каждому поставщику(Name). В процессе
подсчета запомнить элемент с наибольшим количеством, а в конце вывести его на экран(Name).
Помогите разобраться.
Вот часть кода программы:
    #include 
    #include 
    #include 
    using namespace std;

    struct Ttree 
{   int Const;      
    char Name[30];      
    char Detal[30];      
    struct Ttree *left;   
    struct Ttree *right;

};
    struct Ttree* add
    (
     Ttree *beg, int Const, char Name[30], char Detal[30]
    )

   {
      if (!beg) 
        {               
           struct Ttree *temp = new Ttree;
          temp->Const = Const;
          strcpy_s(temp->Name, 30, Name);
          strcpy_s(temp->Detal, 30, Detal);

          temp->left = 0;
          temp->right = 0;
          return temp;
        }
     else if ((Const)>(beg->Const)) 
        {                 
          beg->right = add(beg->right, Const, Name, Detal);
          return beg;
        }
     else 
        {        
          beg->left = add(beg->left, Const, Name, Detal);
          return beg;
        }
    }

___....____
    struct Ttree *Ttree_max (struct Ttree *temp)
    {
        if (temp==NULL)
        return NULL;
        while (temp->right!= NULL) 
        temp= temp-> right;
        return temp;
    }
    


Ответы

Ответ 1



Чтобы найти Name поставщика с максимальным количеством деталей, необходимо запомнить текущий максимум и пройтись по всему дереву, заменяя максимум при нахождении большего количества. Это делается примерно так: #include using namespace std; void find_max(struct TTree *tree, map &strmap, struct Ttree *max) { if (tree == NULL) return; string str(tree->Name); if (strmap.count(str) == 0) strmap[str] = tree->Const; else strmap[str] += tree->Const; if (max == NULL) max = tree; else { string maxstr(max->Name); if (strmap[str] > strmap[maxstr]) max = tree; } find_max(tree->right, strmap, max); find_max(tree->left, strmap, max); } int main(int argc; char **argv) { map names_map; struct Ttree *tree; fill_tree_initial(tree); // это, я надеюсь, вы реализуете сами struct Ttree *max = tree; find_max(tree); puts(max->Name); return 0; } Ключевым элементом здесь является map &strmap, которая содержит агрегируемые значения целочисленного типа по каждому поставщику. Заполнение, конечно, получилось слегка сумбурным, но хороший стиль программирования требует поступать именно так (мы не можем гарантировать, что в max не будет нуля).

Ответ 2



@Danatela, набросал на скорую руку. #include #include #include #include struct tnode { struct tnode *left, *right; void *data; }; struct tdata { char sup_name[20], det_name[30]; unsigned int amount; }; typedef int (*bt_cmp)(void *data, void *tree_data); static void bt_add (struct tnode *root, struct tnode *t, bt_cmp cmp) { if (cmp(t->data, root->data) > 0) { if (root->right) bt_add(root->right, t, cmp); else root->right = t; } else { if (root->left) bt_add(root->left, t, cmp); else root->left = t; } } static int cmp_amount (void *data, void *tree_data) { struct tdata *p = (struct tdata *)data, *q = (struct tdata *)tree_data; return p->amount - q->amount; } static int cmp_sup (void *data, void *tree_data) { struct tdata *p = (struct tdata *)data, *q = (struct tdata *)tree_data; return strcmp(p->sup_name, q->sup_name); } static int cmp_detail (void *data, void *tree_data) { struct tdata *p = (struct tdata *)data, *q = (struct tdata *)tree_data; return strcmp(p->det_name, q->det_name); } struct tdata * get_record () { struct tdata s, *r; char str[LINE_MAX]; fputs("Enter supplier, detail, amount : ", stdout); while (fgets(str, LINE_MAX, stdin)) { if (sscanf(str, "%s %s %u", s.sup_name, s.det_name, &s.amount) == 3) { r = (struct tdata *)malloc(sizeof(*r)); memcpy(r, &s, sizeof(*r)); return r; } puts("Invalid input, try again"); } return 0; } static void add_tree (struct tnode **root, struct tdata *sup, bt_cmp cmp) { struct tnode *p = (struct tnode *)calloc(1, sizeof(*p)); p->data = (void *)sup; if (*root) bt_add(*root, p, cmp); else *root = p; } static void pri_tree (struct tnode *t, int level) { if (t) { pri_tree(t->left, level + 1); int i; for (i = 0; i < level; i++) fputs(" ", stdout); struct tdata *d = (struct tdata *)t->data; printf ("%s %s %u\n", d->sup_name, d->det_name, d->amount); pri_tree(t->right, level + 1); } } static void find_max (struct tnode *t, struct tdata **dmax) { if (t) { find_max(t->left, dmax); find_max(t->right, dmax); struct tdata *d = (struct tdata *)t->data; if (d->amount > (*dmax)->amount) *dmax = d; } } int main (int ac, char *av[]) { struct tdata *sup; struct tnode *atree = 0, *dtree = 0; while(sup = get_record()) { add_tree(&atree, sup, cmp_amount); add_tree(&dtree, sup, cmp_detail); } puts(""); if (!atree) return 0; puts ("amount tree"); pri_tree(atree, 0); puts ("detail tree"); pri_tree(dtree, 0); struct tdata *mxsup = (struct tdata *)atree->data; struct tnode *t = atree; while (t->right) { // amount tree mxsup = (struct tdata *)t->right->data; t = t->right; } printf ("atree: %s supplier is max: %d\n", mxsup->sup_name, mxsup->amount); mxsup = (struct tdata *)dtree->data; find_max(dtree, &mxsup); printf ("dtree: %s supplier is max: %d\n", mxsup->sup_name, mxsup->amount); return puts("") == EOF; } Очевидно, что find_max и pri_tree можно тоже реализовать через обобщенную функцию, скажем, tree_travers с callback-ами для обработки каждого посещаемого узла. Аналогично можно делать и функцию удаления дерева и данных его узлов для освобождения памяти (здесь я их не писал). Сейчас подробнее некогда, появлюсь в воскресенье вечером UPDATE @LHh, Код для построения дерева суммарных поставок каждым поставщиком и поиска поставляющего максимальное количество деталей. struct sumsup { // дерево суммарных поставок по поставщикам struct sumsup *left, *right; char *name; // указатель на имя в узле дерева поставок int sum; }; // сделаем новый узел дерева суммарных поставок по поставщикам // скорректируем текущий максимум (если новый поставщик сразу MAX) struct sumsup * make_sup (struct tdata *d, char **mxname, int *max) { struct sumsup *r = (struct sumsup *)calloc(1, sizeof(*r)); r->name = d->sup_name; if ((r->sum = d->amount) > *max) { *max = r->sum; *mxname = r->name; } return r; } // рекурсивный обход дерева поставок void max_sum (struct tnode *t, struct sumsup **ps, char **mxname, int *max) { if (t) { if (!*ps) { // init *ps = make_sup((struct tdata *)t->data, mxname, max); // это нужно для правильной обработки корня дерева суммарных поставок // т.к. он будет найден в начале обработки дерева // и эта поставка не должна удваиваться *max = (*ps)->sum = 0; } int r; char *nm = ((struct tdata *)t->data)->sup_name; struct sumsup *p = *ps; // дерево суммарных поставок по поставщикам // итеративный поиск в дереве суммарных поставок по поставщикам while (r = strcmp(nm, p->name)) { if (r < 0) { if (p->left) p = p->left; else { // и достраивание этого дерева p->left = make_sup((struct tdata *)t->data, mxname, max); break; } } else { if (p->right) p = p->right; else { // если такого поставщика в нем еще нет p->right = make_sup((struct tdata *)t->data, mxname, max); break; } } } if (!r) // или увеличение суммы поставок найденного поставщика if ((p->sum += ((struct tdata *)t->data)->amount) > *max) { *max = p->sum; *mxname = nm; } max_sum(t->left, ps, mxname, max); max_sum(t->right, ps, mxname, max); } } void del_sumtree (struct sumsup *t) { if (t) { del_sumtree(t->left); del_sumtree(t->right); free(t); } } void del_tree (struct tnode *t, int data) { if (t) { del_tree(t->left, data); del_tree(t->right, data); if (data) free(t->data); free(t); } } А это код в конец main() для вызова построения дерева сумм поставок по всем поставщикам и поиска максимума struct sumsup *sumtree = 0; char *mxsupname = 0; int maxsum; max_sum(atree, &sumtree, &mxsupname, &maxsum); printf("greatest: %s (%d)\n", mxsupname, maxsum); del_sumtree(sumtree); del_tree(atree, 0); del_tree(dtree, 1); UPDATE 2 @LHh, пожалуй, вот такой код построения дерева суммарных поставок выглядит более логичным (и к тому же он короче). // рекурсивный обход дерева поставок void max_sum (struct tnode *t, struct sumsup **ps, char **mxname, int *max) { if (t) { struct sumsup *p; if (p = *ps) { // дерево суммарных поставок по поставщикам уже существует int r; char *nm = ((struct tdata *)t->data)->sup_name; // итеративный поиск в дереве суммарных поставок по поставщикам while (r = strcmp(nm, p->name)) { if (r < 0) { if (p->left) p = p->left; else { // и достраивание этого дерева p->left = make_sup((struct tdata *)t->data, mxname, max); break; } } else { if (p->right) p = p->right; else { // если такого поставщика в нем еще нет p->right = make_sup((struct tdata *)t->data, mxname, max); break; } } } if (!r) // или увеличение суммы поставок найденного поставщика if ((p->sum += ((struct tdata *)t->data)->amount) > *max) { *max = p->sum; *mxname = nm; } } else // создаем корень дерева поставок *ps = make_sup((struct tdata *)t->data, mxname, max); max_sum(t->left, ps, mxname, max); max_sum(t->right, ps, mxname, max); } } Как видите, в нем создание корня дерева поставщиков не рассматривается как особый случай при поиске максимума.

Что не так в моем коде, и как подтянуть навыки?

#android #java


Отправил тестовое задание на позицию Android разработчика, но в ответ они написали:

После ознакомления с тестовым заданием, мы отметили, что у вас недостаточный уровень
знания принципов ООП и принципов построенийAndroid-приложений.
Если вы подтянете свой уровень знаний, лучше изучите ООП и каким образом применять
его принципы для построения приложений, то мы могли бы вернуться к вопросу рассмотрения
вашей кандидатуры в будущем.

Я самоучка, учился по книгам, статьям и т.д. , можете опытным глазом посмотреть что
в моем коде не так в плане ООП и принципов построения? И как апргрейдить эти навыки? 
Код на gitHub, т.к. классов не один и не два https://github.com/Vlad161/Products    


Ответы

Ответ 1



Ответ работодателя очень похож на стандартную отписку, поэтому не стоит воспринимать его буквально. После просмотра вашего проекта (кстати, неплохо было бы написать, что именно от вас хотели, можно выдержку из тестового задания) остались такие замечания: Имена классов. Обычно имена классов - существительные (JSONReadFromAsset стоило бы назвать JSONAssetReader). К тому же стоит придерживаться какого-то общего стиля именования (два класса-активити заканчиваются на Activity, третий почему-то нет). Скорее всего от вас ждали минимальной реализации MVC. Стоило создать bean для хранения сведений о продукте и добавить уровень абстракции DAO для извлечения данных из файла. Как-то так: public interface ProductDAO { List getProducts(); } public class ProductDaoImpl implements ProductDAO { public List getProducts() { // здесь вытаскиваем список продуктов из JSON } } Таким образом вы бы отделили реализацию получения данных от логики их обработки, получив возможность изменять способ получения данных, не затрагивая основную логику программы. Насчёт "подтянуть навыки ООП" - читайте Head First Design Patterns и GOF.

Ответ 2



Вполне нормально написано, действительно похоже на отписку. Я бы немного погундел на: Постоянное использование литеральных констант, которые имеет смысл объявить как final static String ID="id"; ну и т.д. Злоупотребление анонимными классами обработчиков - ухудшает читаемость; Не совсем единообразный стиль именования (naming convention); Отсутствие бина Product, это бы существенно упростили бы код - например даже отсылка через Intent extras, ну не говоря о прочих вкусностях - наверное это самое серьезный недостаток вашего кода; Отсутствие типизированных исключений; Возможно имело бы смысл использовать стороннюю либу для парсинга Json массива (типа Google GSON) - ну типа показали бы что умеете работать со сторонними либами, а не каждый раз изобретаете велосипед. А так вполне нормально. Для начинающего вполне тянет на "четверочку". Update Да, еще из существенного: вам надо "посадить" читалку Json массива в IntentService или в Runnable с извещением об окончании работы через Broadcast. А на отображение продукта поставить "ожидалку" ждущую кастомный приватный Broadcast от читателя Json массива. В противном случае, если придется читать Json из сети - у вас код будет нерабочий.

Ответ 3



Суть претензии в отсутствии ООП вполне ясна: У Вас просто нету прикладной модели. Из Вашего кода невозможно выделить целостные объекты (продукт, список продуктов и т.д.) и их способы взаимодействия. Например, для данной задачи (как я её понимаю без самого описание задачи) я бы выделил следующие объекты: Product //класс содержащий всю информацию о продукте и возможные действия над ним(ид, имя, продать, купить....) ProductCollection //Класс содержащий набор продуктов и операции над этим набором (добавить, удалить, загрузить из адаптера ProductAdapter //Базовый класс который предоставляет методы по получению продуктов из источников данных И далее развивать эти классы, чтобы показать возможности инкапсуляции, наследования и прочих возможностей ООП. Например адаптер - сделать интерфейсом.

Как переименовать базу данных?

#php #mysql


Доброго времени суток.
Как переименовать существующую БД с помощью sql запроса из php?    


Ответы

Ответ 1



Сделайте бэкап всей исходной БД. RENAME TABLE позволяет переименовывать таблицы из одной БД в другую, при условии, что обе БД находятся на общей файловой системе. Так что надо создать новую БД, переименовать таблицы из старой в новую: CREATE DATABASE db_new; RENAME TABLE db_old.table1 TO db_new.table1, db_old.table2 TO db_new.table2, ... db_old.tableN TO db_new.tableN ; Проверьте, перенеслись ли таблицы, осталось ли что-то нужное в старой БД. Удалите старую БД: DROP TABLE db_old;

Ответ 2



Насколько я помню, команду для переименования базы данных убрали из mysql. Чтобы переименовать, можно воспользоваться phpmyadmin, по-моему, там была такая возможность. Если у вас база с типом MyISAM, то можно просто переименовать каталог базы данных. Но мне кажется, что проще скопировать старую базу в новую с нужным названием и затем удалить старую. P.S. Ну и, конечно, ОБЯЗАТЕЛЬНО не забывайте сделать бекап перед всеми манипуляциями. UPD забыл сказать, если вы будете копировать базу с новым нужным именем, то не забудьте проверить права на новую базу данных.

Как вырезать угол блока с помощью CSS3?

#css3


Необходимо вырезать все углы блока с помощью CSS3. Как на картинке 
    


Ответы

Ответ 1



Этого можно добиться с помощью абсолютного позиционирования прозрачного круглого элемента в углах с тенью по краям. Я использовал сочетание
'ов с отключенной прокруткой, которые содержат 'ы, тени, границы и псевдо-селекторы. Вот основной HTML и CSS для начала: a {display:inline-block; width:250px; height:100px; background:#ccc; border:2px solid #000; position:relative; margin:10px;} a div {position: absolute; top: 0; overflow: hidden; width: 15px; height: 100%;} a div:after {content:''; background:#000; width:2px; height:75px; position:absolute; top:12.5px;} a div:first-of-type {left: -14px;} a div:first-of-type:after {left:0;} a div:last-of-type {right: -14px;} a div:last-of-type:after {right:0;} a span {display:block; width:30px; height:30px; background:transparent; position:absolute; bottom:-20px; right:-20px; border:2px solid #000; border-radius:25px; box-shadow:0 0 0 60px #ccc;} a div:first-of-type span {left:-20px;} a div:first-of-type span:first-child {top:-20px;} a div:first-of-type span:last-child {bottom:-20px;} a div:last-of-type span {right:-20px;} a div:last-of-type span:first-child {top:-20px;} a div:last-of-type span:last-child {bottom:-20px;}
Это перевод ответа «Inset border-radius with CSS3».

Ответ 2



Я не думаю, что это было бы возможно, если углы должны быть прозрачными, однако, если фон известен, можно в каждом углу создать
с закруглённой границей. Если у этих
'ов цвет фона такой же как и у страницы, то это даст желаемый результат. #box { position: relative; margin: 30px; width: 200px; height: 100px; background: #ccc; border: 1px solid #333; } .corner { position: absolute; height: 10px; width: 10px; border: 1px solid #333; background-color: #fff; } .top-left { top: -1px; left: -1px; border-radius: 0 0 100% 0; border-width: 0 1px 1px 0; } .top-right { top: -1px; left: 190px; border-radius: 0 0 0 100%; border-width: 0 0 1px 1px; } .bottom-left { top: 90px; left: -1px; border-radius: 0 100% 0 0; border-width: 1px 1px 0 0; } .bottom-right { top: 90px; left: 190px; border-radius: 100% 0 0 0; border-width: 1px 0 0 1px; }
Это перевод ответа «Inset border-radius with CSS3».

Логирование ошибок

#java #android #логирование


Здравствуйте!
Не подскажете, каким способом логировать ошибки в Android-приложениях?
Каким способом лучше отправлять с аппарата на сервер разработчика сообщения об ошибке
в приложении?
Я думаю, что стоит писать все в файл и отправлять на сервер через время, если есть
необходимость. Но как отловить все ошибки в приложении, пока не знаю.
Что можете посоветовать?    


Ответы

Ответ 1



Для отлова есть библиотека Acra. Отлавливает абсолютно всё + есть возможность для отправки баг репорта программисту-создателю. Вот мини-гайд. А для логирования slf4j, правда, как она дружит/недружит с андроидом, я хз.

Ответ 2



Я рекомендую Crashlytics. Есть возможность кидать сообщения об исключениях, фатальных ошибках и т.д. Есть возможность создавать команды, давать роли: программисты, тестеры. В общем, очень удобный аналог Test Flight (iOS) только для Android.

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

#java #файлы


Собственно сабж: есть директория, которую вводит юзер, но она может не существовать
в системе (соотвествено если она не существует, я ее создаю). File.isDirectory возвращает
true, только если эта директория существует. Как еще можно проверить?    


Ответы

Ответ 1



Так нельзя проверить является ли строка директорией. Это проверка на существование, если не существует он вернет fakse. А как мне проверить что директория например /home/user/somedir/ является путем, даже если этой директории у меня нет на компе ? Никак. Т.к. до момента создания файла/директории НЕИЗВЕСТНО, кто это на самом деле будет. Попробуй создать файл без расширения в одной папке и такую же директорию рядом с файлом. По крайней мере в NTFS это невозможно. Отсюда вывод: до того как создан файл/директория, ты не узнаешь, кто это на самом деле.

Ответ 2



Можно вот так: File f = new File(path); if(f.exists()) { } Работает как для файла, так и для директории.

Есть ли в Windows на уровне ОС какая-либо защита от переполнения буфера?

#windows #c #безопасность #защита #cpp


Добрый день!
У меня возникла проблема при реализации переполнения буфера.
Если я делаю прямо в программе так:
char buffer[4];
strcpy(buffer, "AAAA\xf9\xc0_и.т.д._мой_шеллкод_");

То шеллкод выполняется и все работает.
Если же я пишу в программе
char buffer[4];
strcpy(buffer, argv[1]);

И пытаюсь подать программе на вход шеллкод, то программа крашится.
Отсюда у меня возникли мысли, что возможно эту проблему как-то контролирует сама
ОС? (Win 8.1)
Подскажите, так ли это? Если так, то возможно ли отключить этот контроль?    


Ответы

Ответ 1



Такими вещами занимается пара из ОС и компилятора. Например, Visual Studio содержит ключ /GS (по умолчанию включён), который активизирует т. н. stack canary: в определённые места в стеке записывается случайное число, и если впоследствии это число оказывается затёрто, детектируется stack smash. Чтобы отключить, попробуйте ключ /GS-. Кроме того, в отладочном режиме Visual Studio вставляет дополнительные проверки границ массивов, так что вам, возможно, придётся переключиться в Release Mode (или поискать, как это отключается в свойствах проекта). По поводу разницы в поведении Release и Debug Mode. Для начала: выход за границу выделенной памяти есть undefined behaviour. Убедитесь, что вы в курсе этого понятия, оно отвечает за 95% проблем в безопасности; вы, как будущий специалист по software security, должны это особенно отчётливо понимать. Undefined behaviour значит, что компилятор не имеет никаких обязательств в этой ситуации, и любое поведение программы правильно. Теперь, в случае отладочного режима, компилятор специально для разработчиков вставляет проверки на затирание памяти для того, чтобы сообщить об ошибке как только она случится (иначе найти проблему будет сложнее). Такой контроль не требуется по стандарту, и разумеется отнимает время пробега программы. В случае release-режима, такие проверки не вставляются для ускорения работы программы, и вся безопасность держится на stack canaries, ASLR, NX-битах и тому подобных менее надёжных вещах. Которые тоже, строго говоря, не требуются стандартом, и вставляются исключительно по доброй воле разработчиков компилятора (и к тому же отключаются соответствующими ключами).

Последовательное чтение значений из списка в словарь

#python #списки #словари


Здраствуйте. Есть готовый список, который содержит слова в определенной последовательности:
list = ['To', 'be', 'or', 'not', 'to', 'be']

Требуется подсчитать частоту появления слов в этом списке и составить словарь, который
содержит пары значений (слово) : (кол-во повторений этого слова).
Вот мой код:
# -*- coding: utf-8 -*-

list = ['To', 'be', 'or', 'not', 'to', 'be']

counts = dict()
for word in list:
    if word not in counts: # Если символа нет в словаре, создаем новую запись
        counts[word] = 1
    else: # В противном случае инкрементируем d[c]
        counts[word] += 1

print counts

Подсчет слов ведется правильно. 
Проблема в том, что моя программа помещает новые записи в словарь в хаотичном порядке,
а не так, как слова шли в предложении. Вот что интерпретатор выдает на выходе:
{'not': 1, 'To': 1, 'or': 1, 'to': 1, 'be': 2}

А должно быть так:
{'To': 1, 'be': 2, 'or': 1, 'not': 1, 'to': 1}

Как можно получить такой результат? Никак не могу монять.
P.S.: В Python я новичок, поэтому не судите строго.    


Ответы

Ответ 1



Вам нужен OrderedDict, Dict не поддерживает упорядочивание записей по умолчанию.

Ответ 2



Словарь в Питоне не обязан сохранять порядок добавления слов. Хотя некоторые реализации Питона, такие как Pypy, используют упорядоченные словари по умолчанию. Чтобы подсчитать частоту появления слов во входном списке и напечатать их в том порядке как они заданы в списке, можно объединить Counter и OrderedDict, чтобы поддерживать порядок вставки: #!/usr/bin/env python from collections import Counter, OrderedDict class OrderedCounter(Counter, OrderedDict): pass input_list = ['To', 'be', 'or', 'not', 'to', 'be'] frequencies = OrderedCounter(input_list) for item, count in frequencies.items(): print("{}\t{}".format(item, count)) Результат To 1 be 2 or 1 not 1 to 1 Если достаточно только напечатать результат, то можно обойтись только Counter, без OrderedDict или сортировки: #!/usr/bin/env python from collections import Counter input_list = ['To', 'be', 'or', 'not', 'to', 'be'] frequencies = Counter(input_list) for item in input_list: count = frequencies.pop(item, None) if count is None: continue print("{}\t{}".format(item, count)) Результат совпадает с предыдущим кодом. frequencies словарь разрушается во время печати.

Ответ 3



Вот один вариант как отсортировать: ссылка

Ответ 4



Если вам нужно просто отсортировать в алфавитном порядке, просто при выводе сделайте for key in sorted(counts.keys()): print '{0}: {1}'.format(key, counts[key]) А если именно в том порядке, в котором они встречались в первый раз - да, как писал Etki, используйте OrderedDict

Как настроить autocrlf в git для различных систем?

#git #git_config


Если я правильно понял, то в windows при autocrlf = true Git будет делать конвертацию
CRLF -> LF после коммита, а LF -> CRLF при чекауте.

В моем рабочем процессе возможны случаи, когда исходные файлы сбрасываются вручную,
минуя репозиторий, с рабочей директории репозитория первой машины Linux/Windows в рабочую
директорию второй Windows-машины.

При этом в этих исходных файлах строки содержат LF-окончание, а в рабочей директории
второй машины CRLF. Значит ли это, что придется вручную их конвертировать сторонним
софтом к CRLF виду? 

Как правильно настроить core.autocrlf на обеих рабочих машинах, чтобы избежать ошибок
при "ручном" переносе файлов?

Предполагаю, что в Windows - autocrlf = true, а в Linux - autocrlf = input (чтобы
предотвратить случай выше, только уже с CRLF).
    


Ответы

Ответ 1



Как правильно настроить core.autocrlf на обеих рабочих машинах, чтобы избежать ошибок при "ручном" переносе файлов? я думаю, во всех операционных системах имеет смысл присвоить этому атрибуту как минимум значение input. тогда при добавлении «ненормализованных» файлов (т.е., с разделителем строк crlf), будет выдаваться предупреждение, что файл в репозитории будет преобразован, а при последующем коммите файлы будут автоматически «нормализованы» (разделитель crlf будет заменён на lf). а при выполнении команды checkout никаких преобразований делаться не будет — файлы в рабочей копии будут иметь те же разделители, что и в репозитории1. возможно, в операционных системах, где по умолчанию разделителем служит не lf, а crlf (например, ms/windows), имеет смысл «пойти дальше», и присвоить атрибуту core.autocrlf значение true — чтобы и при команде checkout производилось преобразование lf → crlf. но это, вероятно, имеет смысл только в том случае, если используемая для просмотра/редактирования этих файлов программа отображает содержимое файлов некорректно (т.е., не делает перенос строки, встретив символ lf). 1 — посмотреть, как именно хранится файл в репозитории, можно, например, с помощью команды git cat-file -p хэш. пример: инициализируем репозиторий: $ git init добавляем в файл две строки и делаем коммит: $ echo 1 > file; echo 2 >> file $ git add file $ git commit -m 1 [master (root-commit) 1373ad1] 1 1 file changed, 2 insertions(+) create mode 100644 file просматриваем содержимое коммита, указав его хэш (можно сокращённый): $ git cat-file -p 1373ad1 tree d25d3b6082891168b6787cb20783bd332e5b8f74 ... просматриваем объект типа tree, добавленный этим коммитом: $ git cat-file -p d25d3b6 100644 blob 1191247b6d9a206f6ba3d8ac79e26d041dd86941 file просматриваем объект типа blob, содержащий тот самый файл: $ git cat-file -p 1191247 | hexdump -C 00000000 31 0a 32 0a |1.2.| 00000004 и видим, что сохранился он в репозитории с разделителем строк lf.

Ответ 2



Я протестировал все варианты и вот, что вышло: ╔═══════════════╦══════════════╦══════════════╦══════════════╗ ║ core.autocrlf ║ false ║ input ║ true ║ ╠═══════════════╬══════════════╬══════════════╬══════════════╣ ║ git commit ║ LF => LF ║ LF => LF ║ LF => CRLF ║ ║ ║ CR => CR ║ CR => CR ║ CR => CR ║ ║ ║ CRLF => CRLF ║ CRLF => LF ║ CRLF => CRLF ║ ╠═══════════════╬══════════════╬══════════════╬══════════════╣ ║ git checkout ║ LF => LF ║ LF => LF ║ LF => CRLF ║ ║ ║ CR => CR ║ CR => CR ║ CR => CR ║ ║ ║ CRLF => CRLF ║ CRLF => CRLF ║ CRLF => CRLF ║ ╚═══════════════╩══════════════╩══════════════╩══════════════╝ Считаю, что самый оптимальный вариант на всех системах core.autocrlf = input. При этом на всех ОС окончания строк CRLF при необходимости будут неявно преобразованы к LF, если уже есть LF, то так и останется.

Когда в c# class не совсем class?

#c_sharp #net


В одном проекте разбирал багу. Эта бага была связана с тем, что проект прошел некоторую
техническую итерацию,  т.е. бизнес логика в нём  не поменялась, но в него была добавлена
технология, которая неявно поменяла поведение кода, оставив его представление неизменным.
И связано это именно с тем, что в некоторых случая class бывает не совсем class-ом.
Лабораторная по анализу этого бага приобрела форму задачки на знание технологии .NET.
Таким образом, прошу оценить формулировку задачки и её актуальность.
Ну, и если захотите, можете представить её решение. :)  

Задачка  

Есть код консольного приложения на c#:

#region Здесь код изменять нельзя
public sealed class ClassA
{
    private int _value;

    public int Value
    {
        get { return _value; }
        set { _value = value; }
    }
}
#endregion

#region Здесь код изменять нельзя
public sealed class ClassB
#endregion
#region Здесь код изменять нельзя
{
    public void Do(ref ClassA a)
    {
        a.Value = 5;
    }
}
#endregion

public class Program
{
    public static void Main(string[] args)
    {
        #region Для класс Program изменять код только здесь
        ClassB b = new ClassB();
        #endregion

        bool result = Process(b);

        System.Console.WriteLine(result);
    }

    public static bool Process(ClassB b)
    {
        ClassA a1 = new ClassA();
        ClassA a2 = a1;

        b.Do(ref a2);

        return a1.Value == a2.Value;
    }
}


Запустив его на исполнение мы увидим, что  метод Program.Process вернёт значение
true и на консоль будет выведен текст «true».  

Используя стандартный функционал .NET Framework (версией >= 2.0)  допишите код для
классов ClassA и ClassB, а также измените код в методе Program.Main, чтобы метод Program.Process
вернул значение false и, соответственно, на консоль должно быть выведено «false».
Код в регионах #region Здесь код изменять нельзя менять нельзя. Для класса Program
код можно поменять только в регионе region Для класс Program изменять код только здесь.  

UPD Спасибо @DreamChild
Директивы условной компиляции C# не применять.  

UPD
Хотел бы ещё раз уточнить, что нужно только дописать ClassA и ClassB, т.е. не нужно
создавать новые классы.  

UPD  Ответ дал @hazzik
Суть в том, что выполнение функционал класса ClassB перевели в другой домен. Но при
этом неявно поменялась логика работы метода ClassB.Do(ref ClassA) и экземпляр типа
ClassA уже передаётся не как ссылочный объект, а как значимый объект, т.е. в результате
сериализации получается структура значений полей класса ClassA, которая передается
через границу домена. При выходе из метода ClassB.Do(ref ClassA) возвращается структура
полей класс ClassA и, самое интересное, эта структура десериализуется в новый объект,
ссылка на который и записывается в переменную a2. Таким образом, в a1 и в a2 получаются
ссылки на два разных объекта, при чём, значения их внутренних полей различаются.  
    


Ответы

Ответ 1



То же самое, что и предыдущий мой ответ, только все это делаем средствами .NET fx, т.е. используем его прокси и, соответственно, все вызываем из отдельного домена: [Serializable] #region Здесь код изменять нельзя public sealed class ClassA { private int _value; public int Value { get { return _value; } set { _value = value; } } } #endregion #region Здесь код изменять нельзя public sealed class ClassB #endregion : MarshalByRefObject #region Здесь код изменять нельзя { public void Do(ref ClassA a) { a.Value = 5; } } #endregion public class Program { public static void Main(string[] args) { #region Для класс Program изменять код только здесь ClassB b = (ClassB) AppDomain.CreateDomain("X").CreateInstanceFromAndUnwrap(typeof(ClassB).Assembly.CodeBase, typeof(ClassB).FullName); #endregion bool result = Process(b); Console.WriteLine(result); } public static bool Process(ClassB b) { ClassA a1 = new ClassA(); ClassA a2 = a1; b.Do(ref a2); return a1.Value == a2.Value; } } Почему так происходит? ClassA не помечен для маршаллинга через границу доменов с передачей по ссылке (то, что делает MarshalByRefObject), по-этому он будет сериализован до передачи в домен "X" и в домене "X" десериализован в новый объект. Для внешнего домена никто никогда не изменял a1 его Value так и останется 0. При возвращении из домена "X" экземпляр класса ClassA будет сериализован и десериализован уже в обратном направлении и присвоен переменной a2. Если у параметра a метода ClassB.Do убрать модификатор ref то картина будет немного иной: обратной десериализации из "X" в текущий домен происходить не будет, и, следовательно, a2 будет все-еще ссылаться на тот же объект, что и a1, а значение свойства Value этого объекта останется равным 0. Чтобы исправить эти "проблемы" нужно унаследовать ClassA от MarshalByRefObject.

Ответ 2



Так задумано или тут дыра в регионах? ) #region Здесь код изменять нельзя public sealed class ClassB #endregion // сюда можно дописать что угодно, например: : BaseB { public new void Do(ref ClassA a) { a = new ClassA(); base.Do(ref a); } } public class BaseB #region Здесь код изменять нельзя { public void Do(ref ClassA a) { a.Value = 5; } } #endregion

Ответ 3



ClassB наследуем от System.MarshalByRefObject Пишем следующий прокси-класс: class ClassBProxy : RealProxy { public ClassBProxy() : base(typeof (ClassB)) { } public override IMessage Invoke(IMessage msg) { IMethodCallMessage call = msg as IMethodCallMessage; var args = call.Args; // Здесь мы подменяем ClassA на нужный нам args[0] = new ClassA {Value = 100}; return new ReturnMessage(null, call.Args, call.Args.Length, call.LogicalCallContext, call); } } В Program.Main создаем ClassB вот так: ClassB b = (ClassB) new ClassBProxy().GetTransparentProxy(); Полный пример: https://dotnetfiddle.net/GbhXP5

Ответ 4



Сделать это можно с помощью вот такого колдунства: модифицируем класс ClassB таким образом: #region Здесь код изменять нельзя public sealed class ClassB #endregion #if SOME_FLAG // SOME_FLAG нигде не определен, // а потому "старая" реализация метода Do // заменяется "новой" из ветки №else #region Здесь код изменять нельзя { public void Do(ref ClassA a) { a.Value = 5; } } #endregion #else { public void Do(ref ClassA a) { a = new ClassA(); a.Value = 6; } } #endif менять код в Main даже не потребовалось

Поместить static/const в интерфейс или абстрактный класс C#

#c_sharp #const #интерфейс


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


Ответы

Ответ 1



Никак. Это не поддерживается языком. Вы можете сэмулировать константу уровня экземпляра класса через свойство с одним лишь геттером: interface ISomething { string ClassName { get; } } Статические методы в интерфейс не вписываются никак, вообще. В текущей концепции вы получаете доступ к статическому объекту по имени класса, а не по экземпляру объекта. А поддержка интерфейсов реализована обычным образом, через таблицы виртуальных методов. Тем не менее, в будущих версиях языка возможны изменения, разрешающие схожую функциональность (generic-условия на наличие статического метода). Design team языка C# обсуждает эту возможность. Вот пример того, как динамически проверить наличие статического метода: interface ISomething { } static class SomethingChecker { public static Func CheckAndGetBuider() where T : ISomething { var type = typeof(T); var builder = type.GetMethod("GetInstance", BindingFlags.Public | BindingFlags.Static); // а есть ли такой метод? if (builder == null) throw new Exception(); // а не требует ли метод generic-аргумент? if (builder.IsGenericMethod) throw new Exception(); // а не требует ли метод параметров? if (builder.GetParameters().Length != 0) throw new Exception(); // а подходящий ли тип результата? if (!type.IsAssignableFrom(builder.ReturnType)) throw new Exception(); // все проверки пройдены return () => (T)builder.Invoke(null, null); } } Здесь рабочий пример использованием: http://ideone.com/bPyoEf

Ответ 2



На уровне языка это реализовать невозможно. Если вы хотите задать некое свойство для всего класса, то можно вместо статического свойства типа string завести статическое свойство типа IDictionary. Пусть каждый класс в статическом конструкторе записывает в словарь своё название. Если вы используете dependency injection, то подобное свойство можно добавить как мета-информацию к классу, например, с помощью атрибутов. Если при работе с этим классом всегда есть экземпляр, то можно добавить нестатическое свойство. В этом случае свойство не будет статическим, но смысл останется прежним. В целом, возможных реализаций много, и что вы выберете — зависит от вашей конкретной ситуации: как вы используете значение, когда и как создаются экземпляры и т.п.

StreamReader и кодировка

#c_sharp #кодировка


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


Ответы

Ответ 1



Никак. Гарантировано рабочего решения не существует. Для того, чтобы работать с текстовым файлом, система обязана знать его кодировку. Что вы можете попробовать: Используйте StreamReader без указания кодировки. Он попробует продетектировать, и в нормальных случаях (а это означает обычно Unicode-кодировки) ему это удаётся. Попробуйте сдетектировать кодировку на основе частотного анализа. Если вам известен язык, на котором написан ваш текст, вы можете определить относительную частоту символов в текстах (это будет ожидаемое распределение частот), попробовать пооткрывать текст в кодировках, релевантных для этого языка (например, для русского языка это CP1251, CP866, KOI8-R и т. п.), и посмотреть, в какой из них распределение частот символов будет ближе всего к той самой относительной частоте. (Это реализовано, например, в редакторе Far Manager'а). В ответах на этот вопрос есть несколько примеров с кодом, комбинирующих эти подходы. В любом случае, на будущее: текст не имеет права храниться без кодировки. Текст без кодировки — никому не нужные данные. Всегда знайте кодировку, в которой лежит ваш текст. Если же вы знаете кодировку файла, то всё гораздо проще: var srcEncoding = Encoding.GetEncoding(1251); var dstEncoding = Encoding.UTF8; using (var src = new StreamReader(srcFileName, encoding: srcEncoding)) using (var dst = new StreamWriter(dstFileName, append: false, encoding: dstEncoding)) { string line; while ((line = src.ReadLine()) != null) dst.WriteLine(line); }

Ответ 2



Если в начале файла не проставлены теги кодировок, то однозначно определить кодировку нельзя, т.е. вам понадобиться указать кодировку в аргументе encoding. var encoding = Encoding.GetEncoding(1251); using (var src = new StreamReader(filePath, encoding: encoding)) { } Или же вы можете воспользоваться алгоритмами, которые определяют кодировку по содержанию файла. Но надо учитывать, что они не дают 100% результата. Одним из эффективных алгоритмов является Mozilla Universal Charset Detector. Одну из его реализаций на c# вы можете найти на github.

Сформировать коммит с сообщением на основе указанного коммита

#git #git_commit


Задача следующая: нужно скопировать сообщение старого коммита и исправить последнюю
строку в нём для нового коммита. 

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

Узнал недавно про такую возможность, как git commit -C HEAD, которая сделает коммит
с таким же сообщением, как в указанной ссылке, но приходится еще делать git commit
--amend, чтобы подправить последнюю строку. 

Можно ли обойтись одной командой для этого?
    


Ответы

Ответ 1



изспользуйте опцию -c, а не -C: git commit -c <коммит> в этом случае сразу можно внести правки в коммит-сообщение. ещё логично добавить опцию --reset-author, для того, чтобы авторство и время создаваемого коммита не дублировались из указанного существующего коммита.

Ответ 2



git commit -C HEAD -e -e The message taken from file with -F, command line with -m, and from commit object with -C are usually used as the commit log message unmodified. This option lets you further edit the message taken from these sources. Или как правильно подсказал alexander barankin: git commit -c HEAD

Как использовать main() вместо WinMain?

#cpp #windows #visual_cpp


Я хочу написать GUI приложение для Windows, но мне не нравится что MS Visual Studio
для этого надо писать WinMain. Хочу писать привычную main() или main(argc, argv) -
как это сделать?
    


Ответы

Ответ 1



Прежде всего надо понимать, что ни main(), ни WinMain() - не являются "точками входа" .exe файла. Точкой входа (entry point) является некоторая функция, которая будет вызвана операционной системой при старте приложения. В С++ это функция рантайма (CRT), которая проводит инициализацию CRT, вызывает конструкторы глобальных объектов, и затем уже вызывает main или WinMain. Линкеру передается параметр /subsystem, который задает тип приложения, например /SUBSYSTEM:WINDOWS для GUI приложений, или /SUBSYSTEM:CONSOLE для консольных приложений. В первую очередь это нужно операционной системе - тип приложения прописывается в заголовке .exe файла, и по нему ОС понимает надо ли создавать окно консоли, или нет. Также, при помощи этого параметра линкер выбирает точку входа, которая будет использована по-умолчанию: mainCRTStartup (илиwmainCRTStartup) - при использовании /SUBSYSTEM:CONSOLE. Вызывает main (или wmain) WinMainCRTStartup (или wWinMainCRTStartup) - при использовании /SUBSYSTEM:WINDOWS. Вызывает WinMain (или wWinMain). Точку входа можно переопределить, передав линкеру параметр /entry. Для того чтобы использовать main в GUI приложении, мы должны вызвать линкер с параметрами /SUBSYSTEM:WINDOWS и /ENTRY:mainCRTStartup. Тогда ОС не будет создавать окно консоли, а CRT будет вызывать функцию main. Значение параметра /entry можно переопределить в опциях проекта MSVS (linker > advanced > entry point). Либо его можно написать прямо в коде программы, с помощью pragma comment: #include #pragma comment(linker, "/entry:mainCRTStartup") int main() { ::MessageBoxW(nullptr, L"(^._.^)", L"Important message", MB_OK); }