Страницы

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

воскресенье, 15 марта 2020 г.

Не работает ввод русских букв в EditText в Android Studio

#android #android_studio #android_edittext


Добрый день!
Почему-то не работает ввод русских букв в EditText в Android Studio. Пробовала через
стандартный эмулятор и Genimotion. Как только меняю раскладку - пишет на англ. нормально,
на русском не пишет, даже в логах ничего нет.
Заранее спасибо.    


Ответы

Ответ 1



В случае с Genymotion вам поможет включение в настройках эмулятора (в списке эмуляторов) использования виртуальной клавиатуры.

Ответ 2



В настройках Android в эмуляторе нужно выбрать русский язык.

Переходы между экранами - Activity или XML?

#android #activity


Не могу разобраться, как перейти на другое xml или обязательно создавать Activity
для этого? И при каждом переходе на другое окно придется создавать Activity или есть
другой способ!?    


Ответы

Ответ 1



Создаёте 2 Activity (не забудьте указать новую активити в manifest.xml) и для каждого свой layout. Переход из одной активити в другую осуществляется вот так: Intent intent = new Intent(this, SecondActivity.class); или Intent intent = new Intent(FirstActvity.this, SecondActivity.class); Так же можно использовать фрагменты. Вот где можно научиться делать переходы между экранами.

Ответ 2



Activity это и есть "окно" со своим жизненным циклом, можно использовать фрагменты.

Возможно ли “виртуальное клонирование” в С++?

#cpp #gcc


Наткнулся в "More Exceptional C++" на информацию, что виртуальные методы могут вместо
указателей на объекты базового класса возвращать объекты перегруженного класса. Решил
попробовать смоделировать "самоопределяющийся" объект - с виртуальным методом, вместо
указателя базового класса возвращающим указатель на объект производного, чтобы можно
было вызывать функции, отсутствующие в базовом классе. Вот пример с "виртуальным клонированием":
#include 
#include 

class Base
{
public:
    Base(){}
    virtual ~Base()=0;
    virtual Base*   clone()
    {
        qDebug()<<"Base clone";
        return 0;
    }
};

Base::~Base(){}

class Derived: public Base
{
public:
    Derived(){}
    virtual Derived*   clone()
    {
        qDebug()<<"Derived clone";
        return new Derived(*this);
    }
    QString derivedOnly(){return "derivedOnly";}
    virtual ~Derived(){}
};

int main(int argc, char *argv[])
{
    Derived d1;
    Base *  b1=&d1;
    Base *  b2=b1->clone();     b2=b2;
    Derived * d2=d1.clone();    delete d2;
//  Derived * d3=b1->clone();   delete d3;
}

Так всё работает, и вывод qDebug показывает, что запускается клонирование производного
класса. Однако, раскомментировав последнюю строку, при компиляции получаю сообщение
об ошибке "invalid conversion from 'Base' to 'Derived' [-fpermissive]".
Выводы:

Очевидно, что компилятор (g++, Windows/MinGW) проигнорировал описание Derived * Derived::clone(),
сгенерировав вместо него код для Base * Derived::clone().
Эту подмену транслятор сделал, никак меня не уведомив. Я рассчитываю получить указатель
типа Derived, а получаю Base - и ничего об этом не знаю! 
Я понимаю, для чего это сделано. Я мог бы написать что-нибудь типа b1->clone()->derivedOnly(),
и транслятор не знал бы, допустима ли такая конструкция, так как статически неизвестно,
будет ли при исполнении b1 указывать на Base или на Derived.

Вопросы:

Почему так происходит - является ли это частью стандарта (где можно посмотреть?)
или самоуправством g++ (4.6.2)?
Можно ли сделать так, чтобы выдавался warning?
Ведут ли себя так же другие трансляторы?
Есть ли возможность решить изначальную задачу, то есть "развернуть" объект из указателя
на базовый класс, не указывая, в какой именно класс мы его разворачиваем (т. е. без
dynamic_cast'ов)?
    


Ответы

Ответ 1



О выводах Выводы неверные. Пункт 3 верный. Он же является ответом на Ваш вопрос. А вот пункт 1 и, следовательно, 2 - неверные. Derived* Derived::clone(); Base* Base::clone(); Какой из методов Вы бы выбрали, будь у Вас указатель на тип Base*? Ответы 1) Вы же сами отвечаете себе на этот вопрос в выводе 3: статически неизвестно, будет ли при исполнении b1 указывать на Base или на Derived Это приводит к тому, что компилятор использует статический тип объекта, то есть Base*. У объекта такого типа метод Base* clone() возвращает Base*, чтобы привести его к Derived* нужно явное преобразование. Ссылка на стандарт: раздел 10.3.8: [...] its result is converted to the type returned by the (statically chosen) overridden function (5.2.2) 2) Тут я поразмышляю о другом warning'е. Который не будет показан, если написать, например: Derived* d2 = dynamic_cast( b1->clone() ); Явное преобразование static_cast( b1->clone() ) это как бы уже warning. Страуструп пишет в "Дизайн и эволюция C++", что намеренно завел вместо лаконичного, но скрытного синтаксиса приведения типов C, громоздкий и неудобный, привлекающий внимание синтаксис приведения типов в стиле C++ (с _cast<>'ами). Кто Вам гарантирует, что b1 всегда будет указывать на Derived-объект? Только Вы сами и гарантируете. За этот архитектурный "косяк" (см. п.4) Вы и расплачиваетесь dynamic_cast'ом. Или, если производительность важна, static_cast'ом, подкладывая себе мину замедленного действия. Относитесь к явным преобразованиям типов, как к warning'ам, ругающим Вашу архитектуру. 3) да. См. п. 1 Например, VS2013: error C2440: 'initializing' : cannot convert from 'Base *' to 'Derived *' Cast from base to derived requires dynamic_cast or static_cast 4) Итак, Вы хотите реализовать виртуальный метод клонирования. Сам метод реализован правильно, и работает правильно. Неправильно Вы используете результат клонирования - считаете, что там какой-то определенный потомок. На самом деле, имея указатель Base*, Вы можете полагаться только на интерфейс класса Base, никаких QString derivedOnly(). Как же быть? Вариант 0. Вы точно знаете, что Base* в данном контексте - это Derived*. Тогда Вы можете либо сразу указать тип Derived*, либо сделать dynamic_cast. Вариант1. Код оперирует указателем Base* и неизвестно, на какой из наследников есть указатель: Derived1* или Derived2*. Вы клонируете объект, думая, что там Derived1, а на самом деле не он. Что тогда? Логика программы развалилась. Из-за того, что Вы полагаетесь на различный интерфейс сущностей, которые по контракту все имеют единый интерфейс Base*.

Самый простой способ добавить элемент в начало и удалить в конце в Java

#java


Привет!
Подскажите, как Java создать динамический массив (карту) и обработать его, такого вида:
Создаем:
[20,30,40,50,60]
Добавляем  элемент в начало и убираем в конце:
[10,20,30,40,50]
Т.е. мне необходимо оставить тело  20,30,40,50, не трогать, а  к нему добавить голову
10, и убрать хвост 60.
Как реализовать это самым быстрым и дешевым методом это в Java?    


Ответы

Ответ 1



@Andrew F создать динамический массив (карту) для начала определись чего ты хочешь. карту или динамический массив. Я вижу что ты используешь список, так что твой выход - интерфейс Deque и его встроенная реализация LinkedList. насколько дорого? что значит дорого ? В хвосты/голову вствляет быстро. тут подробнее

Ответ 2



Подскажите, как Java создать динамический массив (карту) Вы, наверное, имеете в виду map (обычно ее начинающие ошибочно называют картой)? Слово "map" имеет несколько переводов, в зависимости от контекста употребления, и здесь верный перевод - это "отображение" (этот термин пришел из дискретной математики). Отображение в Java можно создать на базе дерева или hash таблицы, не думаю, что что-то из этого вам подойдет. Как реализовать это самым быстрым и дешевым методом это в Java? Вам нужен двусвязный список: Deque deque = new LinkedList(); deque.addAll(Arrays.asList(20, 30, 40, 50, 60)); deque.addFirst(10); // O(1) deque.removeLast(); // O(1) Подскажите, пожалуйста, в данном случае на организацию списка, вставку и удаление будет затрачено меньше памяти и процессорного времени чем для "сдвига" всего массива Есть эмпирическое правило выбора структуры данных в вашем случае: Массив хорош для быстрого доступа на чтение к любому его элементу, вставки элементов в конец, удаления элементов с конца. Все эти действия выполняются очень быстро. Вставка (либо удаление) в начало или вставка (либо удаление) в середину приводят наихудшему времени (т.к. приходится выделять новый кусок памяти и копировать туда измененный массив). Двусвязный список хорош для быстрой вставки (либо удаления) элементов в конце и в начале. Вставка (либо удаление) элементов в середину требует больше времени, но выполняется все-равно быстрее, чем в массиве (т.к. не требует копирования абсолютно всей структуру данных, как это необходимо для массива). Произвольный доступ к элементам (кроме, первого и последнего) в списке требует больше затрат времени, чем в массиве.

Ответ 3



Если максимальное количество элементов известно, а добавляются и удаляются они только с головы и хвоста, то самой эффективной структурой (независимо от Java или Си или ...) будет использование массива фиксированного размера. Только у него должна быть "плавающая" точка отсчета (так сказать, виртуальный нулевой индекс). Т.е. храните индекс "нуля" (ihead) и текущий размер (length). Индекс последнего (точнее первого свободного в хвосте = (ihead + lenght) % size). Т.е. вставка новой головы это в ihead - 1 и length++, а удаление хвоста -- тривиально length-- Ну, думаю, далее сами разберетесь. -- Кстати (@Xmaster, спасибо за подсказку), подобная структура данных называется кольцевой (или циклический) буфер (cyclic buffer или ring buffer).

Ответ 4



Добавлю свои пять копеек: Если размер массива фиксированный, то наилучшим образом конструкция описывается лимитированным стеком (LimitedStack). Вставка в дно стека приводит к выталкиванию с вершины стека элемента (аналогия с вертикальной трубой где, элементы добавляются/берутся только снизу). В Guava есть такая коллекция EvictingQueue

