Страницы

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

вторник, 30 апреля 2019 г.

Telegram bot php. Inline keyboard. Подскажите, что делать дальше с callback_data. Что бы после нажатия на кнопку inline keyboard - бот ее обработал

Подскажите, пожалуйста как написать простой сценарий для бота, например: написал команду "/test", бот спрашивает: "Вы уверены?" пишешь в ответ: "Да" бот отправляет следующее сообщение по сценарию, если пишешь "нет" - сценарий заканчивается. Важно, что бы мой ответ "Да" не обрабатывался ботом, пока он не спросит "Вы уверены?"(после команды /test)
$access_token = '...'; $api = 'https://api.telegram.org/bot' . $access_token;
$output = json_decode(file_get_contents('php://input'), TRUE); $chat_id = $output['message']['chat']['id']; $first_name = $output['message']['chat']['first_name']; $message = $output['message']['text']; switch($message) { case '/test': sendMessage($chat_id, "Вы уверены?"); break; default: $sorry_text = $first_name . ' , мне нечего ответить'; sendMessage($chat_id, $sorry_text); } function sendMessage($chat_id, $message, $encodedMarkup) { file_get_contents($GLOBALS['api'] . '/sendMessage?chat_id=' . $chat_id . '&text=' . urlencode($message) . $encodedMarkup); }
Понял, что это делается через ForceReply, но как пока не разобрался. UPDATE сделал inline keybord, но пока не понял как выводить сообщение в зависимости от нажатой кнопки case '/test':
$x1 = array("text"=>"First Button","callback_data"=>"test1"); $x2 = array("text"=>"Second Button","callback_data"=>"test2"); $opz = [[$x1,$x2]]; $keyboard=array("inline_keyboard"=>$opz); $keyboard = json_encode($keyboard); sendMessage($chat_id, "testt2", $keyboard); break;
т.е. сейчас при нажатии на кнопку ничего не вывыодится


Ответ

Вот рабочий код, если кому нужен.
"Google url","url"=>"http://google.com"); $inline_button2 = array("text"=>"work plz","callback_data"=>'/plz'); $inline_keyboard = [[$inline_button1,$inline_button2]]; $keyboard=array("inline_keyboard"=>$inline_keyboard); $replyMarkup = json_encode($keyboard); sendMessage($chat_id, "ok", $replyMarkup); break; } switch($data){ case '/plz': sendMessage($chat_id_in, "plz"); break; } function sendMessage($chat_id, $message, $replyMarkup) { file_get_contents($GLOBALS['api'] . '/sendMessage?chat_id=' . $chat_id . '&text=' . urlencode($message) . '&reply_markup=' . $replyMarkup); }

Многопоточность в Django

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


Ответ

Как сказали выше, сервер запускает джангу в нужное количество процессов. Сама джанга написана в синхронном стиле, и по словам разработчиков на асинхронный лад её переписать невозможно.
А многопоточность средствами джанги не предусмотрена. Тем не менее никто не мешает открывать нужные потоки и процессы средствами самого python.

Как правильно реализовать callback в java?

Я недавно начал для себя изучать Android и собственно java, до этого всегда писал на nodeJS, и за долгое время очень привык к js.
И вот, в процессе изучения, настал момент, когда я решил написать один единственный класс который будет отправлять запросы, и в результате ошибки или успеха будет выполнять соответствующие методы класса из которого мы и шлем этот запрос.
Есть класс MainActivity в котором по клику на кнопку шлем запрос на сервер и ответ вставляем в TextView. Сейчас я реализовал коллбэки таким образом:
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
protected void onCreate(Bundle savedInstanceState) {
sendButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { DoRequestClass doRequestClass = new DoRequestClass(){
@Override public void onOK(JSONObject response) { successReq(response); }
@Override public void onError(VolleyError error) { errorReq(error); } }; doRequestClass.execute("http://myserver.local", MainActivity.this); } });
public void successReq(JSONObject response){ txtDisplay.setText("Response => "+response.toString()); }
public void errorReq(VolleyError error){ txtDisplay.setText("Error => "+error.toString()); }
// other methods
Такой вот для теста абстрактный класс DoRequestClass
public abstract class DoRequestClass implements DoRequestInterface {
@Override public void execute(String url, Context context) { RequestQueue queue = Volley.newRequestQueue(context);
JsonObjectRequest jsObjRequest = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener() {
@Override public void onResponse(JSONObject response) { DoRequestClass.this.onOK(response); }
}, new Response.ErrorListener() {
@Override public void onErrorResponse(VolleyError error) { DoRequestClass.this.onError(error); }
});
queue.add(jsObjRequest); } }
С интерфейсом DoRequestInterface
interface DoRequestInterface { void execute(String url, Context context);
void onOK(JSONObject response);
void onError(VolleyError error); }
Все описанное выше работает, но можно ли как-то передать successReq и errorReq в DoRequestClass таким образом, как бы мы это делали это на javascript, о то что я имею ввиду, о желанном результате, смотрите как бы я хотел примерно чтоб они передавались:
sendButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { DoRequestClass doRequestClass = new DoRequestClass(); doRequestClass.setSuccessCallback(successReq); doRequestClass.setErrorCallback(errorReq); doRequestClass.execute("http://lessons.flexiblejs.ru/test.php", MainActivity.this); } });
Как вы поняли из кода выше, setSuccessCallback и setErrorCallback это методы которые будут говорить классу DoRequestClass какие методы класса MainActivity нужно выполнить после успешного или не успешного запроса.
Такое или подобное прекрасно работало бы в javascript'e, но такой java-код работать не будет. Вопрос в том, как создать что-то такое или приближенное к этому? И возможно ли вообще? Суть в том чтобы не писать лишний код и создавать лишнее методы типа как в моем рабочем примере onOK и onError
Прошу вас по возможности дать как можно более развернутый ответ с пояснениями, т.к. мои познания в java совсем не велики.


Ответ

