Имеется код: char field[3][3];
void enterX() {
cout << "Enter X on vertical: ";
int i;
cin >> i;
if (cin.good() && i < 3 && i >= 0)
{ }
else {
cout << "Please, enter the number 0-2!";
cin.clear();
cin.ignore(INT_MAX);
enterX();
}
cout << "Enter X on horizontal: ";
int j;
cin >> j;
if (cin.good() && j < 3 && j >= 0) { }
else {
cout << "Please, enter the number 0-2!";
cin.clear();
cin.ignore(INT_MAX);
enterX();
}
field[i][j] = 'x'; }
Задача - считывание номера элемента массива с консоли и вставке в это место символа 'x'. Однако при неверном вводе не происходит рекурсия. В чём проблема?
Ответ
Вообще-то это - cin.ignore(INT_MAX); - игнорировать все (ну ладно, INT_MAX символов) до конца файла - т.е. пока какое-то ^Z не закроет поток... input.ignore(std::numeric_limits::max(), ' ');
И вообще, я бы делал так (если уж приспичила именно рекурсия): char field[3][3];
void enterX() {
cout << "Enter X && Y: ";
unsigned int i, j;
cin >> i >> j;
if (cin.fail() || i > 2 || j > 2)
{
cin.clear();
cin.ignore(INT_MAX,' ');
cout << "Wrong values! ";
enterX();
}
else
{
field[i][j] = 'x';
}
}
Update Имея типичную оконечную рекурсию, лучше переделать ее в итерацию: char field[3][3];
void enterX()
{
for(;;)
{
cout << "Enter X && Y: ";
unsigned int i, j;
cin >> i >> j;
if (!(cin.fail() || i > 2 || j > 2))
{
field[i][j] = 'x';
break;
}
cin.clear();
cin.ignore(INT_MAX,' ');
cout << "Wrong values! ";
}
}
То есть необходимо добиться того, чтобы элементы группировались по 4 штуки в отдельный div с классом row-n, где n - это номер "группы" элементов. Пытался реализовать так: 'use strict'
var arr = [];
var row1 = [];
var row2 = [];
var row3 = [];
arr.push(document.getElementsByClassName('box'));
var boxes = arr[0];
for (var i = 0; i < boxes.length; i++) {
if(i < 4) { row1.push(boxes[i])
} else if(i >= 4 && i < 8) { row2.push(boxes[i])
} else { row3.push(boxes[i])
}
};
Но ничего не вышло.
Ответ
var box, raw, i = 1, z = 1; // ключевой момент здесь. Пока внутри родителя есть элементы с классом .box (родитель
// в данном случае - body, но у вас может быть любой), то выполняем тело цикла.
while (box = document.querySelector("body > .box")) {
// i - номер итерации. Инкрементируется в конце цикла. Если переваливает за 4, то начинаем
// отсчет заново (это нужно, чтобы сгруппировать элементы по 4 штуки)
if (i > 4) {
i = 1;
} // если это первый заход в группе, то создаем новый div с классом raw-z
if (i === 1) {
// переопределяем raw в новый, свжесозданный div
raw = document.createElement("div");
// с классом raw-z
raw.classList.add("raw-" + z);
// после чего z увеличиваем
z += 1;
} // в созданный на "первом" проходе div с классом raw-z добавляем box'ы
raw.appendChild(box); // если это последний элемент из группы, то отрисовываем всю группу элементов
if (i === 4) {
document.body.appendChild(raw);
} // увеличиваем счетчик на 1
i += 1;
}
В исходную директиву при помощи декоратора внесены незначительные изменения(создание события). $rootScope.$broadcast('customSelect', scope.$selectMultiple.activeMatchIndex);
В контроллере обрабатываю это событие $scope.$on('customSelect', function(event, value){
console.log('from custom select');
$scope.tool = $scope.assembly.tools[value];
});
так же в контроллере слежу за изменением tool при помощи $watch $scope.$watch('tool', function(value){
console.log('from watch');
});
Выбираем любое кол-во инструментов в выпадающем списке, каждая добавленная позиция становится активной, применение класса btn-primary из бутстрапа. При первом клике по одной из выбранных позиций в консоле видно что сработал обработчик события customSelect который в свою очередь меняет $scope.tool, но почему то не срабатывает обработчик из $watch, а если повторно кликнуть тот же элемент то в консоли видно что сработало оба обработчика. Подскажите почему так происходит.
Почему это срабатывает при последующих переключениях: внутри элемента с классом ui-select-match есть элемент с классом ui-select-match-item - у которого прописан ng-click Таким образом при клике, сначала вызывается клик внутреннего элемента, проходит digest цикл, затем шлется твой broadcast и на этом все заканчивается.
При следующем клике при проверке watch определяет, что tools изменился с предыдущего запуска digest - и отрисовывает, а затем в обработчике твоего события ты снова меняешь реальное значение tools.
Соблюдение стандартов кодирования WordPress часто требуется при групповой работе над проектом. Кроме того, выполненный по стандартам код повышает оценку претендента в глазах потенциального работодателя. Сами стандарты описаны в Codex, но подключение их к Code Sniffer в phpStorm вызывает определённые сложности. Подключение требует установки и настройки нескольких пакетов, инструкции для которых разбросаны по разным сайтам. Как выглядит полная последовательность действий по установке стандартов кодирования WordPress для phpStorm под Windows?
Ответ
Анализаторы кода такие, как PHP Code Sniffer, и стандарты кодирования такие, как WordPress Coding Standards, позволяют создавать современный, легко обновляемый код, избежать множества ошибок еще на стадии написания кода, и совершенно незаменимы при командной работе над проектом. Эти средства встроены в phpStorm — мощную современную среду разработки под php. В то же время, у многих разработчиков возникают сложности при установке анализатора кода PHP Code Sniffer и правил оформления кода WordPress Coding Standards для него в PhpStorm под Windows. Ниже сведены воедино сведения по установке, собранные из разных источников. Процедура подключения стандартов кодирования под Windows выглядит следующим образом. Установка PHP Откройте страницу http://windows.php.net/download/ и выберите 32-х или 64-х битный файл в зависимости от битности архитектуры своей системы. Еще есть варианты TS (Thread Safe) и NTS (Non Thread Safe). TS отличается тем, что позволяет PHP работать в нескольких потоках. Для простых приложений и взаимодействия с веб-сервером вполне подойдёт и NTS. Распакуйте содержимое zip-архива, например, в c:\php Переименуйте файл c:\php\php.ini-development в c:\php\php.ini Найдите строку ;On windows: и раскомментируйте после нее extension_dir = "ext"
Для работы с WordPress понадобятся несколько расширений. Найдите секцию ; Windows Extensions и раскомментируйте строки extension=php_mbstring.dll
extension=php_mysqli.dll
Найдите строчку ;date.timezone =, раскомментируйте и задайте вашу временную зону, например: date.timezone = 'Europe/Moscow'
Наконец, добавьте строчки для отладчика Xdebug в самый конец. [xdebug]
zend_extension=c:/php/ext/php_xdebug-2.5.5-7.1-vc14-x86_64.dll
xdebug.remote_autostart=on
xdebug.remote_enable=on
xdebug.remote_handler="dbgp"
xdebug.remote_host="localhost"
xdebug.remote_port=9001
xdebug.remote_mode=req
xdebug.idekey="ваш_пароль"
Сам отладчик в виде dll-файла надо скачать отсюда: https://xdebug.org/download.php и поместить в c:\php\ext. При скачивании выбрать ту же версию и разрядность PHP, что были выбраны при установке PHP. Установка PEAR Сохраните страницу https://pear.php.net/go-pear.phar как файл c:\php\go-pear.phar Запустите cmd.exe и введите команды cd c:\php
php go-pear.phar
Ответьте на вопросы, приняв значения по умолчанию, нажимая Enter Добавьте пути в системный PATH, дважды щёлкнув на созданном в процессе установки файле c:\php\PEAR_ENV.reg Установка PHP Code Sniffer В папке c:\php появился файл pear.bat, с помощью которого надо установить PHP Code Sniffer. Последняя версия PHP Code Sniffer —
https://pear.php.net/package/PHP_CodeSniffer/download В cmd.exeвыполните команду, указанную на странице с последней версией PHP Code Sniffer. На данный момент это: pear install PHP_CodeSniffer-3.1.1
В папке c:\php появились новые файлы, в том числе c:\php\phpcs.bat Установка Composer Для дальнейшей установки понадобится Composer Загрузите файл https://getcomposer.org/Composer-Setup.exe в папку c:\php. Запустите файл Composer-Setup.exe и проведите установку по умолчанию. Для активизации путей Composer надо перезапустить окно командной строки. Composer добавлен, теперь вы можете его использовать для установки других пакетов. Установка PHP Code Sniffer в PhpStorm Откройте в PhpStorm окно установок проекта (Ctrl+Alt+S) и выберите Languages&Frameworks → PHP Установите PHP language level (7.1) Нажмите на многоточие справа от CLI Interpreter В окне CLI Interpreters выберите файл PHP executable (C:\php\php.exe) и Debugger extension (C:\php\ext\php_xdebug-2.5.5-7.1-vc14-x86_64.dll).
Нажмите OK В этом же окне установок выберите Languages&Frameworks → PHP → Code Sniffer Задайте к нему путь C:\php\phpcs.bat
Нажмите OK В этом же окне установок выберите Editor → Inspections → PHP → PHP Code Sniffer validation и требуемый Coding standard. На картинке ниже выбран PEAR.
Нажмите ОК Сейчас PHP Code Sniffer установлен, можно пользоваться командой меню Code-Inspect Code Установка WordPress Coding Standards В папке c:\php запустите команду (вот и пригодился Composer) composer create-project wp-coding-standards/wpcs --no-dev
Появилась папка c:\php\wpcs Добавление WordPress Coding Standards в PhpStorm В окне установок выберите Languages&Frameworks → PHP → Code Sniffer и задайте к нему путь C:\php\wpcs\vendor\bin\phpcs.bat Можете нажать кнопку Validate рядом для проверки. Обратите внимание — вы подключили теперь другой Code Sniffer, из папки c:\php\wpcs Нажмите ОК В этом же окне установок выберите Editor → Inspections → PHP → PHP Code Sniffer validation и требуемый Coding standard. Если в списке стандартов не видите WordPress, нажмите на кнопку обновления справа (кольцевые стрелочки).
Советую использовать WordPress Extra — самый строгий стандарт кодирования, за исключением VIP. Но VIP предназначен для специальных установок WordPress, и на обычных сайтах невозможно удовлетворить его требованиям. Подробнее здесь: https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards На этом процесс установки закончен, и теперь вы можете создавать профессиональный код для своих сайтов на WordPress.
Доброй ночи, Составляю роль для установки Rust. Весь плейбук запущен под become_user = root Игра фейлится после выполнения последнего таска, где нужно запустить скачаный скрипт от пользователя который был до become_user: iwi.yml --- - hosts: localhost
become: True
become_method: su
become_user: root
roles:
- iwi-sys-upgrade-install
- iwi-lang-rust
iwi-lang-rast/tasks/main.yml --- - name: "download rustup-init.sh from https://www.rustup.rs"
get_url:
url: https://sh.rustup.rs
dest: /tmp/rustup-init.sh
mode: 0755 - name: "install Rust with /tmp/rustup-init.sh, run by {{ ansible_user_id }}"
become: yes
become_user: {{ ansible_user_id }}
shell: '/tmp/rustup-init.sh -y'
Почемуто выдает синтаксическую ошибку: ERROR! Syntax Error while loading YAML.
The error appears to have been in '/home/Sharlatan/Projects/prj/iwi/Ansible/roles/iwi-lang-rust/tasks/main.yml': line 11, column 17, but may
be elsewhere in the file depending on the exact syntax problem. The offending line appears to be: become: yes
become_user: {{ ansible_user_id }}
^ here
Ответ
Кавычки добавьте: become_user: "{{ ansible_user_id }}"
Подробности в доках. Без " Ansible думает, что { - это словарик.
Есть метод, который выводит нечетные числа от 1 до 100 public String printUnpared() {
for (d = 1; d <= 100; d++) {
if (d % 2 != 0) {
unpared[d] = d;
} }
String stringUnpared = Arrays.toString(unpared);
return stringUnpared;
И получаю вывод [0, 1, 0, 3, 0, 5, 0, 7, 0, 9, 0, 11, 0, 13, 0, 15, 0, 17, 0, 19, 0, 21, 0, 23, 0, 25, 0, 27, 0, 29, 0, 31, 0, 33, 0, 35, 0, 37, 0, 39, 0, 41, 0, 43, 0, 45, 0, 47, 0, 49, 0, 51, 0, 53, 0, 55, 0, 57, 0, 59, 0, 61, 0, 63, 0, 65, 0, 67, 0, 69, 0, 71, 0, 73, 0, 75, 0, 77, 0, 79, 0, 81, 0, 83, 0, 85, 0, 87, 0, 89, 0, 91, 0, 93, 0, 95, 0, 97, 0, 99]
Как вывести нечетные числа без нулей не используя ArrayList? Как начать массив с 1, а не с 0? Нужно вернуть через return, выводить через System.out.print нельзя.
Ответ
Можно использовать ArrayList: public String printUnpared() {
List unpared = new ArrayList();
for (d = 1; d <= 100; d+=2) {
unpaired.add(d);
}
String stringUnpared = Arrays.toString(unpared.toArray());
return stringUnpared;
}
Либо рассчитывать нечётное число отдельно от индекса: for (i = 0, d = 1; d <= 100; i++, d+=2) {
unpaired[i] = d;
}
При передаче в обработчик, получаем подобный массив: "place":["metro1","metro2","raion1"]
Вопрос: как, если, конечно, возможно, разбить передаваемые данные на вложенные массивы?
Чтобы получилось вроде: "place":{"metro":["metro1", "metro2"],"district":["district1"]}
Если невозможно, то какие способы есть для разделения подобных данных (на ум приходят только префиксы для value)?
Ответ
Если прям так сильно нужно, можно попробовать сделать так, не самый оптимальный вариант конечно: В примере используется Jquery
HTML
Всем доброго времени суток, столкнулся с такой проблемой. Есть чисто абстрактный класс UART который имеет следующий набор виртуальных методов : virtual int8_t initialize(char* port_name, int baud_rate, Parity parity, int dataBits, StopBits stop_bits) = 0;
virtual int8_t EDataReceived(void(*delegate)(char* data, const int16_t & length)) = 0;
virtual void transmitDataToUart(char* data, const int16_t & length) = 0;
и есть 5 различных платформ на которых есть своя реализация класса, но все они унаследованы от класса UART, например class UART_Linux: UART. Это нужно для того что бы единожды написанный драйвер под микросхему SIM666 или SIM777, принимая в качестве параметра конкретный объект наследника UART мог бы работать на всех пяти платформах без изменений в коде. Когда на аппаратный uart приходят данные то класс UART должен делать колбэк вызов и передавать принятые данные с помощью функции, которая регистрируется в методе virtual int8_t EDataReceived(void(*delegate)(char* data, const int16_t & length)).
Эта регистрация происходит внутри конструктора классов SIM666 и SIM777, например: Sim666::Sim666(Uart& in_uart){
in_uart.EDataReceived(ReceiveDataFromUART);
}
сам класс UART_Linux: UART не должен не чего знать о классе SIM666 т. к. это однажды написанный универсальный класс а SIM666 будет написан допустим спустя 5 лет после этого. Проблема заключается в том что метод ReceiveDataFromUART который является частью SIM666 должен обязательно быть статическим. Статическим его сделать не получается т. к. внутри этого метода должны использоваться не статик поля и свойства класса (т. е. конкретные экземпляры объекта). Что бы решить мою проблему можно решить хотя бы один из трёх вопросов: 1) Реализовать возможность вызова внутри UART_Linux не статик стороннего метода. 2) Сделать метод Sim666.ReceiveDataFromUART статическим но реализовать в нём возможность обращения к не статическим полям класса (т. е. на уровне объекта). 3) Можно создать статический объект класса SIM666, тогда если регистрировать метода происходит снаружи класса SIM666 то всё работает, но внутри метода void getPeriphery(const sd::Uart& in_uart) {
in_uart.EDataReceived(ReceiveDataFromUART);
};
компилятор не понимает что объект сейчас статический и данный вызов является корректным. Можно ли как то сообщить об этом компилятору? Что то типа как привести ReceiveDataFromUART к статику? Стандарт языка С++ 0х14 , компиляторы и платформы как вы понимаете различны. Из стандартных библиотек можно использовать только стандартную библиотеку С.
Ответ
Если в Вашем случае использовать std::function, то это может покрыть все необходимые варианты использования #include
#include typedef std::function Callback; class MyClass
{
public:
MyClass(Callback _cb): //регистрация колбэк функции в конструкторе
m_callback(_cb)
{ } void invokeSomeFunc()
{
//много каких-то действий
//...
m_callback(0, 1);
} private:
std::function m_callback;
};
void func1(char* data, const int & length)
{
std::cout << __FUNCSIG__ << std::endl;
} class AnotherClass
{
public:
static void staticFunc(char* data, const int & length)
{
std::cout << __FUNCSIG__ << std::endl;
}
}; class AnotherClass2
{
public:
void notStaticFunc(char* data, const int & length)
{
std::cout << __FUNCSIG__ << std::endl;
}
}; int main(int argc, char *argv[])
{
//вариант использования с свободной функцией
{
MyClass someObj(func1);
someObj.invokeSomeFunc();
} //вариант использования с статической функцией класса
{
MyClass someObj(&AnotherClass::staticFunc);
someObj.invokeSomeFunc();
} //вариант использования с не статической функцией класса
//тут нужно понимать, что объект someAnotherObj не должен быть разрушен на момент
// вызова колбек функции, если invokeSomeFunc - асинхронная, то можно создать объект в куче.
{
AnotherClass2 someAnotherObj; auto fn = [&someAnotherObj](char* data, const int & length)
{
someAnotherObj.notStaticFunc(data, length);
}; MyClass someObj(fn);
someObj.invokeSomeFunc();
} {
AnotherClass2 *someAnotherObj = new AnotherClass2(); auto fn = [someAnotherObj](char* data, const int & length)
{
someAnotherObj->notStaticFunc(data, length);
delete someAnotherObj;
}; MyClass someObj(fn);
someObj.invokeSomeFunc();
} return 0;
}
Если не хочется использовать std::function, можно в колбэк функцию добавить еще один параметр типа void* для пользовательских данных: #include
#include typedef void(*Callback)(char* data, const int & length, void *_userData); class MyClass
{
public:
MyClass(Callback _cb, void *_userData = 0):
m_callback(_cb),
m_userData(_userData)
{ } void invokeSomeFunc()
{
//много каких-то действий
//...
m_callback(0, 1, m_userData);
} private:
Callback m_callback;
void *m_userData;
};
void func1(char* data, const int & length, void *userData)
{
std::cout << __FUNCSIG__ << std::endl;
} class AnotherClass
{
public:
static void staticFunc(char* data, const int & length, void *userData)
{
std::cout << __FUNCSIG__ << std::endl;
}
}; class AnotherClass2
{
public:
void notStaticFunc(char* data, const int & length)
{
std::cout << __FUNCSIG__ << std::endl;
}
}; void funcToCallObjectMethod(char* data, const int & length, void *userData)
{
AnotherClass2 *obj = static_cast(userData);
obj->notStaticFunc(data, length);
delete obj;
} int main(int argc, char *argv[])
{
//вариант использования с свободной функцией
{
MyClass someObj(func1);
someObj.invokeSomeFunc();
} //вариант использования с статической функцией класса
{
MyClass someObj(&AnotherClass::staticFunc);
someObj.invokeSomeFunc();
} //вариант использования с не статической функцией класса
//тут нужно понимать, что объект someAnotherObj не должен быть разрушен на момент
// вызова колбек функции, если invokeSomeFunc - асинхронная, то можно создать объект в куче.
{
AnotherClass2 someAnotherObj; auto fn = [](char* data, const int & length, void *userData)
{
AnotherClass2 *obj = static_cast(userData);
obj->notStaticFunc(data, length);
}; MyClass someObj(fn, &someAnotherObj);
someObj.invokeSomeFunc();
} {
AnotherClass2 *someAnotherObj = new AnotherClass2(); auto fn = [](char* data, const int & length, void *userData)
{
AnotherClass2 *obj = static_cast(userData);
obj->notStaticFunc(data, length);
delete obj;
}; MyClass someObj(fn, someAnotherObj);
someObj.invokeSomeFunc();
} {
AnotherClass2 *someAnotherObj = new AnotherClass2(); MyClass someObj(funcToCallObjectMethod, someAnotherObj);
someObj.invokeSomeFunc();
} return 0;
}
Как третий вариант, можно использовать реализацию паттерна Observer, пример уже приводить не буду. IMHO, первый вариант самый удобный и экономит время в разработке.
Добрый день. Возник дурацкий вопрос:
Есть 2 Dictionary. Нужно получить третий, который будет включать в себя все пары "ключ-значение" из первого и второго. Точно известно, что совпадения ключей в словарях нет. Пробовал так - не получается. Markers = new Dictionary(CreateCommonMarkers(vm));
Markers.Concat(UniqueMarkers);
return Markers;
CreateCommonMarkers - создается правильно
UniqueMarkers - создается правильно
Markers получает первый словарь правильно.
А вот Concat не срабатывает. На выходе - дубликат словаря, создаваемого CreateCommonMarkers(vm)
Соответственно вопрос: что я сделал не так? P.S. сделать через foreach я могу, но может есть менее извращенный способ.
Ответ
Если уверены, что совпадений ключей нет, то можно попробовать так: var dict1 = Enumerable.Range(0,10).ToDictionary(x=>x);
var dict2 = Enumerable.Range(15,10).ToDictionary(x=>x);
Для объединения словарей можно использвать методы Union или Concat. Разница между ними только в том, что Union удаляет доубликаты, что в данном контексте не требуется. Для маленьких словарей нет разницы, какой из методов использовать, для больших, как мне кажется, Concat будет работать быстрей. var combined_version_1 = dict1.Union(dict2).ToDictionary(x=>x.Key, x=>x.Value);
var combined_version_2 = dict1.Concat(dict2).ToDictionary(x=>x.Key, x=>x.Value);
Как видно, на входе получается третий словарь, который можно вернуть как результат.
Есть следующий код: for(let i = 1; i <= length; i++){
VK.Api.call('groups.getById', {group_id: groups[i].gid, fields: 'description'}, (output) => {
showVisual(groups[i]);
console.log(output);
})
}
Проблема в том, что цикл for уже завершается, когда мы получаем ответ в колбеке.
Как сделать запрос синхронным?
Ответ
Предполагая, что Ваша проблема в некорректном значении i в callback, предлагаю замкнуть значение этой переменной: for(let i = 1; i <= length; i++){
VK.Api.call('groups.getById', {group_id: groups[i].gid, fields: 'description'}, ((i) => (output) => {
showVisual(groups[i]);
console.log(output);
})(i)
);
}
Или, можно добавить в замыкание значение group: for(let i = 1; i <= length; i++){
VK.Api.call(
'groups.getById',
{group_id: groups[i].gid, fields: 'description'},
((group) =>
(output) => {
showVisual(group);
console.log(output);
}
)(groups[i])
);
}
С Promise можно реализовать так: function getGroupDescription(group) {
return new Promise(resolve => VK.Api.call(..., resolve));
} for (let i = 1; i <= length; ++i) {
getGroupDescription(groups[i]).then(output => console.log(output));
}
Проблема async/await в его каскадном распространении - чтобы его использовать, клиент должен завернуть свой код в async функцию: function getGroupDescription(group) {
return new Promise(resolve => VK.Api.call(..., resolve));
} async function foo () {
// ...
for (let i = 1; i <= length; ++i) {
groups[i].description = await getGroupDescription(groups[i]);
}
}
foo();
Рабочий пример:
function timedTwice(val, time = 1000) {
return new Promise(res => setTimeout(() => res(2*val), time));
}
timedTwice(5).then(r => console.log(r));
async function foo() {
for (let i = 0; i < 8; ++i) {
let result = await timedTwice(i, 100);
console.log(i, result);
}
}
foo();
Мне надо создать метод, который будет записывать все содержимое введенное пользователем с консоли в файл по заданному пути, не перезаписывая содержимое файла. И запись в файл должна производиться после ввода команды wr в отдельной строке. Метод я сделал, но в результате его работы, срабатывает сразу первый cath. Когда дебажу программу показывает - процесс не может получить доступ к файлу, так как этот файл занят другим процессом. public static void writeToFileFromConsole(String path){ InputStreamReader reader = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(reader); FileWriter writer = null;
BufferedWriter bufferedWriter = null; System.out.println("Enter file content to write in the file:"); try {
String command = "wr";
String line;
line = br.readLine();
if ((line = br.readLine()).equals(command)) {
writer = new FileWriter(path, true);
bufferedWriter = new BufferedWriter(writer); bufferedWriter.append(" ");
bufferedWriter.append(line);
}
}catch (IOException e){
System.err.println("Can't write to file with path " + path);
}
finally {
try {
reader.close();
br.close();
if (writer != null){
writer.close();
}
if (bufferedWriter != null){
bufferedWriter.close();
}
}catch (IOException e){
System.err.println("File with path " + path + " not found" );
}
}
}
Подскажите в чём моя ошибка ? И как исправить, чтобы в файл записывались данные введенные в консоли.
Ответ
Проверил ваш код, ошибок никаких не возникло, кроме исключения сообщавшего, что файла не существует. Переделал, чтобы его не возникало: private static void writeToFileFromConsole(String path) {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("Enter file content to write in the file:"); try (OutputStream output = Files
.newOutputStream(
Paths.get(path),
StandardOpenOption.APPEND,
StandardOpenOption.CREATE);
BufferedOutputStream outputStream = new BufferedOutputStream(output)) { String line;
while (!"rw".equalsIgnoreCase(line = reader.readLine())) {
outputStream.write(System.lineSeparator().getBytes());
outputStream.write(line.getBytes());
}
} catch (IOException e) {
e.printStackTrace();
}
}
Дан двумерный массив: static int[][] multi = new int[][] {
{2, 0, 4, 1241, 424, 1, 12323},
{1, 3, 5, 7},
{321, 320, 32, 41241, -11, -12, -13, -66, -688}
};
Нужно создать метод, который принимает индекс определенного элемента и int range - количество элементов, находящихся рядом с элементом. Метод должен вернут массив. Например: nearby(0, 2, 2) вернет 2, 0, 1241, 424 Я сделал что-то вроде: public static int[] nearby(int x, int y, int range) {
int index = 1;
ArrayList leftSize = new ArrayList();
ArrayList rightSize = new ArrayList();
while (index != range + 1) {
leftSize.add(multi[x][y - index]);
rightSize.add(multi[x][y + index]);
index += 1;
}
leftSize.addAll(rightSize);
int[] stockArr = new int[leftSize.size()];
return stockArr;
}
Но не уверен, что это лучшее решение.
Какой алгоритм использовать, чтобы работать напрямую с массивом, не создавая ArrayList?
Ответ
Если опустить проверки границ, то получается так: public static int[] nearby(int x, int y, int range)
{
int[] result = new int[range * 2];
System.arraycopy(multi[x], y - range, result, 0, range);
System.arraycopy(multi[x], y + 1, result, range, range);
return result;
}
Результат:
[2, 0, 1241, 424]
Если при выходе за границы массива дело должно кончаться не ArrayIndexOutOfBoundsException, а возвратом только допустимых элементов (вплоть до пустого массива), то проще сделать через список: public static int[] nearby(int x, int y, int range)
{
if (x < 0 || x >= multi.length)
return new int[0];
List result = new ArrayList<>();
for (int i = Math.max(y - range, 0); i <= y + range && i < multi[x].length; i++)
{
if (i != y)
{
result.add(multi[x][i]);
}
}
return result.stream().mapToInt(e -> e).toArray();
}
Альтернативным вариантом, с использованием только массивов, тут будет предварительный расчет границ копируемых участков (leftFirst, leftLast, rightFirst, rightLast), но восприниматься это будет тяжелее: public static int[] nearby(int x, int y, int range)
{
if (x < 0 || x >= multi.length || y - range >= multi[x].length || y + range < 0)
return new int[0];
int leftFirst = Math.max(y - range, 0);
int leftLast = Math.min(y - 1, multi[x].length - 1);
int leftLength = leftLast - leftFirst + 1;
int rightFirst = Math.min(y + 1, multi[x].length);
int rightLast = Math.min(y + range, multi[x].length - 1);
int rightLength = rightLast - rightFirst + 1;
int[] result = new int[leftLength + rightLength];
System.arraycopy(multi[x], leftFirst, result, 0, leftLength);
System.arraycopy(multi[x], rightFirst, result, leftLength, rightLength);
return result;
}
Есть типы в БД: CREATE OR REPLACE TYPE my_type IS OBJECT (
id VARCHAR2(20),
name VARCHAR2(40),
phone NUMBER
);
Пытаюсь создать обьекты с использованием этих типов: ....
Object[] myArray = new Object[3];
Object[] struct = new Object[values.size()]; int arrayIndex = 0;
for (User user : values) {
myArray[0] = user.id().toString();
myArray[1] = user.getName().toString();
myArray[2] = user.getPhone(); struct[arrayIndex++] = con.createStruct("my_type",myArray);
}
На строке с созданием структуры con.createStruct выпадает ошибка: java.sql.SQLException: Inconsistent java and sql object types, for classes implementing ORAData or OracleData, respective factory classes ORADataFactory and OracleDataFactory should be registered in typeMap.
В чем может быть дело?
Ответ
Это помогло мне. for (User user : values) {
struct[arrayIndex++] = con.createStruct(
"my_type",
new Object[]{
user.id().toString();
user.getName().toString();
user.getPhone();
});
}
Здравствуйте! Мне нужно загрузить из файла/ресурса png рисунок с альфа пикселями и вывести его на контекст. С загрузкой хорошо справляется GDI+, но вот с выводом изображения Graphics::DrawImage() всё плохо, поэтому я решил использовать GDI (StretchBlt и т.д.). Но в StretchBlt Bitmap не запихнёшь, нужен HBITMAP. У Bitmap есть метод GetHBITMAP(Color, HBITMAP*), и в нём-то и проблема: он, почему-то конвертирует с потерей прозрачности. Я пробовал передавать Color::Black и Color::Transparent, но ничего не помогает. Как тогда получить HBITMAP с прозрачностью? ОБНОВЛЕНО Я понял в чём была ошибка и она глупая. Ниже вы можете увидить мой код, звёздочками я выделил то чего не было. То есть я рисовал изображение на второй буффер, на котором ничего не было, и удивлялся почему-это, альфа пиксели чёрные. Теперь я додумался что нужно сначала нарисовать на буфер фон, а потом уже рисовать изображение. Но опять проблема: Рисую несколько картинок, вместо картинки 1920/1080(мой экран) просто чёрное(у картинки нет альфа пикселей), картинки других размеров, 100/100 например, в произвольных расположениях рисуются, но с чёрным прямоугольником в левом верхнем углу(у картинки нет альфа пикселей). Если закрасить главный фон(перед выводом изображения 1920/1080, то фон таким же и будет(картинка вообще никак не выводится, получается?), у маленьких картинок цвет прямоугольника такой же становится(походу это прозрачность(но альфа пикселей,ещё раз, там нет). Я так понимаю, второй раз использовать SelectObject нельзя, да? В общем, подскажите в чём тут проблема? class Imagee
{
HDC hdc; HBITMAP bm; Imagee(HDC hdc, HBITMAP bm, another args)
{
this->hdc=CreateCompatibleDC(hdc);
this->bm=bm;
SelectObject(this->hdc,this->bm);
} void draw(int hdcc, int x,int y, int cx, int cy)
{
**StretchBlt(this->hdc,0,0,cx,cy,hdcc,x,y,cx,cy,SRCCOPY);
SelectObject(this->hdc,this->bm); ** StretchBlt(this->hdcc,x,y,cx,cy,hdc,0,0,cx,cy,SRCCOPY);
}; }; Imagee *image; void render()
{
for(;;)
{ //здесь я загружая через гди+ битмам, конвертирую его в хбитмап, записывая в перменную HBITMAP hbm if(image==0)
image=new Imagee(hdc_mem, hbm, x, y и т.д.); image->draw(hdc_mem, x, y и т.д.); StretchBlt(hdc_main,0,0,1920,1080,hdc_mem,0,0,1920,1080,SRCCOPY); //hdc_main главный дс, hdc_mem буфер }
}
Ответ
Отвечая на вопрос: _Check_return_ ::HBITMAP
LoadPng(_In_z_ const ::LPWSTR psz_file_path)
{
::HBITMAP bitmap_handle{};
if(psz_file_path)
{
const ::BOOL embedded_color_management{TRUE};
::Gdiplus::Bitmap bitmap{psz_file_path, embedded_color_management};
if(::Gdiplus::Status::Ok == bitmap.GetLastStatus())
{
const ::Gdiplus::Color background{0, 0, 0, 0};
if(::Gdiplus::Status::Ok != bitmap.GetHBITMAP(background, &bitmap_handle))
{
bitmap_handle = NULL;
}
}
}
return(bitmap_handle);
}
Как ни странно, но Color::Transparent это не то же самое, что 0, 0, 0, 0. Еще стоит отметить что полученная картинка будет уже с предварительно умноженным (premultiplied) альфа каналом, т.е. пригодная для рисования посредством GdiAlphaBlend и прочих функций.
Здравствуйте. Необходимо реализовать следующий функционал: пользователь нажимает на блок (в примере ниже это li) и над другими блоками появляется текст из атрибута title. При чем текст должен появится над всем указанными блоками и исчезнуть по повторному нажатию на кнопку (или на li). Пробовал сделать вот так
function showTittles() {
var buttShow = document.getElementById("buttShow");
var titlesContainer = document.querySelectorAll("#servicelist1, #servicelist2, #servicelist3");
var buttonsArr = document.getElementById("buttonsArr");
var listItem = buttonsArr.querySelectorAll("#redBlc, #greenBlc, #blueBlc");
var showingTooltip;
var titles = [];
for (var i = 0; i < titlesContainer.length; i++) {
titles.push(titlesContainer[i].getAttribute('title'));
}
listItem.forEach (function (i) {
listItem[i].addEventListener("click", function() {
switch (i) {
case i === 0:
addTitle(0);
break;
case i === 1:
addTitle(1);
break;
case i === 2:
addTitle(2);
break;
default:
consol.log("жми!");
break;
}
})
})
}
function addTitle(elem) {
var target = titlesContainer[elem];
var tooltipElem = document.createElement('div');
tooltipElem.className = 'tooltip-title';
tooltipElem.innerHTML = titles[elem];
document.body.appendChild(tooltipElem);
var coords = target.getBoundingClientRect();
var left = coords.left + (target.offsetWidth - tooltipElem.offsetWidth) / 2;
if (left < 0) left = 0; // не вылезать за левую границу окна
var top = coords.top - tooltipElem.offsetHeight - 5;
if (top < 0) { // не вылезать за верхнюю границу окна
top = coords.top + target.offsetHeight + 5;
}
tooltipElem.style.left = left + 'px';
tooltipElem.style.top = top + 'px';
showingTooltip = tooltipElem
}
showTittles();
.servicelist {
display: inline-block;
width: 100px;
height: 100px;
position: relative;
}
#servicelist1 {
border: 1px solid #f00;
}
#servicelist2 {
border: 1px solid #0f0;
}
#servicelist3 {
border: 1px solid #00f;
}
.tooltip-title {
position: fixed;
padding: 10px 20px;
border: 1px solid #b3c9ce;
border-radius: 4px;
text-align: center;
font: italic 14px/1.3 arial, sans-serif;
color: #333;
background: #fff;
box-shadow: 3px 3px 3px rgba(0, 0, 0, .3);
}
Показать красный тултип
Показать зеленый тултип
Показать голубой тултип
Некоторый код брал из этого примера Сейчас он ругается на addEventListener и я не знаю как сделать так, чтобы по нажатию на отдельный li появлялся личный title над каждым блоком. P.S в проекте уже есть jquery и bootstrap, так что если легче будет с ними, то подойдет решение с применением этих инструментов, спасибо :)
Ответ
Не совсем понял что вам нужно. Написал как понял. Уточните/напишите если что не так. В примере используется jquery 2.1.1
(function($) {
$('li').click(function(){
var id = $(this).attr('id');
$(document).find('.servicelist').html('');
$(document).find('.servicelist').html($(document).find('[data-id="'+id+'"]').attr('title'));
});
})( jQuery );
/* Удалить CSS */
body {
display: flex;
flex-wrap: wrap;
}
.servicelist {
margin: 5px;
}
ul#buttonsArr {
width: 100%;
}
/* конец CSS */
.servicelist {
display: inline-block;
width: 100px;
height: 100px;
position: relative;
}
#servicelist1 {
border: 1px solid #f00;
}
#servicelist2 {
border: 1px solid #0f0;
}
#servicelist3 {
border: 1px solid #00f;
}
.tooltip-title {
position: fixed;
padding: 10px 20px;
border: 1px solid #b3c9ce;
border-radius: 4px;
text-align: center;
font: italic 14px/1.3 arial, sans-serif;
color: #333;
background: #fff;
box-shadow: 3px 3px 3px rgba(0, 0, 0, .3);
}
Предположим, есть следующая иерархия классов: static interface A
{
void roll();
} static class B implements A
{
@Override
public void roll() {
System.out.println("B");
}
} static class C implements A
{
@Override
public void roll() {
System.out.println("C");
}
}
Требуется положить в HashMap следующее: map.put(Class, List), где E - класс, наследующийся от A, причем, нужно запретить класть разноименно параметризованные классы. Пример:
Должно компилироваться: map.put(Class,List);
map.put(Class,List);
Ошибка компиляции: map.put(Class, List);
Как это можно реализовать, если вообще такое возможно?
Ответ
Если я правильно понял вопрос, то нужно сделать так: private static Map, List> getMap() {
return new HashMap<>();
}
И использовать этот метод следующим образом: Map, List> map = getMap();
map.put(B.class, new ArrayList<>());
map.put(C.class, new ArrayList<>()); //<- ошибка компиляции
UPDATE Боюсь, то что вы хотите, нельзя сделать без создания дополнительного класса, который реализовывал бы данное ограничение. Например так: private static class CustomMap {
private final Map, List> map = new HashMap<>(); @SuppressWarnings("unchecked")
public
List
get(P key) {
return (List
) map.get(key);
} @SuppressWarnings("unchecked")
public
Здесь есть несколько статей по CefSharp, но как правило примеры кода скудные, и не раскрываю как использовать библиотеку . То что здесь нашёл выкидывает исключения, в общем прошу помочь - привести пример . Как без загрузки фрейма получить html текст с исполненным javascript. Скрипты должны выполнятся все, как в браузере , а не отдельно указанный в Task .
Привожу пример с отображением в форме для CefSharp.WinForms , мне нужна аналогия кода для CefSharp.OffScreen 57 . DotNet 4.5.2 public partial class FormMain : Form
{
private ChromiumWebBrowser browser;
private CefSettings settings; public FormMain()
{
InitializeComponent();
InitializeWebBrowser();
}
private void InitializeWebBrowser()
{
settings = new CefSettings(); settings.CefCommandLineArgs.Add("proxy-server", "37.75.9.131:8080");
settings.UserAgent = "Mozila 5.0"; Cef.Initialize(settings); browser = new ChromiumWebBrowser(string.Empty) { Dock = DockStyle.Fill }; Controls.Add(browser);
}
private void btnLoad_Click(object sender, EventArgs e)
{
browser.Load("https://google.com");
}
private async void btnSource_Click(object sender, EventArgs e)
{
var doc = browser.GetMainFrame();
string text = await doc.GetTextAsync();
}
}
Таким образом я задал Proxy и UserAgent получил исходный код с обработанным JS спарсил текст страницы без разметки. Html можно получить сл. образом : заменить string text = await doc.GetTextAsync(); на string html = await doc.GetSourceAsync();
Ответ
Пришёл к такому решению для CefSharp.OffScreen private void btnGetText_Click(object sender, EventArgs e)
{
LoadFullText("https://google.com");
} private async void LoadFullText(string url)
{
CefSettings settings = new CefSettings();
settings.CefCommandLineArgs.Add("proxy-server", "37.75.9.131:8080");
settings.UserAgent = "Mozila 5.0";
Cef.Initialize(settings);
using (var chromium = new ChromiumWebBrowser(string.Empty))
{
Thread.Sleep(1000);
await LoadPageAsync(chromium, url);
string text = await chromium.GetTextAsync();
}
} public static Task LoadPageAsync(IWebBrowser browser, string address = null)
{
var tcs = new TaskCompletionSource();
EventHandler handler = null;
handler = (sender, args) =>
{
if (!args.IsLoading)
{
browser.LoadingStateChanged -= handler;
tcs.TrySetResultAsync(true);
}
};
browser.LoadingStateChanged += handler;
if (!string.IsNullOrEmpty(address))
{
browser.Load(address);
}
return tcs.Task;
}
Для проверки работы просто вставил Thread.Sleep(1000); здесь нужно доработать.
Есть 2 массива с именами и ценами некоторых предметов (x и ItemPrice).
Для того чтобы у меня были отдельно имена двух массивов, сделал для обоих такие циклы: for (i = 0; i < x.length; i++){
names = x[i];
name = names.custom_market_name;
} for (i = 0; i< ItemPrice.length; i++){
namess = ItemPrice[i];
namex = namess.market_name;
}
Теперь мне их нужно отдельно последовательно сравнить(имена одного с именами другого массива). Я пытался сделать это такой функцией: function OnGoPressed(){
var ln1 = namex.length, ln2 = name.length;
for (var i = 0; i < ln1; ++i){
cache = namex[i];
for (var j = 0; j < ln2; ++j){
if (cache == name[j]){
console.log('найдено совпадение: ' + cache);
break;
}
}
}
}
но результата 0.
Ответ
Ваши переменные name и namex - это не массивы, а имена последних элементов в соответствующих массивах. var namesX = x.map(function(item){ return item.custom_market_name; });
var namesIP = ItemPrice.map(function(item){ return item.market_name; }); for (var i = 0; i < namesX.length; i++) {
if (namesIP.indexOf(namesX[i]) != -1)
console.log('найдено совпадение: ' + namesX[i]);
}
Всем добрый день, стало интересно, как работает доступ к локальным переменным из анонимного класса. Допустим у меня такой код public void addListener() {
String s = "Hello World";
this.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
System.out.println(s);
}
});
}
И пусть этот метод будет определён в классе унаследованном от JButton. Вот мы при нажатии на эту кнопку
всегда будет видеть сообщение Hello World! Но мне интересно, как он будет ссылаться на этот Hello World!. Есть предположение, что у него есть некая невидимая ссылка на тот же на объект, что ссылается s т.е. на Hello World!, но я
не уверен в своём предположении, так что прошу у вас ответа на данный вопрос, спасибо.
Ответ
Все просто, анонимные классы компилируются в отдельные классы с названием <название родительского класса>$<индекс>.class. Если посмотреть на его содержимое, в частности, для примера который был в вопросе, то увидим следующее: class ru.izebit.Main$1 implements java.awt.event.ActionListener {
final java.lang.String val$s;
final ru.izebit.Main this$0;
ru.izebit.Main$1(ru.izebit.Main, java.lang.String);
public void actionPerformed(java.awt.event.ActionEvent);
}
ru.izebit.Main - это название класса, в котором я объявил анонимный класс.
val$s - ссылка на строковую переменную со значением "Hello World"
this$0 - ссылка на объект класса, в котором был объявлен анонимный класс, т.к. из анонимного класса есть возможность получать доступ к полям объекта, а это происходит именно через эту переменную
Пишется приложение на Android для сервера WildFly.
Со стороны сервера вход под своим логином и паролем на сайт со страницы авторизации выглядит так: @WebServlet(name = "LoginServlet", urlPatterns = "/login.do")
public class LoginServlet extends HttpServlet{
SecurityManager sm = new SecurityManager(); @Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
String email = request.getParameter("email").toLowerCase();
String pass = request.getParameter("pass"); if (sm.checkUser(email, pass)){
request.getSession().setAttribute("user", email);
response.sendRedirect(request.getContextPath() + "/testpage");
} else {
response.sendRedirect(request.getContextPath());
}
}
}
Также есть WebFilter, не пускающий на /testpageпользователя, если у сессии нет атрибута user. Это достигается следующим методом в классе LogiFilter public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
boolean loggedIn = session != null && session.getAttribute("user") != null; if (loggedIn) {
chain.doFilter(request, response);
} else {
response.sendRedirect(request.getContextPath());
}
}
При попытке осуществления авторизации через браузер сервер адекватно отрабатывает согласно имеющейся в БД паре log | pass. В зависимости от выданного атрибута user на дочерней странице /testpage отображается соответствующая авторизованному пользователю информация. Тем не менее, при попытке авторизации с приложения Android несмотря на отправку методом POST верной (не верной в том числе) пары log | pass атрибут user не закрепляется, из-за чего происходит редирект со страницы /testpage на страницу авторизации. Код осуществления POST-запроса: private class PostTask extends AsyncTask {
@Override
protected String doInBackground(String... data) {
final String USER_AGENT = "Mozilla/5.0"; try {
StringBuilder tokenUri = new StringBuilder("email=");
tokenUri.append(URLEncoder.encode("email", "UTF-8"));
tokenUri.append("&pass=");
tokenUri.append(URLEncoder.encode("password", "UTF-8"));
String url = "http://xxx.xxx.xxx.xxx:xxxxx/sendmsg/login.do";
URL obj = new URL(url);
//HttpURLConnection.setFollowRedirects(false);
HttpURLConnection con = (HttpURLConnection) obj.openConnection(); con.setRequestMethod("POST");
con.setRequestProperty("User-Agent", USER_AGENT);
con.setRequestProperty("Accept-Language", "UTF-8");
//con.setInstanceFollowRedirects(false); con.setDoOutput(true);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(con.getOutputStream());
outputStreamWriter.write(tokenUri.toString());
outputStreamWriter.flush(); int responseCode = con.getResponseCode();
System.out.println(" Sending 'POST' request to URL : " + url);
System.out.println("Post parameters : " + tokenUri);
System.out.println("Response Code : " + responseCode);
System.out.println("Response Body : " + con.getResponseMessage()); BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer(); while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
};
in.close(); System.out.println(response.toString()); }catch (Exception e){e.printStackTrace();}
return null;
} @Override
protected void onPostExecute(String s) {
//new GetTask().execute();
super.onPostExecute(s);
}
}
При использовании параметра HttpURLConnection.setFollowRedirects(false); редирект не производится, а response code становится равным 307 (Temporary Redirect). При попытке получить GET-запросом /testpage приходит response code 302 (Found). При включении редиректа в любом случае приходит страница авторизации. Не исключено, что требуется ручное присвоение сессии атрибутов или использование cookie.
Ответ
Да, вы верно подметили, HttpURLConnection сам сессиями и куками не занимается, ему их надо каждый раз выставлять. Как пример, можете посмотреть образец кода на enSO:
https://stackoverflow.com/a/16171708/5479247
Есть переменная которая объявлена как const char* str_value. Нужно получить самое короткое слово в ней. Например, при выводе в цикле printf("%s = ", str_value[i]); программа завершается, а при сравнении с " " ругается на char*. Как это нужно исправить? Завершение даже при printf("%s = ", str_value[1]); При выводе printf("%d = ", str_value[1]); выходит число. Это код символа? Почему?
Ответ
Примерно так должна выглядеть ваша функция: void findShortestWord(const char* in, char* out)
{
int len = strlen(in); int beginWord = 0;
int lengthWord = 0; for (int i = 0; i < len; i++)
{
while ( (in[i] == ' ') && ( in[i] != '\0') ) i++;
int begin = i;
while ( (in[i] != ' ') && (in[i] != '\0') ) i++;
int end = i;
char tmp[256];
for(int j = begin, k=0; j < end; j++, k++)
tmp[k] = in[j];
tmp[end - begin] = '\0'; int currentLen = end - begin;
if (currentLen > lengthWord)
{
lengthWord = currentLen;
beginWord = begin;
}
} for (int i = beginWord, k = 0; i < beginWord + lengthWord; i++, k++)
out[k] = in[i]; out[lengthWord] = '\0';
}
Добрый утро! Каким образом можно упростить данный триггер и какие замечания будут по данному коду? ...
Ответ
Вам не нужно переустанавливать Content в триггере, если вы хотите изменить свойства уже существующего элемента. Меняйте свойства через , предварительно установив имя для элемента. При этом Content нужно вынести в ControlTemplate, чтобы была возможность обращаться в сеттере к элементу через TargetName Затем в стиле устанавливаем свойство Template
Если в стиле вы больше ничего не делаете, то можно применить шаблон напрямую к кнопке, без создания стиля:
Хочу передавать в процедуру строку с запросом для курсора. Пробую сделать это так: DECLARE
TYPE t_client_cursor IS REF CURSOR RETURN CLIENTS%ROWTYPE;
v_client_cursor t_client_cursor;
v_client CLIENTS%ROWTYPE;
v_query_text VARCHAR2(100) := 'SELECT * FROM CLIENTS C WHERE ROWNUM < 4 ORDER BY C.CLNT_ID';
BEGIN
OPEN v_client_cursor FOR
exec (v_query_text);
....
END;
/
Ругается ORA-06550: Трока 8, столбец 6;
PLS-00455: курсор 'V_CLIENT_CURSOR' нельзя использовать в команде OPEN dynamic
SQL ORA-06550: Строка 8, столбец 1:
PL/SQL: Statement ignored
Но как-то ведь должно быть возможным определить курсор из строки?
Ответ
Я так понимаю, вам нужно что-то вроде этого: declare
v_client_cursor sys_refcursor;
v_query_text VARCHAR2(100) :=
'SELECT * FROM CLIENTS C WHERE ROWNUM < 4 ORDER BY C.CLNT_ID';
begin
open v_client_cursor for v_query_text; ... close v_client_cursor;
end;
/
Из-за повторных соединений с базой возникает существенная нагрузка на сервер MySQL, на эти операции приходится 64% от общей нагрузки, неизбежно приходиться смотреть в сторону постоянного подключения, подскажите как лучше это сделать? PDO или Myqli? Сейчас сайт сверстан на PDO. Читал в интернете, что при постоянном соединений не рекомендуется PDO. С радостью приму также дополнительные советы. Вот статистика нагрузки на базу:
Ответ
Сначала, ссылка, просто прочитайте всё там - минут 10, зато многие вопросы сами собой отпадут.
Не понимаю, откуда взялась эта дурацкая легенда о том, что нужно обязательно "закрывать" соединение? Может так и было в php версии 4 и ниже, на устаревшем ныне расширении mysql, но в PDO совершенно точно это не так. Вот просто реально, все кто про это пишет - зайдите и еще раз внимательно прочитайте
При успешном подключении к базе данных в скрипт будет возвращен
созданный PDO объект. Соединение остается активным на протяжении всего
времени жизни объекта. Чтобы закрыть соединение, необходимо уничтожить
объект путем удаления всех ссылок на него (этого можно добиться,
присваивая NULL всем переменным, указывающим на объект). Если не
сделать этого явно, PHP автоматически закроет соединение по окончании
работы скрипта.
Как правильно пишут товарищи в комментариях - по-хорошему, за выполнение скрипта соединение должно создаваться один лишь раз. Как вы это реализуете - без разницы: можно использовать глобальную переменную, можно использовать статическую переменную функции, можно использовать статический метод класса (со статической переменной класса). Все кто пишут просто "статические методы - плохо", это, конечно, гениально, повторять за большинством, но я реально не вижу ни одной разумной причины, по которой, например, для каждого объекта люди почему-то создают новое соединение. И уж совершенно точно не нужно на каждый запрос открывать отдельное соединение.
Раз уж у вас есть PDO - используйте его возможности на максимум: а. используйте подготовленные запросы и никогда не вклеивайте переменные вручную в строку запроса. б. где нужно именно выполнить несколько запросов в цикле - делаете PDO::prepare перед циклом, записываете в переменную, далее в цикле уже выполняете PDOStatement::execute и PDOStatement::fetchAll. Но всё же в большинстве случаев рекомендую подумать - а нельзя ли все необходимые данные вытянуть, всё же, одним запросом. в. ознакомьтесь с константами PDO::FETCH_*. чаще всего необходимы:
PDO::FETCH_ASSOC - почти всегда (рекомендуется его вообще прописать в опциях соединения, как режим извлечения по-умолчанию)
PDO::FETCH_COLUMN - когда нужно получить массив, в котором собраны все значения лишь по одному из столбцов в бд
PDO::FETCH_KEY_PAIR - ключ - первое поле выборки, значение - второе поле выборки (например массив [ id_клиента => имя_клиента ]).
PDO::FETCH_UNIQUE | PDO::FETCH_ASSOC - когда нужно получить массив, ключом которого станет первое поле из выборки, а значением - массив данных.
PDO::FETCH_GROUP | PDO::FETCH_ASSOC - вообще чудеснейшая комбинация, по первому полю выборка группируется и раскладывается на отдельные "подмассивы".
P.S. ну и, не относится напрямую к PDO, не забывайте про ключи и предподготовку статистических данных (судя по тому, что у Вас всего три апдейта за сутки - это должно сократить время выборок в разы).
Привет всем! Возникла идея написать приложение на подобии USBDeview (приложение, отображающее все подключенные на данный момент USB девайсы). Хочу также реализовать функционал включения/выключения USB устройства по расписанию (USBDeview тоже так умеет). Все манипуляции провожу через запросы к WMI . Столкнулся с рядом проблем:
При подключении нового USB устройства появляются два девайса - USB Mass Storage Device и Disk Drive. Какое из включать/выключать, чтобы USB устройство правильно отключилось?
Запрос "select * from Win32_PnpEntity" возвращает довольно скудный набор свойств (например отсутствуют нужные мне параметры, такие как Matching device Id, Class, Is connected и т.д. - все эти параметры есть в Device Manager'e во вкладке Details). Отсюда вытекает вопрос. Как отобразить ВСЕ свойства, которые есть в Device Manager'e?
Небольшой пример кода на C#:
class Program
{
static void Main(string[] args)
{
ManagementObjectCollection collection;
using (var searcher = new ManagementObjectSearcher(@"Select * From Win32_PnpEntity"))
collection = searcher.Get(); foreach (var device in collection)
{
Console.WriteLine("===================================");
foreach (var prop in device.Properties)
Console.WriteLine("\t{0} : {1}", prop.Name, prop.Value);
Console.WriteLine("===================================");
} collection.Dispose(); Console.Read();
}
При подключении флешки появляется два новых устройства: Disk Drive:
USB Mass Storage Device:
Мне же нужно получить список этих свойств:
Подскажите, пожалуйста, в каком направлении мне идти?
Ответ
При подключении нового USB устройства появляются два девайса - USB
Mass Storage Device и Disk Drive. Какое из включать/выключать, чтобы
USB устройство правильно отключилось?
Я полагаю, USB Mass Storage Device, т.к. Disk Drive является для него дочерним устройством, и отключается автоматически
Как отобразить ВСЕ свойства, которые есть в Device Manager'e?
Не знаю насчет "все", но довольно много свойств можно получить с помощью Setup API. Функция на C++ для вывода всех свойств по заданному ID устройства:
#pragma comment(lib,"Setupapi.lib") #include
#include
#include
#include
#include
#include void ErrorMes(LPTSTR lpszFunction)
{
// Retrieve the system error message for the last-error code LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError(); FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL ); // Display the error message and exit the process lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
wprintf(L"%s failed with error %d: %s",
lpszFunction, dw, lpMsgBuf); LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf); }
/*Вывод информации об устройстве с указанным InstanceID*/
BOOL PrintDevice(wchar_t* id)
{
unsigned index;
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
TCHAR id_upper[1024]=L"";
TCHAR buf[1024]=L"";
DEVPROPTYPE dpt=0;
DEVPROPKEY arr[100];
DWORD count=0; for(int i=0;i // List all connected devices
hDevInfo = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES);
for (index = 0; ; index++) {
DeviceInfoData.cbSize = sizeof(DeviceInfoData);
if (!SetupDiEnumDeviceInfo(hDevInfo, index, &DeviceInfoData)) {
return FALSE; // no match
} BOOL res=SetupDiGetDeviceProperty(hDevInfo,&DeviceInfoData,
&DEVPKEY_Device_InstanceId,&dpt,(PBYTE)buf,1000,NULL,0);
if(res==FALSE)continue;
if(wcscmp(buf,id_upper)==0){
//устройство найдено
res=SetupDiGetDeviceProperty(hDevInfo,&DeviceInfoData,
&DEVPKEY_Device_DeviceDesc,&dpt,(PBYTE)buf,1000,NULL,0); //вывод названия устройства
if(res==FALSE)ErrorMes(L"SetupDiGetDeviceProperty");
else wprintf(L"* %s's properties: *
",buf); //получение свойств
res=SetupDiGetDevicePropertyKeys(hDevInfo,&DeviceInfoData,arr,100,&count,0);
if(res==FALSE)ErrorMes(L"SetupDiGetDevicePropertyKeys"); for(int i=0;i if(res==FALSE){ErrorMes(L"SetupDiGetDeviceProperty");continue;} //вывод DEVPROPKEY
wprintf(L"{%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX; %3d}: ",
arr[i].fmtid.Data1, arr[i].fmtid.Data2, arr[i].fmtid.Data3,
arr[i].fmtid.Data4[0], arr[i].fmtid.Data4[1], arr[i].fmtid.Data4[2], arr[i].fmtid.Data4[3],
arr[i].fmtid.Data4[4], arr[i].fmtid.Data4[5], arr[i].fmtid.Data4[6], arr[i].fmtid.Data4[7],
arr[i].pid); //вывод типа и значения свойства
switch (dpt)
{
case DEVPROP_TYPE_STRING:wprintf(L"String \t%s ",buf); break;
case DEVPROP_TYPE_STRING_LIST:wprintf(L"Strings \tFirst line: %s ",buf);break;
case DEVPROP_TYPE_BOOLEAN:wprintf(L"Bool \t%d ",(bool)*((LPBYTE)(&buf)));break;
case DEVPROP_TYPE_UINT16:wprintf(L"%Uint16 \t%d ",*((LPWORD)(&buf)));break;
case DEVPROP_TYPE_UINT32:wprintf(L"Uint \t%d ",*((LPUINT)(&buf)));break;
case DEVPROP_TYPE_GUID:
wprintf(L"GUID \t{%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX} ",
(*((GUID*)(&buf))).Data1, (*((GUID*)(&buf))).Data2, (*((GUID*)(&buf))).Data3,
(*((GUID*)(&buf))).Data4[0], (*((GUID*)(&buf))).Data4[1], (*((GUID*)(&buf))).Data4[2],
(*((GUID*)(&buf))).Data4[3], (*((GUID*)(&buf))).Data4[4], (*((GUID*)(&buf))).Data4[5],
(*((GUID*)(&buf))).Data4[6], (*((GUID*)(&buf))).Data4[7]); break;
case DEVPROP_TYPE_BINARY:wprintf(L"(Binary data) ");break; default:wprintf(L"Other \tType: 0x%x ",(int)dpt);
break;
} } SetupDiDestroyDeviceInfoList(hDevInfo);
return TRUE;
}//end if
}//end for SetupDiDestroyDeviceInfoList(hDevInfo);
return FALSE;//устройство не найдено
}
int main()
{
setlocale(LC_ALL,"Russian"); PrintDevice(L"USB\\VID_046E&PID_5505\\5&15C311E1&0&6"); system("PAUSE");
return 0;
}
Пример вывода: * Составное USB устройство's properties: * {A45C254E-DF1C-4EFD-8020-67D146A850E0; 2}: String Составное USB устройство
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 3}: Strings First line: USB\VID_046E&PID_5505&REV_0100
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 4}: Strings First line: USB\DevClass_00&SubClass_00&Prot_00
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 6}: String usbccgp
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 9}: String USB
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 10}: GUID {36FC9E60-C465-11CF-8056-444553540000}
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 11}: String {36fc9e60-c465-11cf-8056-444553540000}\0009
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 12}: Uint 0
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 13}: String (Стандартный USB хост-контроллер)
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 15}: String Port_#0006.Hub_#0003
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 16}: String \Device\USBPDO-6
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 17}: Uint 132
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 21}: GUID {9D7DEBBC-C85D-11D1-9EB4-006008C3A19A}
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 22}: Uint 15
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 23}: Uint 0
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 24}: String USB
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 30}: Uint 6
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 32}: (Binary data)
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 33}: Uint 3
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 34}: Uint 3
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 36}: Uint 0
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 38}: GUID {23447943-B752-11E7-B8FD-806E6F6E6963}
{B725F130-47EF-101A-A5F1-02608C9EEBAC; 10}: String Составное USB устройство
{78C34FC8-104A-4ACA-9EA4-524D52996E57; 256}: String USB\VID_046E&PID_5505\5&15C311E1&0&6
{4340A6C5-93FA-4706-972C-7B648008A5A7; 2}: Uint 25182218
{4340A6C5-93FA-4706-972C-7B648008A5A7; 3}: Uint 0
{4340A6C5-93FA-4706-972C-7B648008A5A7; 7}: Strings First line: USB\VID_046E&PID_5505&MI_00\6&157c6e38&0&0000
{4340A6C5-93FA-4706-972C-7B648008A5A7; 8}: String USB\ROOT_HUB30\4&1ed8c4ae&0&0
{4340A6C5-93FA-4706-972C-7B648008A5A7; 9}: Strings First line: USB\VID_046E&PID_5505&MI_00\6&157c6e38&0&0000
{4340A6C5-93FA-4706-972C-7B648008A5A7; 10}: Strings First line: USB\VID_09DA&PID_000A\5&15c311e1&0&3
{AFD97640-86A3-4210-B67C-289C41AABE55; 2}: Bool 0
{8C7ED206-3F8A-4827-B3AB-AE9E1FAEFC6C; 2}: GUID {23447943-B752-11E7-B8FD-806E6F6E6963}
{540B947E-8B40-45BC-A8A2-6A0B894CBDA2; 5}: Bool 1
{540B947E-8B40-45BC-A8A2-6A0B894CBDA2; 6}: Bool 0
{83DA6326-97A6-4088-9453-A1923F573B29; 15}: Bool 1
{540B947E-8B40-45BC-A8A2-6A0B894CBDA2; 16}: Bool 0
{540B947E-8B40-45BC-A8A2-6A0B894CBDA2; 8}: Uint 2026182162
{8C7ED206-3F8A-4827-B3AB-AE9E1FAEFC6C; 4}: Bool 0
{540B947E-8B40-45BC-A8A2-6A0B894CBDA2; 14}: Strings First line: \Driver\usbccgp
{3464F7A4-2444-40B1-980A-E0903CB6D912; 10}: Uint 3
{540B947E-8B40-45BC-A8A2-6A0B894CBDA2; 4}: String USB Multimedia Keyboard
{540B947E-8B40-45BC-A8A2-6A0B894CBDA2; 7}: String usb.inf:USB\COMPOSITE,Composite.Dev.NT
{540B947E-8B40-45BC-A8A2-6A0B894CBDA2; 9}: (Binary data)
{540B947E-8B40-45BC-A8A2-6A0B894CBDA2; 10}: String \_SB.PCI0.XHC.RHUB.HS06
{80497100-8C73-48B9-AAD9-CE387E19C56E; 6}: Uint 0
{80497100-8C73-48B9-AAD9-CE387E19C56E; 7}: Other Type: 0x9
{83DA6326-97A6-4088-9453-A1923F573B29; 3}: String usb.inf:392c3d53461eda3a:Composite.Dev.NT:10.0.15063.674:USB\COMPOSITE
{83DA6326-97A6-4088-9453-A1923F573B29; 10}: String USB\ROOT_HUB30\4&1ed8c4ae&0&0
{83DA6326-97A6-4088-9453-A1923F573B29; 100}: Other Type: 0x10
{83DA6326-97A6-4088-9453-A1923F573B29; 101}: Other Type: 0x10
{83DA6326-97A6-4088-9453-A1923F573B29; 102}: Other Type: 0x10
{A45C254E-DF1C-4EFD-8020-67D146A850E0; 37}: Strings First line: PCIROOT(0)#PCI(1400)#USBROOT(0)#USB(6)
{A8B865DD-2E3D-4094-AD97-E593A70C75D6; 2}: Other Type: 0x10
{A8B865DD-2E3D-4094-AD97-E593A70C75D6; 3}: String 10.0.15063.674
{A8B865DD-2E3D-4094-AD97-E593A70C75D6; 4}: String USB Composite Device
{A8B865DD-2E3D-4094-AD97-E593A70C75D6; 5}: String usb.inf
{A8B865DD-2E3D-4094-AD97-E593A70C75D6; 6}: String Composite.Dev.NT
{A8B865DD-2E3D-4094-AD97-E593A70C75D6; 8}: String USB\COMPOSITE
{A8B865DD-2E3D-4094-AD97-E593A70C75D6; 9}: String Microsoft
{A8B865DD-2E3D-4094-AD97-E593A70C75D6; 14}: Uint 16719875
Для продолжения нажмите любую клавишу . . .
Свойства определяются по значениям DEVPROPKEY. Чтобы понять, что это за свойство, нужно сравнить его с константами из Devpkey.h (например, Matching Device ID - это DEVPKEY_Device_MatchingDeviceId).