Перед запуском сценария хочу проверить есть ли в БД секвенция и если есть - дропнуть
её. Но DROP SEQUENCE не работает в PLSQL, а IF не работает в SQL. Как быть? Сейчас
в начало сценария приписал:
DECLARE
V_TEMP_NUM NUMBER(9) := 0;
BEGIN
SELECT COUNT(*) INTO V_TEMP_NUM FROM USER_SEQUENCES WHERE SEQUENCE_NAME = 'TMM_TEMP10_SEQ';
IF V_TEMP_NUM > 0 THEN
DROP SEQUENCE TMM_TEMP10_SEQ;
END IF;
CREATE SEQUENCE TMM_TEMP10_SEQ
MINVALUE 0
START WITH 10
INCREMENT BY 10
CACHE 20;
END;
Как я и сказал, ругается на DROP.
Ответы
Ответ 1 Много лет назад я написал небольшую процедуру, которая реализует логику:
CREATE/ALTER/DROP IF EXISTS...
Можно воспользоваться ей в вашем случае:
create or replace procedure admin.re_run_ddl (p_sql in varchar2)
AUTHID CURRENT_USER
as
l_line varchar2(500) default rpad('-',20,'-');
l_cr varchar2(2) default chr(10);
l_footer varchar2(500) default l_cr||rpad('*',20,'*');
l_ignore_txt varchar2(200) default 'IGNORING --> ';
ORA_00955 EXCEPTION;
ORA_01430 EXCEPTION;
ORA_02260 EXCEPTION;
ORA_01408 EXCEPTION;
ORA_00942 EXCEPTION;
ORA_02275 EXCEPTION;
ORA_01418 EXCEPTION;
ORA_02443 EXCEPTION;
ORA_01442 EXCEPTION;
ORA_01434 EXCEPTION;
ORA_01543 EXCEPTION;
ORA_00904 EXCEPTION;
ORA_02261 EXCEPTION;
ORA_04043 EXCEPTION;
ORA_02289 EXCEPTION;
PRAGMA EXCEPTION_INIT(ORA_00955, -00955); --ORA-00955: name is already used by
an existing object
PRAGMA EXCEPTION_INIT(ORA_01430, -01430); --ORA-01430: column being added already
exists in table
PRAGMA EXCEPTION_INIT(ORA_02260, -02260); --ORA-02260: table can have only one
primary key
PRAGMA EXCEPTION_INIT(ORA_01408, -01408); --ORA-01408: such column list already indexed
PRAGMA EXCEPTION_INIT(ORA_00942, -00942); --ORA-00942: table or view does not exist
PRAGMA EXCEPTION_INIT(ORA_02275, -02275); --ORA-02275: such a referential constraint
already exists in the table
PRAGMA EXCEPTION_INIT(ORA_01418, -01418); --ORA-01418: specified index does not exist
PRAGMA EXCEPTION_INIT(ORA_02443, -02443); --ORA-02443: Cannot drop constraint
- nonexistent constraint
PRAGMA EXCEPTION_INIT(ORA_01442, -01442); --ORA-01442: column to be modified to
NOT NULL is already NOT NULL
PRAGMA EXCEPTION_INIT(ORA_01434, -01434); --ORA-01434: private synonym to be dropped
does not exist
PRAGMA EXCEPTION_INIT(ORA_01543, -01543); --ORA-01543: tablespace ''
already exists
PRAGMA EXCEPTION_INIT(ORA_00904, -00904); --ORA-00904: "%s: invalid identifier"
PRAGMA EXCEPTION_INIT(ORA_02261, -02261); --ORA-02261: "such unique or primary
key already exists in the table"
PRAGMA EXCEPTION_INIT(ORA_04043, -04043); --ORA-04043: object %s does not exist
PRAGMA EXCEPTION_INIT(ORA_02289, -02289); --ORA-02289: sequence does not exist
procedure p(
p_str in varchar2
,p_maxlength in int default 120
)
is
i int := 1;
begin
dbms_output.enable( NULL );
while ( (length(substr(p_str,i,p_maxlength))) = p_maxlength ) loop
dbms_output.put_line(substr(p_str,i,p_maxlength));
i := i + p_maxlength;
end loop;
dbms_output.put_line(substr(p_str,i,p_maxlength));
end p;
begin
p( 'EXEC:'||l_cr||l_line||l_cr||p_sql||l_cr||l_line );
execute immediate p_sql;
p( 'done.' );
exception
when ORA_00955 or ORA_01430 or ORA_02260 or ORA_01408 or ORA_00942
or ORA_02275 or ORA_01418 or ORA_02443 or ORA_01442 or ORA_01434
or ORA_01543 or ORA_00904 or ORA_02261 or ORA_04043 or ORA_02289
then p( l_ignore_txt || SQLERRM || l_footer );
when OTHERS then
p( SQLERRM );
p( DBMS_UTILITY.FORMAT_ERROR_BACKTRACE );
p( l_footer );
RAISE;
end;
/
show err
Пример использования:
prompt clean-up ...
begin
admin.re_run_ddl('drop sequence BLA_BLA_BLA');
admin.re_run_ddl('drop procedure BLA_BLA_BLA');
admin.re_run_ddl('drop table BLA_BLA_BLA');
end;
/
Ответ 2 А на дроп ругается из за этого (execute immediate), о чём нам напоминает Коннор на
AskTOM:
DDL - считается редким событием в Oracle (в отличие от других СУБД)
DECLARE
V_TEMP_NUM NUMBER(9) := 0;
BEGIN
SELECT COUNT(*) INTO V_TEMP_NUM FROM USER_SEQUENCES WHERE SEQUENCE_NAME = 'TMM_TEMP10_SEQ';
IF V_TEMP_NUM > 0 THEN
execute immediate 'DROP SEQUENCE TMM_TEMP10_SEQ';
END IF;
execute immediate '
CREATE SEQUENCE TMM_TEMP10_SEQ
MINVALUE 0
START WITH 10
INCREMENT BY 10
CACHE 20';
END;
#c_sharp #wpf
Каким образом можно проверить что визуальный объект виден пользователю, и его необходимо
отрисовать, в противном случае ничего не делать пока не станет видим?
В вопросе речь не о свойстве Visibility, а именно о поле видимости.
Ответы
Ответ 1 Используйте свойство IsVisible:
При определении значения IsVisible учитываются все факторы компоновки.
Visibility, которое является настраиваемым свойством,
указывает только на намерение программно сделать элемент видимым или
невидимым.
#java #многопоточность
Имеется два потока. Первый обрабатывает графический интерфейс, а другой должен получить
значение переменной, вводимой пользователей в первом потоке. Я два дня искал информацию,
но никакого толкового объяснения не нашёл.
public class s implements Runnable {
public static void s(){
System.out.println("тест");
}
@Override
public void run() {
s();
}
}
class Testpotok {
public static void main(String[] args) {
Thread t1 = new Thread(new s());
t1.start();
System.out.println("тест1");
}
}
Ответы
Ответ 1 Swing, как и многие другие gui-библиотеки, однопоточен. При создании окна создаётся
Event Dispatch Thread, внутри которого будет работать цикл событий и обработчики событий.
Вы не должны пытаться из главного потока или любого другого потока взаимодействовать
с элементами графического интерфейса - это приведёт к сбою. Вы не должны внутри обработчиков
событий запускать потоки - это приведёт к сбою. Если вам надо из другого потока изменить,
например, текст метки, то придётся создать задание для EDT:
SwingUtilities.invokeLater(() -> someLabel.setText("Hello"));
Если вам нужно внутри обработчика нажатия на кнопку запустить на выполнение длительную
задачу, придётся использовать SwingWorker:
SwingWorker worker = new SwingWorker() {
@Override
protected void doInBackground() throws Exception {
// Выполняется в отдельном потоке
}
@Override
protected void done() {
// Выполняется в EDT после завершения doInBackground
}
};
worker.execute();
#windows #администрирование #windows_10 #usb
Как известно, в Windows, когда завершаешь операции с USB флеш-накопителем, его надо
отключить отдельной командой. После этой команды появляется сообщение "теперь накопитель
ХХХ можно удалить".
Надоело мне каждый раз отключать USB флеш-накопители отдельной командой. Помнится
мне, что когда в ходу были дискеты, то для них не было никакой отдельной команды для
отключения. Конец операции копирования на дискету означал, что дискету можно вынимать.
Вопрос:
Как в Windows 10 сделать так, чтобы не надо было отключать USB флеш-накопители отдельной
командой? Хочу, чтобы как при работе с дискетами, окончание операции копирования (чтения
или записи) означало, что USB флеш-накопитель можно вынимать.
Ответы
Ответ 1 Втыкаем флешку.
Идем в Диспетчер устройств, находим в нем флешку, правый клик - Свойства.
Во второй вкладке активируем верхнюю опцию "Быстрое удаление".
Важно: окончание операции записи/копирования определяется не исчезновением индикатора
процесса копирования, а тем, что на флешке перестал мигать светодиод.
PS. Это в Вин7. Если в Вин10 не так, то удалю ответ.
#java
System.out.println(Paths.get("WordBase.txt").toAbsolutePath());
вывод консоли\\C:\apache-tomcat-7.0.85\bin\WordBase.txt
Могу корректно использовать файл только при указании абсолютного пути, можно как-то
исправить?
Ответы
Ответ 1 Поместите файл в папку src там вы сможете использоватьgetResourceAsStream(). Или
создайте папку с ресурсами мавена где можно хранить текстовые файлы.
Ответ 2 по хорошему файл должен быть внутри web, например, путь из сервлета к файлу будет
выглядеть как getServletContext().getRealPath("/") + "WordBase.txt"
#html #css #шрифты
Допустим, я указываю все размеры шрифтов в rem единицах, далее я при определенном
размере экрана задаю уменьшение шрифта, но выходит так, что шрифты, которые до этого
уже были маленькими, стали еще меньше, до такой степени, что они более нечитабельны.
Вот пример:
html {
font-size: 10px;
}
h1 {
font-size: 4rem;
}
h2 {
font-size: 3rem;
}
h3 {
font-size: 2.5rem;
}
h4 {
font-size: 2rem;
}
p {
font-size: 1.4rem;
}
@media screen and (max-width: 600px) {
html {
font-size: 6px;
}
}
Simple text
Simple text
Simple text
Simple text
Simple text
Вопрос в том, что делать в таких случаях? Как правильно поступать? Для маленьких
шрифтов задавать значения размера в абсолютных величинах?
Ответы
Ответ 1 Подходов для динамической типографики может быть много, я бы на вашем месте обратил
внимание на возможности функции calc() и, может быть, на зависимость размера шрифта
от ширины экрана — простейшая формула font-size: calc(1rem + 1vw), с деталями коэффициентов
надо уже экспериментировать. Также можете поинтересоваться темой CSS-шлюзов.
В вашем конкретном случае получается так, что вы задаете базовый размер шрифта 6
пикселей — потому естественно, что текст будет очень мелким. Вот пример, как этого
частично можно избежать с применением функции calc() и цсс-переменных. Надо добавить
увеличивающий коэффициент к тем значениям, которые становятся слишком мелкими на маленьких
экранах, в то время как на больших оставить его равным единице.
html {
font-size: 10px;
--font-ratio: 1;
}
h1 {
font-size: 4rem;
}
h2 {
font-size: 3rem;
}
h3 {
font-size: 2.5rem;
}
h4 {
color: red;
font-size: calc(2rem * var(--font-ratio));
}
p {
color: red;
font-size: calc(1.4rem * var(--font-ratio));
}
@media screen and (max-width: 600px) {
html {
font-size: 6px;
--font-ratio: 1.25;
}
}
Simple text
Simple text
Simple text
Simple text
Simple text
#c_sharp #wpf
На форме имеется Calendar, когда в нем выбираю дату, то приходится кликать по любому
другому элементу или пустому месту, чтобы остальные элементы стали активны.
То есть после выбора даты, активным остается календарь.
Как от этого избавиться? Чтобы не приходилось делать лишний клик?
В разметке нет ничего особенного:
Получается, когда я нажимаю на него и выбираю дату, то курсор двигается, но остальные
элементы неактивны (нет даже анимации при наведении на кнопки). Мне приходится делать
"пустой" клик, и тогда остальные элементы начинают отвечать.
Ответы
Ответ 1 Дело в том, что Calendar предназначен для размещения его во всевозможных всплывающих
элементах (например, таких как DatePicker), поэтому он захватывает (Capture) мышь.
Такое же поведение можно наблюдать, например, с ComboBox, если открыть выпадающий список,
то первый клик мыши будет закрывать его и только следующий будет обработан целевым
элементом.
К счастью, это поведение можно изменить таким кодом:
if (Mouse.Captured is CalendarItem) Mouse.Capture(null);
Вставьте его, например, в обработчик PreviewMouseUp вашего календаря.
#c_sharp #json
Есть классы-шаблоны под JSON.
Я для своего удобства хочу создать ссылку на объект объекта класса.
Короче говоря, грубый пример:
public class A {
B b = new B();
public int ref i = b.i; << tyt
public class B {
int i = 0;
}
}
Как сделать подобную ссылку?
Ответы
Ответ 1 Одним из вариантом может стать создание свойства у которого get будет брать значение
из объекта, а set - устанавливать:
public class A {
B b = new B();
public int i { get => b.i; set => b.i=value; }
public class B {
public int i = 0;
}
}
#c_sharp #wpf
Как измерить размер текста в текстбоксе от края первой буквы до края последней?
FormattedText formattedText = new FormattedText(str, CultureInfo.GetCultureInfo("en-us-ru"),
FlowDirection.LeftToRight, new Typeface(this.Name_textBox.FontFamily, this.Name_textBox.FontStyle,
this.Name_textBox.FontWeight, this.Name_textBox.FontStretch), Name_textBox.FontSize,
Brushes.Black);
double width = formattedText.Width;
Этот способ возвращает размер текстбокса, а нужна именно длина текста. Ничего другого
не нашел.
Ответы
Ответ 1 Решение простое — нужно создать на основе вашего текста геометрию и просто посмотреть
ее границы:
var dpiX = 96.0 * VisualTreeHelper.GetDpi(this).DpiScaleX;
var formattedText =
new FormattedText(
MyTextBox.Text,
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface(
MyTextBox.FontFamily,
MyTextBox.FontStyle,
MyTextBox.FontWeight,
MyTextBox.FontStretch),
MyTextBox.FontSize,
Brushes.Black,
dpiX);
var geometry = formattedText.BuildGeometry(new Point());
var bounds = geometry.Bounds;
MessageBox.Show($"{bounds.Width}");
Полный код примера. Разметка:
Кодбихайнд:
private void Button_Click(object sender, RoutedEventArgs e)
{
var dpiX = 96.0 * VisualTreeHelper.GetDpi(this).DpiScaleX;
var formattedText =
new FormattedText(
MyTextBox.Text,
CultureInfo.InvariantCulture,
FlowDirection.LeftToRight,
new Typeface(
MyTextBox.FontFamily,
MyTextBox.FontStyle,
MyTextBox.FontWeight,
MyTextBox.FontStretch),
MyTextBox.FontSize,
Brushes.Black,
dpiX);
var geometry = formattedText.BuildGeometry(new Point());
var bounds = geometry.Bounds;
MyCanvas.Height = formattedText.Height;
MyCanvas.Width = formattedText.Width;
MyPath.Data = geometry;
MyRect.Rect = bounds;
MessageBox.Show($"Ширина форматированного текста: {formattedText.Width}\nШирина
границ: {bounds.Width}");
}
#c_sharp #generics #методы
товарищи! Наткнулся я тут на старенькое интеревью с Джоном Скитом на хабре. В его
рамках Джон задал читателям следующий вопрос:
Как вы можете заставить этот код скомпилироваться, так чтобы он вызвал
три различные перегрузки метода?
void Foo()
{
EvilMethod();
EvilMethod();
EvilMethod();
}
Мне не совсем понятно, как можно реализовать такую вещь, ведь даже если использовать
where, то мы получаем ошибку, что метод с таким же названием и параметрами уже существует.
На SO искал, в Google тоже (возможно, искал плохо, так что если что - палками не бейте))
Будет очень интересно выслушать ваши идеи, так что заранее спасибо)
Ответы
Ответ 1 Удалось сделать только так:
public interface IEvilMethod
{
void EvilMethod();
}
public class Example : IEvilMethod, IEvilMethod, IEvilMethod
{
public void Foo()
{
((IEvilMethod) this).EvilMethod();
((IEvilMethod) this).EvilMethod();
((IEvilMethod) this).EvilMethod();
}
void IEvilMethod.EvilMethod()
{
Console.WriteLine(typeof(T));
}
void IEvilMethod.EvilMethod()
{
Console.WriteLine(typeof(T));
}
void IEvilMethod.EvilMethod()
{
Console.WriteLine(typeof(T));
}
}
Update
Нашел решение здесь.
public class ReferenceGeneric where T : class { }
public class EvilClassBase
{
protected void EvilMethod()
{
Console.WriteLine("int?");
}
}
public class EvilClass : EvilClassBase
{
public void Run()
{
EvilMethod();
EvilMethod();
EvilMethod();
}
private void EvilMethod(ReferenceGeneric arg = null) where T : class
{
Console.WriteLine("string");
}
private void EvilMethod(T? arg = null) where T : struct
{
Console.WriteLine("int");
}
}
#python #selenium
К примеру selenium'ом это решается красиво и лаконично, но при этом открывается окно
браузера. Можно ли как-нибудь делать скриншоты без этого? Возможно, используя другой
подход (не через selenium)
from selenium import webdriver
DRIVER = "chromedriver.exe"
driver = webdriver.Chrome(DRIVER)
driver.get("https://ru.stackoverflow.com/")
screenshot = driver.save_screenshot("my_screenshot.png")
driver.quit()
Ответы
Ответ 1 Нашел способ. Просто нужно было использовать PhantomJS, с ним окно браузера не открывается .
from selenium import webdriver
DRIVER = '\phantomjs-2.1.1-windows\\bin\phantomjs.exe'
driver = webdriver.PhantomJS(DRIVER)
driver.get("https://ru.stackoverflow.com/")
screenshot = driver.save_screenshot("my_screenshot.png")
driver.quit()
Ответ 2 Самый простой способ снимок экрана c веб-страницей получить — это запустить браузер
с подходящими опциями:
#!/usr/bin/env python3
from subprocess import check_call
url = 'https://ru.stackoverflow.com'
width, height = 1920, 1080
filename = "my_screenshot.png"
chrome_executable = 'chromium-browser'
check_call([chrome_executable, '--headless', f'--screenshot={filename}',
f'--window-size={width},{height}', '--hide-scrollbars',
url])
Аналог для selenium выглядит как:
#!/usr/bin/env python3
from selenium import webdriver # $ pip install selenium
options = webdriver.ChromeOptions()
options.add_argument('headless')
options.add_argument(f'window-size={width},{height}')
options.add_argument('hide-scrollbars')
# get chromedriver from
# https://sites.google.com/a/chromium.org/chromedriver/downloads
browser = webdriver.Chrome(chrome_options=options)
browser.get(url)
browser.save_screenshot(filename)
Можно напрямую API использовать без selenium, к примеру, у firefox есть marionette:
#!/usr/bin/env python2
import os
# $ pip install marionette_driver
from marionette_driver.marionette import Marionette
firefox_binary = '/usr/bin/firefox' # full path
os.environ['MOZ_HEADLESS'] = '1'
client = Marionette('localhost', bin=firefox_binary, port=2828)
try:
client.start_session()
client.set_window_size(width, height)
client.navigate(url)
with open(filename, 'wb') as file:
file.write(client.screenshot(format='binary'))
finally:
client.quit()
Для chrome можно использовать puppeteer или его аналог для Питона pyppeteer:
#!/usr/bin/env python3
import asyncio
import pyppeteer # $ pip install pyppeteer
async def main():
browser = await pyppeteer.launch()
page = await browser.newPage()
await page.goto(url)
await page.setViewport(dict(width=width, height=height))
await page.screenshot(path=filename, fullPage=False)
await browser.close()
asyncio.get_event_loop().run_until_complete(main())
Все представленные варианты только видимую часть сохраняют. При желании можно целиком
страницу в виде картинки получить. К примеру, в последнем варианте, достаточно fullPage=True
указать.
#java
Нужно вырезать некий блок символов из строки
блок вот такой
ParName{
//content
}
Мне нужно вырезать и ParName и { и content и }
Я использую
Pattern p = Pattern.compile(".*?\\{+\\}");
Matcher m = p.matcher(out);
f(m.find()){
System.out.println(m.group().subSequence(0, m.group().length()));
}else{
System.err.println("Ошибка");
}
Выводит Ошибка, -не нашел?
Ответы
Ответ 1 Регулярные выражения интересная вещь. Когда кажется, что уже предусмотрел всё, что
нужно, возникает еще пятнадцать идей, как усовершенствовать свою регулярку и написать
более однозначно :).
Предлагаю такой вариант регулярки для решения задачи:
Pattern p = Pattern.compile("(?ms)(?:ParName\\{){1}(.*[^}].*){0,1}[}]{1}");
Matcher m = p.matcher("ParName{ my \ninternal\n \t\ttext }");
if(m.find()) {
System.out.println("result: " + m.group(1));
} else {
System.out.println("not found ...");
}
Полезно посмотреть:
Исходники класса Pattern.
Документация Pattern
Пример использования: match-multiline-text-using-regular-expression
java-regex-tester
П.С.
Еще пример регулярного выражения от активного участника "(?ms)(?:ParName\\{)([^}]*)\\}"
Ответ 2 Спустя некоторое время,я наткнулся на более простое решение этой проблемы.
оно заключается в использовании split
String Objects[] = out.split("}\n");
int b = 0;
while(Objects.length > b){
System.out.println("Obj-"+b+": "+Objects[b] + "}");
b++;
}
Вывод будет следующий:
Obj-0: Object1{
##########content###########
}
Obj-1: Object2{
##########content###########
}
Может подойти,как вариант для аналогичных целей.
#c_sharp #регулярные_выражения
Как, используя регулярные выражения задать паттерн вида :
Начало ... конец ,
где ... это любые символы включая пробелы, тире подчеркивания и целые числа причем
сколько их неизвестно. Я пытаюсь сделать это так :
var pattern = new Regex(@"Start:\S*\s*End");
т.к. \S* - ноль или более символов не яв-ся пробелом а
\s* - ноль или более символов являющихся. Однако это неправильно. Как исправить ?
Ответы
Ответ 1 Используйте
var pattern = new Regex(@"Start:.*?End", RegexOptions.Singleline);
Подробности
Start: - начальный разделитель
.*? - 0 и более любых символов, как можно меньше (*? — ленивый квантификатор)
End - конечный разделитель
RegexOptions.Singleline - флаг, благодаря которому . находит все символы, даже символы
перевода строки.
Сининимические конструкции:
var pattern = new Regex(@"(?s)Start:.*?End");
var pattern = new Regex(@"Start:(?s:.*?)End");
Однако, если необходимо найти подстроку, в которой не должно быть разделителей, нужно
использовать "умеренно жадный токен"
(tempered greedy token):
var pattern = new Regex(@"(?s)Start:(?:(?!Start:).)*?End");
^^^^^^^^^^^^^^^^
Этот шаблон в строке Start: 1, Start: 2, End: 56 найдет Start: 2, End, а не Start:
1, Start: 2, End.
#cpp
Имеется класс Description, и его конструктор:
DescriptionWord::DescriptionWord (std::string translate, std::string transcription,
PartOfSpech pos)
: translation_{std::move(translate)}, transcription_{std::move(transcription)},
partOfSpech_{std::move(pos)} {
}
Будет ли создаваемый объект захватывать значения (точнее их копии), переданные в
конструктор при инициализации объекта? Или сдесь std::move не имеет смысла?
Ответы
Ответ 1 Разумеется std::move и семантика перемещения в таком контексте будет прекрасно работать
для объектов, для которых они что-то дают, т.е. в данном случае для std::string. Аргументы
после этого приобретут "moved-from" состояние, т. е. будут условно "разрушены".
То что вы видите в данном примере - это как раз одна из рекомендуемых к использованию
во многих случаях идиом: если вам в любом случае необходимо создать копию объекта,
то лучше дать это сделать компилятору (т.е. использовать передачу по значению), а потом
при необходимости выполнить перемещение из копии внутри метода.
Таким способом вы одним определением метода покрываете почти все преимущества семантики
перемещения:
Если ваш метод будет вызываться с именованным объектом в качестве аргумента
std::string str = "Hello World";
DescriptionWord a(str, ...);
то компилятор выполнит копирование, а затем вы быстренько сделаете дешевое перемещение
из копии.
Если ваш метод будет вызываться с "исчезающим" объектом в качестве аргумента
DescriptionWord a("Hello World", ...);
то произойдет только ваше перемещение после конструкции аргумента, т.е. никакого
копирования не будет.
Если ваш метод будет вызываться с rvalue-ссылкой в качестве аргумента
std::string str = "Hello World";
DescriptionWord a(std:::move(str), ...);
то произойдет два перемещения (одно - компиляторное, другое - ваше), т.е. копирования
не будет.
Это не так эффективно, как пара конструкторов (один для lvalue ссылок, другой - для
rvalue-ссылок) и это не так эффективно, как perfect forwarding аргументов, но это достаточно
эффективно для большинства случаев и, еще раз, покрывает все ситуации одной реализацией.
Если попытаться систематизировать доступные нам подходы к применению современных
семантик перемещения и идеального форвардинга в вашей ситуации, то можно выделить четыре
подхода
Стиль С++98 - не используем семантику перемещения вообще
Передача по константной ссылке и копирование внутри
struct S {
std::string s;
S(const std::string &s) :
s(s) // Вызывается конструктор копирования
{}
};
std::string s("Hello World");
S s1("Hello World"); // Конструкция временного объекта + копирование
S s2(s); // Копирование
S s3(std::move(s)); // Копирование
Это - неэффективный подход, ибо он всегда делает копирование. Даже тогда, когда без
него можно было бы запросто обойтись.
"Ленивая" семантика перемещения
Передача по значению и перемещение внутри
struct S {
std::string s;
S(std::string s) :
s(std::move(s)) // Вызывается конструктор перемещения
{}
};
std::string s("Hello World");
S s1("Hello World"); // Конструкция временного объекта + перемещение
S s2(s); // Копирование + перемещение
S s3(std::move(s)); // Перемещение + перемещение
Это уже лучше. Копирование делается только тогда, когда оно действительно нужно.
Незначительные недостатки этого варианта видны в сравнении со следующим вариантом.
Развитая семантика перемещения
Комбинируем 1 и 2 - предоставляем отдельные перегруженные методы на случай копирования
и на случай перемещения
struct S {
std::string s;
S(const std::string &s) : s(s) {}
S(std::string &&s) : s(std::move(s)) {}
};
std::string s("Hello World");
S s1("Hello World"); // Конструкция временного объекта + перемещение
S s2(s); // Копирование
S s3(std::move(s)); // Перемещение
Это еще лучше. По сравнению с предыдущим вариантом, мы избавились от лишних перемещений
для s2 и s3. Но зато нам пришлось писать два конструктора.
Идеальный форвардинг
Прямой форвардинг аргумента его конечному получателю
struct S {
std::string s;
template S(A &&s) : s(std::forward(s)) {}
};
std::string s("Hello World");
S s1("Hello World"); // Конструкция `S::s` напрямую
S s2(s); // Копирование
S s3(std::move(s)); // Перемещение
Самый лучший вариант - не делается ничего лишнего. Однако теряется контроль типов
через параметры конструктора. Чтобы вернуть его, придется предпринять некоторые усилия.
Ваш пример следует второму варианту. Он самый простой и при этом пользующийся почти
всеми преимуществами семантики перемещения. Его достаточно практически во всех случаях,
когда из кода не нужно выжимать последние процессорные такты.
Ответ 2 Семантика перемещения будет иметь смысл, если вы хотите переместить владение ресурсом.
Объект string, в упрощённом варианте, это указатель на динамический массив char и множество
иных вспомогательных полей. В вашей реализации класса, например строка translate,
после того как вы сделаете из нее перемещение при помощи метода move, будет содержать
поля, КОТОРЫЕ БУДУТ ТАКИМИ, БУДТО ВЫ ВЫЗВАЛИ ДЛЯ translate КОНСТРУКТОР ПО УМОЛЧАНИЮ.
А вот ресурс, на который указывал указатель в объекте translate, получит объект класса
который вы создаёте. Т.е. поле создаваемого объекта класса будет владеть указателем,
который будет указывать на массив чаров
Иными словами: такой конструктор - персонаж из 90ых. Он занимается рэкетом и отбирает
ресурсы у объектов, которые обернуты в move.
Когда стоит заняться рэкетом: если вы не хотите копировать (захват, по вашему. Как
я понял вы имеете ввиду что на динамический массив чаров будут указывать два объекта
стринг. Так вот в этой ситуации такого не будет)
#html #css #bootstrap #sass
Установил SASS через консоль, по этому туториалу sass-scss.ru.
В работе мне потребуется bootstrap.
Вопрос:
Как начать использовать в проекте SASS, создать файл style.scss и писать в него css
код или нужны дополнительные действия?
Как правильно подключить bootstrap и начать его использовать в проекте?
Сейчас на начальной стадии, html код выглядит так:
Hello, world!
Hello, world!
Ответы
Ответ 1 Если честно все не так просто, советую посмотреть/почитать гайд по развёртыванию
проекта на Gulp/Webpack так как если писать тут выйдет очень много кода. Что бы использовать
Sass нужно сначало развернуть NPM + например Webpack.
https://proglib.io/p/webpack-in-15/ - пример, но в интернете их ещё масса, стоит
лишь поискать.
Но для новичка Gulp будет легче в плане понимания.
После того как ты установишь зависимости на свой проект, выполни установку ещё двух
пакетов:
npm install bootstrap
npm install sass
И далее опиши таски в webpack/gulp, опять таки примеров в интернете много.
Будут вопросы пиши:)
Ответ 2 1. Вариант: Использовать webpack или gulp сборщик. Быстро и удобно, но нужно правильно
настроить. Примеров сборки в сети достаточно много.
Для gulp сборки выполнить:
npm i –g gulp
npm i --save-dev gulp
npm i --save-dev gulp-sass
npm i bootstrap
Настроить gulpfile.js.
Подключение bootstrap в style.scss:
@import "node_modules/bootstrap/scss/bootstrap.scss";
2. Вариант: Использовать online конверторы (например sassmeister ). Минусы - долго
и неудобно.
3. Вариант: Конвертер с помощью командной строки ruby. Для этого нужно установить
rubyinstaller. Запустить командную строку ruby. Выполнить команды:
gem install sass
sass input.scss output.css
или
sass --watch input.scss:output.css
#html #css #вёрстка
Стилизованный список очень удобно сделать через значение счетчика, но тогда в content
можно поставить только порядковый номер элемента списка. Возможно ли сделать его составным?
Хочу иметь на выходе число сразу после которого идет точка. Что-то вроде этого:
content:counter(olNum)+'.';
Но запись такого вида не дает никакого результата, и нумерация вовсе не работает.
Вот рабочий пример:
ol {
margin: 0;
padding: 0;
counter-reset: olNum;
list-style: none;
}
li {
position: relative;
margin-bottom: 2px;
padding-left: 50px;
}
li:before {
counter-increment: olNum;
content: counter(olNum);
position: absolute;
top: 1px;
left: 1px;
font-weight: bold;
color: red;
}
one
two
three
one
two
three
one
two
three
one
two
three
Ответы
Ответ 1 Решение слишком простое, нужно без "+" в content'е:
ol {
margin: 0;
padding: 0;
counter-reset: olNum;
list-style: none;
}
li {
position: relative;
margin-bottom: 2px;
padding-left: 50px;
}
li:before {
counter-increment: olNum;
content: counter(olNum)'.';
position: absolute;
top: 1px;
left: 1px;
font-weight: bold;
color: red;
}
one
two
three
one
two
three
one
two
three
one
two
three
#математика #аудио
Я пишу программу, которая генерирует WAV-файл, который содержит плавно меняющийся
звук от частоты seq1 до seq2, частотой дискретизации sampleRate = 44100 и длинной n
секунд. Необходимо найти формулу, по которой вычислять частоту текущего отрезка длинной
в одно полное колебание звука, а так же общее количество отрезков frame.
Текущая частота - seq = k1 * x + seq1, где k1 - скорость роста частоты, x - порядковый
номер отрезка в одно полное колебание;
Число семплов на отрезок - spt = sampleRate/seq = sampleRate/(k1*x+b);
P.S. В принципе, можно упростить, отбросив начальную частоту, и считать по формуле
spt=(sampleRate/k1)/x
Насколько я понимаю, количество отрезков и прирост частоты от отрезка к отрезку должно
выводиться из уравнения
Но я точно не уверен.
Пожалуйста, помогите извлечь количество отрезков и скорость прироста частоты.
int main() {
ofstream out("test.wav", ios::binary);
int time = 30;
waveHeaderInit(2, 44100, 16, time);
waveData = new char[waveHeader.subchunk2Size];
int sequence = 100;
volatile float phase;
volatile int16_t sample;
int maxAmplitude = pow(2, waveHeader.bitsPerSample - 1) - 1;
for (int i = 0; i < time * waveHeader.sampleRate; i++) {
int spt = waveHeader.sampleRate / sequence;
phase = (i % spt) / float(spt);
sample = sin(PI*phase)*maxAmplitude;
for (int channel = 0; channel < waveHeader.numChannels; channel++) {
((int16_t*)waveData)[i*waveHeader.numChannels + channel] = sample;
}
}
out.write((char*)&waveHeader, sizeof(waveHeader));
out.write(waveData, waveHeader.subchunk2Size);
out.close();
return 0;
}
Ответы
Ответ 1 Увеличивайте частоту медленно с экспоненциальной скоростью.
Монотонный звук это A*sin(2Pi*B*t). Заменяем константу B на экспонету B:=C*Exp[D*t].
C*Exp[D*t0]==seq0
C*Exp[D*t1]==seq1
---
D=Ln[seq1/seq0]/(t1-t0)
C=seq0*((seq0/seq1)^(t0/(t1-t0)))
Получаем A*sin(2Pi*C*Exp[D*t]*t). Упрощаем t0=0, t1=T.Результат:
A*sin(2Pi*seq0*((seq1/seq0)^(t/T))*t)
#javascript #yandex_maps_api #яндекс #map #яндекс_карты
Я строю маршрут с использованием путевых и транзитных точек. Но яндекс карта не правильно
строит маршрут. Она соединяется там где не должна.
Вот ссылка на codepen и код:
function init () {
var multiRoute = [];
function createMultiRoute(routeData, viaData, color) {
multiRoute.push( new ymaps.multiRouter.MultiRoute({
referencePoints: routeData,
params: viaData
}, {
editorDrawOver: false,
wayPointDraggable: true,
viaPointDraggable: true,
routeStrokeColor: "000088",
routeActiveStrokeColor: color,
pinIconFillColor: color,
boundsAutoApply: true,
zoomMargin: 30
}));
}
// Создаем карту с добавленными на нее кнопками.
var myMap = new ymaps.Map('map', {
center: [55.750625, 37.626],
zoom: 14
});
createMultiRoute([
[60.014919, 30.649850],
[60.014958, 30.648536],
[60.017671, 30.646447],
[60.019146, 30.645540],
[60.024197, 30.645711],
[60.025782, 30.644554],
[60.028975, 30.640299],
[60.027754, 30.630244],
[60.024331, 30.631359],
[60.023627, 30.637576],
[60.023723, 30.638850],
[60.024200, 30.645713]
], {
viaIndexes: [1,2,3,4,5,6,7,8,9,10]
}, "ff0000");
myMap.geoObjects.add(multiRoute[0]);
}
ymaps.ready(init);
#map {
width: 600px;
height: 400px;
background: #000;
}
Как сделать так, чтобы не было подобных соединений?
Ответы
Ответ 1 Может у вас там по Плоткина одностороннее движение?
Точнее, на неё нет поворота с перекрёстка.
Маршрут построен правильно, чтобы пройти по точкам, приходится делать круг..
Более простой маршрут
Знак на gmaps
#javascript #jquery
Решил заменить чекбоксы с помощью списка ul и стилизовать. В итоге столкнулся с проблемой.
Как взять data-attr значение из списка li ?
И если выбрать другой li, то выберется соответствующий data-attr.
Пробовал эти варианты, но там почему-то берется только первый li и больше не переключается:
function costCalculator() {
document.getElementById('result').innerHTML = parseInt(document.getElementById('area').value) + 1;
}
и
function costCalculator() {
result.innerHTML = parseInt(area.value) + $('.rooms.active').attr('data-attr');
}
\
\
\
\
Песочница для экспериментов:
https://jsfiddle.net/Mesuti/5kugx8j6/5/
1 комнатная
2 комнатная
3 комнатная
Результат:
// Математика Input + Data-attr. ВМЕСТО XXXXXXX НУЖНО ВЗЯТЬ ЗНАЧЕНИЕ LI. ЕСЛИ ВЫБИРАТЬ
ДРУГОЙ LI, ТО ЗНАЧЕНИЕ МЕНЯЕТСЯ.
function costCalculator() {
result.innerHTML = parseInt(area.value) + XXXXXXX;
}
Ответы
Ответ 1 чтобы значение из data-attr складывалось со значением площади area необходимо привести
значение к числу с помощью parseInt():
parseInt($('.rooms.active').attr('data-attr'))
Кроме того при переходе на следующую вкладку необходимо делать пересчет, т.е. вызывать
функцию costCalculator по клику на вкладке.
$('#kvart').click(function() {
$('#area').fadeOut(100, function () {
$('#room').fadeIn('100');
});
});
$('#house').click(function() {
$('#room').fadeOut(100, function () {
$('#area').fadeIn('100');
});
});
$('#kommerc').click(function() {
$('#room').fadeOut(100, function () {
$('#area').fadeIn('100');
});
});
$('#home').on('click', 'li', function(){
$(this).addClass('active').siblings().removeClass('active');
});
$('#room').on('click', 'li', function(){
$(this).addClass('active').siblings().removeClass('active');
costCalculator();
});
function onInput() {
costCalculator();
}
// Математика Input + Data-attr
function costCalculator() {
result.innerHTML = parseInt(area.value) + parseInt($('.rooms.active').attr('data-attr'));
}
document.getElementById('area').addEventListener('input', onInput);
.characteristic {
list-style: none;
margin-left: 0;
opacity: 1;
}
.characteristic li {
display: inline-block;
border: #F03226 solid 1px;
padding: 14px 24px;
color: #606060;
transition: all 0.2s linear;
}
.characteristic li:hover {
background-color: #F03226;
color: white;
cursor: pointer;
}
.active {
background-color: #F03226;
color: white !important;
}
#area {
border: #F03226 solid 1px;
padding: 14px 24px;
color: #606060;
margin-left: 40px;
}
#area:active, #area:focus {
outline: none;
}
.dn {
display: none
}
Квартира
Дом
Коммерческие помещения
1 комнатная
2 комнатная
3 комнатная
Результат:
#javascript
Задача: Найти максимальный/минимальный по модулю элемент массива.
Нагуглил только Math.abs, но не понял как применить, подскажите. Еще очень хочу услышать
критику кода от опытных программистов.
function mission(){
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 200, -210, -10000, -9, -8, -7, -6,
-5, -4, -3, -2, -1, -100];
var numbersPositive = numbers.filter(function findPositive(numbers){return numbers
>= 0});
var maxValue = Math.max.apply(Math,numbersPositive); // Максимальное число
var numbersNegative = numbers.filter(function findNegative(numbers){return numbers < 0});
var minValue = Math.min.apply(Math,numbersNegative); // Минимальное число
document.getElementById('text').value = 'Массив чисел: ' + numbers + '\n' + '\n' +
'Числа с положительным значением из массива: ' + numbersPositive + ' ' + 'Всего:
' + numbersPositive.length + '\n' +
'Числа с отрицательным значением из массива: ' + numbersNegative + ' ' + 'Всего:
' + numbersNegative.length + '\n' + '\n' +
'Максимальное число в массиве: ' + maxValue + '\n' + 'Минимальное число: ' + minValue;
}
Ответы
Ответ 1 Можно как-то так попробовать.
function mission() {
var numbers = [<тут входные данные>],
absNumbers = numbers.map(Math.abs),
minValue = Math.min.apply(Math, absNumbers),
maxValue = Math.max.apply(Math, absNumbers);
<тут вывод результатов>
}
Ответ 2 var array = [267, 306, 108];
var largest = Math.max.apply(Math, array); // 306
#java #сеть #ip
Закрыт. Этот вопрос необходимо уточнить или дополнить
подробностями. Ответы на него в данный момент не принимаются.
Хотите улучшить этот вопрос? Добавьте больше подробностей
и уточните проблему, отредактировав это сообщение.
Закрыт 2 года назад.
Как узнать IP-адреса подключенные к локальной сети?
Ответы
Ответ 1 Если требуется именно на java, то ответ есть здесь https://stackoverflow.com/questions/3345857/how-to-get-a-list-of-ip-connected-in-same-network-subnet-using-java.
Примерно так:
public static void checkHosts(String subnet) throws IOException {
int timeout = 100;
for (int i = 1; i < 255; i++) {
String host = subnet + "." + i;
if (InetAddress.getByName(host).isReachable(timeout)) {
System.out.println(host + " is reachable");
}
}
}
public static void main(String[] arguments) throws IOException {
checkHosts("192.168.1");
}
#php #vkontakte_api
Есть группа в контакте, в ней около 20К записей. Нужно получить общее количество
записей от одного пользователя с помощью API. Из документации я понял что такого метода
нет, но можно сделать таким образом: при добавлении новой записи на стену группы, просто
записывать данные автора и кол-во его записей в базу, а в последующем просто увеличивать
счетчик. Но это не совсем оптимальный способ. Возможно есть более простые решения,
подскажите!?
Ответы
Ответ 1 Если под "записями" подразумеваются посты (не комментарии!) то с помощью метода wall.get
можно брать по 100 постов со стены, а если использовать execute то в одном запросе
можно забирать 25*100=2500 постов, соответственно 20К постов в группе это меньше 10
запросов. Алгоритм возможен следующий - первый раз снимаем все посты и записываем в
БД пары пост/автор и потом с некой периодичностью снимаем 2500 последний постов. Ну
и далее простейший подсчет постов автора в БД.
#linux #bash
Я знаю, что можно удалять старые файлы (старше одного дня) просто командой find /my/path/
-mtime +1 -type f -exec rm {} \; , а можно ли как-то удалять в директории /my/path/
файлы старше одного дня, но только, если их (файлов) там больше, ну, например, 10-ти?
А точнее даже так: удалять в директории /my/path/ файлы, но всегда оставлять 10 самых
новых.
Не могу найти простого способа :( Пока вижу длинный и сложный (для меня) способ с
сортировкой по ls -lsht, условием if ... > 10 и удалением в цикле...
Ответы
Ответ 1 GNU find умеет выводить дату в секундах с 1970года, сортировку по дате поручим sort
-n, cut вырежет первый столбец после сортировки, отбрасывать первые 10 строк умеет
tail. Удалять махом много файлов умеет rm + xargs. Если список файлов на удаление пустой
- команду rm не запускаем.
Все вместе получается вот так:
find /my/path/ -type f -mtime +1 -printf "%A@ %p\n" | sort -n | cut -d" " -f 2 |
tail -n "+10" | xargs --no-run-if-empty rm
То же самое, разделенное по строкам для простоты восприятия:
find /my/path/ -type f -mtime +1 -printf "%A@ %p\n" \
| sort -n \
| cut -d" " -f 2 \
| tail -n "+10" \
| xargs --no-run-if-empty rm
То же самое, но pipe покороче (объединение cut и tail в sed):
find /my/path/ -type f -mtime +1 -printf "%A@ %p\n" \
| sort -n \
| sed -rn '10,$s|^[^ ]* (.*$)|\1|p' \
| xargs --no-run-if-empty rm
#c_sharp #парсер #anglesharp
Подскажите пожалуйста как из этого блока выбрать только вот это : 8.85 р / шт
дисконт 8.60
8.85 р / шт
Сейчас пробую так: var price = document.Result.QuerySelectorAll(@".price");
Но в результате выводится все, что находится в блоке
Ответы
Ответ 1 Я дал вам ссылку на вопрос на enSO, там есть красивый вариант (через чтение AngleSharp'ом
безымянных блоков CSS) и мой варварский в вопросе (вырезанием всех "лишних" нод).
В вашем случае начните с чего-то типа:
var parser = new HtmlParser();
var document = parser.Parse(@"
дисконт 8.60
8.85 р / шт
");
var priceBlocks = document.QuerySelectorAll("div.price");
foreach (var block in priceBlocks)
{
var element = block.ChildNodes.First(o => o.NodeType == AngleSharp.Dom.NodeType.Text
&& o.TextContent.Trim() != "");
element.Text().Trim().Dump();
}
Linqpad говорит, что вам вполне сойдёт для начала:
Писал наспех, поэтому подразумеваю, что вы понимаете, что такое linq.
#java #база_данных #postgresql #spring #kotlin
Дано:
БД postgresql на Mac. В ней есть данные и я могу сделать BackUp из консоли вызвав
/Library/PostgreSQL/10/bin/pg_dump -U db_user_name -w -c -f my_db_name.sql my_db_name,
что создаст файл my_db_name.sql в папке где я вызываю команду.
Задача:
Настроить периодический BackUp БД через Spring.
Проблема:
При вызове вышеуказанного скрипта программно получаю ошибку Файл не найден
Вопрос:
Как же это реализовать? Кажется, проблема в правах доступа к файлам/папкам, но непонятно
какая именно и как узнать конкретно.
Пробовал:
Пробовал указывать абсолютный путь типа {ПУТЬ_К_ПРОЕКТУ_СПРИНГА}/my_db_name.sql или
/Users/myusername/my_db_name.sql - не помогает.
Код:
@Scheduled(cron = "0 * * * * *")
fun backUpDb() {
val executeCmd = "/Library/PostgreSQL/10/bin/pg_dump -U $dbUserName -w -c -f
$database.sql $database"
val runtimeProcess: Process
try {
val pb = ProcessBuilder(executeCmd)
pb.redirectOutput(Redirect.INHERIT)
pb.redirectError(Redirect.INHERIT)
runtimeProcess = pb.start()
val processComplete = runtimeProcess.waitFor()
if (processComplete == 0) {
println("Backup created successfully")
} else {
println("Could not create the backup")
}
} catch (ex: Exception) {
ex.printStackTrace()
}
}
Лог:
java.io.IOException: Cannot run program "/Library/PostgreSQL/10/bin/pg_dump -U db_user_name
-w -c -f my_db_name.sql my_db_name": error=2, No such file or directory
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
at ru.scp.quiz.service.quiz.QuizServiceImpl.backUpDb(QuizServiceImpl.kt:75)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:93)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.io.IOException: error=2, No such file or directory
at java.lang.UNIXProcess.forkAndExec(Native Method)
at java.lang.UNIXProcess.(UNIXProcess.java:247)
at java.lang.ProcessImpl.start(ProcessImpl.java:134)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
Ответы
Ответ 1 Проблема оказалась в том, что команда в одной строке не распознаётся и надо составлять
массив из каждой её части и тогда оно работает. Т.е. надо команду в массив превратить
при передаче ProcessBuilder-у:
val pb = ProcessBuilder(executeCmd.split(" "))
#javascript #jquery #html5
Есть HTML страница на которой плавно по таймеру появляются элементы (jQuery):
$(window).ready(function(){
$("#site--header").fadeIn(1000);
}
В верхней части HTML страницы есть видео. Как сделать так, чтобы появление элементов
начиналось после 100% загрузки видео HTML5, которое есть на странице?
Заранее спасибо!
Ответы
Ответ 1 Согласно документации События в медиа (audio, video) объектах, не существует пока
событий, которые отправляются после 100% загрузки видео.
Но есть события oncanplaythrough и oncanplay, которые, возможно, вам подойдут:
my_video.oncanplaythrough = function(e)
{
//Событие отправляется, когда состояние готовности изменяется к CAN_PLAY_THROUGH.
Указывает, что медиа может быть полностью воспроизведено без перерыва, предполагая,
что скорость загрузки остается, по крайней мере на нынешнем уровне. Примечание: Ручная
установка CURRENTTIME вызовет событие canplaythrough в Firefox. В других браузерах
это может не произойти.
}
my_video.oncanplay = function(e)
{
//Событие отправляется, когда доступно достаточно данных для того, чтобы медиа
могло воспроизвестись, по крайней мере, в течение нескольких кадров. Соответствует
состоянию (readyState) HAVE_ENOUGH_DATA.
}
Ответ 2 никак это не реализуется простым плеером HTML5...
#c_sharp #json #jsonnet
Консольное приложение на С#
Со стороннего сайта получаю json в формате json5:
[{
contentId: 'f1654c004d0207fab3f1f30d9d5f7b1a',
date: new Date('05/14/2018 10:50:00')
},
{
contentId: 'f1954d004d0287fab3f2f30d9d5f7b1a',
date: new Date('08/24/2018 10:50:00')
},
...
]
Хранится в строковой переменной.
Вопрос в том какие варианты работы есть с таким существом в C#??
Что пробовал:
Подключить библиотеку JSON5 .NET. Не работает, не компилируется, написано что билд сломан
Пройти регуляркой, остановился на проблеме полей с new Date: вот тут
Ответы
Ответ 1 Вам может помочь Json.Net от Newtonsoft с кастомным конвертером даты.
Вообще, если гуглить does json.net support json5 мы сразу выходим на то, что поддержка
("большей части" - май 2017 года) уже есть. Но действительно, такие даты как у вас
не поддерживаются.
Странный у вас вообще формат времени. Официальная спецификация json5 вообще ничего
не говорит о формате времени, это оставлено на откуп спецификациям на Javascript:
JSON itself does not specify how dates should be represented, but
JavaScript does.
There is no right format; The JSON specification does not specify a
format for exchanging dates which is why there are so many different
ways to do it.
The best format is arguably a date represented in ISO 8601 format (
(См. тут: The “right” JSON date format)
Но... у вас не ISO 8601 даты... у вас вообще в вопросе одни строки, а по ссылке с
регуляркой другие (и подозреваю, что там правильно: формат MM/DD/YYYY HH:MM:SS).
В принципе, должно помочь написание кастомного конвертера, чего-то типа JavaScriptDateTimeConverter
- вот например, очень похожий пример.
Я не знаю, все ли даты приходят в таком формате, не знаю, насколько этот гос. сайт
специфицирует такой формат (или может неожиданно перейти на ИСО 8601 - 2001 и поломать
вам код), но в принципе, можно написать свой конвертер, обложить для надёжности юнит-тестами
и тогда уже использовать в продакшене.
Вот вам рабочий приме для основы:
void Main()
{
var source = @"[
{
contentId: 'f1654c004d0207fab3f1f30d9d5f7b1a',
date: new Date('05/14/2018 10:50:00')
},
{
contentId: 'f1954d004d0287fab3f2f30d9d5f7b1a',
date: new Date('05/14/2018 17:43:05')
}]";
var parsed = Newtonsoft.Json.JsonConvert.DeserializeObject(source);
parsed.Dump();
}
public class SomeClass
{
public string contentId { get; set; }
[JsonConverter(typeof(JavaScriptGovSiteDateTimeConverter))]
public DateTime date { get; set; }
}
public class JavaScriptGovSiteDateTimeConverter : JavaScriptDateTimeConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer)
{
Type type = (Nullable.GetUnderlyingType(objectType) ?? objectType);
bool isNullable = (Nullable.GetUnderlyingType(objectType) != null);
var token = JToken.Load(reader);
if (token == null || token.Type == JTokenType.Null)
{
if (!isNullable)
throw new JsonSerializationException(string.Format("Null value for
type {0} at path {1}", objectType.Name, reader.Path));
return null;
}
if (token.Type != JTokenType.Constructor)
{
throw new JsonSerializationException(string.Format("Invalid Date constructor
\"{0}\" at path {1}", token.ToString(), reader.Path));
}
var constructor = (JConstructor)token;
if (!string.Equals(constructor.Name, "Date", StringComparison.Ordinal))
{
throw new JsonSerializationException(string.Format("Invalid Date constructor
\"{0}\" at path {1}", token.ToString(), reader.Path));
}
var values = constructor.Values().ToArray();
if (values.Length == 0)
{
throw new JsonSerializationException(string.Format("Invalid Date constructor
\"{0}\" at path {1}", token.ToString(), reader.Path));
}
else if (values.Length == 1)
{
DateTime dt;
if (!DateTime.TryParseExact(values[0].ToString(), "MM/dd/yyyy H:m:s",
null, DateTimeStyles.None, out dt))
throw new Exception("date format is not MM/dd/yyyy H:m:s");
return dt;
}
else
{
throw new Exception("Вот сейчас прям совсем неожиданно было");
}
}
}
#c_sharp #шрифты
Есть строка
string text = "𝚊𝚗𝚊 𝚝𝚎𝚝𝚢𝚊𝚗𝚊 𝚊𝚗𝚊 𝚝𝚎𝚝𝚢𝚊𝚗𝚊 𝚊𝚗𝚊 𝚝𝚎𝚝𝚢𝚊𝚗𝚊";
как из нее получить оригинальний текст без шрифтов ?
вместо
𝚊𝚗𝚊 𝚝𝚎𝚝𝚢𝚊𝚗𝚊 𝚊𝚗𝚊 𝚝𝚎𝚝𝚢𝚊𝚗𝚊 𝚊𝚗𝚊 𝚝𝚎𝚝𝚢𝚊𝚗𝚊
будет
ana tetyana ana tetyana ana tetyana
Ответы
Ответ 1 Вероятно, вам подойдёт одна из форм нормализации:
var text = "𝚊𝚗𝚊 𝚝𝚎𝚝𝚢𝚊𝚗𝚊 𝚊𝚗𝚊 𝚝𝚎𝚝𝚢𝚊𝚗𝚊 𝚊𝚗𝚊 𝚝𝚎𝚝𝚢𝚊𝚗𝚊";
// text.Length = 65
text = text.Normalize(NormalizationForm.FormKD);
// text.Length = 35
FormKC тоже даёт длину 35.
Ссылки на то, что такое нормализация: подробно на английском, чуть-чуть на русском.
#git
Есть 12 коммитов , и как можно объединить к пример 6 и 9 , не потеряв при этом коммиты
между ними .
Ответы
Ответ 1 делаете интерактивный ребейз достаточно глубоко (или указав хэш нужного коммита)
git rebase -i HEAD~5
получаете редактор вида
pick 6e6d42e sample commit 2
pick 393eb9c sample commit 3
pick 1731ac2 sample commit 4
pick 5924b37 sample commit 5
pick 0043963 sample commit 6
в редакторе переставляете коммиты так, как вам хочется и указываете действие squash
для того коммита, который нужно слить
pick 6e6d42e sample commit 2
pick 1731ac2 sample commit 4
pick 5924b37 sample commit 5
s 393eb9c sample commit 3 <----- переставить и слить с 5-м
pick 0043963 sample commit 6
дальше следуете инструкции в консоли - разрешаете конфликты и завершаете ребейз
Ответ 2 Вроде можно сделать следующим образом: Воспользуйтесь командой 'git checkout commit',
вместо 'commit' впишите хеш 6 коммита и от него создайте новую ветку. После вернитесь
на 9 коммит и оттуда произведите мерж.
#python #django
При запуске Django сервера и выполнения каких-то действий в логах всплывает ошибка
"GET /favicon.ico HTTP/1.1" 404 2255
Можете подсказать, из-за чего она возникает, и как её исправить?
Ответы
Ответ 1 favicon.ico - это обычно значок сайта во вкладках браузера и при открытии страницы
его браузер его пытается запросить (дефолтно).
Добавьте в блок вашей страницы следующее:
Либо вы можете убрать из логов nginx'а:
# skip favicon.ico
#
location = /favicon.ico {
access_log off;
return 204;
}
Такой-же вопрос на английском с развернутым ответом.
#javascript
Есть такой код:
function getResult(result) {
response = result.langs;
for (key in response){
switch (response[key][0]){
case 'A':
eval('core_object.language_code.a.'+key+'='+response[key]+';')
break;
//Анологично до конца алфавита
}
Значение response это объект со множеством значений типа:
{
af: 'Afrikaans',
am: 'Amharic'
//И так далее
}
Значение key = af и так далее, а response[key] = 'Afrikaans' и так далее.
Тут возникает проблема разобраться в сути которой я не могу: в коде eval('core_object.language_code.a.'+key+'='+response[key]+';')
переменная key, как и предполагалось используется как строка содержащая значение 'af'
а вот строка содержащаяся в response[key] используется как переменная из за чего получается
ошибка: ReferenceError: Afrikaans is not defined.
Почему и как это исправить?
Ответы
Ответ 1 Строка, которая подается в eval:
core_object.language_code.a.af = Afrikaans;
То, что справа от знака "равно", понимается как переменная. Но такой переменной нет.
eval('core_object.language_code.a.'+key+'="'+response[key]+'";')
Получится core_object.language_code.a.af = "Afrikaans";.
Или
eval('core_object.language_code.a.'+key+'=response.'+key+';')
Получится core_object.language_code.a.af = response.af;.
Или без eval:
core_object.language_code.a[key] = response[key];
Ответ 2 А зачем там вообще eval? По моему так будет то же самое:
case 'A':
core_object.language_code.a[key] = response[key];
break;
#sql #oracle #plsql #plsql_developer
Есть строка '/home/pc/test' ,
и слова в тегах '[/alseko][/logs][/archive]'
Как получить ожидаемый результат =
[/home/pc/test/alseko][/home/pc/test/logs][/home/pc/test/archive]
Мой код, пытаюсь найти:
select '[' || '/home/pc/test' ||
ltrim(substr('[/alseko][/logs][/archive]',
instr('[/alseko][/logs][/archive]', '['),
instr('[/alseko][/logs][/archive]', ']')),'[')
from dual
Ответы
Ответ 1 Надо распарсить теги в таблицу, и потом заново собрать в строку, например так:
with data as (
select
'[/alseko][/logs][/archive]' tags,
'\[(\/\w+)' pattern,
'/home/pc/test' prefix
from dual
),
tags as (
select
'['||prefix||regexp_substr (tags, pattern, 1, level, null, 1)||']' tag,
level sort
from data connect by level <= regexp_count (tags, pattern)
)
select listagg (tag) within group (order by sort)
from tags
;
Вывод:
[/home/pc/test/alseko][/home/pc/test/logs][/home/pc/test/archive]
Ответ 2 Получился сделать через цикл, сперва определил количество вхождений
Declare
vn_count_paths Integer;
vc_paths varchar(1024);
vc_FtpDir varchar(1024);
begin
vn_count_paths:= length('[/alseko][/logs][/archive]')-LENGTH(REPLACE('[/alseko][/logs][/archive]','['));
dbms_output.put_line('Size: ' || vn_count_paths);
for i in 1 .. vn_count_paths
loop
vc_paths:= vc_paths||'['||'/home/pc/test'||ltrim(substr('[/alseko][/logs][/archive]',instr('[/alseko][/logs][/archive]','[',1,i)+1,
instr('[/alseko][/logs][/archive]',']',1,i)-
instr('[/alseko][/logs][/archive]','[',1,i)-1),'[')||']';
end loop;
vc_FtpDir := '['||'/home/pc/test'||']'||vc_paths;
dbms_output.put_line('vc_FtpDir: ' || vc_FtpDir);
end;
#perl
use lib '/full/path/to';
require 'script.pl';
Ответы
Ответ 1 use lib "simplifies the manipulation of @INC at compile time.", в частности, в данном
случае, добавляет /full/path/to к @INC (список путей, в которых ищутся библиотеки).
Поэтому в дальнейшем, чтобы подключить /full/path/to/script.pl, достаточно указать
только имя script.pl, без полного пути.
require — директива, среди прочего, и для подключения библиотек без импорта их символов.
#java #android #rxjava
Стоит задача, отправить пару запросов, получить с этих запросов данные, обработать
их (данные из 2-3 запросов) и отправить в адаптер( например)
Каким образом это правильно и красиво сделать?
Насколько я знаю, для таких задач используется RxJava, хотелось бы чтобы привели
пример правильного решение с использованием Rx и без использование Rx.
Ответы
Ответ 1 Если вам нужно соеденить ответы этих запросов то вполне подойдет оператор concat
Вот небольшая демонстрация
final String[] aStrings = {"A1", "A2", "A3", "A4"};
final String[] bStrings = {"B1", "B2", "B3"};
final Observable aObservable = Observable.fromArray(aStrings);
final Observable bObservable = Observable.fromArray(bStrings);
Observable.concat(aObservable, bObservable)
.subscribe(getObserver());
На выходе получим поток данных
спрерва "A1", "A2", "A3", "A4" а затем "B1", "B2", "B3"
Так же можно использовать оператор merge
Observable.merge(aObservable, bObservable)
.subscribe(getObserver());
тогда на выходе получим поток данных
"A1", "B1", "A2", "A3", "A4", "B2", "B3"
или же zip
Observable stringObservable1 = Observable.just("Hello", "World");
Observable stringObservable2 = Observable.just("Bye", "Friends");
Observable.zip(stringObservable1, stringObservable2, new BiFunction() {
@Override
public String apply(@NonNull String s, @NonNull String s2) throws Exception {
return s + " - " + s2;
}
}).subscribe(new Consumer() {
@Override
public void accept(String s) throws Exception {
System.out.println(s);
}
});
на выход получим
Hello - Bye
World - Friends
Я б не стал писать это чисто андроид потоками ибо это ресурсаемко советую использовать
rxJava.
#github
Ребята, пыталась залить второй проект, но не получилось. пользовалась этой инструкцией:
Использовать папки-поддиректории:
nickname.github.io - корневая директория сайта (главная страница)
nickname.github.io/site 1/ - поддиректория 1 (папка сайта 1)
nickname.github.io/site 2/ - поддиректория 2 (папка сайта 2)
nickname.github.io/site 3/ - поддиректория 3 (папка сайта 3)
но все равно не получается, подскажите что не так?
Ответы
Ответ 1 Для решение проблемы нужно выбрать Settings-GitHub Pages-Source-master branch
#linux #windows #qt #winapi #usb
Я пишу на С++, использую Qt под Windows. Мне надо получить: название модели, изготовителя,
серийный номер устройства(видео камеры, фото , квадрокоптера , флешки или SD Card)
и путь до устройства. Желательно кроссплатформенное решение.
Есть ответ SetupDiGetDeviceProperty. Но тут не кроссплатформенное решение , к тому
же я не совсем понимаю как получить путь до устройства.
Читал о библиотеки libusb. Но тут не выводятся название модели, изготовителя, серийный
номер устройства. То что выводиться :
Dev (bus 2, device 0): 8086 - 1E31
Dev (bus 1, device 4): 04A9 - 1795
Dev (bus 1, device 3): A4Tech - USB Mouse
Dev (bus 3, device 0): 8086 - 1E26
Dev (bus 1, device 1): 8087 - 0024
Dev (bus 1, device 0): 8086 - 1E2D
Dev (bus 1, device 2): 0BDA - 0151
Dev (bus 1, device 6): Logitech Inc. - Logitech USB Headset H340
Dev (bus 3, device 2): 8087 - 0024
Dev (bus 3, device 3): Logitech - USB Keyboard
Dev (bus 3, device 1): 04A9 - 3206
Хотя была вставлена флешка и подключена камера.
Есть изящное решение этой задачи. Если кто сталкивался с такой задачей поделитесь
кодом пожалуйста.
Ответы
Ответ 1 К сожалению, используя библиотеку libusb под Windows нельзя вытянуть всю эту информацию
без установки специального драйвера WinUSB. Можно только получить VID и PID (шестнадцатеричные
значения типа 8086 - 1E31 в вашем примере), и по ним найти производителя и устройство
в таблице известных идентификаторов, например здесь.
Производителя и серийный номер можно получить, используя Setup API и IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION.
Букву диска тоже можно получить только средствами Setup API, это несколько сложнее.
Для этого нужно вначале построить таблицу номеров дисков для всех используемых букв
дисков с помощью IOCTL_STORAGE_GET_DEVICE_NUMBER; затем открыть интересующее устройство
(запоминающее устройство, которое является дочерним для USB-устройства), найти его
номер тем же IOCTL, сравнить его со значениями из таблицы и таким образом определить
букву. Как-то так:
#include
#include
#include
#include
#include
#include
#include
#undef LowSpeed
#include
#include
#pragma comment(lib,"Setupapi.lib")
void ErrorMes(LPCTSTR 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
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen(lpszFunction) + 40) * sizeof(TCHAR));
wprintf(L"%s failed with error %d: %s",
lpszFunction, dw, lpMsgBuf);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
}
//Поиск номера диска для USB-устройства
BOOL FindDiskNumber(LPCWSTR match, STORAGE_DEVICE_NUMBER* lpret){
BOOL retval = FALSE;
DEVPROPTYPE dpt=0;
wchar_t buffer[1024]=L"";
TCHAR id_upper[1024]=L"";
DWORD RequiredSize = 0;
SP_DEVINFO_DATA devinfo = { 0 };
SP_DEVICE_INTERFACE_DATA deviceInterface = { 0 };
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetail = NULL;
BOOL res;
HDEVINFO deviceInfoHandle = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, 0, 0,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (deviceInfoHandle != INVALID_HANDLE_VALUE)
{
int deviceIndex = 0;
while (true)
{
ZeroMemory(&deviceInterface,sizeof(deviceInterface));
deviceInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
//получение всех дисков
if (SetupDiEnumDeviceInterfaces(deviceInfoHandle, 0, &GUID_DEVINTERFACE_DISK,
deviceIndex, &deviceInterface))
{
DWORD cbRequired = 0;
SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterface,
0, 0, &cbRequired, 0);
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
deviceInterfaceDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)(new
char[cbRequired]);
memset(deviceInterfaceDetail, 0, cbRequired);
deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (!SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterface,
deviceInterfaceDetail, cbRequired, &cbRequired, 0))
{
goto Next;
}
// Initialize the structure before using it.
memset(deviceInterfaceDetail, 0, cbRequired);
deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
// Call the API a second time to retrieve the actual
// device path string.
BOOL status = SetupDiGetDeviceInterfaceDetail(
deviceInfoHandle, // Handle to device information set
&deviceInterface, // Pointer to current node in devinfo set
deviceInterfaceDetail, // Pointer to buffer to receive
device path
cbRequired, // Length of user-allocated buffer
&cbRequired, // Pointer to arg to receive required buffer length
NULL); // Not interested in additional data
//получение информации о устройстве
ZeroMemory(&devinfo,sizeof(devinfo));
devinfo.cbSize = sizeof(SP_DEVINFO_DATA);
BOOL success = SetupDiEnumDeviceInfo(deviceInfoHandle, deviceIndex,
&devinfo);
if(success==FALSE){ErrorMes(L"SetupDiEnumDeviceInfo"); goto Next;}
res=SetupDiGetDeviceProperty(deviceInfoHandle,&devinfo,
&DEVPKEY_Device_Parent,&dpt,(PBYTE)buffer,1000,NULL,0);
if(res==FALSE){ErrorMes(L"SetupDiGetDeviceProperty");goto Next;}
int len = wcslen(buffer);
for(int i=0;iDevicePath, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0, OPEN_EXISTING, 0, 0);
if(handle==INVALID_HANDLE_VALUE) {
ErrorMes(L"CreateFile");goto Next;
}
STORAGE_DEVICE_NUMBER sdn = {0};
DWORD nbytes = 0;
//получение номера диска
res = DeviceIoControl(handle, // handle to device
IOCTL_STORAGE_GET_DEVICE_NUMBER, // dwIoControlCode
NULL, // lpInBuffer
0, // nInBufferSize
(LPVOID) &sdn, // output buffer
(DWORD) sizeof(sdn), // size of output buffer
(LPDWORD) &nbytes, // number of bytes returned
NULL // OVERLAPPED structure
);
CloseHandle(handle);
if(res != FALSE){
//устройство найдено
memcpy(lpret,&sdn,sizeof(sdn));
retval = TRUE;
}
else ErrorMes(L"DeviceIoControl");
}
}
}
else
{
break;
}
Next:
if(deviceInterfaceDetail != NULL){
delete[] deviceInterfaceDetail;
deviceInterfaceDetail = NULL;
}
if(retval != FALSE) break; //устройство уже найдено
deviceIndex++; //следующее устройство
}
SetupDiDestroyDeviceInfoList(deviceInfoHandle);
}
else ErrorMes(L"SetupDiGetClassDevs");
return retval;
}
//таблица номеров для всех дисков
bool disk_IsUsed[30]={0};
STORAGE_DEVICE_NUMBER disk_number[30]={0};
int _tmain(int argc, _TCHAR* argv[])
{
setlocale(LC_ALL,"Russian");
HANDLE hVol;
DWORD nbytes;
WCHAR letter;
WCHAR volume[100]={0};
int i;
STORAGE_DEVICE_NUMBER sdn={0};
//заполняем таблицу номеров для дисков
for(i=0;i<30;i++){
letter = 'A' + i;
wsprintf(volume,L"\\\\.\\%c:",letter);
disk_IsUsed[i] = FALSE;
hVol = CreateFile( volume, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);
if(hVol == NULL || hVol == INVALID_HANDLE_VALUE){continue;}
BOOL ret = DeviceIoControl(hVol, // handle to device
IOCTL_STORAGE_GET_DEVICE_NUMBER, // dwIoControlCode
NULL, // lpInBuffer
0, // nInBufferSize
(LPVOID) &(disk_number[i]), // output buffer
(DWORD) sizeof(STORAGE_DEVICE_NUMBER), // size of output buffer
(LPDWORD) &nbytes, // number of bytes returned
NULL // OVERLAPPED structure
);
CloseHandle(hVol);
if(ret == FALSE){continue;}
disk_IsUsed[i] = TRUE;
}
WCHAR match[1024]={0};
GUID guid = { 0xF18A0E88, 0xC30C, 0x11D0, { 0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06,
0xBE, 0xD8 } };
/*USB HUB Interface class GUID*/
HDEVINFO deviceInfoHandle = SetupDiGetClassDevs(&guid, 0, 0, DIGCF_PRESENT |
DIGCF_DEVICEINTERFACE);
if (deviceInfoHandle != INVALID_HANDLE_VALUE)
{
int deviceIndex = 0;
while (true)
{
SP_DEVICE_INTERFACE_DATA deviceInterface = { 0 };
deviceInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
//получение всех USB-концентраторов
if (SetupDiEnumDeviceInterfaces(deviceInfoHandle, 0, &guid, deviceIndex,
&deviceInterface))
{
DWORD cbRequired = 0;
SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterface,
0, 0, &cbRequired, 0);
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetail =
(PSP_DEVICE_INTERFACE_DETAIL_DATA)(new char[cbRequired]);
memset(deviceInterfaceDetail, 0, cbRequired);
deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (!SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterface,
deviceInterfaceDetail, cbRequired, &cbRequired, 0))
{
delete[] deviceInterfaceDetail;
deviceIndex++;
continue;
}
// Initialize the structure before using it.
memset(deviceInterfaceDetail, 0, cbRequired);
deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
// Call the API a second time to retrieve the actual
// device path string.
BOOL status = SetupDiGetDeviceInterfaceDetail(
deviceInfoHandle, // Handle to device information set
&deviceInterface, // Pointer to current node in devinfo set
deviceInterfaceDetail, // Pointer to buffer to receive
device path
cbRequired, // Length of user-allocated buffer
&cbRequired, // Pointer to arg to receive required buffer length
NULL); // Not interested in additional data
BOOL res;
/*Открываем устройство для отправки IOCTL*/
HANDLE handle = CreateFile(deviceInterfaceDetail->DevicePath,
GENERIC_WRITE, FILE_SHARE_WRITE,
0, OPEN_EXISTING, 0, 0);
if(handle!=INVALID_HANDLE_VALUE) {
DWORD bytes_read=0;
UINT ports = 0;
USB_NODE_INFORMATION nodeinfo;
USB_NODE_CONNECTION_INFORMATION_EX coninfo={0};
const UINT BUFSIZE = 1000;
char buffer[BUFSIZE]={0};
USB_DESCRIPTOR_REQUEST* req = (USB_DESCRIPTOR_REQUEST*)&buffer;
USB_STRING_DESCRIPTOR* desc;
ZeroMemory(&nodeinfo,sizeof(nodeinfo));
nodeinfo.NodeType = UsbHub;
//получаем число портов на концентраторе
res=DeviceIoControl(handle,IOCTL_USB_GET_NODE_INFORMATION ,
&nodeinfo,sizeof(nodeinfo),&nodeinfo,sizeof(nodeinfo),&bytes_read,0);
if(res==FALSE)ErrorMes(L"DeviceIoControl");
else ports = (UINT)nodeinfo.u.HubInformation.HubDescriptor.bNumberOfPorts;
for(int j=1;j<=ports;j++){
ZeroMemory(&coninfo,sizeof(coninfo));
coninfo.ConnectionIndex=j;
//получаем инфу о порте
res=DeviceIoControl(handle,IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX ,
&coninfo,sizeof(coninfo),&coninfo,sizeof(coninfo),&bytes_read,0);
if(res==FALSE){ErrorMes(L"DeviceIoControl");continue;}
if(coninfo.ConnectionStatus==0) continue; //нет устройства
printf("\n- Hub %2d, Port %2d: USB v%x device\n",deviceIndex,
j,(int)coninfo.DeviceDescriptor.bcdUSB);
printf("VID: %04X PID: %04X\n",(int)coninfo.DeviceDescriptor.idVendor
,(int)coninfo.DeviceDescriptor.idProduct);
//формируем строку для поиска устройства
wsprintf(match,L"VID_%04X&PID_%04X",(UINT)coninfo.DeviceDescriptor.idVendor
,(UINT)coninfo.DeviceDescriptor.idProduct);
/*Serial number*/
ZeroMemory(buffer,BUFSIZE);
req->ConnectionIndex=j;
req->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE
<< 8) + coninfo.DeviceDescriptor.iSerialNumber;
req->SetupPacket.wLength = BUFSIZE - sizeof(USB_DESCRIPTOR_REQUEST);
req->SetupPacket.wIndex = 0x409; //US English
res=DeviceIoControl(handle,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION ,
&buffer,sizeof(buffer),&buffer,sizeof(buffer),&bytes_read,0);
if(res==FALSE){ErrorMes(L"DeviceIoControl");continue;}
desc = (USB_STRING_DESCRIPTOR*)(&req->Data[0]);
wprintf(L"Serial: %s\n",desc->bString);
/*Vendor*/
ZeroMemory(buffer,BUFSIZE);
req->ConnectionIndex=j;
req->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE
<< 8) + coninfo.DeviceDescriptor.iManufacturer;
req->SetupPacket.wLength = BUFSIZE - sizeof(USB_DESCRIPTOR_REQUEST);
req->SetupPacket.wIndex = 0x409; //US English
res=DeviceIoControl(handle,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION ,
&buffer,sizeof(buffer),&buffer,sizeof(buffer),&bytes_read,0);
if(res==FALSE){ErrorMes(L"DeviceIoControl");continue;}
desc = (USB_STRING_DESCRIPTOR*)(&req->Data[0]);
wprintf(L"Vendor: %s\n",desc->bString);
/*Product*/
ZeroMemory(buffer,BUFSIZE);
req->ConnectionIndex=j;
req->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE
<< 8) + coninfo.DeviceDescriptor.iProduct;
req->SetupPacket.wLength = BUFSIZE - sizeof(USB_DESCRIPTOR_REQUEST);
req->SetupPacket.wIndex = 0x409; //US English
res=DeviceIoControl(handle,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION ,
&buffer,sizeof(buffer),&buffer,sizeof(buffer),&bytes_read,0);
if(res==FALSE){ErrorMes(L"DeviceIoControl");continue;}
desc = (USB_STRING_DESCRIPTOR*)(&req->Data[0]);
wprintf(L"Product: %s\n",desc->bString);
/*Disk letter*/
res = FindDiskNumber(match,&sdn);
if(res != FALSE) {
for(i=0;i<30;i++)
if( disk_IsUsed[i] !=FALSE
&& disk_number[i].DeviceNumber == sdn.DeviceNumber
&& disk_number[i].DeviceType == sdn.DeviceType)
{
letter = 'A' + i;
printf("Disk letter: %c\n",letter);
}
}
else printf("Disk letter not found\n");
}
CloseHandle(handle);
}else{
ErrorMes(L"CreateFile");//failed to open device
}//endif
delete[] deviceInterfaceDetail;
}
}
else
{
break;
}
++deviceIndex;
}
SetupDiDestroyDeviceInfoList(deviceInfoHandle);
}
else ErrorMes(L"SetupDiGetClassDevs");
system("PAUSE");
return 0;
}
Должно вывести подобный результат:
‐ Hub 3, Port 1: USB v200 device
VID: 8564 PID: 1000
Serial: 5B94314A
Vendor: JetFlash
Product: Mass Storage Device
Disk letter: G
‐ Hub 3, Port 4: USB v110 device
VID: 09DA PID: 000A
Serial: ?
Vendor: A4Tech
Product: USB Mouse
Disk letter not found
‐ Hub 3, Port 6: USB v110 device
VID: 046E PID: 5505
Serial: ?
Vendor: BTC
Product: USB Multimedia Keyboard
Disk letter not found
‐ Hub 3, Port 10: USB v200 device
VID: 04E8 PID: 689E
Serial: 1234567890ABCDEF
Vendor: SAMSUNG Electronics Co., Ltd.
Product: Samsung Android USB Device
Disk letter: H