Страницы

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

вторник, 20 ноября 2018 г.

Зачем в getInstance synchronized?

Зачем в этом getInstance synchronized делать ?
Это класс-синглтон для работы с сетью с использованием retrofit.
public static NetworkWorker getInstance(){ if (networkWorker == null){ synchronized (NetworkWorker.class) { if (networkWorker == null) { networkWorker = new NetworkWorker(); } } } return networkWorker; }


Ответ

При реализации синглтона даже с synchronized бывают случаи, когда при использовании многопоточности потокам удается дважды создать инстанс одного класса - что для реализации паттерна неприемлемо.
Synchronized нужен, для того, что-бы в методе\объекте в данный момент мог работать лишь один поток, и остальные ожидали окончания работы. По сути это очередь.
Если-бы это был просто класс, который необходимо защитить экраном synchronized - то проверка на null была бы одна, но поскольку здесь происходит реализация синглтона - то и проверки нужно сделать две.

Возможно ли заставить работать приложение, на ПК, где нет необходимой версии офиса?

Возможно ли заставить работать приложение, на ПК, где нет необходимой версии офиса?
Разрабатывал приложение, где стоял 2016 офис, потом кинул приложение на ПК, где 2007 офис и возникли проблемы при запуске...
На машине стоял 2007 офис и я попробовал кинуть библиотеку(Вроде, от 2016) и получил такую ошибку:
System.IO.FileLoadException: Could not load file or assembly 'office, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040) File name: 'office, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c' WRN: Assembly binding logging is turned OFF. To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1. Note: There is some performance penalty associated with assembly bind failure logging. To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].
От офиса я использую только Access, например выполняю запросы, а где-то открываю RecordSet и делаю обновление по одной записи...


Ответ

У Microsoft для таких случаев есть свободно распространяемые компоненты. Для Access 2016 - можно взять тут. Похожие компоненты есть и для некоторых других приложений из пакета MS Office. Эти компоненты не позволяют создавать файлы, но позволяют просмотреть и напечатать, а если Excel- или Access-файл представляет из себя приложение, то и использовать функции такого приложения. По факту эти компоненты содержат все необходимое кроме интерфейса для создания и редактирования, который вы можете реализовать в свое программе.
Таким образом вы можете не требовать от пользователя наличие установленного офиса, а включить в свой инсталятор такой компонент и устанавливать его вместе с приложением, либо оставить выбор за пользователем, ставить себе полный пакет офис или установить только компоненты для просмотра документов, о чем собственно и написано в описании компонента, например Microsoft Access 2016 Runtime
Microsoft Access 2016 provides a rich platform for developing database management solutions with easy-to-use customization tools. If no end-user customization is required (including report modifications), you can choose to distribute those Access 2016 solutions so that they run without requiring a full installation of Access 2016. To do so, you must package and distribute your application with the Access 2016 Runtime.

как залочить xml на время работы тулзы на JAVA

Есть xml, который открываю для редактирования на java.
Как сделать так, чтобы на время работы тулзы, редактировать файл никто другой не мог?
Дополнение: Нужно учесть, что тулза может быть завершена аварийно, поэтому file.setWritable(false) наверное не подойдет (файл останется залоченым)
К сожалению, вариант
Runtime.getRuntime().addShutdownHook(new Thread(() -> { file.setWritable(true); }));
Не подходит, потому что если, во время работы программы, аварийно ее завершить, файл остается read only.


Ответ

setWritable вполне подходят для ваших целей. А чтобы файл не оставался залоченым после остановки приложения, может помочь вот это
Runtime.getRuntime().addShutdownHook(new Thread(() -> { file.setWritable(true); }));

Ключевое слово для обозначения чистых функций

В википедии читал о чистых функциях и наткнулся на эту фразу:
Некоторые компиляторы, такие как gcc, в целях оптимизации предоставляют программисту ключевые слова для обозначения чистых функций.
Никогда про это не слышал. Нигде в Интернете не нашел это ключевое слово. Может, кто знает? Если такое слово есть, то подскажите его же, но только для clang


Ответ

int output2(int x) __attribute__((pure));
int output2(int x) { return x+1; }

Работа скрипта PHP по принципу транзакций

Я вообще сам по себе Педант и не люблю когда в той или иной директории или БД остается мусор по средствам сбоев или ошибок программы. Я никогда не писал серьезных проектов и дабы получить урок путем прочтения ваших комментов, я задам ряд вопрос детально все расписав.
К примеру, имеется скрипт, который позволяет двум пользователь общаться между собой, обмениваться фотографиями, видео, музыкой и т.д., а принцип скрипта следующий:
Пользователь печатает сообщение, загружает фото (файлы грузятся во временную папку по ajax) и музыкальный файл, затем кликает кнопку "Отправить" и данные улетают на сервер, а на сервере происходит следующее:
Текстовое сообщение записывается в БД, затем следующий шаг это запись в другую таблицу инфо о фотографии (путь к фото, размеры и т.д.), а потом перемещение фотографии из временной директории в постоянную, то же самое и с музыкальным файлом. Казалось бы всё прекрасно, мы получили ожидаемый результат, но а что если после того как текстовое сообщение запишется в БД и информация о файле тоже будет записана, то после произойдет сбой?! Ведь сбои могут быть? Это ведь техника. С сервером, интернетом и т.д. всё что угодно может произойти в процессе выполнения.
На выходе мы получаем сообщение, которое без вложений да и более того, половину информации о вложениях записалось, а половина нет и ещё непонятно где сами файлы остались.
Ко мне в голову пришла идея вначале выполнения кода реализоваться что-то типа карты, к примеру, из массива и в неё записать всю информацию, а именно: - Полный путь к файлам из временной папки - Полный путь к файлам куда мы должны будем переместить файлы из временно папки - И прочую возможную информацию информацию
И эту карту сразу же первым делом записать в таблицу (не буду описывать куда, главное понять, что эта инфа записана)
И по завершению скрипта, если всё прошло успешно, то удаляем карту, а если карта, к примеру, после обновления страницы осталась в таблице, значит скрипт сработал некорректно и просто по этой карте пробегаем и все отовсюду удаляем.
Я не пытаюсь что-то изобрести или открыть, я просто хотел бы знать, нужно ли подобное реализовывать? Или есть более простой способ о котором я никогда не слышал? Или, может быть, всё это дикий бред? С радостью выслушаю вас и получу дельные советы. Спасибо!!!


Ответ

если данные не провалидировались - эксепшен begin в бд, делаем записи в таблицы, произошла ошибка, rollback, эксепшен // баг в валидации //или сломалась бд, кончилось место, неправильный запрос //если все окей с созданием записи в бд: записываем файл, если файл не записался/был испорчен: удаляем файл, rollback, эксепшен иначе - commit
можете, например, если не очень высокая нагрузка, хранить файлы в бд, тогда откат будет и файлы откатывать.
или, допустим, вы можете сделать скрипт, который будет бегать по базе данных и списку файлов каждый день и проверять валидность файлов, плохие - удалять.
тема очень большая, на самом деле и вопрос очень широкий, и для маленьких проектов без супервысокой нагрузки обычное решение в таких случаях просто восстановление из частого бэкапа в случае каких-то ошибок.
в больших проектах - все сложнее и в одном посте не напишешь.
остальной функционал (типа после коммитов файл испортился и т.д.) решается уже по сути кластерными методами - три сервера, если на одном файл испортился, диск поехал и т.д., то правильной считается версия, совпадающая на двух других серверах. в космических аппартах и мэйнфреймах существует примерно такое же дублирование на уровне компьютеров/процессоров
почитайте про архитектуры netflix и google - они такие проблемы как раз решают часто. (netflix c ошибками на машинах борется забавным образом - они рэндомно убивают хосты в сети, каждый день, для того, чтобы процесс восстановления был идеально отлажен)
p.s. вопрос "нужно ли подобное реализовывать" - очень зависит от вашего сервиса и предполагаемого уровня его качества. одно дело - пользователи обмениваются сообщениями в соцсети и один раз из миллиона происходит ошибка выкладки фотографии, пользователь просто перезагрузит ее еще раз, а если допустим, у вас сервис управления сетью ПВО и какая-то из пусковых установок получила сломанный файл с картой местности - oche ploho, на учениях вам в офис может прилететь ракета.

Получить текст кнопки GUI Unity

В Unity создал GUI элемент Button, через визуальный редактор присвоил ему текст "Hello". Собственно вопрос: Как в коде добраться до элемента кнопки и получить его значения Text ?


Ответ