Рефакторинг:
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener, Response.Listener, Response.ErrorListener {
protected void onCreate(Bundle savedInstanceState) { ((Button)findViewById(R.id.send)).setOnClickListener(this); }
@Override public void onClick(View v){ switch(v.getId()){ case R.id.send: doRequestClass.execute("http://myserver.local", this, this, this); break; } }
@Override public void onResponse(JSONObject response) { txtDisplay.setText("Response => "+response.toString()); }
@Override public void onErrorResponse(VolleyError error) { txtDisplay.setText("Error => "+error.toString()); } }
DoRequestClass.java
public class DoRequestClass {
@Override public void execute(String url, Context context, Response.Listener listener, Response.ErrorListener listenerError) { RequestQueue queue = Volley.newRequestQueue(context); JsonObjectRequest jsObjRequest = new JsonObjectRequest(Request.Method.GET, url, null, listener, listenerError); queue.add(jsObjRequest); } }
На самом деле вы продублировали интерфейсы Response.Listener и Response.ErrorListener, просто раскрыв generic и объединив их в один. В приведенном примере это просто не нужно. Впрочем вы можете реализовать как у вас и было этот интерфейс, например обработать response и прокинуть его дальше:
JsonObjectRequest jsObjRequest = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener(){ @Override public void onResponse(JSONObject response) { Log.d(TAG, "JSON:"+ response.toString()); listener.onResponse(response);// listener будет final } },listenerError);
Для колбэков используется свой интерфейс (или несколько) и вносить в него метод execute смысла не очень много. В частности execute может быть в одном классе, а колбэк - в другом.
ЗЫ В приведенном коде есть один недочет. Вы каждый раз создаете новую очередь запросов. Так делать не стоит, для всего приложения достаточно одной очереди. Вариантов когда нужно несколько очередей, притом фиксированное количество не так много, например когда реализуется работа с несколькими акаунтами, на разные сервера слать запросы в отдельных очередях... Поэтому в классе приложения (например) стоит создать синглтон для очереди и брать ее оттуда. Либо сделать DoRequestClass (назвав его RequestManager'ом, например) синглтоном с инициализированной один раз очередью...
ЗЗЫ Еще перенес обработчик клика в активити, это по желанию "на вкус и цвет".

Доступ к приватным полям класса предка

Насколько я понимаю, при создании объекта класса через new выделяется область в Heap для хранения всех полей как самого класса, так и нестатичных публичных (и protected) полей всех его предков. А затем поочерёдно вызываются конструкторы всех предков, начиная со старшего, которые инициализируют, а возможно перезаписывают значения полей данного объекта. И в конце конструктор самого объекта-наследника инициализирует свои новые поля или, возможно, перезаписывает значения полей, которые уже инициализировали конструкторы предков. Вопрос в следующем. Если у предка есть приватные поля и публичные геттеры к ним, а наследник не переопределяет эти поля и геттеры, то из объекта наследника можно, вызвав унаследованный геттер, получить значение поля из приватного поля предка. Как происходит в действительности? При создании объекта создаются объекты всех его предков в отдельных областях памяти, со всеми своими полями? Или же, что мне кажется более вероятным, JVM понимает, что при наличии публичных геттеров у предка наследник может получить доступ к его приватным полям и поэтому создаёт в области памяти объекта-наследника приватные поля его предка?


Ответ

Объектный модуль класса, помимо прочей информации, содержит информацию о иерархии наследования, порядке следования полей и их размерах. То есть после загрузки класса у виртуальной машины в метаспейсе всегда есть "карта" объектов этого класса, по которой можно вычислить по какому смещению от начала блока памяти находится то или иное поле. При создании нового объекта выделяется блок достаточного объёма, чтобы хранить заголовок объекта, его поля, а также поля всех его суперклассов. Причём поля располагаются в порядке от корня наследования - сначала поля суперкласса, потом подкласса. Благодаря такому расположению "карта" суперкласса подходит для ориентирования в объекте подкласса. Для наглядности определим примитивную иерархию классов
class A { int x; int y; }
class B extends A { int z; }
Операция B obj = new B() выделит в куче такой блок
----------- -- | Заголовок | | ----------- |_ Класс A | x | | | y | | ----------- -- | z | |- Класс B ----------- --
Если мы теперь приведём тип объекта к базовому, то виртуальная машина будет выполнять операции доступа к полям объекта так, будто никакого хвостика, содержащего поле z, просто не существует.
Благодаря Алексею Шипилёву мы можем увидеть это вживую с помощью инструмента jol (Java Object Layout).
import org.openjdk.jol.info.ClassLayout; import org.openjdk.jol.vm.VM;
public class ShowLayout { public static void main(String[] args) throws Exception { System.out.println(VM.current().details()); System.out.println(ClassLayout.parseClass(B.class).toPrintable()); } }
Компилируем
javac -cp jol-cli-0.9-full.jar ShowLayout.java
Запускаем
java -javaagent:jol-cli-0.9-full.jar ShowLayout
Получаем
# Running 64-bit HotSpot VM. # Using compressed oop with 3-bit shift. # Using compressed klass with 3-bit shift. # Objects are 8 bytes aligned. # Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] # Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
B object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 12 (object header) N/A 12 4 int A.x N/A 16 4 int A.y N/A 20 4 int B.z N/A Instance size: 24 bytes Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
Для методов каждого класса у JVM тоже есть "карта", указывающая по какому смещению в памяти находится начало того или иного метода. Есть два способа использования этой "карты" - раннее и позднее связывание (на самом деле больше, но это несущественно в текущем контексте). Обычный вызов метода
obj.getZ()
будет скомпилирован в байткод
aload_1 // Загрузка в стек ссылки на obj invokevirtual #4 // Method B.getZ:()I
Инструкция invokevirtual использует позднее связывание. То есть при вызове метода JVM анализирует контекст вызова (call site), определяет какой именно метод нужен и передаёт управление по требуемому смещению. Благодаря этому и возможен полиморфизм.
Вызов метода суперкласса (а также вызовы конструкторов и приватных методов)
super.getX();
будет скомпилирован в байткод
aload_0 // Ссылка this на объект класса B invokespecial #2 // Method A.getX:()I
Инструкция invokespecial использует ранее связывание. То есть ещё на этапе загрузки класса понятно какой именно метод какого именно класса надо будет вызвать, и JVM "зашивает" смещение этого метода в байткод.
Получив управлением метод getX (с помощью JVM, конечно) отсчитает нужное смещение от начала блока памяти, на который указывает переданная ссылка, до места где должно располагаться поле x в классе A, прочитает его значение, положит на вершину стека и вернёт управление вызывающему коду. Даже не догадываясь, что ссылка this на самом деле указывает на объект большего размера, и есть ли в подклассе метод с таким же именем, как у него.

Как корректно записать/считать в/из файла структуру с полями типа string?

Имеется структура
struct User { string login; string password; };
Стоит задача сделать примитивную авторизация пользователя. Т.е. создается файлик, в него записывается заполненный объект вышеуказанной структуры, а при последующих запусках производится запрос логина+пароля, считываются данные из файлика и сравниваются. Код:
#include #include #include #include #include
using namespace std;
struct User { string login; string password; };
void main () { SetConsoleCP (1251); // установка универсальной кодировки SetConsoleOutputCP (1251);
string path; int realsize=0; User u; vector U; bool exit = false;
do { system("cls"); cout<<"Укажите, на каком диске находится файл с регистрационными данными:
"; getline(cin, path); path += ":\\users.txt"; ifstream fin(path, ios_base::binary | ios_base::in);
if (fin.is_open()) { cout<<"Отлично, ваш файл найден!
"; fin.read((char*)&u, sizeof(User)); U.push_back(u); fin.close(); cout << "Введите логин:
"; getline(cin, u.login); cout << "Введите пароль:
"; getline(cin, u.password); if (!U.at(0).login.compare(u.login) && !U.at(0).password.compare(u.password)) { cout << "Вы авторизованы!
"; } else { cout << "Вы не авторизованы!
"; } exit = true; } else { cout << "Файл не найден и будет создан"; ofstream fout (path, ios_base::binary | ios_base::out); if (fout.is_open()) { cout << "Введите логин:
"; getline(cin, u.login); cout << "Введите пароль:
"; getline(cin, u.password); fout.write((char*)&u, sizeof(User)); fout.close(); cout << "Файл создан и данные внесены!
"; } else { cout << "Ошибка при создании файла! Работа приложения будет завершена.
"; exit = true; } } } while(!exit);
system("pause");
}
Вся беда в том, что при выполнении данного кода появляется ошибка:
Необработанное исключение по адресу 0x0FDECCC8 (msvcp110.dll) в test.exe: 0xC0000005: нарушение прав доступа при чтении по адресу 0x0067ADE4.
Кадры стека вызовов:

Путем экспериментов установлено, что замена использования вектора на простой динамический массив никак не влияет на ошибку (т.е. она по-прежнему появляется), а вот замена использования string на char * приводит к устранению проявления данной ошибки. Погуглив, я пришел в выводу, что возникает какая-то ошибка в деструкторе string (могу ошибаться). Может кто-нибудь прояснить ситуацию и дать рекомендации по корректному использованию типа string в данного рода задачах?


Ответ

Самый простой способ (как уже упомянул в комментарии @pavel) - использовать текстовый режим работы с файлом и операторы форматированного ввода/вывода (operator<<, operator>>) для чтения/записи std::string из/в потока.
Чтение:
ifstream fin(path); if (fin) { fin >> u.login >> u.password; }
Запись:
ofstream fout(path); if (fout) { // Разделители нужны для последующего считывания fout << u.login << " " << u.password << "
"; }
При этом данный подход накладывает некоторые ограничения на строки: как минимум они не должны содержать в себе символы пробельной группы, т.к. такой символ будет расценен как разделитель.
Функции istream::read, ostream::write в этом случае не используются вовсе. Причина, по которой они не работают как надо указана в ответе @gbg.

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

Как делается плавная прокрутка страницы на сайте? Мы скроллим страницу, а она прокручивается не рывками, а плавно, как тут. Какие плагины для этого есть?


Ответ

Нашел для этих целей плагин jQuery.scrollSpeed

Стоит ли заменять анонимную реализацию с одним методом лямбдой?

Intllij Idea предлагает заменить анонимную реализацию с одним методом лямбдой. Но по смыслу это не функциональный интерфейс, а просто переопределение одного метода одного класса. Стоит ли заменять?
return new NextImportIdParams() { @Override public String getCollectionName() { return new CollectionName(); } };


Ответ

Все зависит от того под какую версию java пишете + от принятого code style. Если вам никто не связывает руки, то определенно лямбы делают код более компактным и читабельным.

Запуск ssh-agent на debian

На удаленном сервере для развертывания кода с BitBucket используем защишенное соединение иаутентификацию по ssh ключам. Ксамому серверу подключаюсь через putty (с win10 сижу), и каждый раз приходится заново запускать ssh-agent командой eval $(ssh-agent) и добавлять нужные ключи. Посмотрел в запущенные процессы, все ранее запущенные ssh-agent'ы висят в памяти, но если разорвать соединение с сервером и затем снова открыть, ssh-agent снова недоступен. Подскажи в чем может быть проблема?
devloop@s05657c43:~# ssh-agent SSH_AUTH_SOCK=/tmp/ssh-m8EJNB3MFimr/agent.13061; export SSH_AUTH_SOCK; SSH_AGENT_PID=13062; export SSH_AGENT_PID; echo Agent pid 13062;
devloop@s05657c43:~$ ssh-add .ssh/devloop Could not open a connection to your authentication agent.


Ответ

сам факт запуска процесса ssh-agent на отдалённой машине уже намекает на то, что вы, вероятно, используете его не по назначению.
цитата из man ssh-agent
The idea is that the agent is run in the user's local PC, laptop, or terminal. Authentication data need not be stored on any other machine, and authentication passphrases never go over the network.
мой вольный перевод:
идея в том, что ssh-agent запускается на локальном компьютере. чтобы никакие аутентификационные данные не нужно было хранить на другой машине, и никакие пароли не передавались по сети.

судя по этому фрагменту:
$ ssh-add .ssh/devloop
вы хотите с первой отдалённой машины аутентифицироваться на каких-то других отдалённых машинах по ключу, хранящемуся на удалённой машине (в файле ~/.ssh/devloop).
в таком случае вам нет смысла запускать на этой отдалённой машине процесс ssh-agent. для того, чтобы аутентифицироваться на других машинах с помощью этого ключа, можете воспользоваться любым из перечисленных вариантов:
переименуйте файл ~/.ssh/devloop в ~/.ssh/id_rsa. этот вариант не подойдёт, если такой файл уже есть и его содержимое требуется вам для каких-то других целей. указывайте явно этот файл при подключении:
$ ssh -i ~/.ssh/devloop другая-отдалённая-машина добавьте в начало файла ~/.ssh/config строку:
identityfile ~/.ssh/devloop
тогда программа ssh будет пытаться использовать и этот файл при аутентификации.
если этот файл требуется использовать только для аутентификации лишь на нескольких определённых машинах, тогда лучше вместо указанной строки добавить в конец файла ~/.ssh/config секцию:
host машина1 машина2 машина3 identityfile ~/.ssh/devloop

но если я неправильно угадал, и вам на самом деле необходим процесс ssh-agent, то лучше запускать его в качестве «прослойки» (как он собственно, и используется в современных дистрибутивах), т.е. сразу указывать при подключении команду вида ssh-agent оболочка, примерно так:
$ ssh -t отдалённая-машина ssh-agent bash
опция -t здесь необходима для того, чтобы был отведён tty (если не указывать команду, т.е., инициировать запуск оболочки, то tty отводится автоматически).
а ещё, пожалуй, лучше будет использовать терминальный мультиплексор (screen, tmux и т.п.), который, кстати, тоже можно запускать с «прослойкой» в виде ssh-agent, примерно так:
$ ssh -t отдалённая-машина ssh-agent screen

p.s. и, да, вопрос не несёт в себе никакой дистрибутивной специфики, а касается лишь конкретно клиента openssh

Как прослушивать нажатия клавиш клавиатуры вне приложения?

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


Ответ

Можно использовать готовую библиотеку. Например jkeymaster или jnativehook

Выполняется старая версия кода

Установил Visual Studio 2015. Создал проект. написал простую программу из разряда "привет мир". В какой то момент перестает компилироваться программа, то есть меняю реплику на "мир привет", а выдается "привет мир". То есть старый exe файл запускается. Кто подскажет как побороть?


Ответ

Причина запуска старого варианта кода может быть в том, что новый код содержит ошибки и согласно настройкам среды производится запуск последней удачной сборки.
Проверьте настройки на странице Tools - Options - Projects & Solutions - Build & Run

понедельник, 29 апреля 2019 г.

Java. Изменить название класса динамически из String

Есть некий класс Contakt.class, но названия не имеет значение так как классов много, суть в том что вместо Contakt нужно подставить динамически другие значения.
Я получаю данные text и вставляю их в строку String q2=text; далее у меня есть код где есть Contakt.class, но вместо Contakt нужно вставить q2, где и храняться названия других классов.
Получится что-то вроде q2.class, где вместо q2 будут различные значения.
Есть ли такая возможность на Java?


Ответ

С помощью методов Class.forName() и newInstance() объекта Class можно динамически загружать и создавать экземпляры класса в случае, когда имя класса неизвестно до момента выполнения программы.
Class c = Class.forName("com.xyz.MyClass"); Object obj = c.newInstance(); MyClass myClass = (MyClass) obj;

Как сделать события для соответствующих div?

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

Имя


Редактировать

Фамилия


Редактировать

Ума хватило только на такой вот код , но в этом случае появляются все инпуты сразу
jQuery(".edit-settings").click(function () { if($('.sett-drop').is(":visible")){ $('.sett-drop').hide("fast"); }else { $('.sett-drop').show("fast"); }; });
Как же сделать так , чтобы при клике на ссылку открывался именно тот div, который нужно ? Присваивать id не вариант , так как таких блоков довольно таки много.


Ответ

Чуточку поправила код и:
$(".edit-settings").click(function () { var $this = $(this), wrap = $this.closest('.settings-line'), drop = wrap.find('.sett-drop'); if(drop.is(":visible")){ drop.hide("fast"); }else { drop.show("fast"); } }); .sett-drop { display: none; }

Фамилия

Редактировать

P.S: Небольшой алгоритм (мне помогает) --> Берем ссылку на которую кликаем $(this) --> для нее находим обертку в которой она же находится (.settings-line) --> в этой обертке находим контейнер который скрывается\раскрывается и с ним работаем.

Значение this в С#

Не могу разобраться в сути this. Когда метод вызывается, ему автоматически передается ссылка на вызывающий объект, т.е. тот объект, для которого вызывается данный метод
class SomeClass { private string name = "No name"; private static void WriteToLog(SomeClass aSomeObject) { Console.WriteLine("Обрабатывается объект с именем " + aSomeObject.name); }
public SomeClass(string name) { //Хотим присвоить значение аргумента, полю класса this.name = name; }
public void DoWork() { WriteToLog(this); }
}
А что передается в WriteToLog(this) при его вызове? Ссылка на что?
т.е. при
SomeClass tmpObj = new SomeClass("Иван");
tmpObj.DoWork();
передается ссылка на объект tmpObj ?


Ответ

MSDN
The this keyword refers to the current instance of the class and is also used as a modifier of the first parameter of an extension method.

Ключевое слово this указывает на текущий экземпляр класса. Также используется в качестве модификатора для первого параметры в методах расширениях
Таким образом внутри определения класса - это ссылка на конкретный объект, для которого выполняется тот или иной метод.
SomeClass tmpObj = new SomeClass("Иван"); tmpObj.DoWork();
this внутри DoWork в данном случае указывается на tmlObj, так как эта функция вызывается у этого объекта.

Ключевые кадры в анимации

Доброго времени суток.
Не могу вникнуть в ключевые кадры анимации, а точнее, например делаю слайдер, в нем 3 картинки, задаю анимации 15 секунд скорости, и infinite. Теперь например хочу сделать что бы картинка стояла 3 секунды далее уходила влево за 2 сек. И за ней сразу же шла вторая картинка, и она должна стоять 3 секунды, и уходить влево за 2 секунды, далее за ней третья картинка выдвигается и 3 сек стоит. И т.д. Так вот, очень хочется понять эту тему, объясните пожалуйста подробней, как мне грамотно рассчитать ключевые кадры?
Сам я пытался сделать так:
0%{left: 0px;opacity: 1} 16%{left: 0px;opacity: 1} 25%{left: -680px; opacity: 0} 34%{left: -680px; opacity: 0} 43%{left: 680px;opacity: 0} 52%{left: 680px;opacity: 0} 61%{left: 0;opacity: 1} 70%{left: 0;opacity: 1} 79%{left: -680px;opacity: 0} 88%{left: 680px;opacity: 0} 97%{left: 680px;opacity: 0} 100%{left: 0px;opacity: 0}
Но на конечной точке, первая картинка не выдвигается плавно как до этого, а встает на первую точку резко.


Ответ

Это решение для варианта, когда текущий слайд уезжает со следующего. Если требуется просто сдвиг слайдов, то надо использовать другой способ.
Какова длительность всей анимации?
(3 сек + 2 сек) * 5 шт = 25 сек. 1 сек = 4%.
Как сделать анимацию каждой картинки?
3s картинка просто стоит:
0% { left: 0; } 12% { left: 0; } 2s уезжает влево:
18% { left: -100%; } Потом незаметно возвращается обратно:
18.001% { z-index: -1; left: -100%; } 100% { z-index: -1; left: 0; }
Значения повторно использовать нельзя, поэтому добавляем отклонение на .001%. Но надо, чтобы за 2 секунды до конца блок уже был видим, поэтому последнюю строку заменяем на:
92% { z-index: 0; left: 0; } 100% { z-index: 0; left: 0; } Исправить косяк с анимацией z-index - не показывать элемент раньше чем нужно:
91.999% { z-index: -1; left: 0; }
Как сделать анимацию слайдера?
Использовать animation-delay для слайдов.
Что Можно улучшить?
Производительность за счёт использование transform:translate вместо left.
section { position: relative; height: 10em; overflow: hidden; } div { position: absolute; left: 0; top: 0; width: 100%; height: 100%; z-index: -1; animation: slide 25s linear infinite both; } @keyframes slide { 0% { z-index: 1; left: 0; } 12% { z-index: 1; left: 0; } 18% { z-index: 1; left: -100%; } 18.001% { z-index: -1; left: -100%; } 18.002% { z-index: -1; left: 0; } 91.999% { z-index: -1; left: 0; } 92% { z-index: 0; left: 0; } 100% { z-index: 0; left: 0; } }


section { position: relative; height: 10em; overflow: hidden; } div { position: absolute; left: 0; top: 0; width: 100%; height: 100%; z-index: -1; transform: translateX(0); animation: slide 25s linear infinite both; } @keyframes slide { 0% { z-index: 1; transform: translateX(0); } 12% { z-index: 1; transform: translateX(0); } 18% { z-index: 1; transform: translateX(-100%); } 18.001% { z-index: -1; transform: translateX(-100%); } 18.002% { z-index: -1; transform: translateX(0); } 91.999% { z-index: -1; transform: translateX(0); } 92% { z-index: 0; transform: translateX(0); } 100% { z-index: 0; transform: translateX(0); } }

Git Bash/Git GUI некорректное отображение ярлыка

Установил Git-2.10.0-64-bit на Windows 7. Проблема в том что некорректно отображается ярлык в Пуске
и при правом щелчке мышки на рабочем столе.
Как сделать что б отображался нормальный ярлык.


Ответ

Для того, чтобы отображались верные значки в контекстном меню необходимо изменить два значения Icon в ветках реестра HKEY_CLASSES_ROOT\Directory\Background\shell\git_gui и HKEY_CLASSES_ROOT\Directory\Background\shell\git_shell. Соответственно указать путь до какого-либо значка, например, "C:\Program Files\Git\mingw64\share\git-gui\lib\git-gui.ico"

random заполняет две матрицы одинаковыми значениями

Рандом работает не так как нужно: при каждом вызове функции Random, матрицы заполняются одинаково
public void Random() { Random random = new Random();
for (int i = 0; i < N; i++) { for (int j = 0; j < M; j++) { matrix[i, j] = random.Next(0, 10); } } }


Ответ

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

invalid initialization of non-const

#include #include
using namespace std;
class complex { double re, im; public: complex(double = 0, double = 0); ~complex();
complex operator+(complex&); complex operator-(complex&); complex operator*(complex&); complex operator/(complex&); complex operator^(unsigned); friend istream& operator >> (istream &, complex&); friend ostream& operator << (ostream &, complex &); };
complex::complex(double r, double i) { re = r; im = i; }
complex::~complex() { }
complex complex::operator+(complex&y) { return complex(re + y.re, im + y.im); }
complex complex::operator-(complex&y) { return complex(re - y.re, im - y.im); }
complex complex::operator*(complex&y) { return complex(re*y.re - im*y.im, re*y.im + im*y.re); }
complex complex::operator/(complex&y) { double r1 = re; double i1 = im; double r2 = y.re; double i2 = y.im; return complex((r1*r2 - i1*i1) / (r2*r2 + i2*i2), (-r1*i2 + i1*r2) / (r2*r2 + i2*i2)); }
complex complex::operator^(unsigned n) { complex y(1, 0); for (int i = 1; i <= n; i++) y = y*(*this); return y; }
istream& operator >> (istream& is, complex& x) { char c; cin >> c; assert(c == '('); cin >> x.re; cin >> c; assert(c == ','); cin >> x.im; cin >> c; assert(c == ')'); return is;
}
ostream& operator<<(ostream&os, complex&x) { os << '(' << x.re << ',' << x.im << ')' << endl; return os; }
int main(){
complex a(1, 1); complex b(1, 1); complex c(1, 1); complex x;
cout << "Введите комплексное число в формате: (re,im) ->"; cin >> x; cout << "Результат =" << a*(x ^ 2)) + b*x + c << endl; return 0; }
На линуксе выводит ошибку:
invalid initialization of non-const
для строки:
cout << "Результат =" << a*(x ^ 2) + b*x + c << endl;
Саму программу скопировал с Windows, ошибки исправил, только эту выдает. В чем здесь проблема? И как можно ее решить? На Visual Studio работала нормально.


Ответ

Объявите данные операторы следующим образом
complex operator+( const complex&) const; complex operator-(const complex&) const; complex operator*(const complex&) const; complex operator/( const complex&) const; complex operator ^( unsigned int ) const; friend ostream& operator << (ostream &, const complex &);
Нельзя связывать временные объекты с неконстантной lvalue ссылкой.
Обратите внимание , что конструктор класса является преобразующим конструктором. Поэтому у вас будет работать выражение complex + double, как, например,
complex a( 10, 10 ); complex b = a + 10;
Но не будет работать выражение double + complex
complex a( 10, 10 ); complex b = 10 + a; // ошибка компиляции
так как ваши операторы являются членами класса. Вы могли бы их объявить как отдельные функции, не являющиеся членами класса, которые принимают два аргумента. Например,
friend complex operator +( const complex &lhs, const complex &rhs ) { return complex( lhs.re + rhs.re, lhs.im + rhs.im ); }
В этом случае второе выражение было бы также верным.
Эта дружественная функция может быть определена как в самом классе, и тогда при использовании оператора будет применен зависящий от аргумента поиск (ADL), либо вне класса.
Что касается Visual Studio, то его компилятор имеет собственные расширения языка (которые активизированы по умолчанию; вы можете отключить эту опцию в настройках компилятора, и тогда будет выдано сообщение об ошибке), которые порой противоречат стандарту C++. Не стоит полагаться на эти расширения языка компилятора C++ Visual Studio, так как код будет не переносимым.
EDIT: Так как у вас возникают трудности правильно набрать код, то приведу для вас рабочий вариант программы. Я не проверял, определены ли правильно операторы с точки зрения математики.
#include #include
class complex { private: double re, im;
public: complex( double = 0, double = 0 ); ~complex();
complex operator +( const complex & ) const; complex operator -( const complex & ) const; complex operator *( const complex & ) const; complex operator /( const complex & ) const; complex operator ^( unsigned int ) const; friend std::istream & operator >>( std::istream &, complex & ); friend std::ostream & operator <<( std::ostream &, const complex & ); };
complex::complex( double r, double i ) : re( r ), im( i ) { }
complex::~complex() { }
complex complex::operator +( const complex &c ) const { return complex( re + c.re, im + c.im ); }
complex complex::operator -( const complex &c ) const { return complex( re - c.re, im - c.im ); }
complex complex::operator *( const complex &c ) const { return complex( re * c.re - im * c.im, re * c.im + im * c.re ); }
complex complex::operator /( const complex & c ) const { double r1 = re; double i1 = im; double r2 = c.re; double i2 = c.im; return complex( ( r1 * r2 - i1 * i1 ) / ( r2 * r2 + i2 * i2 ), (-r1 * i2 + i1 * r2 ) / ( r2 * r2 + i2 * i2 ) ); }
complex complex::operator ^( unsigned int n ) const { complex c( 1, 0 );
for ( unsigned int i = 1; i <= n; i++ ) c = c * *this;
return c; }
std::istream & operator >>( std::istream &is, complex &c ) { char ch;
is >> ch; assert( ch == '(' );
is >> c.re;
is >> ch; assert( ch == ',' );
is >> c.im;
is >> ch; assert( ch == ')' );
return is; }
std::ostream & operator <<( std::ostream &os, const complex &c ) { return os << '(' << c.re << ',' << c.im << ')'; }
int main() { complex a(1, 1); complex b(1, 1); complex c(1, 1); complex x;
std::cout << "Введите комплексное число в формате: (re,im) ->"; std::cin >> x;
std::cout << "x = " << x << std::endl; std::cout << "x ^ 2 = " << ( x ^ 2 ) << std::endl; std::cout << "a * ( x ^ 2 ) = " << a * ( x ^ 2 ) << std::endl; std::cout << "b * x = " << b * x << std::endl; std::cout << "a * ( x ^ 2 ) + b * x = " << a * ( x ^ 2 ) + b * x << std::endl;
std::cout << "Результат =" << a * ( x ^ 2 ) + b * x + c << std::endl;
return 0; }
Если ввести значение (10,10), то вывод будет выглядеть следующим образом:
Введите комплексное число в формате: (re,im) ->(10,10) x = (10,10) x ^ 2 = (0,200) a * ( x ^ 2 ) = (-200,200) b * x = (0,20) a * ( x ^ 2 ) + b * x = (-200,220) Результат =(-199,221)

Что такое .class?

Constructor constructor = User.class.getConstructor(new Class[]{String.class,String.class,String.class}); System.out.println("Constructor "+constructor); constructor.newInstance("Hello","From","Reflection");
Из данного примера мне понятно что при передачи конструктору создаётся Обьект массива типа Class.
Но вводит в заблуждение: Class.class после чего позволяется вызывать методы Reflection API. Что означает этот .class ?
Я знаю что для доступа к методам надо создать обьект любого класса или если метод статичный то доступ будет произведен через имя класса.. В случае с доступом к Reflection API не понятно это окончание .class, я могу вызвать .class у любого класса или интерфейса или примитива int.class как JVM (если так правильно будет сказать) относится к такого рода конструкциям ? Что это и почему оно используется ?


Ответ

Обращение к .class после имени типа возвращает объект типа Class. Этот объект содержит информацию о типе (будь то класс или интерфейс) и используется в тех местах, где нужно передать информацию о типе (рефлексия как один из примеров).
Вызов .class на типе эквивалентен вызову getClass() на экземпляре типа. Обычно .class используется там, где нужно указать тип, но нет конкретного экземпляра этого типа. Пример для String
System.out.println(String.class.getName()); System.out.println("hello".getClass().getName());

В вашем примере в первой строке вы находите конструктор класса User, который принимает три строковых параметра. Для указания типов параметров используется String.class

Как мне сконвертировать IP?

Имеется IP - 95.153.128.120 и данный IP как то конвертируется, на выходе получается - 1603895416
С помощью какой функции и или еще чего конвертируется данный IP?


Ответ

в php есть функция
int ip2long ( string $ip_address )
ip2long — Конвертирует строку, содержащую (IPv4) Интернет-адрес с точками в целое число (long)
Пример
$long = ip2long($ip);
Возвращает целое число или FALSE, если параметр ip_address содержит ошибку.
документация

и обратное функция
string long2ip ( string $proper_address )
long2ip — Конвертирует адрес в формате "длинное целое"(long integer) в, содержащую адрес Интернет сети(IPv4), стандартную строку с точками
Возвращает Интернет IP адрес в виде строки.
документация

Перегрузка оператора +=

// Реализовать класс String для работы со строками. Перегрузить операторы = + += - > < [] (подстрока) ++ -- #pragma once #include using namespace std;
class String {
char* s; int length;
public:
String(const char* str="") { this->length = strlen(str); this->s = new char[this->length+1]; for (int i = 0; i < length; i++) this->s[i] = str[i]; }
String(const String& s1) { this->length = s1.length; this->s = new char[this->length]; for (int i = 0; i < this->length; i++) this->s[i] = s1.s[i]; }
~String() { delete[] s; }

String& String::operator=(String& right); String String::operator+(String right); //String& String::operator+=(const String& right); friend String& operator+=(String& left, const String& right); void String::show();
};
А это цпп файл:
#include "String.h"
void String::show() { for (int i = 0; i < this->length; i++) cout << this->s[i]; }
String& String::operator=(String& right) { delete[] this->s; this->length = right.length; this->s = new char[this->length]; for (int i = 0; i < this->length; i++) this->s[i] = right.s[i]; return *this; }
String String::operator+(String right) { String new_string; new_string.length = this->length + right.length; new_string.s =new char[this->length + right.length+1]; for (int i = 0; i < this->length; i++) new_string.s[i] = this->s[i]; for (int i = 0; i < right.length; i++) new_string.s[this->length + i] = right.s[i]; return new_string; }
String& operator+=(String& left, const String& right) { return left+right; }
Почему у меня s3 всё равно при выводе пустая? Помогите начинающему!
#include "String.h"
void main() { String s2("Hello"); String s3; s3 += s2; s3.show(); system("pause"); }


Ответ

Мы, начинающие программисты, должны помогать друг другу.:)
Начнем с того, что вам следует включить заголовок
#include
так как вы используете функции, объявленные в этом заголовке.
Длину строки лучше определять, как имеющую тип size_t вместо int
class String { char* s; size_t length; //...
Ваши конструкторы неверно копируют строки. Они не копируют в результирующую строку завершающий символ нуля '\0'. Например,
String(const char* str="") { this->length = strlen(str); this->s = new char[this->length+1]; for (int i = 0; i < length; i++) // символ нуля не входи в диапазон `[0, length)` this->s[i] = str[i]; }
Иначе непонятно, зачем вы выделяете память длиною this->length+1 вместо this->length. Непонятно, зачем вы вообще используете циклы для копирования строк, когда вы уже используете стандартные C функции из заголовка
Лучше было бы объявить конструктор следующим образом
String( const char *str = "" ) { this->length = std::strlen( str ); this->s = new char[ this->length + 1 ]; std::strcpy( this->s, str ); }
То же самое замечание справедливо и для конструктора копирования.
В определении класса нельзя указывать квалифицированное имя функций-членов класса при их объявлении. Хотя MS VC++ это допускает, но это является его собственным расширением языка, которое не соответствует стандарту.
String& String::operator=(String& right); ^^^^^^^^
Эти объявления
String String::operator+(String right); friend String& operator+=(String& left, const String& right);
лучше переопределить следующим образом
friend String operator + ( const String &left, const String &right ); String & operator += ( const String &right );
Функцию show лучше объявить как
std::ostream & String::show( std::ostream &os = std::cout ) const;
Переопределите соответствующие функции с учетом выше приведенных замечаний.
Что касается копирующего оператора присваивания, то он может быть определен следующим образом
String & String::operator =( const String &right ) { if ( this != &right ) { size_t n = std::strlen( right.s ); char tmp = new char[ n + 1 ];
std::strcpy( tmp, right.s );
delete [] this->s;
this->s = tmp; this->length = n; }
return *this; }
Аналогичным образом вам нужно определить оператор
String & operator += ( const String &right );
Например
String & String::operator +=( const String &right ) { size_t n = this->length + std::strlen( right.s ); char tmp = new char[ n + 1 ];
std::strcpy( tmp, this->s ); std::strcat( tmp, right.s );
delete [] this->s;
this->s = tmp; this->length = n;
return *this; }
Функция show определяется просто
std::ostream & String::show( std::ostream &os ) const { return os << this->s; }
Что касается вашего вопроса
Почему у меня s3 всё равно при выводе пустая?
то этот оператор
String& operator+=(String& left, const String& right) { return left+right; }
не изменяет левый аргумент. И более того имеет неопределенное поведение, так как возвращает ссылку на временный объект, создаваемый выражением left+right.
EDIT: Если оператор operator [], который, как я понимаю, вы также должны определить, позволяет вставлять в объект класса символ '\0', то вам следует изменить определения конструктора копирования, копирующего опреатора присваивания, оператора operator +=, и дружественной функции operator +, заменив стандартные C функции strXXX на memXXX. Ниже приведена демонстрационная программа, которая показывает, как это можно сделать на примере некоторых членов класса. Другие члены класса постарайтесь определить сами.
#include #include
class String { private: char *s; size_t length;
public: String( const char *str = "" ) { this->length = std::strlen( str ); this->s = new char[ this->length + 1 ];
std::strcpy( this->s, str ); }
String( const String &src ) { this->length = src.length; this->s = new char[ this->length + 1 ];
std::memcpy( this->s, src.s, this->length + 1 ); }
String & operator =( const String &src ) { if ( this !=+ &src ) { char *tmp = new char[ src.length + 1 ];
std::memcpy( tmp, src.s, src.length + 1 );
delete [] this->s;
this->s = tmp; this->length = src.length; }
return *this; }
String & operator +=( const String &src ) { size_t n = this->length + src.length; char *tmp = new char[ n + 1 ];
std::memcpy( tmp, this->s, this->length ); std::memcpy( tmp + this->length, src.s, src.length + 1 );
delete [] this->s;
this->s = tmp; this->length = n;
return *this;
}
~String() { delete [] this->s; }
std::ostream & show( std::ostream &os = std::cout ) { return os << this->s; } };
int main() { String s1( "Hello world!" ); String s2;
s2 = s1;
s2.show() << std::endl;
s2 += " Glad to see you!";
s2.show() << std::endl;
return 0; }
Вывод программы будет следующим
Hello world! Hello world! Glad to see you!

Как добавить ведущие нули к hex?

Преобразую число:
int num = 1155; string end = Convert.ToString(num , 16).TrimStart('0'));
В end записывается результат 483, а нужно получить 0483


Ответ

int num = 1155; string end = num.ToString("X8"); // end = @"00000483"
Строки стандартных числовых форматов

Что можно подставлять в качестве значения параметра X при использовании этого класса в программе?

Предположим, у нас есть параметризованный класс
public class Example { ... }
Что можно подставлять в качестве значения параметра X при использовании этого класса в программе?
имя любого интерфейса (например, CharSequence) символ "?" или более сложное выражение с ключевыми словами extends и super значение X можно не указывать, т.е. использовать класс Example как обычный непараметризованный имя любого класса (например, Object) имя любого примитивного типа (например, int) ссылку на метод (например, Object::toString) имя любого перечисления (например, DayOfWeek) значение примитивного типа (например, 42)
Объясните пожалуйста, почему не подходят ответы 1, 2, 3, 4 ?


Ответ

Аргументы типов в Java определены в спецификации в п.п. 4.5.1
В качестве аргумента по спецификации можно поставить ссылочный тип (ReferenceType в Java любой непримитивный тип) либо маску (WildCard, т.е. выражение ? extends/super T).
Вот пример допустимого использования Example
Example a = new Example(); Example b = new Example(); Example c = new Example(); Example d = new Example(); Example e = new Example();

Удалить дубликаты в массиве без использования коллекций. Java

Необходимо удалить дубликаты в массиве без использования коллекций.
C ArrayList или HashSet все понятно, тут делать не чего, но мне задание дали удалить дубликаты не используя ничего, кроме массивов. При чем метод должен работать, даже если дубликатов больше двух.
Исходный массив {1 ,1, 1, 2, 1, 3, 3} Искомый результат {1, 2, 3}
В общем уже голову сломал, может кто поможет?
Спасибо.


Ответ

Как я полагаю, ваше задание на использование циклов при работе с массивами. Если так, то прямолинейный подход с использованием циклов может выглядеть следующим образом
import java.util.*; import java.lang.*; import java.io.*;
class Ideone { public static void main (String[] args) throws java.lang.Exception { int[] a = { 1, 1, 1, 2, 1, 3, 3 };
int n = a.length;
for ( int i = 0, m = 0; i != n; i++, n = m ) { for ( int j = m = i + 1; j != n; j++ ) { if ( a[j] != a[i] ) { if ( m != j ) a[m] = a[j]; m++; } } }
if ( n != a.length ) { int[] b = new int[n]; for ( int i = 0; i < n; i++ ) b[i] = a[i];
a = b; }
for ( int x : a ) System.out.print( x + " " ); System.out.println(); } }
Вывод программы
1 2 3

Аннотация @intDef

Пытаюсь создать свою аннотацию на основе @intDef , имеется следующая конструкция - но он её не видит:
import android.support.annotation.IntDef;
@intDef(Importance.noMatter, Importance.green, Importance.yellow, Importance.red) public @interface Importance {
public static int noMatter = 0; public static int green = 1; public static int yellow = 2; public static int red = 3; }
Создал через java класс.
Пытался через @Annotations, выдает следующее:


Ответ

Ошибка с @annotation все еще остается загадкой, но основную проблему я исправил.
Дело было в том, что @intDef написано с маленькой буквы.
Напомню, что @IntDef является правильной заменой Enum в Android и гугл не рекомендует использовать последнее, поскольку @IntDef хранит простые инты, а не сложные объекты, которые всегда подгружаются, и занимают уйму памяти.

Приведение const char* к char*

Пытаюсь с QByteArray получить указатель на данные с помощью data(), ругается:
ошибка: invalid conversion from 'const char*' to 'char*' [-fpermissive] char * TempPtrBuff = ARes.data();
В документации пишется, что возвращается char *
Почему может возникать ошибка?


Ответ

Результат вывода QByteArray::data() зависит от константности метода, в котором производится вызов обозначенной функции. Проще говоря:
void MyClass::method() { char *data = ARes.data(); }
void MyClass::method() const { const char *data = ARes.data(); }
Соответственно, если вывод QByteArray::data() отличен от желаемого, то измените константность метода или осуществите приведение типа, например, тем же const_cast()

Можно-ли изменить данные в массиве VBO?

Здравствуйте. Обращаюсь к специалистам OpenGL. Рисую трехмерную сцену с группой объектов VAO
for(auto VAO: vao_list) { glBindVertexArray(VAO); glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, nullptr); glBindVertexArray(0); }
Все по "букварю", все работает. Но вот один из объектов, размером этак 40К вершин, потребовалось немного изменить: удалить 3 из 40 000 вершин. Можно конечно перезалить модифицированный объект, но для этого его образ надо вначале построить в оперативной памяти а потом перезалить в память графического процессора. А если меняющихся объектов в сцене большинство, то все их (копии) придется держать в оперативке, там править и перезаливать в графичекий буфер. Получается двойная работа, наверно тогда проще использовать "glDrawArrays", который рисует массивы прямо из оперативной памяти:
glEnableVertexAttribArray(idx_vertex_coord3d); glEnableVertexAttribArray(idx_texture_coord); glDrawArrays(GL_TRIANGLES, 0, count_of_vertices); glDisableVertexAttribArray(idx_texture_coord); glDisableVertexAttribArray(idx_vertex_coord3d);
но в этом случае память графического процессора (очень дорогая и быстрая) простаивает. Вот собственно вопрос: а можно ли как-то частично изменять объект размещенный в VAO (в графической памяти), удаляя/добавляя часть вершин в нем не перезаписывая VAO полностью?


Ответ

VAO и VBO
На всякий случай вначале скажу немного про VAO и VBO. VAO не хранит данные объекта, а хранит только ссылки на один или несколько VBO и прочее состояние, необходимое для рисования объекта. Поэтому работать мы будем с VBO. Если несколько атрибутов вершин хранятся в нескольких VBO, то все их придётся править по отдельности. Изменение VBO будет сразу же доступно пользователям связанного VAO.
Рассуждения об удалении
Начнём с экстремально простого случая: при удалении вершин с конца вообще ничего изменять не нужно. Просто рисуем вызовом
glDrawElements(GL_TRIANGLE_STRIP, num_elements - 3, GL_UNSIGNED_BYTE, nullptr);
вместо
glDrawElements(GL_TRIANGLE_STRIP, num_elements, GL_UNSIGNED_BYTE, nullptr);
Если же удаляемые вершины хранятся в начале или в середине, то задача их удаления аналогична задаче удаления элементов из середины обычного массива в памяти. Например, если есть массив:
int a[] = {1,2,3,4,5,6};
то мы не можем удалить из него элементы 2 и 3, не оставив на их месте нули или какие-нибудь специальные значения значения, указывающие на то, что данные удалены. Чтобы не оставлять этих значений, мы можем либо перевыделить память под новый массив нужной длины и скопировать туда значения, либо скопировать 5 и 6 на место 2 и 3 и запомнить, что теперь длина массива равна 4 вместо 6. Оставшаяся в хвосте память под 2 элемента будет потрачена впустую, но при 40000 элементов ей можно пренебречь.
То же самое можно применить и к массиву в видеопамяти:
Можно вызвать glBufferData для выделения нового буфера. Можно заменить кусок данных от начала удаляемого куска до конца буфера новыми значениями с помощью glBufferSubData, не забыв про уменьшение num_elements. Сдвинуть данные копированием внутри буфера не получится, ибо регионы памяти при копировании внутри буфера не должны пересекаться.
Вышеперечисленные методы могут иметь смысл при изменении/"удалении" большого количества данных, но, как вы заметили, совершенно не подходят для удаления трёх точек из 40000. То есть полностью удалить точки не получится, и придётся искать обходной путь.
Возможное решение
Функция glBufferSubData позволяет указывать смещение и длину заменяемых данных. Поэтому с её помощью можно переписать как весь буфер, так и любую его часть, хоть один единственный элемент. Если нам нужно удалить 3 из 40000 точек из модели, то не обязательно их удалять из буфера! Давайте просто перезапишем их значениями подходящей соседней вершины. Например, пусть есть ломаная из 8 вершин на плоскости:
2 3 5 7 /-------\ /\ /----8 / \ / \ / / \/ \/ /1 4 6
Если мы сделаем вершину 5 равной вершине 6, то получим тот же эффект, что и при удалении вершины 5: появится отрезок, визуально соединяющий вершины 4 и 6, а длина отрезка 5-6 станет нулевой:
2 3 7 /-------\ /----8 / \ / / \------/ /1 4 5,6
В выборе между перерасходом памяти на 3 вершины или расходом времени на пересоздание буфера на 40000 вершин логично отдать предпочтение первому варианту.
Usage pattern
Из вашего описания кажется, что "удалять" удалять точки вы будете редко, т.е. не на каждом кадре. Буфер же будет использоваться только для вывода графики, но не для transform feedback и прочих таких хитростей. Если так, то при создании буфера не забудьте в последнем аргументе glBufferData указать GL_DYNAMIC_DRAW. Однако, без тестов производительности конкретного приложения здесь нельзя давать однозначную рекомендацию. При очень редком обновлении буфера GL_STATIC_DRAW может оказаться быстрее. Напротив, при очень частом лучшим выбором может быть GL_STREAM_DRAW
Комментарий от автора вопроса
Небольшой пример. Спасибо, все встало на свои места. В добавление к вашему ответу хочу добавить демо-код для одного из перечисленных вами вариантов решения:
GLfloat* vertices = new GLfloat[9]; // элемент из 3 вершин ...
GLuint pos_Buf; glGenBuffers(1, &pos_Buf); // передаем данные в GPU glBindBuffer(GL_ARRAY_BUFFER, pos_Buf); glBufferData(GL_ARRAY_BUFFER, 9*sizeof(float), vertices, GL_STATIC_DRAW); // освободить память после переноса данных в GPU delete [] vertices; ...
// Если надо изменить, например, седьмой элемент массива: // Пример изменения данных, размещенных в графической памяти // Вариант - glUnmapBuffer // ---------------------------------------------------- glBindBuffer(GL_ARRAY_BUFFER, pos_Buf); data = (GLfloat *) glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); data[7] = 0.4f; glUnmapBuffer(GL_ARRAY_BUFFER); ...
// Вариант 2 - glBufferSubData // ---------------------------------------------------- glBindBuffer(GL_ARRAY_BUFFER, pos_Buf); GLintptr offset = 7*sizeof(float); float pos_SubD[] = {0.0f}; glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(float), pos_SubD); ...
// В нужный момент этот VBO можно удалить glDeleteBuffers(1, &vboId);

Чтение из TreeMap по порядковому номеру?

Приветствую, коллеги!
Есть готовый и отсортированный как надо TreeMap
Как получить из него пары ключ-значение на основании порядкового номера i? По типу:
for (i = 0; i < map.size(); i++)


Ответ

Получить определенную пару по индексу index можно, например, так:
TreeMap foo = new TreeMap(); Object key = foo.keySet().toArray(new Object[foo.size()])[index]; Object value = foo.get(key);

Перегрузка оператор С++

Такой вопрос. Я перегружаю операторы для работы с вектором, который состоит из трек точек. Есть несколько задач:
Найти скалярное произведения векторов; (возвращает double) Найти векторное произведения векторов; (возвращает вектор)
И получается такая проблема, что компилятор не знает какой из двух методов вызвать (хотя они отличаются возвращающимися параметрами). И как все это решить?
using namespace std; class Vec3D { private: double x, y, z; public: Vec3D(double xx = 0, double yy = 0, double zz =0); Vec3D operator+ (const Vec3D & V); // double operator* (const Vec3D & V); // проблема тут friend ostream& operator<< (ostream& cout, Vec3D & V); friend Vec3D operator* (const double c, const Vec3D & V); friend Vec3D operator* (const Vec3D & V1,const Vec3D & V2); // и тут };
P.S. То что нужно реализовать семеричные\бинарные операции через friend функции я знаю


Ответ

Компилятор в общем случае не может определить, какую вызывать перегруженную функцию только по возвращаемому значению. Например, рассмотрите следующий фрагмент кода
void f() {} int f() { return 0; }
f();
Как определить, какая функция из двух вызывается?
Поэтому функции не перегружаются по возвращаемому значению.
Перегрузите этот оператор следующим образом, как показано в демонстрационной программе ниже.
#include
class Vec3D { private: double x, y, z;
public: Vec3D( double x = 0, double y = 0, double z =0) : x( x ), y( y ), z( z ) { }
friend std::ostream & operator <<( std::ostream &os, const Vec3D &v ); friend Vec3D operator *( const Vec3D &V, double d ); friend Vec3D operator *( double d, const Vec3D &v ); friend Vec3D operator *( const Vec3D &V1, const Vec3D &V2 ); // и тут };
std::ostream & operator <<( std::ostream &os, const Vec3D &v ) { return os << "( " << v.x << ", " << v.y << ", " << v.z << " )"; }
Vec3D operator *( const Vec3D &v, double d ) { return Vec3D( d * v.x, d * v.y, d * v.z ); }
Vec3D operator *( double d, const Vec3D &v ) { return v * d; } Vec3D operator *( const Vec3D &v1, const Vec3D &v2 ) { return Vec3D( v1.x * v2.x, v1.y * v2.y, v1.z * v2.z ); }
int main() { Vec3D v1( 1, 2, 3 ); Vec3D v2( 1, 2, 3 );
std::cout << ( 2 * v1 ) * ( v2 * 3 ) << std::endl; return 0; }
Ее вывод на консоль
( 6, 24, 54 )
Нельзя перегрузить оператор по возвращаемому типу. Но вы могли бы взять еще один оператор, как, например, operator ^, чтобы использовать его для одного из видов произведения векторов.
В итоге у вас может получиться два оператора
operator *
и
operator ^
Объявление перегруженного оператора operator ^ может выглядеть аналогично объявлению оператора operator * за исключением типа возвращаемого значения.

Как возвращать const ссылку из методов класса? C++

Помогите пожалуйста, как возвращать const ссылку из методов класса?
class CCalculator { public: CRepository GetRepository() const;
....
CRepository CCalculator::GetRepository() const { return m_repository; }


Ответ

Очень просто
class CCalculator { public: const CRepository & GetRepository() const; // ...
и
const CRepository & CCalculator::GetRepository() const { return m_repository; }

Будет ли копироваться значение при передаче умных указателей в функцию или будет передаваться ссылка?

Например, имеется некоторый класс:
class CSomeClass { double GetLengthLine(std::shared_ptr firstVertex, std::shared_ptr secondVertex) const; }

double CTriangle::GetLengthLine(std::shared_ptr firstVertex, std::shared_ptr secondVertex) const { .... return std::hypot(dx, dy); };
Будет ли копироваться значение при передаче умных указателей в функцию, или будет передаваться ссылка?


Ответ

Если я правильно понял вопрос (хотя на этот счет есть сомнение, т.к. уже имеется принятый ответ), то речь всё же о копировании объекта типа CPoint, которым параметризован std::shared_ptr. В этом случае совершенно не важно как будет передаваться объект умного указателя по ссылке или по значению - это не приведет к дополнительному копированию объекта, хранимого в указателе. Пример:
#include #include
struct S { S() { std::cout << "ctor
"; } S(const S&) { std::cout << "copy
"; } S(S&&) { std::cout << "move
"; } };
void f(std::shared_ptr) {} void g(const std::shared_ptr&) {}
int main(){
auto s = std::make_shared(); f(s); g(s); }
Вывод:
ctor
Т.е. был создан только один объект. Ни копирований, ни перемещений не произошло. Это в принципе логично, т.к. подобным же образом не происходит создания (полезных) объектов при передаче обычных (не умных) указателей.
В общем случае, любой достаточно большой (более нескольких sizeof(int)) объект имеет смысл передавать по константной ссылке, если не предполагается его модифицировать.

C# Приложение с входными и выходными параметрами [дубликат]

На данный вопрос уже ответили: Передать параметры программе и получить результат 3 ответа Подскажите, пожалуйста: например
Запуск приложения -> Указываем строковое значение -> Работа приложения -> Получаем строковое значение
Т.е. есть цель создания некоего модуля, который бы мог использоваться разным софтом с указанием некоторых входных данных и получением в зависимости от этого результата. К примеру указали приложению ссылку на сайт , получили результат, есть ли там указанный текст - получили true/false
Вопросы:
можно ли это сделать в консольном приложении? если да то как принимать и как отправлять значения? другой вариант?


Ответ

В других ответах уже написали про параметры командной строки и код возврата.
Но, как мне кажется, вам больше подойдут стандартные потоки ввода-вывода и их перенаправление
Например, напишем такую простейшую консольную программку:
using System;
class Program { static void Main() { // Читаем из стандартного потока ввода string line = Console.ReadLine();
// Обрабатываем введенное значение line = line.ToUpper();
// Пишем в стандартный поток вывода Console.WriteLine(line); } }
Кстати, можно явно писать Console.In.ReadLine() и Console.Out.WriteLine(), указывая потоки ввода и вывода.
Если её запустить, то нужно будет ввести строку в консоли. Результат тоже появится в консольном окне.
Теперь можно использовать перенаправление потоков. Например, подадим на вход нашей программе текстовый файл, из которого она прочтёт значение (одну первую строку). Вывод перенаправим в другой текстовый файл.
app < in.txt > out.txt
Где app.exe - имя нашей программы. in.txt - входной файл. out.txt - выходной файл.
Про конвейер и поток ошибок почитаете сами.

Поддержка уникальности строк в QStringLiteral

Из справки известно, что QStringLiteral размещает текст непосредственно в исполняемом файле в области только для чтения. Однако я не нашёл информации о том, что в случае использования одинаковых строк в разных местах кода проекта, эти строки будут храниться по уникальности значения. Или каждый экземпляр строки будет сохранён отдельно?
Допустим, имеется сетевой запрос к некоему внешнему ресурсу. Этот запрос имеет строковую команду, скажем, "https://ru.stackoverflow.com/". Также есть два класса: class A и class B. В обоих требуется выполнять указанный запрос:
class A { void getSo() { sendRequest(QStringLiteral("https://ru.stackoverflow.com/")); // Далее выполняем что-то специфическое для класса A. } };
class B { void getSo() { sendRequest(QStringLiteral("https://ru.stackoverflow.com/")); // Далее выполняем что-то специфическое для класса B. } };
Вопрос заключается в том, что именно попадёт в исполняемый файл: две строки с адресом запроса или одна? Или я неверно понимаю принцип работы указанного макроса?


Ответ

Стандартом не оговорено. Зависит от компилятора и настроек. Например, в Visual C++ 2015 имеется опция (зависящая от использованных параметров оптимизации)
/GF включить объединение строк только для чтения
Так что эти литералы будут объединены. Но если скомпилировать без этого ключа или с с /GF-, то в exe'шнике каждая займет свое место (при отключенной оптимизации - включение оптимизации автоматически включает эту опцию).

суббота, 27 апреля 2019 г.

Конвертировать текст на русском из pdf в txt python

Пытаюсь конвертировать кирилицу из pdf в txt c помощью PyPDF2 в Python
import PyPDF2 pdf_file = open('mail_cir.pdf', 'rb') read_pdf = PyPDF2.PdfFileReader(pdf_file) number_of_pages = read_pdf.getNumPages() page = read_pdf.getPage(0) page_content = page.extractText() print (page_content.encode('utf-8'))
Ошибки не выдает, но и текст не видит.
Пыталась изменить:
pdf_file = codecs.open('mail_cir.pdf', 'rb', encoding='utf-8')
Тогда выдается ошибка:
TypeError: Can't convert 'bytes' object to str implicitly
И другой вопрос:
Если конвертировать стих, то после окончания строки на пустом месте выводится

. Как избавиться от этих символов?


Ответ

Можно воспользоваться PDFMiner, чтобы текст, включающий русские буквы, из pdf достать:
#!/usr/bin/env python import sys import pdfminer.high_level # $ pip install pdfminer.six
with open('mail_cir.pdf', 'rb') as file: pdfminer.high_level.extract_text_to_fp(file, sys.stdout)
pdf2txt.py показывает как эта функция может быть использована—можно много опций передать.
Ввод (в pdf)
English 🇬🇧 На русском 🇷🇺 Smiley: ☺ non-BMP smiley: 😂
Вывод (текст в консоли)
English На русском Smiley: ☺non-BMP smiley:
Русский текст нормально извлёкся, но non-BMP смайлик 😂 (U+1F602) и флаги 🇬🇧 (U+1F1EC U+1F1E7), 🇷🇺 (U+1F1F7 U+1F1FA) потерялись при конвертации.

Код с PyPDF2, похожий на приведённый в вопросе, смог извлечь только символы в ASCII диапазоне.

JQuery. Поворот изображения туда-обратно

Доброго времени суток! Не могу сообразить, как реализовать поворот картинки на 45 и -45 градусов непрерывано, то есть, картинка все время наклоняется то в одну, то в другую сторону. Пока только при наведении мыши реализовано:


Ответ

Позволил себе чуть изменить код Abmin чтобы подходил по условию:
#me { -webkit-animation: rotation 2s infinite linear; padding: 20px; } @-webkit-keyframes rotation { 0% { -webkit-transform: rotate(0deg); } 50% { -webkit-transform: rotate(90deg); } 100% { -webkit-transform: rotate(0deg); } }

Получение кода символа

int main(void) {
printf("%d",(int)'А'); }
По идее, программа должна вывести код 'А'(кириллица), т.е. 192, но почему-то выводит -64.


Ответ

Тип char может вести себя либо как тип signed char либо как тип unsigned char в зависимости от установленных опций компилятора.
В вашем случае тип char ведет себя как тип signed char
Для типа signed char максимальное положительное значение равно 127 или в шестнадцатиричной форме 0x7F
Если хотите получить положительное значения кода, то напишите
printf("%d",(unsigned char)'А');
При этом русская буква не должна быть представлена как многобайтная константа.

Почему алиас «cd» работает так странно?

Хотел сделать алиас cd, который будет сразу перечислять директории.
Попробовал все следующие варианты:
alias 'cd'='cd $1; l' alias 'cd'='cd $1; l $1' alias 'cd'='cd $1 && l' alias 'cd'='cd $1 && l $1'
Где, l (строчная «L») — алиас другого приложения (tree).
Всегда перегружал терминал, чтобы наверняка, так как . ~/.bash_aliases у меня почему-то не срабатывает.
Все вышеперечисленные алиасы при вводе cd / перечисляют список директорий / файлов в точке монтирования /, однако смена директории не происходит.
Тогда я попробовал прописать в том же .bash_aliases функцию (оба варианта, по очереди):
cd() { cd $1 l }
function cd() { cd $1 l }
В итоге, при выполнении cd / команда «виснет» ...
Единственный способ, который я нашёл, это сделать так:
cdl() { cd $1 l }
То есть задать другое имя ... Но в тоже время, если вернуться к первому варианту алиаса:
alias 'cd'='cd $1; l'
Здесь же срабатывает cd при вводе cd /, так как l перечисляет список директорий / файлов по пути /, так почему же тогда он возвращает обратно в домашнюю директорию?


Ответ

псевдоним оболочки (shell alias) — это не функция и не программа. у псевдонима нет аргументов, его описание всего лишь подставляется в команду вместо его имени. поэтому, если вы определили, например, такой псевдоним
$ alias cd='cd $1; ls'
то при вводе команды
$ cd /tmp
она преобразуется в
$ cd ; ls /tmp
обратите внимание на пустое место после cd — туда ничего не будет подставлено (вместо $1), т.к. переменная $1 не содержит никакого значения.
в результате вашим текущим каталогом станет ваш домашний каталог (так действует внутренняя команда cd, если ей не передать никаких параметров), а затем будет выполнена команда ls /tmp когда вы определяете функцию:
$ function cd() { cd $1; ls; }
команда cd $1 внутри её тела трактуется как рекурсивное обращение к этой же функции, вот и происходит «зависание». кстати, обратите внимание, что в теле псевдонима не происходит такой рекурсии — cd $1 там трактуется именно как обращение к внутренней команде оболочки cd

и напоследок, в виде факультативного дополнения к ответу на вопрос «почему», приведу пример того, как сделать, чтобы «работало так, как хочется»:
$ function cd() { command cd "$@"; ls; }
использовать надо именно функцию (кстати, само ключевое слово function в данном случае — опционально), чтобы получить и обработать список аргументов. для вызова внутренней команды оболочки надо использовать внутреннюю же команду command правильнее передавать не только первый аргумент, а все аргументы ($@), а чтобы корректно обрабатывались спец-символы (например, пробелы/кавычки и т.п.) внутри аргументов, список лучше заключить в двойные кавычки ("$@").

MVVM для начинающих

Пытаюсь вникнуть в суть MVVM, рассматривая простейшие примеры и мне непонятны некоторые вещи,такие как:
public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged([CallerMemberName]string prop = "") { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(prop)); }
Также непонятно как работает интерфейс INotifyPropertyChanged Может ли кто-нибудь все это объяснить? P.S. на MSDN и других сайтах был и читал,но понятнее не стало


Ответ

Попробую объяснить.
Между View(графический интерфейс программы (кнопки, текстовые поля, и проч.)) с помощью так называемого байдинга (кто-то называет биндинг, хотя это неправильное произношение) устанавливается связь со свойствами во ViewModel. Например с текстовым полем ввода мы связываем свойство (ViewModel) - public string Name { get; set; } с помощью записи в XAML (View) Для этого во ViewModel реализуют (наследуют) от стандартного интерфайса INotifyPropertyChanged. В вашем примере используется один из вариантов такой реализации:
public event PropertyChangedEventHandler PropertyChanged; - собственно само объявление нужного события.
public void OnPropertyChanged([CallerMemberName]string prop = "") - вспомогательный метод для вызова этого события из блока set;
[CallerMemberName] - атрибут у параметра, который позволяет не указывать название свойства программисту, компилятор сам подставит имя свойства, которое вызывает метод OnPropertyChanged, т.е. вы можете вызвать как OnPropertyChanged("Name") или же так OnPropertyChanged() и тогда ("Name") вместо вас подставит компилятор.
Далее в самом методе происходит проверка; а если ли у этого события подписчики? И в случае наличия таковых (у нас это Такой вариант вызова события не единственный, в интернетах и в книгах можно найти еще пару-тройку вариантов. Все это дело вкусовщины. Лично я люблю прямой вызов события, что называется "в лоб", покажу на примере, может вам станет все еще яснее.
public class MainViewModel : INotifyPropertyChanged //не забываем о наследовании
Присваиваем в объявлении события пустой делегат, чтобы потом не заниматься проверкой, а если ли подписанты на событие? Они теперь всегда есть, по крайней мере один пустой подписант.
public event PropertyChangedEventHandler PropertyChanged = delegate { };
А вот пример свойства с вызовом этого события (использую новую конструкцию nameof(), чтобы передать название свойства)
///

/// Имя скачиваемого видео файла /// private string _NameFileVideo; public string NameFileVideo { get { return _NameFileVideo; } set { if (_NameFileVideo == value) return; _NameFileVideo = value; PropertyChanged(this, new PropertyChangedEventArgs(nameof(NameFileVideo))); } }

Порядок выполнения git commit и git pull

Недавно начал работать с гитом. Какая разница сделать pull до commit или после commit, и есть ли она вообще?


Ответ

В целом разницы нет. Если конфликта в ваших изменениях и изменениях из upstream не будет, то все пройдет без вопросов. Если же возникнет конфликт слияния, git так или иначе сообшит об этом, и вам в любом случае придется его решать.
Но я бы предпочел сначала сделать коммит, чтобы зафиксировать изменения. Тогда легко можно будет откатиться к исходной версии ваших изменений, если что-то пойдет не так.
Если коммит по каким-то причинам делать не хочется (например, работа не завершена), можно временно спрятать изменения командой git stash, потом сделать git pull, а потом вернуть изменения командой git stash apply. Этому посвящен отдельный раздел в документации

Перебор файлов и копирование в определенную папку

Как вызвать метод List?
public static void SearchAllFiles() { List files = new List(); String[] extensions = new String[] { "*.jpg", "*.txt", "*.asp" };
foreach (String extension in extensions) { String[] files = Directory.GetFiles(path, found, SearchOption.AllDirectories);
foreach (String file in files) files.Add(file); } }
И не могу сообразить в каком месте вставить копирование файлов:
File.Copy(path, path + Path.GetFileName(path));


Ответ

Для начала сделаем метод для поиска файлов по маске. Работает с .NET 4.0 и быстрее, чем Directory.GetFiles
public static IEnumerable nGetFiles(string path, string searchPatternExpression = "", SearchOption searchOption = SearchOption.AllDirectories) { Regex reSearchPattern = new Regex(searchPatternExpression); return Directory.EnumerateFiles(path, "*", searchOption).Where(file => reSearchPattern.IsMatch(Path.GetFileName(file))); }
Теперь так:
public static void SearchAllFiles() { //Искомые расширения: string LookForExt = "\.jpg|\.txt|\.asp"; //Пути папок источника и приёмника: string SourcePath = @"D:\SourceDir\"; string TargetPath = @"D:\TargetPath\"; //Получаем файлы и копируем их: IEnumerable files = nGetFiles(SourcePath, LookForExt); foreach (f in files) //Можно было и так: foreach (f in nGetFiles(@"D:\SourceDir", LookForExt)) { try { File.Copy(f, TargetPath + Path.GetFileName(f), true); } catch (Exception e) { throw e; } } }
В результате будут просканированы все файлы в папке SourcePath и ее подпапках, найденные файлы, соответствующие искомым расширениям будут скопированы в TargetPath без сохранения структуры подпапок. Более того, если есть файл D:\SourceDir\test.asp и есть файл D:\SourceDir\111\test.asp, то в результирующей папке D:\TargetPath\ будет только один из этих файлов, который будет копироваться последним (он и перезатрёт существующий, и скопированный первым в целевую папку файл).
Если же нужно скопировать файлы из папки с сохранением структуры вложенных папок и файлов, то вот тут уже давал ответ

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

Есть такое приложение GetTaxi так вот когда есть доступное обновление, то при открытии приложения появляется pop-up и сообщает юзеру о доступном обновлении.
Я знаю что play market тоже предлагает обновления, но ведь это все регулируется настройками и можно отключить автоматическое обновление, нотификациию и все прочие.
Так вот я думаю сделать так, когда есть новый versionCode сохранять его значение на сервере, а приложение каждый раз при запуске отправляет запрос на сервер и проверяет совпадает ли цифра с цифрой на сервере, если нет то показываем pop up и прикрепляем ссылку
Вот такая идея)
Я не уверен что такое решение самое правильное поэтому интерисуюсь здесь
Спасибо


Ответ

Есть готовый библиотеки для такого(дофига). Просто поищи на гитхабе. Первая ссылка на гитхабе: https://github.com/rampo/UpdateChecker
Нужно еще подключить апаче в градл так как с 23 версией появились изменения
apply plugin: 'com.android.application'
android { ... useLibrary 'org.apache.http.legacy' ... }

Почему не отображается карта гугл сайте

Почему не отображается карта гугл на сайте хотя на denwer все работает отлично


Ответ

Вы не указали API ключ при подключении API

Про ключ можете узнать здесь: https://developers.google.com/maps/documentation/javascript/get-api-key

Узнать версию Runtime для сборки не загружая ее

Мне нужно отобразить список всех сборок в GAC, а так же их RuntimeVersion. Если делать так:
Assembly.ReflectionOnlyLoadFrom(systemAssemblyModel.Path).ImageRuntimeVersion;
то пямять забивается на лишние 80 мб и непонятно как их очистить. Если же загружать сборки полностью и затем выгружать ее вместе с доменом. То проиcходит OutOfMemoryException
internal class Program { static void Main(string[] args) { var appDomain = AppDomain.CreateDomain("TestDomain"); appDomain.DoCallBack(() => LoadModule()); var worker = (Worker) appDomain.CreateInstanceAndUnwrap(typeof (Worker).Assembly.FullName, typeof (Worker).FullName); var a1 = worker.GetAssembliesFullName();
foreach (var assemblyFullName1 in a1) { Console.WriteLine(assemblyFullName1); } Console.WriteLine(); var a2 = AppDomain.CurrentDomain.GetAssemblies(); foreach (var assembly1 in a2) { Console.WriteLine(assembly1.FullName); } AppDomain.Unload(appDomain);
Console.ReadKey(); }
private static void LoadModule() { foreach (var systemAssemblyModel in AssemblyLoader.LoadAssemblies()) { try { var version = Assembly.Load(systemAssemblyModel.Desc.Path).ImageRuntimeVersion; } catch (Exception) {
} } } }
class Worker : MarshalByRefObject { public string[] GetAssembliesFullName() { return AppDomain.CurrentDomain.GetAssemblies().Select(a => a.FullName).ToArray(); } }


Ответ

Может кому пригодится. По совету
Вам поможет пакет Mono.Cecil – Pavel Mayorov
Подключил библиотеку и использовал следующий код
AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(assemblyDescription.Path); Console.WriteLine(assemblyDescription.Name + " " + assembly.MainModule.RuntimeVersion);

Как получить имя доменой учетной записи в MS SQL

Возможно ли в запросе получить имя учетки не той от чего имени выполняется запрос, а той под кем залогинены на ПК? С БД работает ПО от единого прописанного пользователя, на столбец повесил триггер и хочу понимать какой юзер выполняет действия, к исходному коду ПО доступа нет.


Ответ

Ответ на ваш вопрос - нет. Штатными средствами - никак.
Логика такая - сервер, это отдельная изолированная сущность, которая знать не знает ничего о том, кто и под каким именем работает на компьютере.
Грубо говоря, для выполнения запросов нужно подключиться к серверу. После подключения вся работа с сервером выполняется от имени того пользователя, который был подключен к серверу.
Сам сервер знает имя и пароль этого пользователя, и не более. Для того, что бы сервер смог вам выдать имя пользователя, который у вас залогинен в операционной системе, MS SQL должен уметь опрашивать на этот счет операционную систему. Но зачем это ему? Так что сервер не умеет опрашивать винду и узнавать какой пользователь там залогинен, ибо как это вообще относится к функциям сервера и базам данных? Никак.
Но есть один момент, когда для подключению к серверу используется механизм аутентификации Windows. В этом случае система аутентификации Windows и MS-SQL взаимодействуют. В этом случае для авторизации на сервере используются учетные данные Windows. И только в этом случае имя пользователя в Windows и на MS SQL Server совпадают.
Но вот уже дальнейшие распределения прав на объекты внутри сервера обеспечиваются самим сервером, вне зависимости от роли учетной записи Windows.
Итого, получаем, что варианты у нас крайне ограничены:
Подключаться к БД через windows-аутентификацию, тогда имя домена и учетной записи будет передано внутрь сервера. Но это не всегда возможно. Передавать серверу имя домена и пользователя из клиента самостоятельно (нужно подумать, каким именно способом).
2а. Можно попробовать заставлять сервер самостоятельно, каждый раз при подключении пользователя выполнять какой-то внешний инструмент (программу), которая получала бы имя пользователя Windows, подключалась к серверу, и записывала бы в отдельную таблицу имя виндового пользователя, который подключился к серверу.
Но п. 2 и 2а сами по себе мне кажутся очень неудобными, громоздкимии кривыми костылями.

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

Представим, что есть некая программа, которая отдает данные вот в таком формате:
$ cat foo.bs #!/bin/bash
echo "[INFO] Инициализация временных сдвигов" sleep 1 echo "[INFO] Подготовка к временному увеличению скорости света" sleep 1 echo "[WARN] u.speed_of_light: NaN" sleep 1 echo "[INFO] Скорость света увеличена, начинаем создание темной материи" sleep 1 echo "[ERROR] java.lang.NullPointerException: null"
$ ./foo.bs [INFO] Инициализация временных сдвигов [INFO] Подготовка к временному увеличению скорости света [WARN] u.speed_of_light: NaN [INFO] Скорость света увеличена, начинаем создание темной материи [ERROR] java.lang.NullPointerException: null
Что хотелось бы получить:
[INFO] Подготовка к временному увеличению скорости света [WARN] u.speed_of_light: NaN [INFO] Скорость света увеличена, начинаем создание темной материи [ERROR] java.lang.NullPointerException: null
Пошаговое воспроизведение:
Выводим [INFO] Инициализация временных сдвигов Перезаписываем предыдущую строку, потому что у нее флаг [INFO], теперь последняя отображаемая строка [INFO] Инициализация временных сдвигов Выводим новую строку [WARN] u.speed_of_light: NaN. Выводим новую строку [INFO] Скорость света увеличена, начинаем создание темной материи потому что перезаписывать варнинги нельзя Выводим новую строку [ERROR] java.lang.NullPointerException: null.
Необходимо именно перезаписывать предыдущую выведенную строку (см. пункт 2), поскольку необходима индикация процесса.
Подскажите, есть ли стандартные методы для осуществления этого? Набросал простой скрипт, который решает конкретную задачу (хотя есть пара тонких моментов), но хотелось бы иметь стандартные средства для подобного.
#!/bin/bash
last_line=""
while IFS= read -r line do if [[ $line != \[INFO\]* ]]; then echo -e "
$line" elif [[ $last_line == \[INFO\]* ]]; then echo -en "
$line" else echo -en "$line" fi
last_line="$line" done


Ответ

вот такая минипрограмма для интерпретатора awk
x!=$номер;{x=$номер}
(где номер — это номер сортируемого столбца) делает примерно то, что вам нужно: удаляет последовательные дубликаты, встречющиеся в указанном столбце:
$ cat foo | awk 'x!=$1;{x=$1}' [INFO] Инициализация временных сдвигов [WARN] u.speed_of_light: NaN [INFO] Скорость света увеличена, начинаем создание темной материи [ERROR] java.lang.NullPointerException: null
но, как видите, печатается содержимое той строки, которая встретилась первой.
чтобы печаталось содержимое последней из встреченных строк, можно, конечно, «помудрить» с программой (насколько я понимаю, существенно её усложнив), а можно просто «перевернуть» содержимое файла — чтобы первой шла последняя строка, второй предпоследняя и т.д., а после обработки — «перевернуть» опять. сделать это можно программой tac (даже в названии отражён ей смысл: cat «наоборот»):
$ tac foo | awk 'x!=$1;{x=$1}' | tac [INFO] Подготовка к временному увеличению скорости света [WARN] u.speed_of_light: NaN [INFO] Скорость света увеличена, начинаем создание темной материи [ERROR] java.lang.NullPointerException: null

идея минипрограммы позаимствована отсюда: http://www.unixcl.com/2009/05/remove-duplicate-consecutive-fields-or.html

обновление
придумал, как обойтись без tac. минипрограмма, правда, значительно усложняется:
$ cat foo | awk 'END{print y}{if(x!=$1&&x!=""){print y};x=$1;y=$0}'
чтобы сортировать по другому столбцу, надо подставить его номер вместо 1 в оба вхождения $1
обновление2
из уточнений стало понятно, что требуется не просто конечный результат, а «интерактивное шоу», когда последняя выведенная строка стирается, если следующая за ней начинается тем же самым словом.
тогда можно сделать примерно так:
#!/bin/bash
prevline="" prevtag=""
while read line; do newtag=$(echo $line | cut -d ' ' -f 1) if [ -n "$prevline" ]; then if [ "$newtag" == "$prevtag" ]; then echo -n "$prevline" | sed 's/./\x08/g' else echo fi fi echo -n "$line" prevtag=$newtag prevline=$line done echo
\x08 — это символ «забоя» (backspace). к сожалению, программа sed, которой я воспользовался в данном случае, не воспринимает распрастранённую escape-последовательность \b в качестве данного символа. связано это с тем, что на данную escape-последовательность «подвешена» функция определения границы слова.