Объясните все возможные причины использования заголовков в мультифайловых проектах С

#c #gcc


Посмотрите в начало стр. 5 здесь и объясните популярно, зачем в принципе нужен заголовок
calc.h, если проект спокойно компилируется и запускается без заголовков вообще через: 
Andrey@AsusP5B ~/2
$ gcc driver.c calc.c -o prog

Andrey@AsusP5B ~/2
$ ./prog

Square of 5 is 25

Andrey@AsusP5B ~/2
$

Это что, новым компиляторам уже на заголовки наплевать или на прототипы функций,
или это чистота написания кода, или просто лучше заголовки лучше сразу создавать, чтобы
не было путаницы или х.з., так как в будущем они понадобятся для других целей... В
теории, ПОЧЕМУ?    


Ответы

Ответ 1



Все работает, потому что си компилятор полагается на то, что Вы самостоятельно угадали сигнатуру. Возьмите driver.c, закомментируйте #include "calc.h" и "сделайте ошибку в вызове функции, где-то так: printf("\nSquare of %d is %d\n", x, square()); Код скомпилируется и даже никто не ругнется. Но вот только работать он будет странно (как именно странно - зависит от ситуации, может упасть, а может выводить странные результаты). У меня, к примеру, выводит просто "Square of 5 is 1". Правильные заголовочные файлы позволяют компилятору знать правильную сигнатуру функции и находить подобные ошибки. Но почему же оно все-таки компилируется? Да все просто. Когда компилятор видит объявление функции, он генерирует для нее код и запоминает адрес начала в специальной таблице в виде имя-адрес (да, там нет параметров!). Когда нужно вставить вызов функции, просто смотрит в таблицу и поставляет "call адрес". Сами параметры перед этим напихает в стек push'ем. Но тут есть ещё одна хитрость. На самом деле вначале туда проставляются не адреса. Адреса уже проставляет линковщик. Именно по этой причине порядок компиляции файлов не столь важен. Почему же оно не работает, хотя и компилируется? Вызывающая сторона в стек параметры добавляет, но их фактическое кол-во нигде не отмечает. Вызываемая сторона просто достает с стека их. Но опять же, она не может никак узнать, что там именно то, что положила вызывающая сторона. Поэтому, что достали с стека, то и обработали. В с++ этот трюк уже не проходит. Там компилятор делает "манглироване имен". То есть в таблицу функций вставляет имя функции с хитрым описанием типов параметров. Это нужно, так как в С++ есть возможность создать несколько функций с одним именем и разным кол-вом/типом параметров.

Ответ 2



В данном случае все работает без calc.h потому, что функция square() из calc.c возвращает int, а это значение результата функции по умолчанию. Измените в calc.c на double square (int x) и Вы увидите, как все сломается. Update Смотрите, вот код и результаты avp@avp-xub11:hashcode$ more cf1.c cf2.c | cat :::::::::::::: cf1.c :::::::::::::: #include int main () { int x = 5; const char *fmt = "square of %d is " #ifdef TINT "%d\n" #else "%f\n" #endif ; printf(fmt, x, square(x)); return 0; } :::::::::::::: cf2.c :::::::::::::: #ifdef TINT int #else double #endif square (int x) { return x * x; } avp@avp-xub11:hashcode$ gcc cf1.c cf2.c -DTINT avp@avp-xub11:hashcode$ ./a.out square of 5 is 25 avp@avp-xub11:hashcode$ gcc cf1.c cf2.c avp@avp-xub11:hashcode$ ./a.out square of 5 is -0.000000 avp@avp-xub11:hashcode$ Update 2 Добавим calc.h #ifndef _CALC_H // это так называемый guard, почти всегда нужен в заголовочных файлах #define _CALC_H #ifndef TINT double #else int #endif square (int); #endif который в зависимости от TINT определяет либо int либо double square(). avp@avp-xub11:hashcode$ more cf1.c cf2.c | cat :::::::::::::: cf1.c :::::::::::::: #include #include "calc.h" int main () { int x = 5; const char *fmt = "square of %d is " #ifdef TINT "%d\n" #else "%f\n" #endif ; printf(fmt, x, square(x)); return 0; } :::::::::::::: cf2.c :::::::::::::: #include "calc.h" #ifdef TINT #define CAST int #else #define CAST (double) double #endif square (int x) { return CAST x * x; } avp@avp-xub11:hashcode$ gcc cf1.c cf2.c -DTINT avp@avp-xub11:hashcode$ ./a.out square of 5 is 25 avp@avp-xub11:hashcode$ gcc cf1.c cf2.c avp@avp-xub11:hashcode$ ./a.out square of 5 is 25.000000 avp@avp-xub11:hashcode$ И все, как видите, заработало. Конечно, в простых случаях (а на практике лучше все делать проще (это я тут от лени начал ваять шаблоны (templates))) никакой препроцессор (для условной компиляции, конечно же) не нужен.

Отладка приложения - количество памяти

#c_sharp #visual_studio_2012


Как узнать сколько памяти потребляет приложение (на С#) при работе? Либо "участок
кода" - допустим есть метод который считывает данные, можно ли узнать сколько памяти
он потребляет во время работы.

ds.ReadXml(xml);


IDE - VS2012
    


Ответы

Ответ 1



Отслеживание изменений в оперативной памяти: С помощью кода: long before = GC.GetTotalMemory(false); // ваш код тут long after = GC.GetTotalMemory(false); int consumedInMegabytes = (after - before) / (1024 * 1024); Опционально может потребоваться собрать мусор до и/или после тестируемого кода (параметр GetTotalMemory поставить в true). С помощью профайлеров (суть аналогична): снять снэпшот до тестируемого кода, выполнить код, снять снэпшот после, сравнить два снэпшота. Профайлер поможет ответить не только на на вопрос "сколько?", но и "на что?".

Консоль. Считывание нажатой клавиши

#cpp #c


Нужно, чтобы после нажатия на кнопку программа работала дальше. Чтобы после этой
кнопки не приходилось еще жать Enter. Как я понял, этим занимается getchar(), но у
меня он не работает, приходится жать Enter. Код для Windows:

while (z != ' ') {
    cout<< "Нажмите SPACE " << endl;
    z = getchar();
}

    


Ответы

Ответ 1



На Windows можно использовать getch() вместе с заголовочным файлом conio.h. #include #include int main() { int z while (z != ' ') { cout<< "Нажмите SPACE " << endl; z = getch(); } } На *nix-OS есть curses.h (ncurses.h), там также имеется функция getch(). Однако при использовании данной функции вы остаетесь привязаны к curses, поэтому желательно использовать следующую конструкцию: #include #include int getch( ) { struct termios oldt, newt; int ch; tcgetattr( STDIN_FILENO, &oldt ); newt = oldt; newt.c_lflag &= ~( ICANON | ECHO ); tcsetattr( STDIN_FILENO, TCSANOW, &newt ); ch = getchar(); tcsetattr( STDIN_FILENO, TCSANOW, &oldt ); return ch; } Также на Windows можно использовать PDCurses для создания мультиплатформенных консольных приложений, он почти полностью совместим с ncurses.

Ответ 2



Переносимым образом — никак. C++ рассчитан на то, что стандартные потоки могут быть перенаправлены, поэтому ввод буферизуется, и доступа напрямую к клавиатуре нет. Тем не менее, есть способы, основанные на системно-зависимых библиотеках. Например, под Windows-системами вы можете воспользоваться WinAPI-функциями ReadConsoleInput/GetNumberOfConsoleInputEvents. Под Linux-системами вам поможет библиотека curses/ncurses. На старых DOS-системах есть getch в conio.h. Учтите, что если вы пользуетесь низкоуровневым вводом/выводом, нормальный потоковый ввод-вывод скорее всего не будет функционировать нормально. Так что или cin/cout, или низкоуровневые трюки, иначе сюрпризов не избежать.

Сборка приложения из JAR в EXE с JRE

#java


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


Ответы

Ответ 1



Самые популярное решение Launch4j или exe4j , но это всего лишь Загрузчик приложения на java, то есть jre все равно необходимо.

Ответ 2



Можете приобрести Excelsior Jet. А можете собрать приложение с помощью gcj. Но размер вас не порадует. Можно собрать с JVM "в пузе", например с JamaicaVM.

Ответ 3



Установите JRE. иначе никак. преобразование в .exe не спасёт. Ну если очень хочется преобразовать jar -> exe то вот ссылка, но jre - обязательный компонент

Разные лейауты для разных телефонов

#android #android_layout


Такая проблема. Создаем приложение для зоопарка устройств. и необходимо чтобы дизайн
совпадал пиксель в пиксель. Впринципе все смогли разрулить с помощью dpi, выставляя
значения в них. на разных екранах делаем скрин, вставляем в фотошоп и все накладывается
пиксель в пиксель. Но есть такие телефоны типо нексуса 6, у которых нет конкретного
размера в  dpi тоесть он между xxhdpi  и  xxxhdpi. И соотвественно когда я указываю
размер кнопки например 50dpi то она выглядит иначе чем я ожидаю. Я не знаю как это
решить. Из этого вопросы


Как это решается?
Как сделать чтобы на определенном телефоне поставлялся определенный лейаут?


НАШЕЛ

res/layout-sw600dp/main_activity.xml   # For 7” tablets (600dp wide and bigger)
res/layout-sw720dp/main_activity.xml   # For 10” tablets (720dp wide and bigger)


смущает 600dp wide and bigger это что этот лейаут будет и для экранов с большей плотностью
тоже? а как сделать только для конкретного экрана?
    


Ответы

Ответ 1



Можно например так: if(android.os.Build.MODEL.contains("Nexus 6")) setContentView(R.layout.my_layout_for_nexus_6); Мне и самому то не нравится такое выделывать, но что делать раз Nexus такой специфичный :)

Ответ 2