Метод для получения объекта кнопки
public Button GetButton(string caption) { var go = GameObject.Find(caption); var button = go.GetComponent

Можно ли убрать с карты Google Maps значки “станции метро”, “зоопарки”, “остановки”?


Реализована ли в Google Maps такая возможность?


Ответ

Можно с использованием Styled Maps
Например, чтобы убрать все автобусные остановки, при создании объекта google.maps.Map в options нужно указать:
styles: [{ featureType: 'transit.station.bus', elementType: 'all', stylers: [ { visibility: 'off' } ] ]}

Появление блока по клику

Подскажите, как сделать так, чтобы кликая по li с индексом 1 показывался div.section с индексом 1,а все остальные div.section с другими индексами были скрыты, тоже самое нужно и для других li
$(".section").hide(); $(".section").eq(0).show(); $(document).on("click", ".active_element", function() { var idx = $(this).index(); $(".section").eq(idx).toggle(); }) .active_element { position: relative; } .active_element:after { display: block; position: absolute; top: 44px; width: 114px; content: ''; border-bottom: 8px solid #fdd901; }

  • об услуге
  • цены
  • преимущества

text

text 2

text 3


Ответ

$(".active_element").on("click", function(){ var idx = $(this).index(); $(".active_element").removeClass("highlight"); $(this).toggleClass("highlight"); $(".section").hide(); $(".section").eq(idx).toggle(); }); .active_element { position: relative; display: block; width: 114px; cursor: pointer; } .highlight { background-color: #fdd901; } .section { display: none; }

  • об услуге
  • цены
  • преимущества

text

text 2

text 3


Корректная работа свойств vw и vh

Не могу понять как работает свойство vw и vh
На css-tricks пишет:
1vw = 1% of viewport width; 1vh = 1% of viewport height
Но, например, у меня ширина окна 768рх, по этому когда я выставляю font-size: 100vw по логике размер шрифта должен заполнить 768рх, или нет? А то у меня залезает значительно дальше 768рх.
P.S. Уже не одну статью перечитал, и никак не могу понять как корректно вычислить зависимость расширения экрана от значения vw/vh
Пример в песочнице: https://jsfiddle.net/obats/wf6vu3a8/


Ответ

Вот тут хорошо написано по этому поводу:
Что такое «размер шрифта»? Это вовсе не «размер самой большой буквы в нём», как можно было бы подумать. Размер шрифта – это некоторая «условная единица», которая встроена в шрифт. Она обычно чуть больше, чем расстояние от верха самой большой буквы до низа самой маленькой. То есть, предполагается, что в эту высоту помещается любая буква или их сочетание. Но при этом «хвосты» букв, таких как р, g могут заходить за это значение, то есть вылезать снизу. Поэтому обычно высоту строки делают чуть больше, чем размер шрифта.
Так что измерить размер шрифта с помощью каких-то стандартных формул не получится, более того разные шрифты имеют разные размеры этих запасных отступов.
Сам обычно использую для шрифта метод подбора, он заключается в том, что в отладчике подбирается подходящее значение в px соотносимое со значением в vh или в vw, а дальше уже используется коэффициент. Например, если 14px = 2.8vh, то получается коэффициент 5, сл-но 20px/5 = 4vh.
UPD.
В роли отладчика для сравнения шрифтов выступает обычный браузерный отладчик, например, в Chrome. Пишите в css так:
.class { font-size: 14px; font-size: 2.8vh; }
А дальше уже играете с чекбоксами в отладчике включая/выключая нижнее значение и подгоняя размер в vh, пока перестанете замечать разницу от включения/выключения.

StringBuilder или + в цикле

String str=""; for (int i = 0; i < count; i++) { str+="я"; }
это правда, что вот этот код превращается компилятором в этот:
StringBuilder sb = new StringBuilder(); for (int j = 0; j < i; j++) { sb.append("я"); }
Если это так, есть ли смысл использовать второй вариант? Ведь первый более читаем.


Ответ

Почитайте тут
//медленно String[] fields = new String[] {"a","b","c","d","e","f","g"}; String s = ""; for (int i = 0; i < fields.length; i++) { s = s + fields[i]; } return s;
//быстро String[] fields = new String[] {"a","b","c","d","e","f","g"}; StringBuilder s = new StringBuilder(); for (int i = 0; i < fields.length; i++) { s.append(fields[i]); } return s.toString();
Никогда не используйте операции конкатенации (оператор +) строки в цикле, особенно если таких операций у вас много, это может очень существенно снизить производительность. Все это происходит потому, что в приведенном выше примере «s = s + fileds[i]» выполняется целых 3 операции: создается StringBuilder на основе строки s, вызывается метод конкатенации append, после конкатенации вызывается метод toString (выглядит так: s = new StringBuilder(s).append(fields[i]).toString();). Целых 3 операции вместо одной! Помимо этого каждый результат s + fileds[i] будет занимать память в куче, как отдельная строка.
Так что ответ на ваш вопрос такой: да, есть смысл использовать StringBuilder вместо конкатенации.

Манипуляции с элементом, когда он появляется в поле зрения по центру?

Сейчас код такой:
function aboutUsAmination() { $(window).scroll(function () {
var aboutUs = $('.about_us'); var top = $(aboutUs).offset().top; var scrollFromTop = $(window).scrollTop(); if (scrollFromTop >= top) { console.log("Hello") }
});
};
В консоль выводится сообщение когда мы непосредственно доскролили до блока(то есть, он в самом верху экрана). Мне нужно, что бы хотя бы когда он по середине экрана. Можно вычислить точное число и отнимать его от top, но это нужно будет отнимать для каждого разрешения экрана. И так: Как вывести в консоль сообщение, когда блок по вертикали по центру, а не вверху


Ответ

Для этого - скорректруйте scrollFromTop на половину высоты окна, а top - на половину высоты блока:
function aboutUsAmination() { $(window).scroll(function () { var aboutUs = $('.about_us'); var top = $block.offset().top + $block.outerHeight() / 2; var scrollFromTop = $(window).scrollTop() + $(window).height() / 2; if (scrollFromTop >= top) { console.log("Hello") } }); };
При таком варианте - сообщение в консоли вы увидите, когда середина блока окажется по вертикали посередине, или выше.
Рабочий пример на jsfiddle

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

Приложение каждый раз когда обращается к серверу прикрепляет к запросу Json файл в который складывается все данные
JSONObject data = new JSONObject(); data.put("1", 1); data.put("2", 2); data.put("3", 3);
Но теперь нужно с этим файлом отправить 30 мб данных...
Не пойму как правильно сделать? Я так понимаю, что я не могу положить в Json 30 мб байтов...
Как правильно передать такой запрос?


Ответ

В итоге нужно было прикрепить к заголовку самого HTTPUrlConnection...
То есть поток для записи открываем так же просто в заголовок вкладываем все что нам нужно как сопутствующие файлы
@Override public HttpURLConnection getHttpURLConnection(URL url, String newValue, Context context) {
JSONObject service = getJsonObject(context);
HttpURLConnection urlConnection = null; try { urlConnection = (HttpURLConnection) url.openConnection();
if (urlConnection != null) { urlConnection.setRequestProperty("authorization", UtilClass.getAuthToken(context)); urlConnection.setRequestProperty("service", service.toString()); urlConnection.setRequestMethod("POST"); urlConnection.setRequestProperty("Content-Type", newValue); urlConnection.setDoInput(true); urlConnection.setDoOutput(true); urlConnection.setConnectTimeout(10000); urlConnection.connect(); }
} catch (IOException e) { e.printStackTrace(); }
return urlConnection; }

Утеря key store для signed apk

Что будет, если случайно key store, которым подписано signed apk (которое в продакшине) потеряется/удалится? Можно будет ли потом сгенирировать новый key store для следующих версий приложения и подписать приложение ним? И примет ли такое приложение Google Play?


Ответ

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

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

Создал клавиатуру в своем боте, но она отправляет сразу после нажатия, а мне надо, чтобы она работала как стандартная: пока не нажал отправить, он не отправит, например:
клавиатура: 1 2 3 + 4 5 6 - 7 8 9 * 0 . /
Как сделать, чтобы после нажатия символы появлялись в строке, а не сразу отправлялись боту?


Ответ

В текущей версии Telegram Bot API (Bot API 3.0, 18/05/2017) это не реализовано. Вы можете использовать для этого встроенную клавиатуру, выполняя свои вычисления и после нажатия кнопки = отправлять сообщение с результатом вычислений пользователю.
Unlike with custom reply keyboards, pressing buttons on inline keyboards doesn't result in messages sent to the chat.

Так же по теме - Telegram Bot API кастомная клавиатура, отправка нескольких значений в одном сообщении

Q_LIKELY и Q_UNLIKELY как помощь компилятору в оптимизации кода

В справочном примере для макроса Q_LIKELY указан цикл и рассматривается ситуация, когда состояние false может возникнуть, как говорится, в одном случае на миллион:
// the condition inside the "if" will be successful most of the times for(int i = 1; i <= 365; i++) { if(Q_LIKELY(isWorkingDay(i))) { ... } ... }
В целом, эту пользу можно увидеть, учитывая не редкость ситуаций, когда в цикле проверяется значение, подразумевающее нахождение лишь в одном из двух состояний, и при этом одно из них практически всегда будет в подавляющем большинстве случаев.
Но сбивает с толку пример для Q_UNLIKELY, хотя и являющийся, судя по наименованию, всего лишь обратным вариантом:
bool readConfiguration(const QFile &file) { // We expect to be asked to read an existing file if(Q_UNLIKELY(!file.exists())) { qWarning() << "File not found"; return false; }
... return true; }
Какая тут может быть "помощь компилятору" в оптимизации кода, и если она всё-таки имеет место быть, то будет ли справедлива и для Q_LIKELY? Может быть существуют какие-либо критерии для определения характерных ситуаций, в которых использовании обозначенных макросов имеет смысл?


Ответ

В тексте ответа представлено моё субъективное мнение
Я считаю что эти макросы бесполезны в 99.99% случаев и должны применятся лишь после измерений, которые показали, что их использование оправдано. Почему? Потому что то, что сегодня «likely», может стать «unlikely» завтра, а программисты очень часто забывают менять вещи, которое явно не отражаются на программе. Таким образом, у нас может быть какая-то проверка помечена как Q_LIKELY, тогда как на самом деле всё наоборот. И это будет сбивать с толку программиста, который в дальнейшем будет это читать.
«Но как же так, это же оптимизация?!» — довольно спорное заявление, на самом деле, т.к. предсказатели ветвления(branch predictors) в CPU очень хороши, и чем тут реально сможет помочь компилятор непонятно. Вот возьмём цикл из вопроса, после первой же итерации, наиболее вероятно, что CPU начнёт выбирать инструкции по той ветке, что была в первой итерации. Что нам даст явное указание, потенциальный выигрыш в первой итерации? Смехотворно.
Всё это настолько нанооптимизации, что, повторюсь, прибегать к ним стоит лишь по нахождении проблемы с ветвлением, но не раньше. Программисты, помимо плохой памяти, ещё и не очень хороши в определении того, что же будет чаще(likely) исполняться.

В чём смысл “уступки” выполнения текущего потока иному в QThread?

В справке Qt для статического метода QThread::yieldCurrentThread() сказано, что можно, как я это понимаю, "уступить" (yield) контекст выполнения текущего потока иному потоку:
Yields execution of the current thread to another runnable thread, if any. Note that the operating system decides to which thread to switch.
В чём смысл и для каких случаев может быть полезно применение данного метода?


Ответ

Вообще говоря, инструкция yield говорит планировщику операционной системы, что в настоящее время потоку не требуется процессорное время и планировщик может прервать его исполнение до истечения отведённого потоку кванта времени и передать управление другому потоку. Планировщик может проигнорировать это заявление и не передавать управление другому потоку.
Применять можно, например, для увеличения производительности каких-либо рабочих потоков многопоточных приложений, снижая таким образом производительность вспомогательных потоков. Но следует иметь в виду, что производительность возрастёт только в том случае, когда работающих потоков (реально работающих, а не простаивающих!) больше, чем число ядер процессора.
Польза этого, ИМХО, сомнительная и вместо yield лично я бы использовал приоритеты потоков. На практике я это не использовал ни разу.

Как сохранять в коде изменения при перезапуске страницы

В примере 3 "div" при нажатии меняют цвет. Вопрос как сделать так чтобы это все сохранялось и при перезагрузке страницы изменения сохранялись. Например зашел пользователь пощелкал остановился на втором. Вышел на следующий день зашел на сайт а активный див остался тот же что он щелкнул последний раз.
Буду рад даже литературе в этом направлении. Заранее спасибо=)
$('.toggler').click(function () { $('.toggler').removeClass('toggler_active'); var toggler = $(this); toggler.addClass('toggler_active'); }); .toggler { width: 100px; height: 100px; background-color: red; display: inline-block; } .toggler_active { background-color: green; }



Ответ

Если у вас на сайте нет процедуры регистрации и возможности хранить эту информацию на сервере, то можно посоветовать вам использовать localStorage для хранения этой информации в браузере пользователя, например:
Записываем выбор:
localStorage.setItem('squareNumber', '2');
При загрузке страницы считываем предыдущий выбор:
var squareNumber = localStorage.getItem('squareNumber');
Естественно, это будет работать только если пользователь будет заходить с одного и того же компьютера.

Почему у select и input разная высота и как это исправить?

Здесь два вопроса, но из первого вытекает второй.
Почему у select и input разная высота?
* { box-sizing: border-box; } select, input[type="text"] { padding: 2px; border: 1px solid #ccc; font-size: 13px; }
И как это исправить чтобы это было гибко?
Нюансы
Пытаюсь установить для select и input одинаковую высоту, но очень хочется это сделать гибко, а это значит, что не хочу просто установить фиксированную высоту. Чтобы я менял без проблем font-size без необходимости менять высоту. И я не совсем понимаю почему у них получается разная высота ввиду того, что у них одинаковый размер шрифта и одинаковые padding, border и box-sizing
Ещё понимаю, что можно подобрать разные padding для input и select, но хочется понять механику и причины данных результатов, а также решить их "без хаков".
Из браузеров больше всего любопытен Chrome, но кроссбраузерное решение будет вообще идеальным.


Ответ

Это не во всех браузерах. Разная высота- это одна из особенностей стилизации определённого браузера.
Что бы select имел такую же высоту, нужно убрать у него стрелку справа. Но тут нюанс: если мы добавим стрелку текстовому полю, то оно высоту не изменит. так что утверждать на 100%, что это из за стрелки нельзя, но это одно из решений.
Для данного случая можно применить 3 варианта решения:
Вариант 1:
Добавление фоновой картинки вместо стандартной стрелки
* { box-sizing: border-box; } select, input[type="text"] { width: auto; padding: 2px; border: 1px solid #ccc; font-size: 13px; -webkit-appearance: none; } select { padding-right: 10px; background-image: url(http://s1.iconbird.com/ico/2013/8/426/w32h321377581133134TriangleDown.png); background-size: 16%; background-repeat: no-repeat; background-position-y: center; background-position-x: calc(100% - 5px); }
Вариант 2:
Обрамление select'а в div и добавление псевдокласса :after
За основу взят ответ со eng stackoverflow: css-change-dropdown-arrow-to-unicode-triangle
* { box-sizing: border-box; } select, input[type="text"] { padding: 2px; border: 1px solid #ccc; font-size: 13px; -webkit-appearance: none; } select {padding-right: 10px;} .select {display: inline-block; position: relative;} .select:after { display: block; position: absolute; right: 5px; content: '▼'; font-size: 0.6rem; top: 50%; pointer-events: none; transform: translateY(-50%); }


Вариант 3:
Это вариант схожий с Вариантом 2, но здесь мы вместо :after используем svg
* { box-sizing: border-box; } select, input[type="text"] { padding: 2px; border: 1px solid #ccc; font-size: 13px; -webkit-appearance: none; } select {padding-right: 10px;} .select {display: inline-block; position: relative;} .select svg { display: block; position: absolute; right: 5px; width:20px;height:20px; font-size: 0.6rem; top: 50%; pointer-events: none; transform: translateY(-50%); }

Данные способы также решат проблему того, что select отрисовывается по разному в разных браузерах и ОС.

Подключение SVG спрайта

Здравствуйте. Хочу использовать на сайте картинки svg вместо png, скорее всего их спрайт. Интересует возможность масштабировать картинки (для разных устройств) и менять цвет (например при hover). Кроссбраузерность. Поддержка "старых" браузеров не принципиальна (будет поддерживать - хорошо, не будет - не страшно), анимация тоже не обязательна... Необходима обязательная поддержка IPAD, MAC OS, IPhone...
Как подключить svg спрайты написано много, есть споры, в основном статьи написанные несколько лет назад ... Подскажите, как это сделать по best practics в нынешних реалиях? (возможно личный опыт) Использую SASS, возможно под него есть "заточенные" решения.


Ответ

Поскольку Gulp является уже де-факто стандартом для сборки фронтенда, думаю, будет уместно сразу начать с предложения использовать для создания SVG-спрайта плагин gulp-svg-sprites. Теперь что касается ваших вопросов:
возможность масштабировать — поскольку это SVG, то проблем с масштабированием не будет даже исходя из аббревиатуры. возможность менять цвет — имеется, через CSS (в режиме symbols). кроссбраузерность — ИЕ9 и выше
Без дополнительных настроек результатом работы плагина gulp-svg-sprites будет SVG-файл со всеми вашими иконками в виде обычного спрайта, подобного PNG-спрайту, и CSS-файл со стилями вида .%icon_name% {}. При необходимости получить другие результаты на выходе, придется конфигурировать плагин. Плюс использования такого спрайта в том, что иконки можно использовать в псевдоэлементах. Минус — простыми способами перекрасить элемент спрайта нельзя (можно перекрасить через CSS-фильтры или заранее сгенерировать элемент во всех нужных цветах).
Также есть возможность сделать спрайт как набор элементов symbol, как группы, есть вариант с генерацией png-фоллбека. Если вы используете SASS в синтаксисе SCSS, то можно также получить сгенерированный SCSS-файл со стилями.

WPF. Messagebox. Как поменять стиль диалогового окна?

Стандартный стиль не вписывается в мой дизайн, а вся валидация идет через Messagebox.Show("Сообщение"). Где изменить стиль? Причем надо функционал изменения, как у обычного окна, так как я сделал прозрачный стиль основных окон и использую стилизированные элементы...


Ответ

Никак. MessageBox — системный, он не стилизуется.
Используйте самописный MessageBox, благо там писать не сильно много.
Вот вам пример:
XAML:

Code-behind:
public partial class MessageBox : Window { public MessageBox() { InitializeComponent(); }
void AddButtons(MessageBoxButton buttons) { switch (buttons) { case MessageBoxButton.OK: AddButton("OK", MessageBoxResult.OK); break; case MessageBoxButton.OKCancel: AddButton("OK", MessageBoxResult.OK); AddButton("Cancel", MessageBoxResult.Cancel, isCancel: true); break; case MessageBoxButton.YesNo: AddButton("Yes", MessageBoxResult.Yes); AddButton("No", MessageBoxResult.No); break; case MessageBoxButton.YesNoCancel: AddButton("Yes", MessageBoxResult.Yes); AddButton("No", MessageBoxResult.No); AddButton("Cancel", MessageBoxResult.Cancel, isCancel: true); break; default: throw new ArgumentException("Unknown button value", "buttons"); } }
void AddButton(string text, MessageBoxResult result, bool isCancel = false) { var button = new Button() { Content = text, IsCancel = isCancel }; button.Click += (o, args) => { Result = result; DialogResult = true; }; ButtonContainer.Children.Add(button); }
MessageBoxResult Result = MessageBoxResult.None;
public static MessageBoxResult Show(string caption, string message, MessageBoxButton buttons) { var dialog = new MessageBox() { Title = caption }; dialog.MessageContainer.Text = message; dialog.AddButtons(buttons); dialog.ShowDialog(); return dialog.Result; } }
В результате у вас получается нормальное окно, и вы можете стилизовать его, как вам угодно.


Вам придётся ещё решить проблемы с локализацией, с изменением размеров окна (не стоит давать пользователю возможность максимизировать окно) и т. п.

Логгирование в журнал событий ОС с помощью NLog

Добрый день, только недавно начал использовать Nlog, довольно быстро в нем разобрался, но не смог понять как писать логи в журнал событий WIndows (7). Нужно ли что-то дописывать в конфиг файл? Как писать логи в ОС с помощью System.Diagnostic я знаю, но хотелось бы использовать для этого NLog. Заранее спасибо.


Ответ

Вам сюда (пример оттуда):

Mark-and-sweep алгоритм сборки мусора

Насколько я понимаю, есть два фундаментальных подхода к сборе мусора:
Copying collectors Mark-and-sweep
Оба алгоритма описываются в этой статье. По второму алгоритму автор статьи пишет:
Объекты аллоцируются в памяти Нужно запустить GC Приложение приостанавливается Сборщик проходится по дереву объектов, помечая живые объекты Сборщик проходится по всей памяти, находя все не отмеченные куски памяти, сохраняя их в "free list" Когда новые объекты начинают аллоцироватся они аллоцируются в память доступную в "free list"
Если я правильно понимаю, то объекты, которые необходимо удалить, переносятся в "free list". Но где, собственно, происходит удаление этих объектов? Или они явно не удаляются, а просто перезаписываются при создании новых объектов?


Ответ

Насколько я понимаю, нет необходимости производить дополнительные операции по удалению объектов в памяти. JVM будет создавать новые объекты на месте старых.
Статья о том, как производится создание и удаление объектов в C++
The delete operator does not actually delete anything. It simply returns the memory being pointed to back to the operating system. The operating system is then free to reassign that memory to another application (or to this application again later).
Думаю в java аналогично, только там не операционная система, а jvm. (Не совсем уверен, буду рад, если кто поправит)

Работа с большим количеством записей в сессии

Каким образом правильно работать с большим количеством записей с SQLAlchemy?
У меня есть две таблички. В первой 5 миллионов записей вида: question_id, view_count, counted. Во второй таблице находятся сумма view_count для каждого уникального question_id. Если мы учли запись из первой таблицы во второй, counted выставляется в истину.
Сейчас это выглядет так:
def update_most_viewed(): query = QuestionViewHistory.query.filter_by(counted=False).distinct() question_count = query.count() frame_size = 1000 counter = 0
while counter <= question_count: all_questions = query.offset(counter*frame_size).limit(frame_size).all() counter = counter + frame_size
for question in all_questions: most_viewed_question = MostViewedQuestion.query.filter_by(question_id=question.question_id).first()
if most_viewed_question is None: most_viewed_question = MostViewedQuestion(question.question_id, question.view_count) db.session.add(most_viewed_question) else: most_viewed_question.view_count += question.view_count
question.counted = True
db.session.commit()
Вызываю функцию из консоли. Инициализация:
app = Flask(__name__) db = SQLAlchemy(app)
Проблема в том, что с каждым проходом время растет экспоненциально: после пятого прохода все зависает. Если запустить программу повторно, все повторяется один в один.
На сколько я понимаю, проблема в том, что при каждом вызове commit, SQLAlchemy обновляет все атрибуты всех объектов в сессии, но способа как это поправить, к сожалению, не нашел.
Обновление
Классы моделей, которые фигурируют в запросе.
class MostViewedQuestion(db.Model): __tablename__ = 'most_viewed_question'
id = db.Column(db.Integer, primary_key=True) question_id = db.Column(db.Integer) view_count = db.Column(db.Integer) is_associated = db.Column(db.Boolean) can_be_associated = db.Column(db.Boolean) title = db.Column(db.String(500)) body = db.Column(db.String(30000)) tags = db.Column(db.String(500)) last_update_date = db.Column(db.DateTime)
def __init__(self, question_id, view_count, is_associated=False): self.question_id = question_id self.view_count = view_count self.is_associated = is_associated self.can_be_associated = True self.last_update_date = datetime.datetime.now()
def __repr__(self): return '' % str(self.id)
class QuestionViewHistory(db.Model): __tablename__ = 'question_view_history'
id = db.Column(db.Integer, primary_key=True) question_id = db.Column(db.Integer) view_count = db.Column(db.Integer) view_date = db.Column(db.DateTime) counted = db.Column(db.Boolean)
def __init__(self, question_id, view_count, view_date): self.question_id = question_id self.view_count = view_count self.view_date = view_date self.counted = False
def __repr__(self): return '' % str(self.id)
Код всего проекта доступен на GitHub, все модели находятся в файле models.py, функция update_most_viewed в файле database.py. В папке cvs_data_ru данные для тестов.


Ответ

Стоит начать с того, как делать не нужно. Например, не нужно перебирать объекты в базе по-одному:
for question in all_questions: most_viewed_question = MostViewedQuestion.query.filter_by(question_id=question.question_id).first()
этот цикл - совсем нет-нет-нет. Такого поведения нужно избегать любой ценой - НАМНОГО лучше запросить сразу миллион строк, чем миллион раз по одной строке. Если нужно получить все объекты MostViewedQuestion, то лучше это сделать одним запросом:
most_viewed_questions = MostViewedQuestion.query.filter_by(question_id.in_=questions)
В таком случае отпадает нужда и во внешнем цикле while, потому что по-прежнему, лучше запросить один раз миллион, чем тысячу раз по тысяче. После такого запроса БД вернет те most_viewed_questions, для которых есть соответствующая запись. Встает вопрос: что делать с теми, у которых такой записи нет? Такие запросы выполняются в БД очень часто и часто их называют UPSERT (UPDATE + INSERT) - нужно одновременно и обновить какую-то запись, а если ее нет, то создать ее. Все, что нужно - это выполнить вот этот вот upsert средствами sqlalchemy. Состоять запрос будет из двух подзапросов - один обновит существующие записи (update), другой создаст новые (insert).
UPDATE в целом довольно прямолинейный:
from sqlalchemy import not_, select, exists
update_query = MostViewedQuestion.__table__.update().values( view_count=MostViewedQuestion.view_count + QuestionViewHistory.view_count ).where(and_( MostViewedQuestion.question_id == QuestionViewHistory.question_id, QuestionViewHistory.counted == True ))
Оно генерирует вот такой SQL:
UPDATE most_viewed_question SET view_count=(most_viewed_question.view_count + question_view_history.view_count) FROM question_view_history WHERE most_viewed_question.question_id = question_view_history.question_id AND question_view_history.counted = true
Я использовал запись MostViewedQuestion.__table__, потому что мои модели наследуются от declarative_base(), а методы update(), delete(), insert() есть у класса Table(у Base их нет). Для declarative_base сама таблица находится в поле __table__
INSERT немного более запутанный, но самая мякотка - from_select(), который генерирует INSERT ... FROM SELECT
insert_query = MostViewedQuestion.__table__.insert().\ from_select([MostViewedQuestion.question_id, MostViewedQuestion.view_count], select([QuestionViewHistory.question_id, QuestionViewHistory.view_count]). where(and_(not_(exists([MostViewedQuestion.question_id]).where(MostViewedQuestion.question_id == QuestionViewHistory.question_id) ), # WHERE ... AND ... QuestionViewHistory.counted == True)) )
SESSION.execute(update_query) SESSION.execute(insert_query) SESSION.commit()
SQL:
INSERT INTO most_viewed_question (question_id, view_count) SELECT question_view_history.question_id, question_view_history.view_count FROM question_view_history WHERE NOT (EXISTS ( SELECT most_viewed_question.question_id FROM most_viewed_question WHERE most_viewed_question.question_id = question_view_history.question_id)) AND question_view_history.counted = true
Я бы не сказал, что данный запрос - образец скорости, но самое главное в этих запросах - так это то, что работает БД. Питонский код в это время просто ждет ответа от БД и нам вообще не надо думать об оптимизации питоновского кода. Не нужно ломать голову об устройстве SQLAlchemy. Зато стоит подумать об оптимизации SQL, но с этим несколько легче, потому что UPSERT - операция типичная и по ней много всего написано. Но это не повод расслабляться, потому что при обновлении/вставке большого количества записей в БД есть свои нюансы (например, раздувание таблиц (table bloating) или индексы/триггеры, которые тормозят процесс и перед массовой вставкой их выключают).

Как программа копирует экземпляры разных классов?

Есть два класса: A и B.
Если производится копирование обьектов одного и того же класса, то вызывается конструктор копирования и копирует соответствующие поля. А вот если произвести такое:
A a; B b;
a = (A)b;
Как работает копирование в этом случае?


Ответ

Если в классе B имеется доступный оператор преобразования типов из типа класса B в тип класса A, то он вызывается в выражении приведения типа (A)b, результатом которого является временный объект типа A. Этот временный объект присваивается объекту a с помощью копирующего или перемещающего оператора присваивания в предложении
a = (A)b;
Вот демонстрационная программа
#include
struct A { A & operator =( const A & ) { std::cout << "A::operator =" << std::endl; return *this; } };
struct B { operator A() const { std::cout << "operator B::A()" << std::endl; return A(); } };
int main() { A a; B b;
a = ( A )b;
return 0; }
Ее вывод на консоль
operator B::A() A::operator =
Оператор преобразования может быть объявлен также со спецификатором функции explicit. Например,
explicit operator A() const;
Или более "запутанный" пример преобразований, когда оператор преобразования перегружен для lvalue и rvalue
#include
struct A { A() { std::cout << "A::A()" << std::endl; }
A( const A & ) { std::cout << "A::A( const A & )" << std::endl; }
A & operator =( const A & ) { std::cout << "A::operator =( const A & )" << std::endl; return *this; }
A & operator =( A && ) { std::cout << "A::operator =( A && )" << std::endl; return *this; } };
struct B { explicit operator A() const & { std::cout << "operator A() &" << std::endl; return A(); }
explicit operator A() const && { std::cout << "operator A() &&" << std::endl; return A(); } };
int main() { A a; B b;
a = ( A )b;
std::cout << std::endl;
a = ( A )B();
return 0; }
Вывод этой программы на консоль
A::A() operator A() & A::A() A::operator =( A && )
operator A() && A::A() A::operator =( A && )
Например, для предложения
a = ( A )B();
вызывается оператор преобразования для rvalue временного объекта, созданного вызовом B()
operator A() &&
Затем внутри этого оператора создается временный объект типа A
A::A()
Этот временный объект с помощью перемещающего оператора присваивания присваивается объекту a
A::operator =( A && )
Самый простой вариант - это когда в классе A имеется конструктор преобразования. Например,
#include
struct A { A() {}
explicit A( const struct B & );
A & operator =( const A & ) { std::cout << "A::operator =( const A & )" << std::endl; return *this; }
};
struct B { };
A::A( const B & ) { std::cout << "A::A( const B & )" << std::endl; }
int main() { A a; B b;
a = ( A )b;
return 0; }
Вывод программы на консоль
A::A( const B & ) A::operator =( const A & )
В определении класса A объявлен преобразующий конструктор
explicit A( const struct B & );
который вызывается при приведении типов в выражении ( A )b
И, наконец, если класс B является производным от класса A, то вы можете просто записать
a = b;
В этом случае объект класса B неявно преобразуется в объект класса A и вызывается копирующий оператор присваивания класса A

Метод inflate() в Android

Может кто доходчиво объяснить суть параметров метода inflater.inflate(int resource, ViewGroup root, boolean attachToRoot)? С первым вроде понятно, он по сути, преобразуется из XML в полноценный объект. По второму и третьему как то сухо написано, что один - это родительский элемент (не совсем понятно что за родительский элемент), а второй - отвечает за присоединение этого элемента к родителю или что такое.


Ответ

Вот отличная статья на англосаксонском: Understanding Android's LayoutInflater.inflate()
Краткая выжимка:
LayoutInflater.inflate(int resource, ViewGroup root, boolean attachToRoot) - 1 аргумент указание какой файл разметки загрузить. Второй - родительский элемент разметки, в который будет автоматически добавлена загружаемая разметка если 3 параметр true или откуда будут взяты LayoutParams для загружаемой вьюхи, если attachToRoot false Из п.1 следует, что следующие строки делают одно и тоже:

//загружаем файл разметки и вручную добавляем его в контейнер View v = inflater.inflate(R.layout.custom_button, mLinearLayout, false); mLinearLayout.addView(v); //загружаем файл разметки и автоматически добавляем его в контейнер inflater.inflate(R.layout.custom_button, mLinearLayout, true); //загружаем файл разметки и автоматически добавляем его в контейнер inflater.inflate(R.layout.custom_button, mLinearLayout);
В некоторых случаях система сама добавляет загруженную вьюху в контейнер и ей не надо мешать. Примеры - загрузка разметки для фрагмента и для ячейки списка (ListView, RecyclerView, GridView etc). В этих случаях обязательно надо передавать false последним аргументом. Система сама определит в какой момент разметку надо будет добавить в родительский контейнер В некторых случаях нет смысла передавать второй аргумент, т.к. его как бы нет. Это случай кастомной разметки диалогов. В этом случае можно передать null вместо родительского элемента загружаемой разметки. В некоторых случаях используется тэг в качестве корневого в файле разметки. Такие вьюхи нельзя поместить в переменную, можно только сразу в разметку. Тут никак не обойтись без передачи true в качестве последнего параметра. Такое может пригодится если вы хотите иметь возможность, например, добавлять 2 кнопки, определённые в одном файле разметки в разные контенеры. Например в тот же LinearLayout но с разной ориентацией последнего.

Имя переменной, переданной в функцию

Можно ли как-то узнать имя переменной, которую передали в функцию:
def f(x): ...
y = 1 z = 2 f(y) # напеччатет y f(z) # напеччатет z


Ответ

Это можно сделать в CPython, но не рекомендуется -- в зависимости от вашей конкретной задачи, могут более удачные решения существовать, чем пытаться имя объекта из вызываемого окружения определить:
>>> import inspect >>> def f(x): ... caller_locals = inspect.currentframe().f_back.f_locals ... print(*[name for name, value in caller_locals.items() if x is value]) >>> y = 1 >>> z = 2 >>> f(y) y >>> f(z) z

В зависимости от того как REPL реализована, можно различить f(y) от f(z) вызовы, даже если y = z = 1
>>> import dis >>> import inspect >>> def f(x): ... caller_frame = inspect.currentframe().f_back ... dis.dis(caller_frame.f_code) ... >>> y = z = 1 >>> f(y) 1 0 LOAD_NAME 0 (f) 2 LOAD_NAME 1 (y) 4 CALL_FUNCTION 1 6 PRINT_EXPR 8 LOAD_CONST 0 (None) 10 RETURN_VALUE >>> f(z) 1 0 LOAD_NAME 0 (f) 2 LOAD_NAME 1 (z) 4 CALL_FUNCTION 1 6 PRINT_EXPR 8 LOAD_CONST 0 (None) 10 RETURN_VALUE >>> f(1) 1 0 LOAD_NAME 0 (f) 2 LOAD_CONST 0 (1) 4 CALL_FUNCTION 1 6 PRINT_EXPR 8 LOAD_CONST 1 (None) 10 RETURN_VALUE
Имя переданной переменной присутствует в байт-коде вызывающего frame. Программно можно найти вызов функции (CALL_FUNCTION инструкция) и посмотреть какое именно имя передано (если вообще имя было использовано) из caller_frame.f_code.co_names списка. К примеру в CPython 2:
>>> import inspect >>> import byteplay # $ pip install byteplay >>> def f(x): ... bc = byteplay.Code.from_code(inspect.currentframe().f_back.f_code) ... i = next(i for i, (opcode, _) in enumerate(bc.code) if opcode == byteplay.CALL_FUNCTION) ... print bc.code[i-1][1] ... >>> y = z = 1 >>> f(y) y >>> f(z) z >>> f(1) 1
Disclaimer: ответ для образовательных целей, не для использования в рабочем коде.

Создание выпадающего checkbox списка для текстового input

Необходимо вместо обычного текстового поля сделать выпадающий список с чекбоксами. Что-то похожее на вот такой вид:

При этом, в исходном виде значения вписывались вот так:

То есть, через запятую, а если еще так-то отметить первый пункт, вообще было бы прекрасно. Чтоб, например, отметив 3-е значение как первое оно встало в начало списка, а остальные уже по порядку.
Уже склепал скрипт:
$(document).ready(function() { // Добавляем значения var val_data = { "val1": "Значение 1", "val2": "Значение 2", "val3": "Значение 3", "val4": "Значение 4", "val5": "Значение 5" }; var input = $('[name="other1"]'); // Создаем общий блок с классом var val_cont = document.createElement('div'); $(val_cont).addClass("dropdown"); // Создаем кнопку открытия списка и поле для записи значений $(val_cont).append("Выбрать значение"); // Создаем выпдающий список и вкладываем в общий блок var ul = document.createElement('ul'); for (elem in val_data) { $(ul).append("

  • "); } $(ul).appendTo(val_cont); $(ul).hide(); // Размещаем общий блок после нужного input-а $(input).after(val_cont); // Скрываем/открываем выпадающий список $(".dropdown a").on('click', function() { $(".dropdown ul").slideToggle('fast'); }); $('.dropdown ul input[type="checkbox"]').on('click', function() { var title_val = $(this).closest('.dropdown ul').find('input[type="checkbox"]').val(), title = $(this).val() + ", "; if ($(this).is(':checked')) { var html = '' + title + ''; $('.value').append(html); $(".open").hide(); } else { $('span[data-atr="' + title + '"]').remove(); } if ($('.value').text() == "") { $(".open").show(); $(input).val(""); } else { $(input).val($('.value').text()); } }); }); * { box-sizing: border-box; } body, ul { margin: 0; padding: 0; font-family: Arial; } input[type="text"] { display: none; } .dropdown { position: relative; display: table; margin: 10px auto; color: #333; min-width: 220px; } .dropdown a { display: block; text-decoration: none; color: #fff; background: #333; padding: 12px 20px 10px; border-radius: 20px; text-transform: uppercase; font-size: .95em; text-align: center; } .dropdown ul { position: relative; list-style: none; background: #eee; margin-top: 10px; padding: 5px 0; border-radius: 20px; font-size: .9em; } .dropdown ul:before { content: ''; position: absolute; right: 20px; bottom: 100%; width: 0; height: 0; border-style: solid; border-width: 0 7px 6px 7px; border-color: transparent transparent #eeeeee transparent; } .dropdown ul li { padding: 10px 14px; border-bottom: 1px solid #e0e0e0; } .dropdown ul li:last-child { border: none; } .dropdown input[type="checkbox"] { display: none; } .dropdown label { display: block; position: relative; padding-left: 22px; cursor: pointer; } .dropdown label:before { content: ''; position: absolute; left: 0; top: 0; width: 12px; height: 12px; border: 2px solid #666; border-radius: 4px; } .dropdown input[type="checkbox"]:checked ~ label:before { background: #666; } .dropdown label:after { content: ''; position: absolute; display: block; width: 5px; height: 12px; top: -5px; left: 6px; border: 2px solid #fff; box-shadow: 1px 2px 2px #555; border-top-color: transparent; border-left-color: transparent; -webkit-transform: rotate(45deg); transform: rotate(45deg); z-index: 2; opacity: 0; visibility: hidden; } .dropdown input[type="checkbox"]:checked ~ label:after { opacity: 1; visibility: visible; }
    Итак. Как видим из примера, все работает. Однако, необходимо проверить сам код скрипта, я уверен, что в нем есть косяки или его можно сократить. Самое важное, с чем справится никак не удается, в общем-то, это и есть вопрос: Как проверить содержимое input и при совпадении значений отметить нужные пункты выпадающего списка?


    Ответ

    Комментарии внутри кода. Вводить значения необходимо через запятую с пробелом (как в изначальном примере).
    $(document).ready(function() { // Добавляем значения var val_data = { "val1": "Значение 1", "val2": "Значение 2", "val3": "Значение 3", "val4": "Значение 4", "val5": "Значение 5" }; var input = $('[name="other1"]'); // Создаем общий блок с классом var val_cont = document.createElement('div'); $(val_cont).addClass("dropdown"); // Создаем кнопку открытия списка и поле для записи значений $(val_cont).append("Выбрать значение"); // Создаем выпдающий список и вкладываем в общий блок var ul = document.createElement('ul'); for (elem in val_data) { $(ul).append("

  • "); } $(ul).appendTo(val_cont); $(ul).hide(); // Размещаем общий блок после нужного input-а $(input).after(val_cont); // Скрываем/открываем выпадающий список $(".dropdown a").on('click', function() { $(".dropdown ul").slideToggle('fast'); }); $('.dropdown ul input[type="checkbox"]').on('click', function() { var inputValue, innerObj = {}; /* проверяем value текстового инпута. это необходимо для очистки от лишних запятых при удалении всех элементов и накликивания чекбоксов заново. если эту проверку не делать, то пустой инпут добавляется как пустой элемент массива */ if(input.val()) { /* если инпут не пустой, то закидываем данные из него в массив по разделителю ", " */ inputValue = input.val().split(', ') } else { inputValue = []; // если пустой - присваиваем переменно пустой массив }; /* промежуточный объект нам необходим для составления массива только с уникальными элементами */ inputValue.forEach(function(item) { innerObj[item] = true; }); /* если чекбокс активен — добавляем его value как ключ к объекту, а если нет — удаляем этот ключ */ if ($(this).is(':checked')) { innerObj[$(this).val()] = true; } else { delete innerObj[$(this).val()]; } inputValue = Object.keys(innerObj); // преобразуем ключи объекта в массив input.val(inputValue.join(', ')); // преобразуем массив в строку, разделяя элементы ", " и записываем в value инпута /*var title_val = $(this).closest('.dropdown ul').find('input[type="checkbox"]').val(), title = $(this).val() + ", "; if ($(this).is(':checked')) { var html = '' + title + ''; $('.value').append(html); $(".open").hide(); } else { $('span[data-atr="' + title + '"]').remove(); } if ($('.value').text() == "") { $(".open").show(); $(input).val(""); } else { $(input).val($('.value').text()); }*/ }); // новая функция $('.check').click(function() { var valuesArray = input.val().split(', '), // собираем данные из инпута в массив, разделитель ", " $checkboxes = $(ul).find('li input').removeClass('protected'); // удаляем со всех инпутов класс $.each(valuesArray, function(index, value) { // проходимся циклом по собранному массиву из инпутов $checkboxes.each(function() { // для каждого значение запускаем цикл по всем чекбоксам if ($(this).val() === value) { // и если value инпута равно элементу из собранного массива $(this).prop('checked', true).addClass('protected'); // "чекаем" чекбокс и добавляем ему класс, чтобы на следующем условии чекбокс не стал обратно не выделенным return true; // уходим на следующую итерацию } else if ( !$(this).hasClass('protected') ) { // если у чекбокса нет класса protected $(this).prop('checked', false); // то снимаем выделение с чекбокса } }); }); }); });

    Вызов С++ функции из Python

    Есть Python скрипт имеющий путь к файлу, необходимо открыть этот файл в С/С++ функции, провести с ним манипуляции и вернуть результат в Python скрипт.
    Прочитал: https://docs.python.org/2/extending/embedding.html, но так и не понял как все это сделать.


    Ответ

    Здесь очень хороший пример как это сделать github.com/gil9red/SimplePyScripts/tree/master/using_custom_‌​dll
    Вот пример для UNIX, на основе указанного выше
    test.py
    from ctypes import *
    libc = CDLL("libmath.so") print(libc.add(1, 2)) print(libc.sub(1, 2))
    math.c
    int add(int a, int b) { return a + b; }
    int sub(int a, int b) { return a - b; }
    сборка в библиотеку (shared library)
    gcc -shared -o libmath.so -fPIC math.c
    Запуск как и всегда
    python test.py

    Как пользоваться справкой VisualStudio

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


    Ответ

    Т.к. читать сегодня тоже не очень модно, начну с главного, как быстро получить интересующую информацию.
    В десктопных приложениях, исторически сложилось, что клавиша F1 служит для вызова справки. VisualStudio также использует эту клавишу для работы со справкой, но в более широком смысле. Если вас интересует справка по какому то классу, методу и или функции поставляемым в библиотеках Microsoft, достаточно поставить текстовый курсор (выделять полностью не обязательно) в редакторе кода на имя интересующего элемента и нажать F1. VisualStudio автоматически создаст поисковый запрос к справочной системе и откроет соответствующий раздел справки, если такой имеется в наличии.
    Microsoft предоставляет два варианта справки доступной напрямую из IDE: online и offline. В настоящее время, визуальное представление Online и Offline версий практически не отличается. Слева навигация по дереву разделов документации, справа - навигация по разделам статьи.
    Качество документации:
    Сначала о хорошем:
    в той или иной степени документировано все. много рабочих примеров кода, некоторые из которых довольно часто используются практически без изменений и дополнений в рабочих проектах. есть пошаговые инструкции для выполнения типовых задач, таких как, например, чтение и запись файлов, создание простых оконных приложений, создание простых сервисов и т.д.
    Ну и о плохом:
    если есть возможность, то лучше читать документацию на оригинальном английском, т.к. с некоторых пор MSDN использует систему автоматического перевода для локализации, что негативно сказывается на качестве локализованных текстов. присутствуют некоторые неточности и неоднозначности в оригинальной версии. отдельные разделы документированы весьма условно (камень в огород WinAPI и еще некоторых).
    Но не смотря на все недостатки не очень хорошая документация однозначно лучше чем ее полное отсутствие.
    Offline вариант можно установить вместе с VisualStudio или добавить позже. Важная особенность Offline-справки - ее можно загружать частями, по мере необходимости. Установка локального содержимого и управление им. Сразу хочу предупредить, что полный объем справочной информации превышает несколько десятков гигабайт и это только для .NET, так что это не быстрый процесс, но в результате вы сможете искать информацию независимо от наличия выхода в сеть.

    GCC: internal compiler error

    gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
    Вот ошибка которую мне выдал компилятор:
    internal compiler error: Segmentation fault int delete_struct(ProgramLang * structList, int num) Please submit a full bug report, with preprocessed source if appropriate. See for instructions.
    Я в первые сталкивуюсь с такого рода ошибками и не знаю что делать. Может кто-нибудь объяснить, что это за ошибка и как исправлять подобные ошибки?
    Команда для компиляции, которую я использовал:
    g++ -Wall -W -std=c++11 -o Kursach_2 main.cpp Database_functions.cpp ioStruct_functions.cpp ioFile_functions.cpp
    Ссылка на github: https://github.com/JokerSamStrew/Kursach_2term (код очень сырой и кривой)


    Ответ

    Это сообщение означает, что вы столкнулись с ошибкой в компиляторе. Такое бывает — ничего страшного.
    Будет здорово, если вы поможете авторам исправить её. Для этого установите разрабатываемую версию компилятора (пакет gcc-snapshot в Debian / Ubuntu) и проверьте, воспроизводится ли эта ошибка снова (пакет ставит GCC в каталог /usr/lib/gcc-snapshot).
    /usr/lib/gcc-snapshot/bin/g++ -Wall -W -std=c++11 -o Kursach_2 main.cpp Database_functions.cpp ioStruct_functions.cpp ioFile_functions.cpp
    Если ошибка не повторяется, обновите версию компилятора. В противном случае, пожалуйста, заполните отчёт об ошибке в баг-трекере GCC. Обязательно укажите используемую версию компилятора (достаточно вывода gcc -v). Очень вероятно, здешние товарищи помогут вам, если с английским не очень.
    Более подробную инструкию, как сообщить об ошибке, смотрите в файле /usr/share/doc/gcc/README.Bugs

    Исследовал вашу ситуацию. Поведение GCC подтверждаю. В последней сборке компилятора (от 2016-04-14) ошибка не воспроизводится.
    В вашем случае компилятор падает из-за предкомпилированного заголовка Database_functions.hpp.gch. Иногда такое может быть, если он создавался с другими флагами нежели использующиеся при текущей компиляции. Для решения проблемы просто удалите этот файл.
    N.B.: компилятор производит такой заголовок для ускорения компиляции, если в качестве входного файла передать .hpp

    Возможно ли присвоить результат new не указателю?

    Насколько мне известно, результат выполнения new нужно присваивать указателю, т.е.:
    T t = new T(); //должна быть ошибка. Несоответствие типов т.к. new возвращает указатель T *t = new T(); // Правильный вариант
    Однако, необъяснимым для меня образом, следующий код делает первый вариант возможным. Причем только для одного конечного класса C1. Если попытаться сделать подобное с другим C2, появляется ошибка. Причем если упростить конструктор (убрать список инициализации и аргументы), то все будет работать по-обычному.
    #include
    class A { private: int id; static int instrumentsCount; static int lastId; public: A(); virtual ~A() = 0; }; class B:public A { private: int field1; public: B(int arg):A(),field1(arg) {std::cout<<"B
    ";} }; class C1:public B { private: const bool field2; public: C1(bool o = true):B(170),field2(o){std::cout<<"C1
    ";} ~C1(); }; class C2:public B { private: const int field3; public: C2(int d = 20):B(120),field3(d){std::cout<<"C2
    ";} ~C2(); }; int A::instrumentsCount = 0; int A::lastId = 0; A::A() { this->id = A::lastId++; A::instrumentsCount++; std::cout<<"A "<id<<" created
    "; } A::~A() { std::cout<<"A "<id<<" destroyed
    "; A::instrumentsCount--; } C1::~C1(){} C2::~C2(){}
    int main(int argc, char *argv[]) { C1 c1 = new C1(true); C2 *c2 = new C2(10); return 0; }
    Как результат выводится следующее:
    A 0 created B C1 A 1 created B C1 A 2 created B C2 A 1 destroyed
    Что в принципе логично, но почему конструктор базового класса A вызывается при создании C1 два раза? Прошу открыть мне глаза на мои ошибки( Использую QT Creator 5.9


    Ответ

    Имеется фундаментальный тип, для которого вы можете написать выражение
    T t = new T();
    Таким типом является фундаментальный тип bool.
    bool b = new bool();
    Если инициализатор отличен от нуля, то переменная получает значение true , в противном случае значение false
    Из стандарта C++ (4.14 Boolean conversions)
    1 A prvalue of arithmetic, unscoped enumeration, pointer, or pointer to member type can be converted to a prvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true. For direct-initialization (8.6), a prvalue of type std::nullptr_t can be converted to a prvalue of type bool; the resulting value is false.
    Однако такой код ведет к утечке памяти, так как значение указателя на выделенную память теряется.
    В примере кода из вашего вопроса в классе C1 имеется конструктор преобразования
    C1(bool o = true):B(170),field2(o){std::cout<<"C1
    ";}
    Параметр этого класса имеет тип bool, а переданный в качестве аргумента указатель может неявно быть преобразован в тип bool

    Как правильно создать функцию Delphi

    Я хочу написать 10 функций в отдельном .pas файле, а потом вызывать их по мере необходимости. Делаю так:
    unit Unit5;
    interface
    uses System.SysUtils, System.Classes, myTypes;
    type RGetInfo = record function GetGroups(ClientName: String): XGroups; function GetLanguages(ClientName: String): XLanguages; function GetSettings(ClientName: String): XSettings; end;
    implementation
    ... end.
    Вызываю так:
    var GetInfo: RGetInfo; Groups: XGroups; begin Groups := GetInfo.GetGroups('Client1');
    Может есть, более грамотный, способ? Например вместо record.


    Ответ

    Статические методы класса:
    RGetInfo = class public class function GetGroups(ClientName: String): XGroups; class function GetLanguages(ClientName: String): XLanguages; class function GetSettings(ClientName: String): XSettings; end;
    var Groups: XGroups; begin Groups := RGetInfo.GetGroups('Client1');
    или просто отдельные функции:
    interface
    function GetGroups(ClientName: String): XGroups; function GetLanguages(ClientName: String): XLanguages; function GetSettings(ClientName: String): XSettings;
    implementation
    function GetGroups(ClientName: String): XGroups; begin result := ... end;
    var Groups: XGroups; begin Groups := GetGroups('Client1');

    Восстановление пиктограммы в трее при перезапуске проводника

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


    Ответ

    Подпишитесь на событие TaskbarCreated. Оно вызывается каждый раз при создании связки «Меню «Пуск» — Панель быстрого запуска — Панель задач — Панель уведомлений»; из неё нас интересует только последний пункт.
    Объявите где-нибудь глобальную переменную для хранения идентификатора оконного сообщения, соответствующего имени «TaskbarCreated»
    static UINT _uTaskbarRestartMessage; Где-нибудь при инициализации приложения необходимо выполнить собственно подписку:
    _uTaskbarRestartMessage = RegisterWindowMessage(TEXT("TaskbarCreated")); При получении оконного сообщения с uMsg, равным значению _uTaskbarRestartMessage, необходимо пересоздать все необходимые значки своего приложения так, как мы делали это первый раз при запуске приложения:
    LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch(uMsg) { // ...
    default: if(uMsg == _uTaskbarRestartMessage) { // Создаём иконки в панели уведомлений return 0; } else return DefWndProc(hwnd, uMsg, wParam, lParam); } }

    Объединить два репозитория

    У меня возникла проблема, нужно объединить два репозитория, ситуация следующая:
    Я создаю проект бэкенда, он находится в папке MyProject Внутри я создаю папку frontend и создаю в ней второй проект. Так получилось, что скрипт, который инициализирует данный проект, также производит инициализацию git-репозитория.
    И таким образом, когда я в главной папке MyProject выполняю создание репозитория, то git не видит файлы в папке frontend, потому что это уже второй репозиторий.
    Иерархия следующая:
    -- MyProject ---- frontend
    Не чего не клонировалось обе папки инициализировались через git init
    Вопрос: как мне второй репозиторий frontend слить с первым, чтобы у меня был всего один целый репозиторий MyProject?


    Ответ

    короткий ответ:
    вам всего лишь надо удалить каталог frontend/.git
    после этого программа git, запущенная в, например, каталоге myproject, «увидит» и содержимое каталога frontend
    длинный ответ с пояснениями:
    если программе git при её вызове не был явно указан (параметрами или переменными окружения) путь к хранилищу («репозиторию»), первым делом она его (т.е., каталог .git) ищет. сначала в текущем каталоге, затем в вышестоящем, и так далее. а рабочим каталогом (если он тоже не был явно указан параметром или переменной окружения) будет считаться тот, в котором находится подкаталог .git (т.е. само хранилище).
    многие из команд, понимаемых программой git, требуют просмотра рабочего каталога — work tree (и вложенных каталогов, разумеется) на предмет изменений (например, status, diff и т.д.).
    и если при просмотре под-каталогов рабочего каталога в каком-нибудь из них будет обнаружен каталог (или файл) с именем .git, то программа git будет считать, что этот под-каталог является рабочим каталогом для какого-то другого git-хранилища, и его содержимое надо игнорировать.
    именно такая ситуация и описана в вопросе.
    и если содержимое хранилища в каталоге frontend/.git не нужно, то его можно удалять. тогда программа git «увидит» содержимое каталога frontend — бывшего рабочего каталога для хранилища, располагавшегося в каталоге frontend/.git

    Как проверить правильно ли введен рост в футах и дюймах?

    Программа запрашивает рост в футах и дюймах. Нужно преобразовать рост в футах и дюймах в рост в дюймах (1 фут = 12 дюймов).
    Ввод роста должен производиться в формате (футы.дюймы). Максимальный размер дробной части не может превышать 11. Например, значение 5.12 не может быть принято, потому что в одном футе двенадцать дюймов, т.е. 5.12 футов == 6 футов. Я начал решать задачу, но столкнулся с проблемой: если принятое значение поместить в переменную типа float, то это значение нужно проверить на правильность прежде чем продолжить вычисления. Я использовал для этого функцию modff(), которая помещает целую и дробную части числа в две разные переменные. Как можно проверить дробную часть на правильность, если, например, 5.1 и 5.10 воспринимаются как одно число, но если речь идет о футах и дюймах, то это два разных числа. Ниже я привожу код, который написал. Помогите, пожалуйста, продолжить его или предложите другое решение.
    //calculate BMI #include #include int main() { using namespace std; const double Inches_per_foot = 12;
    float height; cout << "Enter your height in foots and inches: _____\b\b\b\b\b"; cin >> height; float foots ; float inches = modff(height, &foots); cout << foots << " - The integer part of number" << inches << " - The float part of number " << endl; if ( inches >= 0.12 ) { cout << "Error: Inches value must be less than 12" << endl; } else if ( ) {
    } else { cout << " foots = " << foots << ", inches = " << inches << endl; }
    return 0; }


    Ответ

    #include #include #include int main() { using namespace std;
    string input{}; int foots{}; int inches{}; cout << "Enter your height in foots and inches: _____\b\b\b\b\b"; while (true) { cin >> input; float foots; //float inches = modff(height, &foots); int pos = input.find_first_of('.'); if (pos > 0) { string sfoots = input.substr(0, pos); string sinches = input.substr(pos + 1); foots = atoi(sfoots.c_str()); inches = atoi(sinches.c_str()); } else { if (input.size() > 0) { foots = atoi(input.c_str()); } }
    if (inches > 11) { cout << "Wrong inches. Retype height in foots and inches" << endl; cout << "Enter your height in foots and inches: _____\b\b\b\b\b"; } else { cout << foots << " - The integer part of number " << inches << " - The float part of number " << endl; cout << "The size in inches:" << foots * 12 + inches<

    Как настроить дебаг Android Studio?

    При попытках дебага студия постоянно ныряет в какие-то глубины библиотек, чего нет, допустим, в IntelliJ IDEA, где код, как правило, прыгает только по классам, написанным разработчиком. Не знаю, с чем это связано, но это замечают многие.
    Есть ли возможность настроить студию таким образом, чтобы она "прыгала" при дебаге только по классам, написанным разработчиком?


    Ответ

    Согласно тык можно исключить при дебаге классы по шаблонам их именования (т.е. по пакету) так:
    File > Settings > Build, Execution, Deployment > Debugger > Stepping.
    далее ищем кнопку "Add Pattern", вбиваем нужный паттерн для исключения, например
    android.*
    И больше не видим при дебаге классы, которые находятся в пакете android

    Как сделать отступы в виде точек между текстом

    Есть текст: условное расписание. К примеру:
    Пн-Сб ........ 8 19 Вс .......... Выходной
    Нужно с помощью css и/или js сделать так, чтобы точки располагались между текстом, причём они не должны быть дефолтными (круглыми), а квадратными, определённого цвета(не цвета текста), размера и с определённым отступом между собой. При это при всём эта конструкция должна быть адаптивной, т.е. при сужении кол-во точек должно изменяться так, чтобы текст в правой части оставался на одной линии.
    Я не прошу писать за меня код, я прошу лишь дать совет, в какую сторону копать. Пока есть вот такая мысль: сделать обёртку и запихать туда текст по краям, с помощью float'ов, а между затолкать какой-то блок и с помощью фона и его repeat'а заполнить точками. Но как сделать его всегда нужной ширины не понятно.
    Спрашиваю тут потому, что уверен, что эта задача тривиальная и уже наверняка имеет красивое решение.


    Ответ

    Просто dotted:
    div:first-child { float: left; } div:last-child { float: right; } section { overflow: hidden; } section:after { content: "\A0"; display: block; overflow: hidden; border-bottom: 3px dotted red; margin-top: -6px; } div:first-child:after, div:last-child:before { content: ""; display: inline-block; width: .25em; }

    123
    456

    С регулируемыми расстояниями:
    div:first-child { float: left; } div:last-child { float: right; } section { overflow: hidden; line-height: 1.2em; } section:after { content: ""; display: block; overflow: hidden; padding-top: 1em; height: 3px; box-sizing: content-box; background: repeating-linear-gradient(to right, red, red 3px, transparent 3px, transparent 9px); background-clip: content-box; } div:first-child:after, div:last-child:before { content: ""; display: inline-block; width: .5em; }
    123
    456

    Как найти информацию про установленный пакет на Linux?

    Доброго времени суток.
    Вопрос довольно глобального характера. Я не могу понять саму концепцию.
    Как найти информацию по работе установленного пакета? Где найти примеры использования? Где расположены в системе файлы, файлы с примерами, мануалы? Какие методы использует этот пакет, чтобы к нему обратиться?
    На данный момент я представляю себе поиск информации так:
    Поиск на форумах и сайтах статей и вопросов от тех, кто уже делал похожий проект и устанавливал данные пакеты (оттуда и знание о существовании самого пакета) Stackoverflow Git репозиторий проекта и его Вики apt-cache show [пакет] - обычно лишь общие слова о работе пакета, которые я уже знаю man [пакет] - не работает, потому что нужно знать название методов данного пакета
    В результате я получаю отрывки информации, нет полной картины. Я использую методы, какие озвучены, но не знаю о существовании других. Часто никакого Вики вообще нету..
    А хотелось бы получить хотя бы название методов, чтобы дальше уже копать по ним, примеры использования. В идеале структурированную информацию о пакете
    Для примера: установил я пакеты sudo apt install zbar-tools python-zbar python-qrtools - для распознавания qr кода на изображении или же sudo apt-get install bluetooth bluez blueman (это для работы с bluetooth на Raspberry Pi). Я знаю о существовании мифического файла blescan.py с примером работы, но не могу найти его расположения.
    Буду признателен за объяснения и разжёвывание общих принципов.


    Ответ

    начинать можно с просмотра файлов, входящих в пакет:
    $ dpkg -L имя.пакета

    например, рассмотрим пакет bluez
    исполняемые файлы обычно располагаются в каталогах, содержащих в пути строку bin
    $ dpkg -L bluez | grep bin /bin /bin/hciconfig /usr/sbin /usr/bin /usr/bin/bluetoothctl /usr/bin/bccmd /usr/bin/btmon /usr/bin/rctest /usr/bin/hciattach /usr/bin/hcitool /usr/bin/sdptool /usr/bin/ciptool /usr/bin/l2ping /usr/bin/l2test /usr/bin/rfcomm /usr/bin/gatttool /usr/sbin/bluetoothd
    видим ряд исполняемых файлов, начиная с hciconfig и заканчивая bluetoothd
    man-страницы обычно располагаются в каталогах, содержащих в пути строку man
    $ dpkg -L bluez | grep man /usr/share/man /usr/share/man/man8 /usr/share/man/man8/bluetoothd.8.gz /usr/share/man/man1 /usr/share/man/man1/bluetoothctl.1.gz /usr/share/man/man1/btmon.1.gz /usr/share/man/man1/l2test.1.gz /usr/share/man/man1/hid2hci.1.gz /usr/share/man/man1/l2ping.1.gz /usr/share/man/man1/rctest.1.gz /usr/share/man/man1/rfcomm.1.gz /usr/share/man/man1/ciptool.1.gz /usr/share/man/man1/hcitool.1.gz /usr/share/man/man1/hciconfig.1.gz /usr/share/man/man1/hciattach.1.gz /usr/share/man/man1/bccmd.1.gz /usr/share/man/man1/sdptool.1.gz
    видим ряд man-страниц, начиная с bluetoothd и заканчивая sdptool. просмотреть их можно командами man bluetoothd, ..., man sdptool
    документацию (иногда содержащую примеры) можно отобрать по признаку «содержит строку doc в пути»:
    $ dpkg -L bluez | grep doc /usr/share/doc /usr/share/doc/bluez /usr/share/doc/bluez/README.Debian.gz /usr/share/doc/bluez/changelog.Debian.gz /usr/share/doc/bluez/changelog.Debian.amd64.gz /usr/share/doc/bluez/NEWS.Debian.gz /usr/share/doc/bluez/changelog.gz /usr/share/doc/bluez/copyright
    нередко, если документации много, её выделют в отдельный пакет, имя которого заканчивается суффиксом -doc (а иногда ещё и с дополнительным разбиением на языки, с добавлением суффикса -язык). например, документация к пакету aptitude содержится в таких пакетах:
    $ apt-cache search aptitude doc aptitude-doc-cs - Czech manual for aptitude, a terminal-based package manager aptitude-doc-en - English manual for aptitude, a terminal-based package manager aptitude-doc-es - Spanish manual for aptitude, a terminal-based package manager aptitude-doc-fi - Finnish manual for aptitude, a terminal-based package manager aptitude-doc-fr - French manual for aptitude, a terminal-based package manager aptitude-doc-it - Italian manual for aptitude, a terminal-based package manager aptitude-doc-ja - Japanese manual for aptitude, a terminal-based package manager aptitude-doc-ru - Russian manual for aptitude, a terminal-based package manager

    Конвертирование Color в ConsoleColor

    Здравствуйте, пишу программу которая получает фотографию, и рисует ее на консоли, но поскольку приложение консольное, а как вы знаете что нельзя использовать Bitmap в консоли пришлось создать формочку. Все работает но когда дело доходит до вывода на консоль, то я получаю цвет пикселя в формате Color, а для изменения цвета консоли нужна ConsoleColor. Прошу помочь переконвертировать Color в ConsoleColor, спасибо!


    Ответ

    Немного погуглив я наткнулся на вот этот код:
    Color BEGIN_COLOR = Color.Red; ConsoleColor END_COLOR = ClosestConsoleColor(BEGIN_COLOR.R, BEGIN_COLOR.G, BEGIN_COLOR.B);
    public static ConsoleColor ConvertColor(byte r, byte g, byte b) { ConsoleColor ret = 0; double rr = r, gg = g, bb = b, delta = double.MaxValue;
    foreach (ConsoleColor cc in Enum.GetValues(typeof(ConsoleColor))) { var n = Enum.GetName(typeof(ConsoleColor), cc); var c = System.Drawing.Color.FromName(n == "DarkYellow" ? "Orange" : n); var t = Math.Pow(c.R - rr, 2.0) + Math.Pow(c.G - gg, 2.0) + Math.Pow(c.B - bb, 2.0); if (t == 0.0) return cc; if (t < delta) { delta = t; ret = cc; } } return ret; }