Кроме всего ранее озвученного можно попробовать вынести размеры елементов и шрифтов в dimens. Причем раскидать их по папкам с комбинацией денсити и размера: values-sw320dp-xhdpi values-sw600dp-xhdpi values-sw720dp-xhdpi values-sw320dp-xxhdpi values-sw600dp-xxhdpi values-sw720dp-xxhdpi values-sw320dp-xxxhdpi values-sw600dp-xxxhdpi values-sw720dp-xxxhdpi см. также http://developer.android.com/guide/topics/resources/providing-resources.html

Ответ 3



Nexus 6 - 730 x 410 dp Nexus 9 - 1024 x 768 dp Если используются разные layout'ы для портретной и альбомной ориентации (как часто бывает), то можно учесть это: In order to take advantage of the screen real estate on the Nexus 6 and Nexus 9, we emphasize the importance of responsive design. In the past, if you assumed that landscape mode is significantly wider than portrait mode, you may run into problems on a device like the Nexus 9, which has an aspect ratio of 4:3. Instead of declaring layouts using the layout-land or layout-port resource folder qualifiers, we strongly recommend switching to the wdp width resource folder qualifier so that content is laid out based on available screen width. Тогда для Nexus 6 получаем layout-w410dp-h730dp (портретная) и layout-w730dp-h410dp (альбомная)

как определить при старте приложения что получена нотификация?

#android


У меня есть нотификации (уведомления) которые приходят от GCM. Даже если моя программа
закрыта, я кликаю на нотификашку и открываю прогу. В ней чищу кое-какие данные в бд,
и показываю кое-что на экране.

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

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


Ответы

Ответ 1



Всё намного проще, чем пишут другие. Когда вы создаёте Notification, вы передаёте ему Intent, который содержит информацию о том, какую Activity запустить при клике на Notification. Intent notificationIntent = new Intent(context, HomeActivity.class); // по клику на уведомлении откроется `HomeActivity` Так вот, достаточно просто добавить в этот Intent какие-нибудь данные о том, что это запуск из Notification, например так: notificationIntent.putExtra("isStartedFromNotification", true); Чтобы проверить это значение, делаем так: В onCreate() у HomeActivity добавляем if (getIntent().getBooleanExtra("isStartedFromNotification", false)) { //делаем, что надо в случае открытия из Notification } else { //делаем, что надо в случае открытия НЕ из Notification }

Ответ 2



Обычно, приложение получает уведомление через BroadcastReceiver. Можно из этого ресивера инициировать запись некой настройки. void onReceive(Context context, Intent intent) { context.getSharedPreferences("gcm", Context.MODE_PRIVATE) .edit() .putBoolean("notification_pending", true) .apply(); // Показать уведомление и тд. } Когда пользователь открывает программу "обычным способом", нужно проверить, есть ли запись о том что уведомление ждет void onCreate(Bundle savedState) { SharedPreferences prefs = getSharedPreferences("gcm", Context.MODE_PRIVATE); boolean needToDoStuff = prefs.getBoolean("notification_pending", false); if (needToDoStuff) { prefs.edit().remove("notification_pending").apply(); // TODO: Выполнить "необходимые действия" } } При этом когда пользователь открывает программу через уведомление, то этот код так же будет выполнен. Удачи!

Ответ 3



Мне кажется вот эта ссылка может помочь. Там пишется о том, что нужно зарегистрировать правильно GcmIntentServiце, который будет получать сообщение, даже если ваше приложение выключено. Также даются ссылки на Set up a GCM Client App on Android и Google Cloud Messaging

Ответ 4



Вобщем всем спасибо за ответы. Ближе всех был @pepyakin Так как я юзаю БД у себя в проекте я сделал так. когда получаю нотификацию, то в своем сервисе делаю просто public void broadcast(String messageType, final Bundle message) { if (!ScanActivity.ACTIVITY_STATUS) { new NotificationStorage() .setTicker("Receipt") .setTitle("Receipt") .setBundle(message) .setMessage(message.getString("receipt_id")).generateNotification(this); ReceiptQueue receiptQueue = new ReceiptQueue(); receiptQueue.setReceptId(message.getString("receipt_id")); ReceiptQueueDao.save(receiptQueue); } if (ScanActivity.ACTIVITY_STATUS) { Observer.getInstance().send(MessageType.RECEIPT_SHOW, message); } } тоесть тут моя проверка небольшая (открыто ли уже активити или нет). если открыто - я шлю обсервером нужное мне. если закрыто, то сохраняю данные нужные мне в БД. Дале два пути: 1. юзер тыкает на нотификацию 2. Юзер открывает через лаунчер В любом случае открывается активити, в котором я достаю данные из БД и если там чтото есть, делаю то что мне нужно. После этого очищаю табличку с этим данными. ВСЕ!)))

Ответ 5



Вообще штатными средствами для всех версий Android'а это сделать невозможно, остаются только хаки. Проблема в том, что к сервису управления нотификациями нет доступа штатными средствами. Есть хак, через AccessibilityService, описан здесь, но проблема с ним, в том, что юзер должен сначала включить в телефоне этот сервис - то есть гарантии что это будет работать нет. Второй вариант использование NotificationListener, но с ним проблема, что работает только для версии Android >= 4.3 Дальше остаются нудные варианты, если вы сами размещаете нотификацию, то можно в момент размещения нотификации где-то что-то сохранять, правда при этом совершенно неясно как убивать сохраненный флаг, когда юзер сам убьет нотификацию. А если не сами размещаете нотификацию, то тогда только хардкор типа вешать сервис, который просматривает список активных задач смотреть сервис нотификации, выискивать среди них свою нотификацию и все такое прочее.

C#. Как программе подключиться к БД access, если у пользователя microsoft access не установлен?

#c_sharp #база_данных #access


База данных в access, .mdb (97-2003г)
При подключении к базе данных использую следующую конструкцию

public OleDbConnection con1 = new OleDbConnection();
public OleDbCommand cmd1 = new OleDbCommand();
public void loadDb()
    {   
        con1.ConnectionString = Data.connectionString;
        cmd1.Connection = con1;
    }


где

Data.connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\\db.mdb";


Проверяю, есть ли подключение таким способом:

    public bool checkCon(OleDbConnection con)
    {
        try
        {
            con.Open();
            con.Close();
            return true;
        }
        catch
        {
            return false;
        }
    }


На моем пк подключение работает исправно. У преподавателя пишет, что не может цепануться
к бд. (Но у него Access есть на компьютере, однако отсутствует visual)
У знакомых некоторых цепляется (у них тоже установлен acess, visual studio)
У других подключение не создается. (нет access"a, нет visual studio)

Собственно, как быть?
Быть может ConnectionString изменить? Использовать более старые драйвера или как.
    


Ответы

Ответ 1



Вроде как сам разрешил проблему, корявенько конечно, ну как умею %) Для начала воспользовался информацией про connectionString https://www.connectionstrings.com/access/ Затем, Data.connectionString у меня формируется таким способом: StreamReader s = File.OpenText(Application.StartupPath + "\\path.txt"); Data.connectionString = s.ReadLine(); s.Close(); Data.connectionString = Data.connectionString + Application.StartupPath + "\\db.mdb"; Где path.txt содержит одну строку: Provider=Microsoft.Jet.OLEDB.4.0;Data Source=

Ответ 2



Так у Вас в решении ответ на Ваш вопрос. Если Вы в первом случае измените "Provider=Microsoft.ACE.OLEDB.12.0" на "Provider=Microsoft.Jet.OLEDB.4.0" все должно работать. В первом случае вы указываете что у Вас Access 2012 (по-моему, если не ошибаюсь), а во-втором (Jet.OLEDB.4.0) Вы указываете на Access 97-2003. Начиная с Access 2007 там большие изменения произошли.... Я боюсь напутать в версиях, но Microsoft.ACE.OLEDB.12.0 ставится, по-моему, с Net.Framework 4.5..., а Microsoft.Jet.OLEDB.4.0 стоит даже на ХР.

Регулярное выражение для разделения по запятым, кроме экранированных

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


Дано: Строка, например, вида такого: "Казнить|, нельзя, помиловать.".
Задача: Разделить строку по запятым, но там, где | (вроде экранирования), запятую
нужно игнорировать.
Т.е. должно вернуть это:

["Казнить|, нельзя", " помиловать."]


Возможно просмотр назад дал бы пользу, но в JS, где мне это нужно сделать, такой
фичи нет.
Максимум что добился - это деление по запятой (/([^,]+)/g, это было легко), без учёта
| (а тут забуксовал) и головная боль.
Заранее благодарен за любую помощь!

UPD:

По большому счёту не важно что будет номинально считаться экранированием запятой
- обратный слэш, пайп или квадратик из ASCII-арта, но некто в ответах упёрся бараном
в новые ворота на свойства экранирования \, поэтому теперь экранирует пайп.
    


Ответы

Ответ 1



Могу предложить решение с match вместо split: "Казнить|, нельзя, помиловать.".match(/([^\|,]|\|.)+/g) # ["Казнить|, нельзя", " помиловать."]

Ответ 2



Давайте отталкиваться от того, что javascript поддерживает негативный просмотр вперед. Тогда последовательность действий такова: Развернуть исходную строку Разбить полученную строку с помощью следующего регулярного выражения: /,(?![|])/ Развернуть каждый элемент полученного массива совпадений и сам массив совпадений, чтобы получить искомый результат Вот код: // (!!!) Будьте осторожны, используя эту функцию * var naiveReverse = function(string) { return string.split('').reverse().join(''); } var string = "Казнить|, нельзя, помиловать."; var reversed_array = naiveReverse(string).split(/,(?![|])/); var result_array = reversed_array.map(function(item) { return naiveReverse(item); }).reverse(); Результат: ["Казнить|, нельзя", " помиловать."] Составлено на основе ответов к этим вопросам на StackOverflow: Javascript: negative lookbehind equivalent? * How do you reverse a string in place in JavaScript?

Ответ 3



Вот вам такое уродство: "Казнить|, нельзя, по,мил|,овать.".replace(/([^\|])\,/g, '$1###').replace(/\|\,/g,',').split('###')

Ответ 4



Увидел что Вы отказались от регулярного выражения и решил предложить вариант, который, наверное, в тысячу раз быстрее будет - var text = "Казнить|, нельзя, помиловать."; function cut(text, search, ignore){ var startIndex = 0, endIndex = 0, result = []; while((endIndex = text.indexOf(search, endIndex)) > -1){ if(text.substring(endIndex, endIndex - 1) != ignore){ result.push(text.substring(startIndex, endIndex)); startIndex = endIndex; } endIndex++; } result.push(text.substring(startIndex, text.length)); return result; } console.log(cut(text, ',', '|')); // [ 'Казнить|, нельзя', ', помиловать.' ] var text = "Казнить|, нельзя, помиловать."; function cut(text, search, ignore){ var startIndex = 0, endIndex = 0, isNotComplete = true, isPush = false, result = []; while(isNotComplete){ isNotComplete = (endIndex = text.indexOf(search, endIndex)) > -1; if(isNotComplete && text.substring(endIndex, endIndex - 1) != ignore){ isPush = true; }else if(!isNotComplete){ isPush = true; endIndex = text.length; } if(isPush){ result.push(text.substring(startIndex, endIndex)); startIndex = endIndex; isPush = false; } endIndex++; } return result; } console.log(cut(text, ',', '|')); // [ 'Казнить|, нельзя', ', помиловать.' ]

Что должно попадать в коммит?

#java #eclipse #git #gitignore


Я пользуюсь Eclipse и Egit для работы с Git. Каждый раз, когда я делаю коммит, мне
предлагается выбрать из файлов которые нужно закоммитить. Часть файлов уже выбраны,
а часть нет. Из выбранных файлов мне Eclipse обычно предлагает закоммитить все измененные
java файлы а также некоторые class файлы и некоторые другие. Насколько я понимаю class
файлы генерируются автоматически и по идее их коммитить не обязательно так же как и
jar файлы. Но Eclipse мне регулярно предлагает их включать в коммит.

Подскажите как поступать в этом случае? Надо ли включать в коммит файлы с расширением
class, jar и другие? 
    


Ответы

Ответ 1



Если для соответствующего class файла у вас есть java файл, то включать class файл нет никакого смысла. Другое дело, что иногда у Вас есть только class файл, тогда наверное его стоит включить. Аналогично и с jar файлами. Если этот jar - продукт компиляции Вашего кода - нет смысла его включать. Если это сторонняя библиотека - возможно есть, а может проще просто правильно настроить maven/gradle, что бы он сам все умел вытянуть. Что бы git не предлагал включать ненужные файлы, их нужно добавить в список исключений - в файл .gitignore. В целом, в коммиты нужно включать то, что нужно для компиляции. Сторонний человек должен спулить репозиторий, открыть его в эклипсе и просто нажать "скомпилируй".

Ответ 2



Предложенный KoVadim инструмент для генерации .gitignore-файлов gitignore.io предлагает следующий файл для сочетания [java]+[eclipse]: # Created by https://www.gitignore.io ### Java ### *.class # Mobile Tools for Java (J2ME) .mtj.tmp/ # Package Files # *.jar *.war *.ear # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* ### Eclipse ### *.pydevproject .metadata .gradle bin/ tmp/ *.tmp *.bak *.swp *~.nib local.properties .settings/ .loadpath # Eclipse Core .project # External tool builders .externalToolBuilders/ # Locally stored "Eclipse launch configurations" *.launch # CDT-specific .cproject # JDT-specific (Eclipse Java Development Tools) .classpath # PDT-specific .buildpath # sbteclipse plugin .target # TeXlipse plugin .texlipse

Ассоциация программы с собственным типом файла

#c_sharp #net #winforms #clickonce


Имеется файл программы в виде:

[project]
type=MyApp 1.0 project
directory=D:\Папка проекта
Еще какие-то значения.


При открытии файла внутри программы (Файл->Открыть проект) всё работает замечательно.
Но появилась нужда открывать этот файл двойным щелчком.
С помощью ClickOne создал файл ассоциаций. 

Открытие проекта пытаюсь сделать так:

private void MainForm_Load(object sender, EventArgs e)
{
    string[] args = Environment.GetCommandLineArgs();
    if (args.Length >= 2)
    {
        MessageBox.Show("Открыт проект! УРА!");
        OpenProject(args[1]);
    }
}


В Program.cs прописано, что принимаются аргументы:

public static void Main(string[] args)


Как решить эту проблему?
    


Ответы

Ответ 1



При регистрации с помощью ClickOnce аргументы приходят не в командную строку, а в AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData: foreach (string arg in AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData) MessageBox.Show(arg);

Добавление приложения в “Open With” диалог Android

#java #android


Мое приложение работает с базами данных SQLite, хотелось бы, чтобы пользователь мог
увидеть мое приложение в диалоге "Открыть с помощью" при попытке открытии базы даных
в файловой системе. Как реализовать такое?
    


Ответы

Ответ 1



вместо \\.sqlite можете поставить любое другое расширение файла. И дальше в классе Activity: public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final Intent intent = getIntent(); final String action = intent.getAction(); if(Intent.ACTION_VIEW.equals(action)){ Uri uri = intent.getData(); new File(uri.getPath()); //дальше делаем все, что надо с файлом } else { Log.d(TAG, "intent was something else: "+action); } }

Ответ 2



Вам нужно в манифесте настроить интент-фильтр на расширение вашей базы ( либо на mime-тип ) подробности

Преобразование Bitmap ресурса в ImageSource

#c_sharp #wpf #xaml


Имеется Bitmap ресурс Properties.Resources.part1. Нужно установить этот ресурс в
свойство заполнения прямоугольника Rectangle.Fill. Но Fill свойство принимает только
тип ImageSource
    


Ответы

Ответ 1



Ваша задача имеет два решения: На одно @Mints97 привел ссылку Get ImageSource from Bitmap?, выглядит оно так: System.Drawing.Bitmap br = Properties.Resources.part1; System.Windows.Media.Imaging.BitmapSource b = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap( br.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); Но я бы не помещал рисунок в ресурсы, а поступил иначе: 1.Создал бы в проекте папку, например IMAGES; 2.Поместил ваш рисунок (part1) в эту папку; 3.Тогда бы код выглядел так: System.Windows.Media.Imaging.BitmapImage b = new BitmapImage( new Uri("pack://application:,,,/IMAGES/part1.bmp")); Ну и соответственно: rectangle.Fill = new ImageBrush(b);

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

#net


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


Ответы

Ответ 1



Зависит от того, что подразумевается под "загружаться". По умолчанию сборки загружаются с диска в память только один раз. Это можно проверить в окне Debug/Windows/Modules - сборка будет упомянута несколько раз, но значение в колонке Address для нее будет одним и тем же для разных доменов. Если этого недостаточно, то можно: Отметить точку входа вашего приложения как [LoaderOptimization(LoaderOptimization.MultiDomain)] - это позволит максимально шарить загруженные ресурсы между доменами. Под шарингом ресурсов подразумевается: возможность дополнительным доменам использовать готовые native image - результаты предварительного прохода NGEN. шаринг результатов JIT. Установить сборку в GAC и прогнать ее NGEN-ом - это тогда сборка будет загружаться в память не только один раз для различных AppDomain но и один раз для одновременно запущенных приложений, которые ее испольуют. Это обычный подход при хостинге большого количества одинаковых приложений - например, одинаковых сайтов на одном сервере.

Ответ 2



По идее, никак, AppDomain'ы изолированы друг от друга. Возможно, вы сможете обойти проблему тем, что загрузите эту сборку только в один AppDomain, и будете маршаллировать вызовы в него? Учтите, что это может оказаться медленнее, чем таки загрузить сборку в каждый AppDomain, тестируйте!

android ImageView разметка

#android #xml #изображения #разметка


Доброго времени суток. Подскажите, можно ли используя только лишь Layout-ы, не используя
Surface, Canvas и прочее, сделать подобное ( см. аттач )? Имеется ввиду именно расположение
контроллов с поддержкой landscape. Спасибо!

    


Ответы

Ответ 1



Да, можно. Нужна комбинация 5-6 (может и больше) вложенных друг в друга лейаутов. На верхнем уровне LinearLayout с горизонтальной ориентацией, далее в него 2 вложенных LinearLayout один с аватаркой, а второй (справа) содержащий все остальное. В правом надо будет организовать RelativeLayout, где слева большой ImageView а справа снизу Button. Мелкие ImageView сгруппировать в TableView с двумя строчками, в каждой строчке еще по одному RelativeLayout Это как бы версия, возможно она не сработает, а может и сработает. Но смысл простой - комбинацией различных типов лейаутов всегда можно нарисовать практически все что угодно. Еще ни разу не было, чтобы я не смог нарисовать какой угодно сложный набор. Дерзайте. Update Большой круг с фотиком можно например сделать так: Где drawable/ball: В итоге получится примерно так:

Ответ 2



А можно и без 5-6 наложений, надо всего лишь использовать RelativeLayout. Делал на скорую руку, так что сильно не пинайте. Update Для этих кругов используйте стиль из ответа @Barmaley и подключайте его через android:background

Внедрение списка зависимостей с помощью контейнера Castle.Windsor

#c_sharp #dependency_injection


В качестве IoC-контейнера используется Castle.Windsor.

Корневой элемент приложения - планировщик Scheduler, который выполняет в определенной
последовательности различные задания. Задания реализуют интерфейс IWorker, поэтому
я решил внедрить(inject) List в Scheduler(список заданий). Впоследствии, планируется
много различных типов заданий, сейчас их два: Cleaner и Writer. Cleaner нужен в одном
экземпляре, используем Синглтон. 
Необходимо правильно внедрить N экземпляров Writer, где N - количество XML файлов
в поддиректории приложения. Каждый из XML-файлов надо десериализовать и передать в
качестве входного параметра каждому Writerу. Т.е. надо внедрить в Schedulerимплементацию
для каждого XML. Как это правильно реализовать? Вообще какой паттерн используется в
таком случае? Фабрика?

Конфигурация контейнера Castle.Windsor:

var container = new WindsorContainer();
// Для внедрения List
container.Kernel.Resolver.AddSubResolver(new ListResolver(container.Kernel, true));
// Регистрация Scheduler
container.Register(CastleRegistration.Component.For().ImplementedBy);
// Регистрация Workers...
container.Register(CastleRegistration.Component.For().ImplementedBy());
container.Register(CastleRegistration.Component.For().ImplementedBy());
// ...количество зависит от количества файлов + каждому надо передать десериализованный
XML в качестве параметра
container.Register(CastleRegistration.Component.For().ImplementedBy());
// Забираем Scheduler
var sched = container.Resolve();


Scheduler:

public class Scheduler : IScheduler
{
    public IList Workers { get; set; }

    public Scheduler(IList workers)
    {
        Workers = workers;
    }
}


Writer:

public class Writer : IWorker
{
    public string Source { get; set; }

    public Writer()
    {
    }

    public Writer(string source)
    {
        Source = source;
    }
}


Cleaner:

public class Cleaner : IWorker
{
    public Cleaner()
    {
    }
}


UPDATE:
Дополнительный вопрос:

Содержимое Xml-файлов переехали в одну из таблиц БД. В Scheduler (корневой компонент)
нужно внедрить по Writerу с параметром на каждую запись в таблице. Из полезного совета
в ответе(Andrew Prigorshnev), следует, что обращаться к БД будет правильным после настройки
контейнера и получения из него корневого компонента.

С точки зрения архитектуры, правильным ли будет внедрить в Scheduler компоненты:
WriterFactoryи Repository(слой доступа к БД), после чего получить экземпляр Scheduler,
затем в нем с помощью Repository получить список параметров, а потом сделать на каждый
параметр по Writerу с помощью WriterFactory?
    


Ответы

Ответ 1



Насколько я понимаю в наиболее общем виде вопрос состоит в следующем: как правильно внедрить список зависимостей с помощью контейнера Castle Windsor? Ответ следующий. Сам подход с внедрением списка через конструктор вполне корректный и Castle Windsor умеет работать с такими сценариями. Чтобы внедрить список зависимостей надо сделать следующее: Зарегистрировать в контейнере резолвер списков. Вы это уже сделали в строчке container.Kernel.Resolver.AddSubResolver(new ListResolver(container.Kernel, true)); Зарегистрировать в контейнере несколько компонентов, которые должны быть внедрены в виде списка. При этом если вы внедряете список типа IList контейнер добавит в список все компоненты типа IWorker, которые вы зарегистрируете. Это вы сделали частично. В вашем примере не учтено, что когда вы регистрируете несколько одинаковых компонентов они должны быть именованными (делается с помощью метода .Named()), и по всей видимости вы не знаете как внедрить строку в конструктор компонента - это делается с помощью метода .DependsOn() Таким образом правильная реализация вашей задачи должна выглядеть вот так: var container = new WindsorContainer(); // Для внедрения List container.Kernel.Resolver.AddSubResolver(new ListResolver(container.Kernel, true)); // Регистрация Scheduler container.Register(Component.For().ImplementedBy()); // Writers container.Register(Component .For() .ImplementedBy() .DependsOn(Dependency.OnValue("source", "files/first.xml")) .Named("firstWriter")); container.Register(Component .For() .ImplementedBy() .DependsOn(Dependency.OnValue("source", "files/second.xml")) .Named("secondWriter")); container.Register(Component .For() .DependsOn(Dependency.OnValue("source", "files/third.xml")) .ImplementedBy() .Named("thirdWriter")); // Cleaner container.Register(Component.For().ImplementedBy()); // Забираем Scheduler var scheduler = container.Resolve(); И еще несколько замечаний, касающихся конкретно вашей реализации: Вы хотите передавать в воркеры xml, но это плохая идея. Тогда вам придется прочитать его из файла прямо в корне компоновки, в том месте где вы настраиваете контейнер. Но чтение из файла это отдельная задача, никак не связанная с разрешением зависимостей, поэтому делать ее в корне компоновки не стоит. Пусть этим занимается один из ваших компонентов. В связи с этим, в примере кода выше вы можете увидеть что во Writer'ы передается путь к файлу, а не его содержимое. Если файлы, которые вы обрабатывате меняются редко и их имена и количество известны на этапе написания кода, пример приведенный выше может вас полностью устроить. Но если это не так, надо сделать еще немного дополнительной работы, и как вы правильно предположили, надо использовать фабрики. Возможное решение здесь следующее. Надо добавить новую абстракцию - поставщик воркеров, который будет представлять собой фабрику, создающую воркеры: public interface IWorkersProvider { IEnumerable GetWorkers(); } Поставщик Cleaner'ов будет просто возвращать один Cleaner. А поставщик Writer'ов может получать как аргумент конструктора путь к папке, в которой надо искать файлы, и затем в методе GetWorkersсоздавать по одному воркеру на каждый найденный файл: public class WritersProvider : IWorkersProvider { public WritersProvider(string folderPath) { } public IEnumerable GetWorkers() { // здесь создаем по одному воркеру на каждый найденный файл } } При такой архитектуре ваш Sheduler должен получать вместо списка воркеров, список поставщиков воркеров: public class Scheduler : IScheduler { public Scheduler(IList providers) { // здесь надо опросить все поставщики, чтобы сформировать // список воркеров } } Регистрация такой конфигурации в Castle Windsor делается с помощью тех же методов, что и регистрация в первом примере, поэтому не буду здесь ее описывать. UPDATE: Ответ на дополнительный вопрос Лучше сделать так: В Scheduler внедрить список поставщиков воркеров (IEnumerable), как описано выше Внедрить Repository в конструктор WritersProvider и уже во WritersProviderопрашивать базу данных Идея здесь вот в чем. Каждый класс должен выполнять одну единственную задачу. Задача Scheduler-а взять готовый список воркеров и запустить их. Задача поставщиков воркеров - создать воркеры на основе какого-то правила (из xml-файлов, таблиц бд и т.д.). Разделив обязанности таким образом, вы получите код, который легко модифицировать. Если вы захотите поменять что-то в логике запуска воркеров, вы прийдете и поменяете только один класс - Scheduler, при этом вы будете уверены, что вы никак не сломали логику создания воркеров, потому что эту работу выполняют совсем другие классы. Потенциально у вас может быть множество поставщиков воркеров, работающих по разным правилам. Один поставщик может всегда возвращать один и тот же жестко закодированный воркер, второй создавать по воркеру на каждый xml-файл в какой-нибудь директории, третий создавать воркеры на основе таблицы в базе данных, четвертый получать список воркеров, которые надо создать, у удаленного сервиса и т.д. Более того, в процессе развития проекта у поставщика воркеров может меняться правило, по которому он создает воркеры (у вас это уже произошло - вместо xml-файлов у вас теперь таблица в бд.) Если поставщику воркеров для выполнения его работы нужен доступ к бд, внедряйте Repository прямо в поставщик. Если потом это правило изменится, прийдете и поменяете только конкретный поставщик, не трогая другие поставщики и не трогая Scheduler. Вариант с фабрикой похуже, но тоже годится. Но если будете внедрять фабрику воркеров то Repository внедряйте уже в нее, а не в Scheduler. Фабрика хуже, потому что, когда количество воркеров вырастет, вы все равно будете вынуждены разнести создание воркеров разных типов по отдельным классам, иначе фабрика будет слишком большой и запутанной. В итоге вы все равно создадите несколько фабрик (что полность аналогично моему варианту со списком поставщиков воркеров, отличие только в названии, фабрика и поставщик в данном случае одно и то же).

“Тонкая блокировка” в хэш-таблицах

#алгоритм #многопоточность


В чем суть "тонкой блокировки" в хэш-таблицах и как её реализовать?
    


Ответы

Ответ 1



Суть в том, что с каждым входом (цепочкой синонимов хэш-функции) связывают свой mutex. Реализация на Си тривиальна: struct hash_entry { pthread_mutex_t mutex; struct hash_item *list; // если, например, используете односвязный список }; При создании таблицы struct hash_entry table[HASH_SIZE]; устанавливаете table[i].list в NULL и вызываете pthread_mutex_init(&table[i].mutex, 0); (если нет особых требований к атрибутам мьютекса). Update После комментария от @VladD решил добавить немного рассуждений на тему параллельной работы с хэш-таблицей. В принципе для действий, затрагивающих всю таблицу, можно добавить rwlock (см., например, man pthread_rwlock_init и др. man для pthread_rwlock...). Тогда функции, требующие "тонкой блокировки" будут вызывать pthread_rwlock_t tablock; ... pthread_rwlock_rdlock(&tablock); // совместная блокировка таблицы int i = hash_func(key, keylen) % HASH_SIZE; pthread_mutex_lock(&table[i].mutex); // блокировка цепочки // действия с цепочкой синонимов ... pthread_mutex_unlock(&table[i].mutex); pthread_rwlock_unlock(&tablock); а функции, которые затрагивают всю таблицу pthread_rwlock_wrlock(&tablock); // монопольная блокировка таблицы // действия с таблицей ... pthread_rwlock_unlock(&tablock); т.е. получаем схему писатель-читатели с вложенной монопольной блокировкой цепочек коллизий. Однако, на мой взгляд, в большинстве случаев подобные схемы (и вообще "тонкая блокировка") не оправдывают возлагаемых на них надежд из-за накладных расходов на блокировку. Реально, если не удается вообще уйти (а к этому всегда надо стремиться (KISS-принцип)) от многопоточной работы с таблицей, выгодней просто блокировать ее всю, независимо от вида операций, поскольку обычно цепочки синонимов короткие и большинство операций с элементами таблицы весьма быстрые. Еще одним доводом в пользу такого подхода может быть тривиальная экономия памяти (размер объекта pthread_mutex_t 40 байт на 64-bit X_86), которая (как это ни странно, на первый взгляд) часто приводит к ускорению программы (поскольку доступ к памяти может быть раз в 100 медленней доступа к кэшу). Если возникают сомнения по поводу времени работы самой хэш-функции от ключа (например, известно, что ключи на самом деле весьма длинные и используется какая-то изощренная схема хэширования), то ее вычисление можно проводить до блокировки таблицы (а вот вычисление самого индекса, конечно же, уже получив блокировку).

Как реализован счётчик лайков ВКонтакте?

#javascript #jquery #вконтакте


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

При этом в коде число 555 не разбивается на цифры, вставленные в div'ы или span'ы,
а отображается в блоке post_like_counter целиком.

Каким образом это реализовано? 
    


Ответы

Ответ 1



У вас вопрос построен на неверном предположении, что число не разбивается на цифры. А оно разбивается. Взгляните на DOM в момент перехода. Вот скриншот из Chrome Dev Tools посреди перехода из 13 в 14. counter_const для цифры 1, которая осталась неподвижной. классы counter_anim_* для цифр 3 и 4, участвующих в анимации. Как убедиться? Chrome Dev Tools это штука довольно продвинутая. Найдя элемент DOM, в котором должны произойти изменения, можно щёлкнуть на нём правой кнопкой мыши и установить на нём "Break on" > "Subtree modifications". Тогда любые изменения в этом поддереве приведут к останову всех процессов на странице и запуску JS-отладчика (хотя в данном случае это вторично).

OpenGL Освещение

#cpp #qt #opengl #qt5


Проблема: некорректно работает освещение, выглядит так, будто источник света перемещается
параллельно с вращением объекта. По идее источник света должен быть статичным. Объект
может вращается вокруг своего центра с помощью мыши (и функции glRotated()).
Код:  

//Инициализация света, находится в методе initializeGL()
//Часть параметров такие же как и стандартные
GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f }; 
GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightSpecular[]= { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightPosition[]= { 10.0f, 10.0f, 10.0f, 1.0f };
glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); //Я предположил, что загрузка единичной матрицы мне поможет, но нет
glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
glLightfv(GL_LIGHT1, GL_SPECULAR, LightSpecular);
glEnable(GL_LIGHT1); //Источник света один


//Отрисовка фигуры
void Canvas::drawAll() //Отрисовка всех фигур
{
   names = 0;
   for(int i = 0; i < figures; i++)
   {
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
      glTranslated(motionX, motionY, zoom); //motionX/Y вычисляются при перемещении
курсора при нажатой ПКМ
      glRotated(rotationX, 1.0, 0.0, 0.0); //rotationX/Y также, только при ЛКМ
      glRotated(rotationY, 0.0, 1.0, 0.0);
      if(allFigures[i]->visible)draw(allFigures[i]);
   }
}


Пишу на Qt5.3. Вот как это выглядит: ссылка
    


Ответы

Ответ 1



Оказалось что это ответ: Похоже на глючные нормали

Прозрачность в navigationBar

#java #android #material_design


Каким образом можно сделать прозрачность у Navigation Bar, как на картинке?



update:





    

    

    



    


Ответы

Ответ 1



Работает на api >= 19 Тема: Теперь мы можем указывать paddingBottom для ListView вместе с android:clipToPadding="false", иначе список будет перекрываться Navigation Barом. В обще это применительно ко всем элементам. Для корневых элементов активности я указываю paddingBottom с отрицательным значением = -navigationBarHeight, потом для дочерних делаю обратный отступ как в примере ниже. Пример: android:clipToPadding="false" - не обрезать элементы, выходящие за пределы размеров элемента. update: Стили: 28dp -28dp 72dp -72dp Разметка главной (Toolbar заменяет ActionBar) Как использовать Toolbar вместо ActionBar, наследуемся (начиная c 22.1) с android.support.v7.app.AppCompatActivity: Toolbar app_bar = (Toolbar) findViewById(R.id.app_bar); setSupportActionBar(app_bar); В общем это на изучения с конкретным работающим примером. Ссылку на google play выложить не могу, только завершается разработка версии 1.0.

Как создать ассерт времени компиляции(аналог static_assert) в C?

#c #компиляция #отладка


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

В С++ для этого применяется static_assert. 

Примеры:

Утверждение о версии подключенной библиотеки: 

#include "SomeLibrary.h"

static_assert(SomeLibrary::Version > 2, "Старые версии SomeLibrary не поддерживаются,
используйте новые.");


Утверждение о количестве бит в unsigned int:

static_assert(sizeof(unsigned int) * CHAR_BIT == 32, "Компиляция на неподдерживаемой
платформе");


Как создавать подобные утверждения в обычном C, где есть только ассерты времени выполнения
в виде макроса из assert.h?
    


Ответы

Ответ 1



Для этого можно использовать любую ошибку компиляции, например структуры с битовыми полями отрицательного размера: #define CT_ASSERT_NULL(x) ((void *)sizeof(struct { int:-!!(x); })) #define CT_ASSERT_ZERO(x) sizeof(struct { int: -!!(x); })) #define CT_ERROR sizeof(struct { int: -1;}); Кроме того такая функция добавлена, начиная со стандарта C11 и в gcc-4.6 теперь можно делать так: _Static_assert( sizeof(int) == sizeof(long int), "Error!");

Реализация condition variables

#cpp #windows #winapi


Подскажите правильную реализацию condition variables. Реализовал на WaitForMultipleObjects()
и PulseEvent() , и получил баг, когда поток не просыпался, оказалось это проблема в
PulseEvent(). Подскажите правильную реализацию в которой поток будет точно просыпаться
и работать как надо.
    


Ответы

Ответ 1



Начиная с Vista, WinAPI содержит синхронизационные примитивы наподобие CONDITION_VARIABLE, которые делают именно то, что вам нужно. Вот пример использования (из официальной документации): CONDITION_VARIABLE cv; CRITICAL_SECTION lock; InitializeConditionVariable (&cv); InitializeCriticalSection (&lock); ... // ожидание EnterCriticalSection(&lock); while (!(условие)) // защищаемся от spurious wakeup SleepConditionVariableCS(&cv, &lock, INFINITE); // работать с данными можно только внутри критической секции // и при выполнении условия работаем_с_данными(); LeaveCriticalSection(&lock);

Парсинг html с помощью Jsoup

#android #jsoup #синтаксический_анализ


Есть html строка:

DSC_0320_1

Нужно получить адрес изображения:http://www.postfactum.ks.ua/wp-content/uploads/2015/06/DSC_0320_1-300x163.jpg. Пытаюсь парсить: Document doc = Jsoup.parse(image_url); if (doc.select("img[src]").size() > 0) { Element image = doc.select("img[src]").get(0); } else { image_url = "null"; } Ошибок нету, но строка пуста. В чем может быть проблема?


Ответы

Ответ 1



Во-первых вам нужно использовать метод first() или last() в зависимости от порядка елемента. В вашем случае нужно использовать метод first(). Element image = doc.select("img[src]").first();. Во-вторых вы не указали атрибут "src": image_url = image.attr("src");. Полный код: Document doc = Jsoup.parse(mage_url); if (doc.select("img[src]").size() > 0) { Element image = doc.select("img[src]").first(); image_url = image.attr("src"); } else { image_url = "null"; }

WPF Interactions CallMethodAction для DataTemplate в ListCheckBox ругается на входные параметры метода во ViewModel

#c_sharp #wpf #checkbox


Пытаюсь воспользоваться механизмом поведения, однако не могу правильно прописать
аргументы в методе во ViewModel. Использую ListBox состоящий из item включающих в себя
CheckBox, собственно перепробовал разные комбинации входных параметров метода, но никак
не могу получить объект Item из ListBox при снятии галочки у CheckBox.

XAML


            
                
                    
                               
                            
                                
                                    
                                
                            
                        
                        
                        
                            
                        
                        
                    
                
            
        


C#

public void PropertyUnchecked()
{
    MessageBox.Show("Unchecked");
}


в итоге получаю ошибку:


  Thrown: "Could not find method named 'PropertyChecked' on object of
  type 'CheckedListItem 1' that matches the expected
  signature."(System.ArgumentException)   Exception Message = "Could not
  find method named 'PropertyChecked' on object of type
  'CheckedListItem`1' that matches the expected signature.", Exception
  Type = "System.ArgumentException", Exception WinRT Data = null


Исходя из сообщения, я посчитал, что метод в коде ViewModel не имеет нужных входных
параметров (CheckedListItem именно такие итемы хранятся в ListBox), начал
экспериментировать:

[1]    

public void PropertyUnchecked(CheckedListItemtr, object sender, RoutedEventArgs e)
{
    MessageBox.Show("Unchecked");
}


[2] 

public void PropertyUnchecked(object sender, RoutedEventArgs e)
{
    MessageBox.Show("Unchecked");
}


[3] 

public void PropertyUnchecked(object sender)
{
    MessageBox.Show("Unchecked");
}


Также поэкспериментировал с разметкой:


    
        
            
        
    



С такой разметкой заработал пустой C# метод, а также [2] и [3], однако ничего кроме
CheckBox и его свойств как элемента (в sender) мне не пришло, но нужен именно Item
в котором сидит объект типа CheckedListItem .
Нашел как реализовать нечто подобное командами с параметрами, но мне нужен именно
вызов метода, и обойтись без команд.
    


Ответы

Ответ 1



Я получил ответ на свой вопрос, звучит он так: This is probably what you're looking for: public void PropertyUnchecked(object sender, RoutedEventArgs e) { var item = ((ContentPresenter)((CheckBox)e.Source).TemplatedParent).Content as CheckedListItem; } Собственно сам вопрос и ответы доступны по ссылке: Вопрос и ответ

Как показать N последних тегов (меток)?

#git #git_tag


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

git tag

v1.0.0
v1.1.0
v2.0.0
v2.0.0RC1
v2.0.0RC2
v2.0.0RC3
v2.0.1
v2.1.0
v2.1.0RC1
v2.1.0RC2


Что я хочу:

git magic

v2.1.0RC2
v2.1.0RC1
v2.1.0


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




Для будущей пометки связанных вопросов на разных языках: https://stackoverflow.com/questions/30805098/how-to-display-last-n-tags-in-git 
    


Ответы

Ответ 1



С помощью git tag --sort (Git v 2.0.0+ ) Обратите внимание, я использую знак минуса -, чтобы инвертировать порядок сортировки (по умолчанию используется от более старых к новым). UNIX, Linux, OS X: утилита head git tag --sort=-version:refname | head -n Windows, UNIX-way Установите Cygwin Используйте ответ для UNIX Windows, команда Select git tag --sort=-version:refname | Select -First С помощью git describe git describe --tags $(git rev-list --tags --max-count=) (Это перевод собственного ответа. Вариант с describe предложен @hsirah.)

Высота iframe по контенту

#javascript #html5 #css3 #iframe


Друзья,перелопатил половину интернета, но рабочего решения так и не нашел. В общем,
в iframe необходимо загрузить сайт и взять его высоту, пробовал плагин iFrame Resizer,
высота не менялась, стандартные 150рх, пробовал easyXDM - ошибка, пробовал вот такую штуку

function doIframe() {
  o = document.getElementsByTagName('iframe');
  for (i = 0; i < o.length; i++) {
    if (/\bautoHeight\b/.test(o[i].className)) {
      setHeightIframe(o[i]);
      $(o[i]).load(function() {
        doIframe();
      });
    }
  }
}

function setHeightIframe(e) {
  if (e.contentDocument) {
    $(e).height(e.contentDocument.body.offsetHeight + 35);
  } else {
    $(e).height(e.contentWindow.document.body.scrollHeight);
  }
}

    


Ответы

Ответ 1



Если я правильно понял Ваш вопрос: Вы хотите загрузить в iframe некоторый контент, но проблема в том, что Вы не знаете высоту загружаемого контента, и соответственно не знаете какую высоту iframe-а Вам нужно указать. Я сталкивался с подобной проблемой, когда мы разрабатывали виджеты, например для edx. Вы не можете выставить высоту iframe во "внутренностях" iframe. Как вариант, Вы можете посчитать высоту во "внутренностях" iframe и передать ее в js который подключает iframe в родительском окне. Для того чтобы связать js во "внутренностях" iframe и js в родительском окне, мы использовали библиотеку от Mozilla jschannel. Обратите внимание, что высота загруженного контента не всегда будет одинаковой, к изменению высоты могут привести как изменение ширины окна браузера (если у Вас респонсив страница) так и действия пользователя внутри iframe - все эти кейсы можно решить добавляя новые события к jschannel. В случае если у Вас нет доступа к содержимому iframe и Вы хотите получить его высоту, к сожелению, я не знаю что Вам можно посоветовать, и вообще возможноли это.

Различное отображение rgba у border-color и backgroud

#css


Устанавливаю одно и то же значение rgba(0,0,0,.1) для border-color и background.
Получается так, что граница немного темнее фона.
Почему так происходит, и можно ли это как-нибудь отключить?

Пример на input'e:

input[type="text"], input[type="password"] {
    float: left;
    margin: 0;
    outline: none;
    padding: 0 9px;
    height: 28px;
    background: rgba(0,0,0,.1);
    border: 1px solid rgba(0,0,0,.1);
    border-radius: 3px;
    line-height: 30px;
}


Мне надо, чтобы обводка была темнее, поэтому сделал их одинаковыми. Везде ли так будет?
    


Ответы

Ответ 1



Так происходит, потому-что фон "заползает" под border. И видно этот эффект, потому-что цвет бордера у вас с прозрачностью, происходит накладывание цветов, поэтому бордер становится чуть темнее. Это стандартное поведение, если вам необходимо его изменить, то почитайте про свойство background-clip : http://htmlbook.ru/css/background-clip

Ответ 2



фоновый цвет для input черный с 10% прозрачностью к нему добавляется border тоже на 10% и получается 20% то есть rgba(0,0,0,.2);

Как добавлять файлы в Git по их номеру в отчете `git status`?

#git #git_add #git_status


Я часто сталкиваюсь со следующей ситуацией:

modified:   assembly/main.debug.s
modified:   ../src/cd/Config.java
modified:   ../src/cd/memoization/cfg/SubgraphFinder.java
modified:   ../src/cd/memoization/cfg/SubgraphMap.java
modified:   ../src/cd/profiler/Profile.java
modified:   ../test/cd/test/TestSamplePrograms.java
modified:   ../../notes/20150521.txt


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

git magic-status

1 modified:   assembly/main.debug.s
2 modified:   ../src/cd/Config.java
3 modified:   ../src/cd/memoization/cfg/SubgraphFinder.java
4 modified:   ../src/cd/memoization/cfg/SubgraphMap.java
5 modified:   ../src/cd/profiler/Profile.java
6 modified:   ../test/cd/test/TestSamplePrograms.java
7 modified:   ../../notes/20150521.txt

git magic-commit 2,3,5 -m "Простой и удобный способ"


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


Для пометки связанных вопросов на разных языках: https://stackoverflow.com/questions/30411901/how-to-add-specific-files-in-git-by-their-number-in-git-status

Это перевод собственного ответа с EN.SO
    


Ответы

Ответ 1



Демонстрационный репозиторий: Для примеров я использую репозиторий с четырьмя файлами: a, b, c, d. Из них a - отслеживается, изменен, добавлен (tracked, changed and staged); b отслеживается, изменен, но не добавлен (tracked, changed and not staged); c не отслеживается, но добавлен; d просто ещё не отслеживается. 1. Отдельная утилита: git-number При запуске без аргументов, git number выполняет обычный git status, добавляя уникальный номер каждой выводимой строке с именем файла. Он "запоминает" соответствие номера файлу. При запуске с аргументами: $ git number <любая команда git> [одно или несколько чисел, и/или --аргументов] git number запускает эту <любую команду>, заменяя все числа соответствующими именами файлов. Нечисловые аргументы передаются в git без изменений. Пример с командой diff : 2. Отдельная утилита: SCM Breeze SCM Breeze - это набор shell-скриптов для bash и zsh. Он дает новые возможности работы с Git. Он интегрируется в вашу командную оболочку и добавляет упоминание файла по номеру, индекс репозитория с автодополнением по Tab и многие другие функции. SCM Breeze использует горячие клавиши и псевдонимы (aliases) команд: Ctrl + x, c => git_add_and_commit - добавить выбранные файлы и сделать коммит всех добавленных изменений. Ctrl + x, Space => git_commit_all - сделать коммит всех имеющихся изменений. git add: $ ga 1 git diff: $ gd 2 git reset: $ grs 3 git commit: $ gco 4 3. "Родными" средствами: git add -i git add -i Из Git reference: -i --interactive Добавить содержимое рабочей папки в индекс в интерактивном режиме... Этот режим можно запомнить как -iнтуитивный, поскольку он невероятно понятен и удобен (по крайней мере, для бывалого пользователя Vim). Если не можете выйти из режима добавления, нажмите Return с пустой строкой. Входим в интерактивный режим: Добавляем измененный отслеживаемый файл: Добавляем неотслеживаемый файл: Смотрим на результат: Если вам интересно, что это за консоль/цвета/оформление: iTerm2 + zsh + oh-my-zsh

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

#алгоритм #массивы #любой_язык


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

Например, для массива arr[4, 50, 11, 20] это будут 1 и 3 (arr[1], arr[3]) - индексы
максимальных значений.
    


Ответы

Ответ 1



Ну, почему бы не пробежаться по массиву и держать текущие k наибольших значений? Вот вам псевдокод: list maximalK = empty // инвариант: maximalK содержит отсортированный список наибольших // k из всех просмотренных элементов foreach e in sourceList p = position of e in maximalK // (binary search) if (p >= k) continue insert e into maximalK at position p if maximalK.size > k remove last from maximalK Заметьте, что при k == sourceList.size вы получаете просто алгоритм сортировки (бинарными) вставками. Временная сложность: O(n * k) (n — размер списка), за счёт сдвига при вставке. (Используя sorted map для maximalK, можно уменьшить до O(n * log k).)

Дружественная функция из другого класса

#cpp #классы


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

// файл Complex.h
#include "Float.h"
class Complex
{
private:
    Float Re, Im;
public:
    Complex(Float re, Float im);
    void readFloat(Float);
};
// файл Complex.cpp
#include "Complex.h"
#include 
using namespace std;
void Complex::readFloat(Float)
{
    cout << "Чтение из дружественной функции: " << Re.Num;
}
// файл Float.h
class Float
{
private:
    float Num;
public:
    Float(float num);
    friend void Complex::readFloat(Float);
};

    


Ответы

Ответ 1



Не получается потому, что для объявления дружественного метода требуется полное определение Complex, ведь вы обращаетесь к его члену. Самый простой вариант - сделать другом не метод, а весь класс Complex: // файл Float.h class Float { private: float Num; public: Float(float num); friend class Complex; }; Если, всеж таки, необходим именно дружественный метод, тогда нужно обеспечить чтобы полное определение Complex гарантированно происходило до определения Float. Это можно сделать, применив технику с предварительным объявлением (forward declaration) Float в файле Complex.h: // файл Complex.h // #include "Float.h" // этот инклюд нужно убрать class Float; // предварительное объявление class Complex { private: Float * Re; Float * Im; public: Complex(Float & re, Float & im); ~Complex(); void readFloat(Float &); }; // файл Complex.cpp #include #include "Complex.h" #include "Float.h" // а здесь он нужен void Complex::readFloat(Float&) { std::cout << "Чтение из дружественной функции: " << Re.Num; } // файл Float.h #include "Complex.h" // мы обращаемся к членам Complex // поэтому он должен быть объявлен заранее class Float { private: float Num; public: Float(float num); friend void Complex::readFloat(Float&); }; Техника работает следующим образом. Так как в файле Complex.h используются только указатели и ссылки на Float компилятору для вычисления размеров этих переменных и полей не требуется полное определение класса Float. Ведь размер указателей и ссылок фиксированный и заранее известен, вне зависимости от того, на что они указывают или ссылаются. Компилятору нужно только намекнуть что понимается под именем Float то есть что он класс, а не структура например. Компилятор не может работать с неизвестными именами. Из-за этой тонкости, можно убрать #include "Float.h" из файла Complex.h. Однако, когда мы обращаемся к членам Float необходимо его полное определение, поэтому в файле Complex.cpp обязательно наличие #include "Float.h". После всего этого можно безопасно добавлять #include "Complex.h" в файле Float.h. В результате всех этих манипуляций получается, что класс Complex всегда определен до Float, хотя объявлен Float раньше Complex. Ну и в итоге, как вы помните, строгий порядок определений классов позволяет нам законно объявить дружественным метод Complex::readFloat.

Как узнать используемую память

#java #intellij_idea


Как можно узнать сколько памяти занимает выполнение программы или класса в Intellij
Idea? 
    


Ответы

Ответ 1



Есть такой инструмент как jmap, выводящий гистограмму с показателями сколько памяти занимают объекты и т.п. Также, утилиту jstat можно использовать для сбора самых разнообразных статистических данных. Статистика jstat сортируется в "свойства", указанные первым параметром командной строки. Чтобы увидеть список свойств, нужно запустить jstat с параметром -options. В документации утилиты в JDK говорится, что именно показывает каждое из свойств, но большинство из них используется для сбора информации о работе сборщика мусора или его компонентов. Свойство -class показывает загруженные и выгруженные классы (что делает утилиту полезной для обнаружения утечек ClassLoader в пределах сервера приложений или вашего кода), а -compiler и -printcompilation предоставляют сведения о JIT-компиляторе Hotspot. По умолчанию jstat отображает информацию по состоянию на момент обращения. Если нужны регулярные снимки текущего состояния, укажите после -свойств интервалы в миллисекундах. jstat будет постоянно отображать снимки текущего состояния контролируемого процесса. Если нужно, чтобы jstat сделал лишь определенное количество снимков, укажите его за значением интервала/периода.

Ответ 2



Можете включить индекатор памяти в File | Settings | Appearance and Behavior | Appearance поставить галочку в Show Memory Indecator ссылка

Ответ 3



Можно запустить java с выводом данных gc, например -verbose:gc параметр, посмотреть что он будет выводить, там данных будет достаточно. Второй вариант, использовать jstat

Передача данных без сервера

#c_sharp #передача_данных


К программе нужно добавить функционал передачи данных между ноутбуками. Написана на С#.
Есть доступ к интернету через WiFi. Есть пара ноутбуков.


Как передать файл с одного на другой? 
Как найти ір адрес другого ноутбука?


Как вариант можно использовать торрент сеть, но тогда другой вопрос.
Как ее прикрутить к С# проекту?
    


Ответы

Ответ 1



Вы пытаетесь решить две раздельных проблемы (в каждой из которых "сервер" используется в своем смысле) Первая - поиск второго ноутбука. В этой проблеме "сервер" - это какая-то машина, которая знает про все ноутбуки, и к которой ноуты обращаются за списком других ноутов. От этого сервера можно избавится. В System.Net.PeerToPeer есть пачка классов для поддержки одноранговых сетей. Примеры слишком объемны чтобы привести их в ответе, но можете начать с MSDN Blogs: Writing Peer-to-Peer Applications Using .NET: Регистрация peer: PeerName peerName = new PeerName("MikesWebServer", PeerNameType.Secured); PeerNameRegistration pnReg = new PeerNameRegistration(); pnReg.PeerName = peerName; pnReg.Port = 80; //OPTIONAL //The properties set below are optional. You can register a PeerName without setting these properties pnReg.Comment = "up to 39 unicode char comment"; pnReg.Data = System.Text.Encoding.UTF8.GetBytes("A data blob associated with the name"); /* * OPTIONAL *The properties below are also optional, but will not be set (ie. are commented out) for this example *pnReg.IPEndPointCollection = // a list of all {IPv4/v6 address, port} pairs to associate with the peername *pnReg.Cloud = //the scope in which the name should be registered (local subnet, internet, etc) */ //Starting the registration means the name is published for others to resolve pnReg.Start(); Console.WriteLine("Registration of Peer Name: {0} complete.", peerName.ToString()); Console.WriteLine(); Console.WriteLine("Press any key to stop the registration and close the program"); Console.ReadKey(); pnReg.Stop(); Поиск и получение информации о зарегистрованных: // create a resolver object to resolve a peername PeerNameResolver resolver = new PeerNameResolver(); // the peername to resolve must be passed as the first command line argument to the application PeerName peerName = new PeerName(args[0]); // resolve the PeerName - this is a network operation and will block until the resolve completes PeerNameRecordCollection results = resolver.Resolve(peerName); // Display the data returned by the resolve operation Console.WriteLine("Results for PeerName: {0}", peerName); Console.WriteLine(); int count = 1; foreach (PeerNameRecord record in results) { Console.WriteLine("Record #{0} results...", count); Console.Write("Comment:"); if (record.Comment != null) { Console.Write(record.Comment); } Console.WriteLine(); Console.Write("Data:"); if (record.Data != null) { Console.Write(System.Text.Encoding.ASCII.GetString(record.Data)); } Console.WriteLine(); Console.WriteLine("Endpoints:"); foreach (IPEndPoint endpoint in record.EndPointCollection){ Console.WriteLine("\t Endpoint:{0}", endpoint); Console.WriteLine(); } count++; } Console.ReadKey(); Вторая - собственно передача файла. Тут "сервер" - это комп, принимающий входящее соединение. Или комп, отдающий файл. Т.к. к этому моменту у вас будет адрес второго ноута, то достаточно взять любой пример по работе с сокетами, вычитать файл как массив байт, и передать его на другую сторону вместо строки из примера. И если вдруг не заработает - оформить это отдельным вопросом.

Не получается сделать правильный массив целых чисел и чисел с десятичными дробями

#php #html #jquery #регулярные_выражения


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

1 × 360.000 руб.


Я пробую из нее вытащить массив:

var quantity = $(".quantity").text().match(/\d+\.\d+/g)


получаю массив ["360.000"]
делаю вот так

var quantity = $(".quantity").text().match(/\d+/g)
match(/\d+/g)


Я получаю: ["1", "360", "000"]

Мне нужно получить ["1", "360.000"].

Что я делаю не правильно?
    


Ответы

Ответ 1



Необходимо поправить выражение вот так: var quantity = $(".quantity").text().match(/\d+(?:\.\d+)?/g) Объяснение: \d+ - 1 или более цифр (?:\.\d+)? - Необязательная группа, которая находит \. - точку \d+ - 1 или более цифр Если необходимо, можно добавить знаки + или -, но мне кажется, что это в Вашем случае не нужно. А вот как это выражение выглядит на рисунке: Демо на Debuggex В сети есть множество сервисов для расшифровки и отладки регулярных выражений, например вышеупомянутый Debuggex и Regex101. Пример кода: var quantity = $(".quantity").text().match(/\d+(?:\.\d+)?/g) console.log(quantity);
1 × 360.000 руб.
Результат: ["1", "360.000"]

Добавление кода в нативные функции

#javascript


Как можно добавить немного своего кода в функцию (не свою, а [native code]).

Пример кода:

Math.__defineGetter__('pow', function() {
    console.log( 'USE: Math.pow' );
    return function() { return 100500; };
});


То есть при вызове Math.pow(1,2); в консоль пишется 'USE: Math.pow' и возвращается
100500.

Надо сделать так, чтобы функция писала в консоль и продолжала свою "правильную" работу. 

Я пишу "юзерскрипт" и хочу знать какие методы использует сайт. Не все, конечно, а,
например, только из Math.

for (var i in Math ) {
    eval('Math.__defineGetter__( "' + i + '", function() { console.log( "USE Math.'
+ i + '" ); return 1; });');
}


Сейчас я могу это узнать, в консоль всё пишет, но функции не работают и вызывают ошибки.
    


Ответы

Ответ 1



Простой пример с Math.pow() для демонстрации идеи: var savedPow = Math.pow; Math.pow = function(number, exp) { console.log('USE: Math.pow'); return savedPow(number, exp); }; console.log(Math.pow(10, 3));

AngularJS установить элементу класс, если он скрыт за границами другого блока

#javascript #angularjs


Есть у меня блок, внутри которого элементы выводятся в ng-repeat. Если элемент (class="item")
частично или полностью (при склоре блока) выходит за его границы, этому элементу мне
нужно установить класс например "novisible".

Еще раз, что мне нужно. Пользователь прокручивает родительский блок, все дочерние
элементы (div class="item"), которые за границей видимости, должны получить класс "novisible".



.item {
height:30px;
border: 1px solid #ff0000;
}
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item
item


Ответы

Ответ 1



Оборачивайте весь блок в директиву, а далее работайте с DOM и её event'ами (scroll) + addClass/removeClass (ng-class, если больше нравится). При первом старте, чтобы дождаться когда ng-repeat отработает, можно использовать решение наподобие такого: https://stackoverflow.com/questions/15207788/calling-a-function-when-ng-repeat-has-finished

Ответ 2



var Model = (function(){ var allItems = []; for(var i = 0; i < 20; i++){ allItems.push({name: 'item-' + i }); } return { getAllItems: function(){ return allItems; } }; })(); var app = angular.module('app', []); app.controller('ItemController', ['$scope', function($scope){ $scope.model = Model.getAllItems(); }]); app.directive('customScroll', ['$injector', function(){ // Runs during compile return { link: function($scope, iElm, iAttrs, controller) { var dataCollection = $scope[iAttrs['customScroll']]; var length = dataCollection.length; var element; for(var i = 0; i < length; i++){ element = angular.element('
' + dataCollection[i].name + '
'); iElm.append(element); } // а вот теперь делайте все так же, как я показал Вам раньше. // Но если со временем появятся ошибки при скроле, то напишите о них, // мне самому интересно. iElm[0].addEventListener('scroll', iElem_scrollHandler); function iElem_scrollHandler(event){ var allChildren = event.target.children; var length = allChildren.length; var item; for(var i = 0; i < length; i++){ item = allChildren[i]; if(item.getBoundingClientRect().y > 0){ if(false /*что-то тут*/){ /*что-то делаем*/ }else{ break; } } /*оффаем*/ } } } }; }]); .item { height:30px; border: 1px solid #ff0000; }