Страницы

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

среда, 20 февраля 2019 г.

Убирание свойства cheked при повторном нажатии на радиокнопку

Подскажите пожалста, как сделать так, чтобы кликая повторно на выбранную радио кнопку, она снова становилась не cheked. Я так понимаю, я где-то ошибся в коде $(document).ready(function(){ $('input[type="radio"]').click(function(){ var ir = $(this).prop("checked") if(ir){ $(this).removeAttr("checked") } }) })


Ответ

$(document).ready(function(){ $('input[type="radio"]').click(function(){ $(this).attr('checked', function(index, attr){ return attr ? null : 'checked'; }); }) })

в чем заключается типизация в тайпскрипте?

Всем привет. Изучаю тайпскрипт, и в первую очередь меня интересуют интерфейсы. Для проверки того, что как они работают, я написал следующее:
interface I1 { stringProp: string; numProp: number; }
printI1(i1: I1): void { console.log(i1); console.log(i1.numProp * 2); }
От поведения этого интерфейсного типа я ожидаю следующего: В stringProp может попасть только строка, а в в numprop - только число. Интерфейс позволит мне абстрагироваться от полей того типа, который я привожу к нему.
Ну хорошо, возьмем такой класс.
class T1 { public propNotExistedInInterface: boolean = true; public stringProp: any; public numProp: any; }
И попробуем привести его к I1 следующим образом.
let a: T1 = new T1(); a.stringProp = 13; a.numProp = "asd";
this.printI1(a);
И результат:
Object { propNotExistedInInterface: true, stringProp: 13, numProp: "asd" }
NaN
Ни одного из моих ожиданий не оправдалось. Ни одного предупреждения транслятора. Так в чем заключается хвалёная типизация? пробовал менять NoImplicitAny - один и тот же результат.
Следующий пример:
Берем интерфейс:
interface INumberWithFuncProcessor { num: number; func(number): string; }
Мы будем использовать его в качестве параметра метода (при этом допускаем ошибку):
useProcessor(param: INumberWithFuncProcessor): string { return param.func(param); // ошибка, подразумевали param.num }
И используем наш метод:
let something = this.useProcessor( { num: 12, func: (x) => { return x.toString() } });
При попытке вывести something на экран мы увидим [object Object]. Транслятор молчит. По всей видимости в наш параметр интерфейсного типа попадает что-то вроде.
{ num: number; func(object): string; }
Вопрос, как видите, риторический: есть ли статическая типизация в ts, или это просто рекламный ход.


Ответ

Типизация, очевидно, есть. Просто в данном случае происходят некорректные проверки.
Если разобрать первый пример:
Есть интерфейс, в котором указаны конкретные поля, и указанным полям проставлен конкретный тип.
Что происходит дальше, объявляется класс, у которого присутствуют эти поля, но им задан тип any. Что такое any - это заглушка, которая показывает, что тип может быть любой. В следствие этого переменную типа any можно присвоить переменной любого типа.
Что получилось в итоге, компилятор не проверяет реальный тип полей, так как типизация работает только во время компиляции, и чтобы определить какое именно из значений в итоге будет у поля, и, соответственно, какой тип, компилятору нужно выполнить всю программу. В общем случае это неразрешимая задача, и определение типа any отдается на откуп программисту.
В то же время, если убрать одно из полей в классе T1, например stringProp, компилятор может проверить, что у объекта передаваемого класса, отсутствуют обязательное поле и кинет ошибку. А также, если вместо any использовать конкретные типы, например public stringProp: number; компилятор опять подскажет, что типы не совпадают.
Примеры для проверки
Что касается второго примера:
interface INumberWithFuncProcessor { num: number; func(number): string; }
Ошибочно само описание интерфейса, и при выборе опции noImplicitAny компилятор подсказывает, что number - это параметр, и так как у него не указан напрямую тип, его тип будет any и как мы помним - any не проверяется в compile-time. Таким образом, вполне нормально передавать в него переменные любого типа.
Если же указать конкретный тип параметра, например:
interface INumberWithFuncProcessor { num: number; func(a:number): string; }
То компилятор вполне резонно покажет ошибку:
Argument of type 'INumberWithFuncProcessor' is not assignable to parameter of type 'number'
Пример для проверки

Как сохранять пароль от ключа в FileZilla?

Для подключения по SFTP мы используем public key. Как мне в FileZilla сохранить пароль от этого ключа не на сессию, а навсегда?
FileZilla 3.15.0.2
Ubuntu 16.04


Ответ

«навсегда» — это значит «убрать пароль вообще».
как и в случае изменения/установки пароля, убрать его можно с помощью программы ssh-keygen, вызванной с опцией -p
$ ssh-keygen -p
сначала будет запрошен путь к секретному ключу (с предложенным вариантом по умолчанию — ~/.ssh/id_rsa, с которым можно согласиться, нажав enter, а можно ввести путь к другому файлу; можно вообще указать путь к файлу с помощью опции -f /путь/к/секретному.ключу).
затем будет запрошен существующий пароль (конечно, если установлен), и, если он введён правильно, дважды будет запрошен новый пароль. если оба раза ничего не вводить, а нажимать enter, пароль будет «пуст», т.е., секретный ключ не будет зашифрован, и ничего впоследствии не будет запрашиваться при использовании данного файла с секретным ключом.

Переделать веб приложение с сервлетами в RESTful

Есть приложение, которое соединяется с бд через glassfish ресурсы и все работает. Используются servlet. Как это можно реализовать с использованием RESTful. Не понимаю что куда должно передаваться и как. Как REST принимает из формы и возвращает. Все что я находила было с возвращением статуса, а не ресурсов. Так же интересно как реализовать ввод логина и пароля и получать приветствие с именем пользователя, соответствующего этим логину и паролю в бд. Я совсем плаваю в этом.(
CRUD операции:
@Stateless public class UserLogIn {
@PersistenceContext(unitName = "LEADER") public EntityManager em;
public UserLogIn(){}

public void add(User user){ if (!user.getLogin().equals("") || !user.getPassword().equals("") || !user.getUsername().equals("")){ em.persist(user); } } public void delete(int id){ em.remove(getUser(id)); }
public User getUser(int id){ return em.find(User.class, id);
} public void update(User user){ em.merge(user); }
public List getAll(){ TypedQuery namedQuery = em.createNamedQuery("User.getAll", User.class); return namedQuery.getResultList(); }
}
Сущность:
@Entity @Table(name = "annusers") @NamedQuery(name = "User.getAll", query = "SELECT u FROM User u") public class User { @Id @SequenceGenerator(name="ad_point_gen",allocationSize=1,sequenceName="ad_points_id_ad_point_seq") @GeneratedValue(generator="ad_point_gen",strategy=GenerationType.SEQUENCE) @Column(name = "id", nullable = false) private Integer id; @Column(name = "login", nullable = false) private String login; @Column(name = "password", nullable = false) private String password; @Column(name="username", nullable = false) private String username;
public User() { }
public User(String login, String password, String username) { this.login = login; this.password = password; this.username = username; }
public String getLogin() { return login; }
public void setLogin(String login) { this.login = login; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
@Override public String toString() { return "User{" + "login='" + login + '\'' + ", password='" + password + '\'' + ", username='" + username + '\'' + '}'; }
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; } }
Классы сервлетов для работы с CRUD операциями
@WebServlet("/add") public class AddAndEditUserServlet extends HttpServlet{ @EJB private UserLogIn userLogIn;
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ resp.setContentType("text/html"); req.setCharacterEncoding("UTF-8");
if(req.getParameter("edit")!=null){ int id = Integer.valueOf(req.getParameter("edit")); User user = userLogIn.getUser(id); req.setAttribute("user",user); }
req.getRequestDispatcher("/add.jsp").forward(req,resp); }
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ resp.setContentType("text/html"); req.setCharacterEncoding("UTF-8");
String login = req.getParameter("login"); String password = req.getParameter("password"); String username = req.getParameter("username");
if(!req.getParameter("id").equals("")){ int id = Integer.valueOf(req.getParameter("id")); User user = userLogIn.getUser(id); user.setLogin(login); user.setPassword(password); user.setUsername(username); userLogIn.update(user); }else { userLogIn.add(new User(login, password,username)); }
resp.sendRedirect("list"); }
}
package com.mkyong.rest.servlet;

@WebServlet("/delete") public class DeleteUser extends HttpServlet {
@EJB private UserLogIn userLogIn;
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if(req.getParameter("id") != null && req.getParameter("id") != ""){ int id = Integer.valueOf(req.getParameter("id")); userLogIn.delete(id); } resp.sendRedirect("list"); } }


@WebServlet("/list") public class UserServlet extends HttpServlet{
@EJB private UserLogIn userLogIn;
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ List allUsers = userLogIn.getAll(); req.setAttribute("users", allUsers); req.getRequestDispatcher("/list.jsp").forward(req,resp); }
}


Ответ

rest сервисы, как правило нужны для CRUD операций(создание, удаление, редактирование, удаление).например:
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ List allUsers = userLogIn.getAll(); req.setAttribute("users", allUsers); req.getRequestDispatcher("/list.jsp").forward(req,resp); }
для запроса /list делает из бд выборку всех пользователей и перенаправляет запрос в list.jsp, где отображается список пользователей. Все что пришло от клиента, находится в объекте класса HttpServletRequest, например:
req.getParameter("id")
содержит http параметр id
Update.
Если делать именно рестовский сервис, то надо подключить библиотеку jackson для xml и GSON для json.в методе вместо resp.sendRedirect("list"); возвращаете свой объект, например:
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ List allUsers = userLogIn.getAll(); //.. String json = new Gson().toJson(allUsers); response.setContentType("application/json"); response.setCharacterEncoding("UTF-8"); response.getWriter().write(json); }

Как настроить Log4Net, что бы было определенное кол-во логов?

Сейчас имеется такая конфигурация:

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


Ответ

Проблема связана, очевидно, с тем, что у Вас имена файлов лога основаны на шаблоне с датой. Причём формат даты такой, что ограничение на количество файлов лога будет иметь значение только в пределах 1 секунды. Проще говоря, логи будут чиститься сами только если их количество будет превышать 3 файла в секунду и удаляться будут именно те, которые были записаны в эту секунду первыми. Смотрим документацию:
The maximum applies to each time based group of files and not the total.
Возможное решение (на уровне патча) есть тут, сам не пробовал.

Рекомендовал бы поэкспериментировать с этим и попробовать изменить шаблон имени файла, ограничив, например, 1 днём. Таким образом, если в течении дня будет записано более 3 файлов - должно произойти усечение.

Вызов дочернего метода через базовый класс

Есть базовый класс Shapes, в нем есть два абстрактных метода P (Периметр) и S (Площадь). Также есть дочерний класс Circle, в котором реализованы методы P и S с помощью полиморфизма.
Вопрос: как вызвать метод P и S из класса Circle через класс Shapes?
Это же называется динамическое связывание?
Shapes.h
class Shpes { private: public: Shpes(); virtual double P() = 0; virtual double S() = 0; };
Shpes::Shpes() {
}
Circle.h
#include "Shpes.h"
class Circle : public Shpes { private: double r; void SetCheck(double R);
public: Circle(double R = 0); virtual double P(); virtual double S(); void Print(); };
Circle.cpp
#include "Circle.h" #include #include
using namespace std;
void Circle::SetCheck(double R) { R < 0 ? r = abs(R) : r = R; }
Circle::Circle(double R) { SetCheck(R); }
double Circle::P() { return 2 * 3.12 * r; }
double Circle::S() { return 3.14 * r * r; }
void Circle::Print() { cout << "При радиусе круга = " << r < Это можно сделать через указатель или ссылку на базовый класс, инициализированными объектом производного класса.
Например,
Circle c( 10 );
Shape *ps = &c;
ps->R(); ps->S();
Shape &rs = c;
rs.R(); rs.S();
Имейте в виду, что деструктор в базовом классе также следует объявить как виртуальный. Например,
virtual ~Shape() = default;
или
virtual ~Shape(){}
ОБратите внимание на расхождение
double Circle::P() { return 2 * 3.12 * r; ^^^^^ }
double Circle::S() { return 3.14 * r * r; ^^^^ }
Чтобы не допускать такого вида ошибки, лучше используемым константам назначать имена. Вы могли бы определить соответствующий член в вашем классе (при условии, что компилятор поддерживает данную конструкцию), например,
class Circle : public Shpes { private: double r; void SetCheck(double R); constexpr static double PI = 3.14;
public: Circle(double R = 0); virtual double P(); virtual double S(); void Print(); };
И записать определения функций следующим образом
double Circle::P() { return 2 * PI * r; ^^^^^ }
double Circle::S() { return PI * r * r; ^^^^ }
Если компилятор не поддерживает такое объявление члена класса, то можно просто написать
class Circle : public Shpes { private: double r; void SetCheck(double R); const static double PI;
public: Circle(double R = 0); virtual double P(); virtual double S(); void Print(); };
И затем определить эту статическую переменную
double Circle::PI = 3.14;

Расположить кнопку, что бы она была между двумя RelativeLayoout

Нужно расположить кнопку, что бы она была, как на рисунке:

Сейчас кнопка неправильно расположена:

Сейчас верстка выглядит вот так вот:
















Ответ

Используйте CoordinatorLayout и anchor







Атрибут app:layout_anchor="@id/viewA" закрепит FAB в Layout с @id/viewA. Атрибут app:layout_anchorGravity означает, что кнопку закрепится в правом нижнем углу.
Результат

Почему браузер дважды обращается к Symbol.unscopables?

with(new Proxy({}, { has() { return true }, get(obj, key, proxy) { return console.log(String(key)) } }) ) { a-- }
Вывод в Chrome:
Symbol(Symbol.unscopables) a Symbol(Symbol.unscopables)
Вывод в Firefox:
Symbol(Symbol.unscopables) Symbol(Symbol.unscopables) a
Насколько я понимаю, одно обращение связано с чтением, а другое с записью.
Логично, что конструкция a-- должна записать значение в то же место, откуда прочитала. Нет, это не так.
А двойное чтение из Symbol.unscopables как бы намекает, что это не так и у меня есть возможность отдать нечто для чтения, но сказать, что в мой объект этого записывать не надо?
Неужели это так и задумано? Что на эту тему говорит стандарт?
Собственно, в Хроме и FF такое почти прокатывает - чтение и запись связаны с разными объектами, однако работает по-разному:
Update: Safari 10 читает Symbol.unscopables только один раз.
var a, b, flag = true with (a = { x: 7 }) with (b = { x: 4, get [Symbol.unscopables]() { return { x: flag=!flag } } }) x++ // Chrome FF Safari Edge console.log(a) // {x:5} {x:7} {x:7} {x:5} console.log(b) // {x:4} {x:8} {x:5} {x:4}
PS: Этот вопрос по-английски.


Ответ

Согласно спецификации, @@unscopables в этом случае должно читаться только один раз. Детали (к сожаления по английски) в https://mail.mozilla.org/pipermail/es-discuss/2017-February/047725.html
Следовательно Chrome и Firefox не следуют спецификации, а Safari следует.
Смотрите также https://bugzilla.mozilla.org/show_bug.cgi?id=1341061 и https://bugs.chromium.org/p/v8/issues/detail?id=5992

Windows 10 не записывается con.png file

Пытаюсь разархивировать zip, не получается, и все время из-за con.png файла. Подумал что архив испорченный и попробовал из гугла скачать картинку, переименовать в con.png, не получилось. Где-то прочитал, что в win существуют зарезервированные какие то слова.
Кто нибудь знает, как это обойти, кроме как удалить его из архива?


Ответ

Можно переименовать.
Да, действительно, в Windows есть зарезервированные слова, которые не могут использоваться для задания имен файлов, и con — одно из них. Почему так? Это ограничение еще со времен MS DOS, когда эти ключевые слова были зарезервированы для устройств ввода-вывода. Тот же con - сокращение от "консоль", если верно помню.
Не претендуя на полный список зарезервированных слов, попробую их перечислить: con, nul, prn, AUX, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9 при этом регистр букв значения не имеет, если опять же, не ошибаюсь.
Вы же пытаетесь создать файл с именем con.png, где имя - con и оно зарезервировано, а расширение png - это всё же расширение, и в данном случае может быть любым, так что создать такой файл не получится. хотя можно создать файл con.pngсхожий по написанию - заменив английские буквы c или o на аналогичные русские. В этом случае схожесть будет лишь внешняя, ибо имя-то будет другим. При этом делать так (смешивать алфавиты) строго не рекомендуется
Решением будет открыть архив, например, в WinRAR и переименовать этот файл в, например, _con.png. Или сохранять с гугла картинку в файл с именем, отличным от con

Как установить толщину рисуемой линии?

Рисую так:
cnvs.drawLine(0, 0, 300, 300, point);
Как выставить ширину рисуемой линии например 3 пикселя?


Ответ

Можно через Paint класс установить. Вот так youpaint.setStrokeWidth(число)

MVP, слой models

Такой вопрос по поводу MVP, а именно хочу уточнить по поводу слоя models, если класс является объектом структуры БД, и в нем никакой другой бизнес логики, можно ли его считать model?
Пример класса:
public class User extends RealmObject {
@SerializedName("username") String username; @SerializedName("name") String name; @SerializedName("email") String email; @SerializedName("properties") private Properties properties; @SerializedName("password") String password;
public User(String username, String name, String email, Properties properties) { this.username = username; this.name = name; this.email = email; this.properties = properties; }
public User() {
}
public User(String username, String password) { this.username = username; this.password = password; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public Properties getProperties() { return properties; }
public void setProperties(Properties properties) { this.properties = properties; }
@Override public String toString() { return username + " (" + name + ")"; }
}


Ответ

Да, безусловно это модель данных. ORM (к которым относится и Realm) вообще специально для того и задумывалось, чтобы совместить возможности СУБД и CRUD-операции с удобным для ООП форматом хранения данных (объекты-модели)

Константы в коде

Здравствуйте знаю что вопрос такой не соответствует тематике RUSO но тем не менее хочу спросить что лучше в коде хранить цифры либо константы?
к примеру лучше так:
case APP_ZTIP_VALUE_REC:
или
case "REC":


Ответ

Если вы используете ее в одном месте, то проще использовать второй вариант case "REC". Константу лучше создавать тогда, когда ее значение нужно в нескольких местах или в принципе часто используется.
Например если частенько в классах задают константы public static final в случае, если их надо передавать в метод класса как параметр. И вместо прописывания стринги вручную, ты пишешь SomeClass.APP_ZTIP_VALUE_REC. Это позволит тебе быстро находить нужную константу и исключить риск ошибки в стринге.

Использование criteria из JPA

В новом Hibernate использование Criteria является Deprecated. Как я могу заменить такой код с использованием org.hibernate.Criteria
Criteria criteria = session.createCriteria(Role.class); long id = ((Role) criteria.add(Restrictions.eq("name", name)).uniqueResult()).getId();
на его эквивалент с использованием javax.persistence.criteria.CriteriaBuilder из JPA ?


Ответ

em - экземпляр EntityManager
public Long query(String name) { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(Role.class); Root root = cq.from(Role.class); cq.where(cb.equal(root.get("name"), cb.parameter(String.class, "name"))); // cq.distinct(true); Query q = em.createQuery(cq); q.setParameter("name", name); List result = q.getResultList(); if (result.size() > 0) { return result.get(0).getId(); } return null; }

Oracle автоматическое секционирование по дате

Доброго всем дня, имеется вот такая вот таблица
CREATE TABLE test ( ID NUMBER(*) PRIMARY KEY NOT NULL, NAME VARCHAR2(40) NOT NULL, TEXT VARCHAR2(4000), DATE_CREATE DATE DEFAULT sysdate NOT NULL )
нужно сделать по ней автоматическое секционирование по столбцу DATE_CREATE, интервал в один день , что бы на следующий день автоматически создавалась новая партиция и следовательно в нее заносили данные за этот день, слышал что в 11g эту реализацию добавили, пытался разобраться, но как доходит до partition ... values less than (..) сразу теряюсь. Мой первый вопрос, все замечания по вопросу приветствуются, дабы в дальнейшем не допускать ошибок.


Ответ

Как-то так:
create table test(id number, date_create date default sysdate not null) partition by range (date_create) INTERVAL(NUMTODSINTERVAL(1,'DAY')) (PARTITION FIRST VALUES LESS THAN (TO_DATE('2016-11-30 00:00:00', 'YYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) );
PS в первую партицию (секцию) попадут все дни < 2016-11-30 00:00:00
Из доки
You must specify at least one range partition using the PARTITION clause.
UPDATE:
вместо select * from tab partition(p1); можно воспользоваться след. запросом, который должен прочитать только одну дневную партицию и вернуть из нее записи:
select * from test where date_create between to_date('2016-11-29','yyyy-mm-dd') and to_date('2016-11-30','yyyy-mm-dd');

Как использовать ключи из /etc/ssh_known_hosts в скриптах git

Сценарий. Пользователь alice заходит на сервер msk-web-01 (centos7.2, selinux включен) по своему ssh ключу и хочет в папке /www/mysite.ru/htdocs/ (владелец папки -- пользователь apache) запустить команду git pull.
Для этого написан небольшой батник:
#!/bin/sh
#see http://ru.stackoverflow.com/questions/548545/ for details sudo setfacl -m apache:x $(dirname "$SSH_AUTH_SOCK") sudo setfacl -m apache:rwx "$SSH_AUTH_SOCK"
cd /www/mysite.ru/htdocs/ pwd sudo su -s /bin/sh apache -c "/usr/bin/git pull" ....
И он работает... выдавая многочисленные предупреждения:
/www/site1.ru/htdocs Could not create directory '/usr/share/httpd/.ssh'. Failed to add the ECDSA host key for IP address '1.2.3.4' to the list of known hosts (/usr/share/httpd/.ssh/known_ho). Already up-to-date. /www/site2.ru/htdocs Could not create directory '/usr/share/httpd/.ssh'. Failed to add the ECDSA host key for IP address '1.2.3.4' to the list of known hosts (/usr/share/httpd/.ssh/known_ho). Already up-to-date.
Задача -- избавиться от этих лишних записей, добившись чистого вывода при помощи добавления записей в глобальный known_hosts.
Требуемый эффект можно получить если создать /usr/share/httpd/.ssh/known_hosts со строкой CheckHostIP no
/www/site1.ru/htdocs Already up-to-date. /www/site2.ru/htdocs Already up-to-date. /www/site3.ru/htdocs Already up-to-date.
Разумеется, такой способ не рассматривается как решение задачи, так же как и другие обходные пути типа "совсем отключить проверку" (скажем, раз или два)
PS Ключи сохранял одним из двух способов, первый:
ssh-keyscan -t rsa,dsa git.mycomany.ru >> /etc/ssh/ssh_known_hosts
второй:
ssh-keyscan git.mycomany.ru >> /etc/ssh/ssh_known_hosts
Разница не особо велика: в первом случае Failed to add the RSA host, во втором - Failed to add the ECDSA host key.
И даже так с горя:
ssh-keyscan git.mycomany.ru,1.2.3.4 >> /etc/ssh/ssh_known_hosts


Ответ

В итоге, всё оказалось достаточно просто.
Сначала ещё раз о постановке задачи. Есть ряд доверенных серверов организации, между которыми сотрудникам нужно перемещаться с сохранением авторизации (ForwardAgent), поэтому нужно уметь заполнять файл /etc/ssh/ssh_known_hosts доверенными данными.
Во-первых, гит в своём общении с удалёнными репозиториями по протоколу ssh полагается на системные утилиты, особых настроек ssh-подключения нет -- можно почитать про хаки с созданием файла ssh и экспортированием переменной GIT_SSH. Поэтому изначально в вопросе было больше про ssh, чем про конкретно git.
Во-вторых, когда я начал разбираться с ключами (rsa, dsa, esdca) и версиями протоколов -- я решил не только абстрагироваться от гит, но и от ансибл - чтобы не влияло, на всякий случай.
После тестов у меня получилось, что ключи были сгенерированы правильно, настройки ssh (как дефолтные центоса, так и мои кастомные) тоже не влияют на работу.
Всё, что нужно -- это сдампить отпечатки и записать в общий known_hosts:
ssh-keyscan -t rsa,dsa git.mycomany.ru >> /etc/ssh/ssh_known_hosts
Включение хеширования не влияет на итог - тоже. А что влияет?
Как ни странно -- выяснилось, что влияет ansible. Если файла /etc/ssh/ssh_known_hosts на диске нет -- он создаёт файл с правами rw-r--r-- но стоит лишь ещё раз запустить повторно -- права чудесным образом становятся rw------- Разумеется, что процессы, которые хотят прочитать хранилище и проверить, нет ли там такого отпечатка обламываются и ничего не находят. Стоит лишь восстановить права на файл -- и работа снова восстанавливается.
Пример заполнения ключей практически такой же, как и в документации
- name: global pubkes for servers known_hosts: path='/etc/ssh/ssh_known_hosts' name='{{ item }}' key="{{ lookup('file', 'files/pubkeys/{{ item }}.pub') }}" with_items: - git.mycompany.ru
Я хотел было создать баг на гитхабе -- но перед заведением поискал, нет ли готового. И нашёл, вот: https://github.com/ansible/ansible-modules-extras/issues/2513

Склеить, объединить фото (jpeg карта)

Есть много файлов одной карты COLUMN_LINE.jpeg все файлы одинакового размера - 256х256 px
Как их можно склеить в один файл jpeg?
P.S.: Если входные файлы 001_001.jpeg 001_002.jpeg 002_001.jpeg 002_001.jpeg, то полученный map.jpeg будет 512х512 px

Простите, пожалуйста. Может я не достаточно явно описал проблему.
Уточняю: входных файлов может быть очень МНОГО (например 100х100=10 000 изображений). И надо запусть это на 4 ГБ RAM (ну учитывая, что и система должна как-то работать).

На 10 000 не тестил. Просто загрузить такое количество картинок напряжно. Но поделюсь кодом с помощью которого произвел склейку.
И еще я напутал - у меня .png,а не .jpeg. Но принцип тот же. Разница есть, но кому надо разберетесь.
using System; using System.IO; using System.Drawing;
class IMGhelper { public int NeedCOLUMN; // я знаю сколько должно быть колонок public int NeedLINE; // я знаю сколько должно быть строк // потому что я сначала задал программе скачать это кол-во колонок и строк
private string[,] m_filesExist; // тут будут хранится пути ко всем картинкам
private void getFiles() // будьте осторожны! Этот метод работает в МОИХ условиях // У вас тут может выпасть ИСКЛЮЧЕНИЕ! { m_filesExist = new string[NeedCOLUMN, NeedLINE]; string[] dirs = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory + "Map\\", "*.png"); // маленькие картинки в папке Map foreach (string dir in dirs) { // мои файлы называются ххх_ххх.png (например 017_010.png) string[] tmp = Path.GetFileName(dir).Split('.')[0].Split('_');
int col = int.Parse(tmp[0]); // тут 017 int row = int.Parse(tmp[1]); // тут 010 m_filesExist[col, row] = dir; } }
public void ImgCombine() { readFiles(); // Создаем новый image нужного размера (это будет объединенный image) Image img = new Bitmap(256 * NeedCOLUMN, 256 * NeedLINE);// у меня каждое изображение 256x256 px
// Делаем этот image нашим контекстом, куда будем рисовать Graphics g = Graphics.FromImage(img);
// рисуем существующие маленькие image в созданный нами большой image for (int c = 0; c < NeedCOLUMN; c++) { for (int r = 0;r < NeedLINE; r++) { g.DrawImage(Image.FromFile(m_filesExist[c,r]), new Point(256*c, 256*r)); } }
// Записываем обобщенный image в файл рядом с исполняемым файлом
img.Save("output.png", System.Drawing.Imaging.ImageFormat.Png); } }
И вызов
static void Main(string[] args) { IMGhelper IH = new IMGhelper(); //у меня 600 изображений из них должно получится 20 колонок и 30 строк IH.NeedCOLUMN = 20; IH.NeedLINE = 30;
IH.ImgCombine(); }


Ответ

Примерно так:
Создаёшь Bitmap нужного размера Graphics.FromBitmap По нужным координатам рисуешь куски через Graphics.DrawImageUnscaled Сохраняешь Bitmap в файл

Принудительное завершение дочернего процесса из родителя в fork() в си

Возможно ли завершить дочерний процесс не дожидаясь его окончания с помощью функции wait()? Например, как завершить вот такой дочерний процесс:
pid_t pid; switch(pid=fork()) { case 0: for(;;){} default: //здесь код, который завершает дочерний процесс return 0;
P.S. Если вы знаете какой-то адекватный, не сильно мудреный материал по fork(), где можно почерпнуть теоретические знания, то направьте меня, пжл.


Ответ

Жестокий метод:
kill(pid, SIGKILL);
Или более мягко:
kill(pid, SIGTERM);
В первом случае дочерний процесс будет просто убит, во втором получит сигнал, который может обработать. Но SIGKILL убъёт процесс гарантированно, а в случае SIGTERM процесс может отказаться заканчивать работу.
В приведённом коде, поскольку процесс, похоже, не содержит обработчиков сигналов, можно использовать любой метод, поскольку, как верно указал на мою ошибку @avp, SIGTERM при отсутствии обработчика также убьёт процесс.

Эффект набора текста

Столкнулся с проблемой вывода текста с эффектом "набора текста", то.е. нужно,дабы появляющаяся во вьюшке надпись "Пони захватывают твой разум" выглядела так, будто бы ее медленно набирают на клавиатуре. Слышал, что есть некий атрибут для этого, но проштудировав 40 минут гугл так и не нашел ответа. Помогите, пожалуйста!


Ответ

Вы можете попробовать вот это сторонее решение: HTextView
Оно умеет то что вам нужно плюс много чего ещё.

Подключаем в gradle:

compile 'hanks.xyz:htextview-library:0.1.5'
Добавляем в разметку:


Находим в коде и анимируем

hTextView = (HTextView) findViewById(R.id.text); hTextView.animateText("Слава библиотекам!"); // animate

Либо посмотрите как подобное реализовано тут

Как соединить точки в matplotlib

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

import matplotlib.pyplot as plt import numpy as np
def polar(n,m,L=(0,0),scale=1): #n - кол-во кругов, m - кол-во точек, L - центр, scale - масштаб dr=1/n#Расстояние df=(2*np.pi)/m#Поворот for i in range(n+1): for k in range(m+1): z=i*dr*np.cos(k*df)+1j*i*dr*np.sin(k*df) w=(z-1)**2 plt.subplot(122) plt.plot(w.real*scale,w.imag*scale,'r.') circle=i*dr*np.cos(k*df)+1j*i*dr*np.sin(k*df) plt.subplot(121) plt.plot(circle.real*scale,circle.imag*scale,'r.') plt.axis('equal') plt.ylabel('Imaginary') plt.xlabel('Real') plt.grid(True) plt.show()
polar(25,25)


Ответ

Если задача - соединить точки, принадлежащие концентрическим окружностям, то можно так сделать:
def polar(n,m,L=(0,0),scale=1): #n - кол-во кругов, m - кол-во точек, L - центр, scale - масштаб dr=1/n#Расстояние df=(2*np.pi)/m#Поворот
ax1 = plt.subplot(122) ax2 = plt.subplot(121) ax1.grid(True) ax2.grid(True)
k = np.arange(m+1)
for i in range(n+1): z=i*dr*np.cos(k*df)+1j*i*dr*np.sin(k*df) w=(z-1)**2 ax1.plot(w.real*scale,w.imag*scale,'.r-') circle=i*dr*np.cos(k*df)+1j*i*dr*np.sin(k*df) ax2.plot(circle.real*scale,circle.imag*scale,'.r-')
plt.axis('equal') plt.ylabel('Imaginary') plt.xlabel('Real') plt.show()
polar(25, 25)

PS я избавился от внутреннего цикла по двум причинам:
для удобства соединения точек одной окружности чтобы быстрее считать координаты "векторизованными" NumPy методами

Webpack. Сборка отдельных css и скриптов в общие файлы

Как собрать разрозненные в проекте стили/скрипты в один файл (bundle.js/bundle.css)с помощью webpack?
Проект содержит стили и скрипты для каждого приложения, которые лежат в отдельном каталоге. Папка фронтенда:
├── frontend │   ├── common │   ├── node_modules │   ├── app1 │   ├── app2 │   ├── app3 │   ├── ... │   └── webpack.config.js
Папка каждого приложения имеет одинаковую структуру, но содержит разное количество скриптов, стилей, шаблонов, который располагаются на одном уровне:
├── app │   ├── static │   │   └── app │   │   ├── css │   │   │   └── app.css │   │   └── js │   │   ├── app-detail.js │   │   └── settings.js │   └── templates │   └── app │   ├── app__element-detail.html │   ├── app.html │   ├── app__periodic-table.html │   └── app__settings.html
Как собирать все эти файлы в один?
Применительно к стилям - видел способ с extract-text-webpack-plugin, но во всех примерах показыват один и тот же сценарий - одна точка входа, стили импортированы в скрипт и из них уже собирается.
Мне же нужно просто сделать бандл, его подключу в базовом шаблоне.
Аналогичный вопрос можно задать и по сборке всех скриптов, только кроме своих скриптов в сборку нужно включить скрипты нпм.
Дайте, пожалуйста, советы
Мой конфиг вебпака https://jsfiddle.net/9qkwuru1/
'use strict';
const NODE_ENV = process.env.NODE_ENV || 'development'; const webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = { context: __dirname, entry: "./table/static/table/js/settings.js", output: { path: __dirname + "/common", filename: "bundle.js" },
watch: NODE_ENV == 'development', watchOptions: { aggregateTimeout: 100 },
devtool: NODE_ENV == 'development' ? 'source-map' : null,
resolve: { moduleDirectories: ['node_modules'], extension: ['', '.js', '.styl'] },
resolveLoader: { moduleDirectories: ['node_modules'], moduleTemplates: ['*-loader'], extension: ['', '.js' ] },
module: { loaders: [{ test: /\.js$/, loader: 'babel', exclude: [ /(node_modules|bower_components)/ ], query: { presets: ['es2015'] } }, { test: /\.jade$/, loader: 'jade' }, { test: /\.css$/, loader: ExtractTextPlugin.extract({ fallbackLoader: "style-loader", loader: "css-loader" }) }, { test: /\.styl$/, loader: 'style!css!autoprefixer?browsers=last 2 version!stylus?resolve url' }, { test: /\.(png|jpg|svg)/, loader: 'file?name=[path][name].[ext]' }] },
plugins: [ new webpack.NoErrorsPlugin(), new webpack.DefinePlugin({ NODE_ENV: JSON.stringify(NODE_ENV) }), new webpack.ProvidePlugin({}), new ExtractTextPlugin({ filename: "bundle.css" }) ] };
if (NODE_ENV == 'production') { module.exports.plugins.push( new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false, drop_console: true, unsafe: true } }) ) }


Ответ

Мне приходилось решать такую задачу в одном из боевых проектов.
Для этого я использовал функцию glob, которая собирает все файлы по маске. https://www.npmjs.com/package/glob И обертку для нее, которая позволяет задавать несколько таких масок массивом: https://www.npmjs.com/package/glob-all Она довольно простая, не смотрите что звезд не очень много.
Ставим этот пакет (сам glob он вытянет зависимостью):
npm install glob-all --save-dev
В вебпак конфиге:
var glob = require("glob-all");
После этого выдаем точкам входа результат, например так:
entry: { yourAwesomeEntryPoint: glob.sync([ "./someFolder/*.js", "./anotherFolder/*.js" ]),
Соответственно маски могут задаваться довольно хитро, в том числе регуляркой, подробнее в документации к пакетам.
В моем случае этого хватило.

Когда уничтожается ValueType и семантика работы GC с ValueType

Ходят мифы и легенды,мол ValueType удаляется посредством GC(то бишь GC деаллоцирует как ReferenceType,так и ValueType). Но на самом то деле это не так. К примеру у нас есть код:
class A {} class B { void TestMethod() { A a = new A(); int x = 100; } }
в контексте(Scope) метода TestMethod(), создается объект(ReferenceType) типа А,а так же переменная X(ValueType).
По завершению работы метода, переменная X уничтожается,а объект типа А теряет ссылку на объект,и становится претендентом для удаления от GC.
Иными словами,ValueTypе существует в контексте до тех пор,пока выполняется,и соответственно Stack, по типу метода Pop() сам удалит эти данные из памяти, и никакого участия в этом не принимает GC, поэтому ValueType и работает быстрее (хотя все зависит от задачи).
И сам вопрос,всегда ли это так работает? (читал разные статьи,иногда пишут,что это происходит только тогда,когда стек забивается, т.е. доходит до заполнения)
Что делает CLR,когда стек уже почти переполнен,а все данные в нем к примеру являются ссылками на объекты в куче? Как и когда удаляются пользовательские структуры? Как именно CLR решает удалять ли данные из стека или оставить их еще существовать N-ое кол-во времени!??


Ответ

Локальные переменные типов ValueType [на которых нет замыканий из анонимных методов и лябмд] лежат прямо в стеке или в регистрах процессора (как захочется оптимизатору).
Вы можете прямо посмотреть, как выполняется ваш код, нажав правой кнопкой по нему в отладке, и выбрав Go To Disassembly, может быть это прояснит картину. Вот как это выглядит в отладочном режиме (что выключает оптимизации). Я добавил комментарии в важных местах:
{ 025B2E48 push ebp // это так называемый пролог функции 025B2E49 mov ebp,esp // https://en.wikipedia.org/wiki/Function_prologue 025B2E4B push edi // суть его - сохранить текущее положение 025B2E4C push esi // стека в "базовый указатель" - [e]bp 025B2E4D push ebx
в стек запихнули значения 3-х регистров, так что его указатель теперь отличается уже на 12 от того, который был в начале функции
025B2E4E sub esp,3Ch
esp - это указатель на начало стека. Уменьшить его на 3Ch - это выделить в стеке 3Сh (60) байт под локальные переменные (или другие накладные расходы) к этому моменту он уже отличался на 12 от значения, которое лежит в ebp, так что локальные переменные находятся в диапазоне по адресам от [ebp-13] до [ebp-72]. Он же [ebp-0Dh] до [ebp-48h].
Потом делаем кучу проверок и долго и мучительно создаем объект (это все из-за отладочного режима). Я пропущу большую часть кода, она не имеет отношения к вопросу:
025B2E51 mov esi,ecx 025B2E7C nop A a = new A(); 025B2E7D mov ecx,700F98h 025B2E82 call 024130F4 025B2E87 mov dword ptr [ebp-48h],eax 025B2E8A mov ecx,dword ptr [ebp-48h] 025B2E8D call 025B0D18 025B2E92 mov eax,dword ptr [ebp-48h]
и вот наконец ложим указатель на созданный объект в стек (в ebp лежит положение стека на момент начала вызова функции) 025B2E95 mov dword ptr [ebp-40h],eax
С целым числом попроще - просто запихиваем нужное значение в относительно epb - т.е. относительно начала стека на момент функции.
int x = 100; 025B2E98 mov dword ptr [ebp-44h],64h } 025B2E9F nop
А вот теперь фокус. Берем и загружаем в указатель стека значение, которое в нем было сразу после 025B2E4D push ebx. По сути это esp = ebp-0Ch
025B2EA0 lea esp,[ebp-0Ch] 025B2EA3 pop ebx 025B2EA4 pop esi 025B2EA5 pop edi
и после следующей строчки получаем значение esp равное тому, которое было в начале функции.
025B2EA6 pop ebp 025B2EA7 ret
За счет чего при этом выделалась и освобождалась память в стеке?
Выделалась за счет уменьшения указателя стека на нужное значение. Освобождалась - за счет восстановления старого значения указателя. Расходов на разрушение или "сброрку мусора" локальных переменных при этом не было.
Это стандартный механизм на x86, так что можно считать что так происходит почти всегда. По возврату из функции значение Stack Pointer восстанавливается в то, что было до ее вызова.

Назначить через jquery элементу display:flex

Вывожу блок
//block search $('.openSearch').click(function () { $('.social__hidd').stop().css({ opacity: 0.0, display:'none' }); $('.search').stop().fadeIn(0).css({ display:'flex' }).css({ // display: '-webkit-flex' }); }); $('.closeSearch').click(function () { $('.social__hidd').stop().css({ opacity: 1, display:'block' }); $('.search').fadeOut(0); }); .search{ color: @search; position: absolute; right: 0; top: 20%; display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: none; -webkit-box-orient: horizontal; -webkit-box-direction: normal; -webkit-flex-direction: row; -ms-flex-direction: row; flex-direction: row; -webkit-box-align: center; -webkit-align-items: center; -ms-flex-align: center; align-items: center; -webkit-box-pack: center; -webkit-justify-content: center; -ms-flex-pack: center; justify-content: center; z-index: 25; i{ color: #fff; } &__cont{ display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-box-orient: horizontal; -webkit-box-direction: normal; -webkit-flex-direction: row; -ms-flex-direction: row; flex-direction: row; -webkit-box-align: center; -webkit-align-items: center; -ms-flex-align: center; align-items: center; border-bottom: 1px solid @search; margin-right: 13px; } &__input{ width: 207px; background-color: transparent; border:none; height: 30px; outline: none; }


По нажатию на кнопку поиск .openSearch:
Скрываются соц сети .social и показывается блок .search. Блок .search организован на flex, поэтому через jq назначаю ему display:'flex'. Во всех браузерах, кроме Safari, работает нормально:
Но в Safari не так: Причину узнал, дело в том что во всех браузерах код jq работает корректно и блоку .search назначается инлайновый стиль display:flex, однако в Safari вместо этого назначается инлайновый стиль display:block. Почему так происходит понять не могу, что делаю не так? Спасибо!


Ответ

У вас есть код для flexbox с вендорными префиксами наверняка для поддержки старых браузеров.
display: -webkit-box; display: -webkit-flex; display: -ms-flexbox;
Так вот, чтобы это работало сделайте так. Вынесите этот код в класс
.flex { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; }
Затем из jQuery используйте функцию toggleClass с классом flex. Либо ещё функции addClass и removeClass
Также в jQuery UI функция toggleClass расширена и позволяет анимировать включение/отключение класса.
Либо также можно просто перестать поддерживать довольно старые браузеры (если это допустимо для вас). Я считаю, что имею право с нынешним темпом развития называть браузеры 2012 года старыми.

SQL получить названия поля с PRIMARY KEY

Есть произвольные таблицы и необходимо узнать название поля c PRIMARY KEY, как это можно сделать SQL (использую MySQL) запросом или средствами Python v3 и библиотечки PyMySQL?

Есть допустим табличка такой структуры:
CREATE TABLE `test` ( `name` text, `this_id` int(11) NOT NULL, PRIMARY KEY (`this_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
И необходимо вернуть this_id


Ответ

Немного изменил запрос от @L. Vadim
-- Выводим значения поля COLUMN_NAME из таблице information_schema.TABLE_CONSTRAINTS SELECT C.COLUMN_NAME FROM information_schema.TABLE_CONSTRAINTS AS pk /* Делаем INNER JOIN из-за того что нам нужны только пересечения полей: TABLE_NAME название таблицы, CONSTRAINT_NAME название поля с ключом TABLE_SCHEMA название базы */ INNER JOIN information_schema.KEY_COLUMN_USAGE AS C ON C.TABLE_NAME = pk.TABLE_NAME AND C.CONSTRAINT_NAME = pk.CONSTRAINT_NAME AND C.TABLE_SCHEMA = pk.TABLE_SCHEMA
/* Условия: TABLE_NAME название таблицы, TABLE_SCHEMA название базы CONSTRAINT_TYPE поле где указан PRIMARY KEY */ WHERE pk.TABLE_NAME = 'test' AND pk.TABLE_SCHEMA = 'test_db' AND pk.CONSTRAINT_TYPE = 'PRIMARY KEY';
Вариант без комментариев:
SELECT C.COLUMN_NAME FROM information_schema.table_constraints AS pk INNER JOIN information_schema.KEY_COLUMN_USAGE AS C ON C.TABLE_NAME = pk.TABLE_NAME AND C.CONSTRAINT_NAME = pk.CONSTRAINT_NAME AND C.TABLE_SCHEMA = pk.TABLE_SCHEMA WHERE pk.TABLE_NAME = 'test' AND pk.TABLE_SCHEMA = 'test_db' AND pk.CONSTRAINT_TYPE = 'PRIMARY KEY';

Я не уверен в правельности текста ниже, так-как он был написан из быстрого изучения таблиц: information_schema.TABLE_CONSTRAINTS и information_schema.KEY_COLUMN_USAGE
Как я понял, в таблице information_schema.TABLE_CONSTRAINTS храниться информация о всех ключах для всех баз и соединяем их с таблицей information_schema.KEY_COLUMN_USAGE по полю CONSTRAINT_NAME где хранится название нашего ключа в нашем случаи это PRIMARY и уже в information_schema.KEY_COLUMN_USAGE находятся все поля с ключами, название поля в поле COLUMN_NAME

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

Как передавать в метод массив фиксированной длины?
class A { final int length;
void foo(Object[length] objects) {} // ? }


Ответ

Никак. Можно только все значения массива сделать отдельными параметрами метода:
void foo(Object first, Object second, Object third) { }
Также можно использовать проверку длины массива с пробросом исключения в теле метода:
void foo(Object[] objects) { if (objects.length != length) { throw new IllegalArgumentException("Incorrect array size"); } ... }
Но это уже проверка, а не ограничение.

Индекс в кольцевом буфере, поддерживающем многопоточность

Вводные данные: вектор элементов постоянного размера (кольцевой буфер), плюс атомарное число, указывающее на текущее положение в этом самом векторе.
const int MAXIMUM = 100; QVector _buffer(MAXIMUM);
QAtomicInt _atomic_index;
Далее метод, который позволяет многопоточно вставлять данные в вектор:
void insert(const Data &data) { _buffer[_atomic_index++] = data; }
Здесь очевидна проблема, что по достижению границы размера вектора необходимо вернуться к нулевому индексу:
void insert(const Data &data) { _atomic_index.testAndSetOrdered(MAXIMUM,0); _buffer[_atomic_index++] = data; }
Это не решение, т.к. если, например, два или более потоков одновременно пройдут проверку в первой строке и при этом значение _atomic_index будет неподалёку от границы вектора, то выход за неё и последующий сегфолт будут фактически гарантированы.
Получается, что в данной ситуации требуется атомарная операция, состоящая из проверки на равенство максимуму, плюс в ней же инкрементация индекса:
void insert(const Data &data) { mutex.lock(); if(index == MAXIMUM) index = 0; _buffer[index++] = data; mutex.unlock(); }
Но этот вариант полностью нивелирует профит при многопоточной вставке данных.
Я попытался самостоятельно решить проблему, однако нет полной уверенности в корректности решения:
void insert(const Data &data) { int index = _atomic_index++; if(index >= MAXIMUM) { const int new_index = index - MAXIMUM; _atomic_index.testAndSetOrdered(index+1,new_index); index = new_index; }
_buffer[index++] = data; }
Смысл в том, чтобы использовать локальную и индивидуальную для каждого из потоков переменную, содержащую значение текущего индекса:
int index = _atomic_index++;
Именно эту переменную проверяем на выход за пределы размера вектора:
if(index >= MAXIMUM) {...}
А уже внутри этого условия _atomic_index, по моему соображению, должен принять значение самой последней операции инкрементирования индекса. Прав ли я? Или, быть может, существует иной способ решения обозначенной задачи?
Обновление
Дабы акцентировать внимание только на моменте проверки индекса на выход за границу размера вектора, примем по умолчанию, что кол-во записывающих потоков в данном конкретном примере значительно (в разы) меньше, нежели чем кол-во элементов в векторе и, тем самым, исключим из внимания возможность перезаписи ещё не прочитанных (занятых) элементов вектора вновь вставляемыми элементами. Например:
записывающих потоков: 10 читающих потоков: 20 длина вектора: 100
Читающие потоки не отстают от записывающих, что означает, что все вновь заполненные ячейки будут практически сразу прочитаны. Или даже радикально: записанные ячейки можно хоть сразу перезаписывать, поскольку данные для чтения не важны.
Интересует только момент сброса значения счётчика текущего индекса записи при многопоточной вставке, когда, например, все 10 потоков одновременно будут пытаться его увеличить на единицу и текущий индекс будет равен 98 из 100 возможных элементов. В этом случае правильная обработка должна одному потоку назначить индекс 99, тогда как оставшимся девяти: от 0 до 8. При этом значение текущего индекса (в коде это _atomic_index) должно сравняться с именно последним индексом из присвоенных, т.е. также 8.
Обновление 2
В зачёркнутом утверждении - ошибка. Текущий индекс должен стать равным 9, т.е. на единицу больше от последнего вставленного, поскольку в строке:
int index = _atomic_index++;
... используется пост-инкремент.


Ответ

Мой ответ основывается на собственном опыте с java; с с++ у меня практически не было опыта, но семантика должна быть одна и та же.
Я бы хотел разобрать предложенный пример. Сделаем мысленный эксперимент со следующей ситуацией:
void insert(const Data &data) { int index = _atomic_index++; // Thread B if(index >= MAXIMUM) { const int new_index = index - MAXIMUM; _atomic_index.testAndSetOrdered(index+1,new_index); // Thread A index = new_index; }
_buffer[index++] = data; }
Thread A успел пройти несколько выражений быстрее, чем Thread B, и в тот момент, когда Thread A пытается сбросить индекс на ноль, Thread B его инкрементирует, поэтому сброс индекса на ноль провалится, и (так как операция не создает преград для ее повторения) это дает возможность для неограниченного увеличения _atomic_index - если ситуация постоянно повторяется. Как только _atomic_index достигнет значения MAXIMUM * 2 - 1, index будет вычислен со значением MAXIMUM, что приведет к попытке записи за пределы ожидаемого диапазона значений.
Первое решение, которое придет в голову - использовать оператор modulo вместо однократного вычитания MAXIMUM - позволит уменьшить вероятность возникновения такой ситуации, но не спасет от нее, потому что при переполнении int в _atomic_index вернется неожиданное значение.
Один из классических подходов для такой ситуации - реализовать spinlock вручную на основе оптимистичной блокировки. Дальше идет псевдокод, т.е. я не знаю реальных методов в используемой библиотеке, равно как и синтаксиса с++:
void insert(const Data &data) { // это все без проблем выносится в отдельный метод int current; int next; do { current = _atomic_index.get(); next = (current + 1) % MAXIMUM; } while (!_atomic_index.compareAndSet(current, next))
_buffer[current] = data; }
В этом случае можно говорить о следующем инварианте:
Следующее значение = текущее значение + 1 % MAXIMUM Следующее значение может быть установлено вместо текущего, только если текущее значение является верным (= не изменилось с момента чтения)
У алгоритма остается ровно два пути:
Установить следующее значение индекса, если он не изменялся Пойти на новый круг, если между двумя операциями индекс изменился
Если у нас есть конкурирующие потоки, это будет выглядеть примерно так:
Индекс: 1 Максимум: 3 Т1: пробует установить 2 вместо 1 Т2: пробует установить 2 вместо 1 Т3: пробует установить 2 вместо 1
(театральная пауза, магия за кулисами)
Т1: успех, установлен 2 Т2: провал, пробует установить 0 вместо 2 Т3: провал, пробует установить 0 вместо 2
(театральная пауза, магия за кулисами)
Т1: отработал Т2: провал, пробует установить 1 вместо 0 Т3: успех, установлен 0
(театральная пауза, магия за кулисами)
Т1: отработал Т2: успех, установлен 1 Т3: отработал
Что будет, если поток "заснул", и за время сна счетчик прошел полный цикл?
Если я ничего не напутал - ничего страшного. Воспроизведем алгоритм:
Индекс: 1 Максимум: 4 Т1: считывает 1 и засыпает Т2: считывает 1 и обновляет на 2 Т2: считывает 2 и обновляет на 3 Т2: считывает 3 и обновляет на 0 Т2: считывает 0 и обновляет на 1 Т2: считывает 1 Т1: просыпается и обновляет 1 на 2 Т2: терпит неудачу в обновлении, заходит на новый круг
Безопасен ли этот подход? Конкретно в этом случае - нет
Данный ответ подсказывает решение на проблему корректного инкрементирования счетчика, но не алгоритма целиком.
Выбор нового индекса и непосредственно установка значения - это две разных операции, и атомарность выполнения метода insert не гарантируется. ОС имеет право приостановить поток сразу после "резерва" индекса и разбудить его спустя произвольное время, поэтому в одну и ту же ячейку могут быть записаны данные в обратном порядке:
Т1: зарезервировал ячейку с индексом 1 Т1: заснул (некоторое время работы с алгоритмом, в течение которого индекс обнуляется и идет на новый круг) Т2: зарезервировал ячейку с индексом 1 Т2: положил данные Т1: проснулся Т1: положил устаревшие данные Кроме того, индекс инкрементируется до появления данных по адресу - это значит, что прочитавший индекс может обратиться к ячейке, в которой все еще находятся старые данные, считая их актуальными Кроме того, весь алгоритм нельзя считать рабочим, пока не учитывается положение хвоста, иначе хвост может дойти до головы, и в этом случае (!) потеряется MAXIMUM элементов.
Если хотите найти хорошую реализацию подобного алгоритма, стоит поискать в гугле lock-free circular buffer или аналогичную фразу; я, если честно, не могу сходу придумать реализаций кроме linked list с отслеживанием длины (в котором будет очень сложно гарантировать корректность алгоритма без пессимистичной блокировки) и непосредственно пессимистичную блокировку. Последняя может оказаться не настолько плохим варинатом, и, возможно, будет показывать себя даже лучше приведенного примера спинлока в окружении с большим количеством потоков.

Как избежать удаления функции _start при межмодульной оптимизации?

При следующем значении CFLAGS
-Wall -Werror -Wextra -pedantic -std=c99 -O3 -nostartfiles -nodefaultlibs
моя точка входа __start (обратите внимание на -nostartfiles) успешно компилируется и помещается в исполняемый файл.
Однако при добавлении флага -flto и сама точка входа, и все вызываемые только ей функции выкидываются оптимизатором. Более того, дальнейшая компоновка производится без ошибок и предупреждений, но с некорректной (случайной) точкой входа.
Вопрос: как предотвратить удаление функции __start? Также интересно узнать, почему компоновщик во время оптимизации «забывает» о наличие зависимости от моей точки входа при отсутствии встроенной.
Версия GCC: gcc (i686-posix-dwarf-rev1, Built by MinGW-W64 project) 4.9.2
Исходный код (исправлено с учётом замечания об особенностях Windows ABI [в оригинале это был комментарий, но здесь я добавил его в ответ — прим. пер.]):
#include
void _start() { MessageBox(NULL, TEXT("Hello world."), TEXT(""), MB_OK); ExitProcess(0); }
Ассемблерный код, выдаваемый компоновщиком (-S):
Вариант без -flto
Disassembly of section .text:
00401000 <__start>: 401000: 83 ec 1c sub $0x1c,%esp 401003: c7 44 24 0c 00 00 00 movl $0x0,0xc(%esp) 40100a: 00 40100b: c7 44 24 08 00 20 40 movl $0x402000,0x8(%esp) 401012: 00 401013: c7 44 24 04 0d 20 40 movl $0x40200d,0x4(%esp) 40101a: 00 40101b: c7 04 24 00 00 00 00 movl $0x0,(%esp) 401022: ff 15 54 40 40 00 call *0x404054 401028: 83 ec 10 sub $0x10,%esp 40102b: c7 04 24 00 00 00 00 movl $0x0,(%esp) 401032: ff 15 4c 40 40 00 call *0x40404c 401038: 90 nop 401039: 90 nop 40103a: 90 nop 40103b: 90 nop 40103c: 90 nop 40103d: 90 nop 40103e: 90 nop 40103f: 90 nop
00401040 <__CTOR_LIST__>: 401040: ff (bad) 401041: ff (bad) 401042: ff (bad) 401043: ff 00 incl (%eax) 401045: 00 00 add %al,(%eax) ...
00401048 <__DTOR_LIST__>: 401048: ff (bad) 401049: ff (bad) 40104a: ff (bad) 40104b: ff 00 incl (%eax) 40104d: 00 00 add %al,(%eax) Вариант с -flto (обратите внимание на отсутствие _start, но наличие переходников для API-функций):
Disassembly of section .text:
00401000 <_ExitProcess@4>: 401000: ff 25 4c 30 40 00 jmp *0x40304c 401006: 90 nop 401007: 90 nop
00401008 <_MessageBoxA@16>: 401008: ff 25 54 30 40 00 jmp *0x403054 40100e: 90 nop 40100f: 90 nop
00401010 <__CTOR_LIST__>: 401010: ff (bad) 401011: ff (bad) 401012: ff (bad) 401013: ff 00 incl (%eax) 401015: 00 00 add %al,(%eax) ...
00401018 <__DTOR_LIST__>: 401018: ff (bad) 401019: ff (bad) 40101a: ff (bad) 40101b: ff 00 incl (%eax) 40101d: 00 00 add %al,(%eax)

Данный вопрос является переводом «Prevent __start entry point from being optimized out».


Ответ

Необходимо удостовериться, что данный символ воспринимается как точка входа и не выбрасывается при оптимизации на уровне компоновщика.
Чтобы указать точку входа, необходимо передать компоновщику следующий ключ:
-Wl,-e__start
либо написать spec-файл с объявлением данного символа. Однако способ с ключом проще.
И ещё. При использовании Windows ABI компилятор неявно добавляет дополнительное подчёркивание перед именем Си-функций. Как результат, void __start() превращается в ___start, и компоновщик его не видит.

Данный ответ является переводом ответа участника Jean-François Fabre и комментария участника fuz

Праздники и выходные

Появилась задача учитывать официальные праздники и выходные в приложении (Российская Федерация). Вопрос, существует ли какой-нибудь сервис, откуда их можно получить (в начале каждого года например). Не хочется постоянно возвращаться к клиенту и вносить эти даты в базу.


Ответ

То, что Вам нужно, называется "Производственный календарь". В итоговом виде он в официальной версии не существует и составляется на основании календаря года и действующего законодательства.
Получить его можно, например, с правовых сайтов (Consultant.ru, Garant.ru и пр.), порталов занятости (HH.RU, SuperJob.RU и пр.) и других.
Нужен именно сервис, с которого можно получить даты в конкретном формате (XML, JSON), и который не отвалится через год.
Портал открытых данных России устроит?
Альтернативный источник: ссылка 1, ссылка 2

Для каких целей нужен метод PushFrame

Я наткнулся на метод PushFrame у класса Dispatcher. Бегло посмотрел реализацию и прочитал про него в документации. Вот упрощенная версия этого метода.
public void PushFrame(DispatcherFrame frame) { // Stuff _frameDepth++; while(frame.Continue) { // Getting and dispatching messages } _frameDepth--; // Stuff }
Я понимаю что метод просто создает и обрабатывает новый цикл сообщений. Но я не могу понять, какие именно цели такой подход может достигать? Разве одного цикла недостаточно? Более я того, я скольнен полагать, что использование еще одного вложенного цикла может вести к довольно неочевидным ошибкам


Ответ

Хороший вопрос.
Коротко — вы не должны им пользоваться в обычном случае, этот метод — внутренний метод инфраструктуры.
Ситуации, в которых нужно было бы использование PushFrame — блокирующие методы наподобие ShowDialog (в самом ShowDialog тоже используется PushFrame). В них вам нужно на время работы блокирующей функции не прекращать обработку цикла сообщений, и для этодо при помощи PushFrame создаётся вложенный цикл.
В современном C# использование блокирующих методов считается неидиоматичным. Правильным дизайном с позиций сегодняшнего дня было бы использование async-варианта. Здесь есть примеры такого дизайна с кодом.

Визуализация сортировки выбором

for (int i = 0; i < array.Count; i++) { Thread.Sleep(500); int minValueIndex = i; for (int j = i + 1; j < array.Count; j++) { if (array[j] < array[minValueIndex]) { minValueIndex = j; } } int temp = array[i]; array[i] = array[minValueIndex]; array[minValueIndex] = temp;
chart1.Series[0].Points.DataBindXY(null, array); }
Код почему-то виснет и только через секунд 10 строит уже отсортированный график, то бишь промежуточных построений не видно. Из-за чего это может быть?
Догадываюсь, что влияет Thread.Sleep(), но как обойтись без него не знаю, ибо необходимо пошагово [с интервалами между прорисовками] показать сортировку...


Ответ

Ты в основном потоке делаешь остановку на полсекунды (Thread.Sleep), т.е он сначала считает, заносит в chart, при этом поток формы останалвивается на сортировке (не обновляется окно и т.д.) после этого обновляет форму, попробуй сразу после занесения значения в chart вызвать refresh() для него.

GLSL, HLSL Шейдер из нескольких файлов

Например есть 3 шейдера. параллакс, бамп, и солид. В каждом шейдере должны быть общие вычисления типа вычисления источников света.
Реально ли в GLSL и HLSL вынести эти функции в отдельный файл и потом их как бы подключать как .h файл к коду программы? Каковы конструкции, ключевые слова в шейдерных языках и что нужно сделать в коде программы для того чтобы их использовать?


Ответ

Насколько мне видится, самым универсальным решением для HLSL и GLSL может быть написание своего простенького препроцессора, который будет вместо строке #include("bump.glsl") вставлять код этого файла.
Также можно пытаться обойтись дефайнами и таким образом отключать или включать какие-то функции в шейдере.
P.S. В вопросе наверное стоило указать версию GLSL и HLSL, которую вы планируете использовать.

Как правильно организовать структуру бд

Вводная:
Есть таблица sms которая содержит данные об ожидающей отправки sms. Так же есть таблица text_patterns, которая хранит текстовые шаблоны, подготовленные пользователем. В таблице sms есть поле pattern_id - связь с текстовым шаблоном
Пользователь загружает csv файл в систему. В файле csv список на какой номер какой текстовый шаблон отправить. 2 колонки. Номер, id шаблона.
Сейчас все это обрабатывается и работает
Задача:
Хотим добавить фичу, чтобы во второй колонке можно было писать не только существующий текстовый шаблон, но и сам текст для отправки. Т.е. я буду смотреть что в этом поле - если цифра, то это текстовый шаблон, а если строка - то какая-то новая логика обработки.
Никак не могу понять, как мне хранить эти данные в базе.
Варианты решения:
Если текст, то создавать новый текстовый шаблон в таблице text_patterns и дальше работать по старой схеме. Решение не нравится, т.к. шаблоны могу быть очень уникальны и получится для каждого номера свой отдельный шаблон. Пропадает логика шаблонов. Добавить в таблицу sms текстовое поле в котором хранить значение. т.е. добавить поле sms_text и признак связи с тестовым шаблоном is_pattern (0|1). Решение не нравится т.к. у нас будут пустые поля на каждой строке, либо pattern_id либо sms_text. Так же для дальнейшей обработки данных мне нужно будет все время писать 2 запроса вместо одного. Один для sms с шаблонами, другой для sms с кастомным текстом.
Может есть какие-то более красивые решения ?


Ответ

Ваш второй вариант похож на правду, только его надо немного доделать. Нужны два поля: id-шаблона и текст шаблона, оба поля допускают значения NULL. id-шаблона должен быть foraign key, указывающий на таблицу с шаблонами. Не пугайтесь NULL значений, СУБД фактически их не хранит, например MySQL для таких полей хранит один бит в заголовке записи показывающий есть поле или нет, другие СУБД действуют примерно так же. Никакого признака есть "уникальный шаблон" или нет, в записи не нужно, сам факт присутствия текста в поле sms_text является признаком. На уровне триггеров можно не допускать вставки записей где заполнены оба поля или не заполнено ни одно из них.
Так же для получения текущего шаблона два запроса не нужно, все решается одним запросом:
select ..., coalesce(T.text,S.sms_text) from sms S left join text_patterns T on T.id=S.pattern_id
Мы объединяем таблицы по LEFT JOIN, таким образом, если поле pattern_id пустое - то запрос все равно вернет запись, только в ней текст из таблицы шаблонов будет NULL. Функция coalesce() даст первое из перечисленных полей, которое НЕ NULL, т.е. если id-шаблона задан и запись в шаблонах найдена, то текст будет взят от туда, если шаблон не задан, то текст будет взят из поля sms_text в самой записи таблицы sms. Возможно стоит переставить местами аргументы, тогда текст из самого sms будет иметь приоритет над найденным в шаблонах в случае если оба поля заполнены.

Настроить ssl на nginx

Здравствуйте!
Есть некий сервер, на котором nginx слушает один адрес (допустим, 1.1.1.1). Адрес резолвится в большую кучу dns-имён, при чём, самых разных. Допустим, у меня для каждого имени есть свой SSL-сертификат. Как мне настроить nginx, чтоб они для каждого имени ассоциировал свой сертификат?


Ответ

Насколько я понимаю, у вас сервер имеет ip 1.1.1.1, на нем nginx и много dns указывают в A-записи на 1.1.1.1
Тогда так
server { listen 80; server_name site1.com www.site1.com; rewrite ^(.*) https://$host$1 permanent; } server { listen 443; ssl on; ssl_certificate /etc/nginx/ssl/site1.pem; ssl_certificate_key /etc/nginx/ssl/site1.key;
server_name site1.com www.site1.com; root /var/www/site1;
...
}
server { listen 80; server_name site2.com www.site2.com; rewrite ^(.*) https://$host$1 permanent; } server { listen 443; ssl on; ssl_certificate /etc/nginx/ssl/site2.pem; ssl_certificate_key /etc/nginx/ssl/site2.key;
server_name site2.com www.site2.com; root /var/www/site2;
...
}
Для каждого сайта сначала слушаем порт 80, делаем rewrite с http на https, потом слушаем 443.
Это выдержка из рабочего конфига nginx.

(Linux/Ubuntu) Как настроить стрелки на определенные клавиши при зажатом Alt

Надоело постоянно сдвигать правую руку на стрелки каждый раз когда нужно перемещаться по коду. Есть идея для этого использовать к примеру клавиши IJKL при зажатом Alt, но вот как это все настроить даже не представляю. Сижу на Ubuntu.


Ответ

Вариант 1
Можно использовать xdotool и назначить горячие клавиши в Меню - Параметры системы - Клавиатура - Комбинации клавиш - Дополнительные комбинации

Здесь надо добавить 4 кнопки соответственно:
xdotool keyup Ctrl key Up keydown Ctrl xdotool keyup Ctrl key Left keydown Ctrl xdotool keyup Ctrl key Down keydown Ctrl xdotool keyup Ctrl key Right keydown Ctrl
И назначить им комбинации Control + I, Control + J, Control + K, Control + L

Корявый, конечно, вариант. Но раз уж ничего другого не предлагают...
Вариант 2
Использовать xmodmap
$ cat > ~/.Xmodmap keycode 37 = Mode_switch keysym j = j J Left keysym l = l L Right keysym i = i I Up keysym k = k K Down ^C $ xmodmap ~/.Xmodmap
keycode 37 - это левый Control
Команду $ xmodmap ~/.Xmodmap нужно поместить в автозагрузку.
Второй вариант считаю более правильным.

Как предоставить возможность локализовать библиотку

Дано: библиотека, которая запускает свои окна, со своими текстовыми полями и строками. Имеется три файлы string.xml для русскоговорящих и англоговорящих регионов, которые локализуют эти окна.
Требуется: дать возможность локализовать данные окна пользователям библиотеки. Я не могу поддерживать все языки, а значит я должен предоставить эту возможность пользователям библиотеки.
Вариант решения: создать Java-класс, который будет содержать все строки. Строки будут заполняться строковыми ресурсами (что дает возможность Android'y выбирать локализацию). Пользователь будет сам заполнять эти поля, если требуется. Само собой, этот способ неудобный, даже при условии небольшого количества строк.

Вопрос: как предоставить возможность пользователю библиотеки локализовать ее?


Ответ

Т.к. переопределять ресурсы библиотечные можно, то вам надо предоставить юзерам лишь список оных. Они смогут сами создать у себя в проекте папку дл нужной локализации и поместить туда нужные троки для перевода. Приложение будет брать их оттуда.
Т.е. в README приведите ссылку на библиотечный res/values/strings.xml (или отдельный файл если переводить надо не все строки) и укажите юзеру чтобы он взял оттуда строки и сам их перевёл в своём проекте

Какой тип данных используется для хранения строки?

Вот пример кода:
auto size = "Hello, world"; std::cout << sizeof(size);
В консоль выводится 4. Не могу понять, какой тип данных использует компилятор для хранения этой строки?


Ответ

Строковые литералы в C++ имеют типы константных символьных массивов. Данный литерал "Hello, world" имеет тип const char[13]
Используемый в качестве выражения инициализации он неявно преобразуется к указателю на свой первый элемент, который имеет тип const char *
Соответственно переменная size имеет тип const char *
Вы можете убедиться в этом, запустив на выполнение следующий фрагмент кода
auto size = "Hello, world"; std::cout << typeid(size).name() << std::endl;
Если бы вы написали так
decltype(auto) size = "Hello, world"; std::cout << sizeof(size) << std::endl;
то переменная size была бы ссылкой на строковый литерал и имела тип const char ( & )[13], а оператор sizeof вернул бы значение 13

Нечеткий поиск подстроки в строке

Здравствуйте. Необходимо реализовать на Java поиск подстроки в строке. Т.е. строка "Разница между родившимися и умершими" должна быть найдена в строке "Разность между числом родившихся и числом умерших за определенное время (например, за один год) называют естественным приростом населения."
А строка "Ивановыми" должна быть найдена в строке "Иванов - древнейший житель города"
Необходим лишь ответ - есть ли что-то похожее в строке. Посоветуйте что-нибудь, желательно уже реализованное на Java.


Ответ

Грубо говоря это делается в 3 шага:
Разбиваем строку на лексемы/слова Полученные лексемы прогоняем через Apache Lucene c русской морфологией - в итоге получаем список лексем очищенный от падежных/родовых и прочих морфологичечких признаков характерных для великого могучего, то есть вместо:
Разность между числом родившихся и числом умерших за определенное время
получим
Разница между число родить и число умереть за определенный время
Далее для этих лексем вычисляем хэш функцию умеющую выдавать близкие значения хэша для похожих слов - например SimHash или что-то вроде упомянутого Левенштейна
Остальное надеюсь объяснять не надо.

Android Library различия -source и -javadocs артефактов

Написал библиотеку, выложил в jcenter, подцепил и заметил алерт который меня напрягает:

Ни в одной библиотеке, которую я использовал до этого не было такого алерта, следовательно - я где-то накосячил в таске формирования -source и -javadocs артефактов.
Может кто сталкивался с этим до меня?
Скрипт формирования артефактов:
android.libraryVariants.all { variant -> def javadocTask = task("generate${variant.name.capitalize()}Javadoc", type: Javadoc) { description "Generates Javadoc for $variant.name." source = variant.javaCompile.source ext.androidJar = project.files(android.getBootClasspath().join(File.pathSeparator)) classpath = files(variant.javaCompile.classpath.files) + files(ext.androidJar) exclude '**/BuildConfig.java' exclude '**/R.java' }
javadocTask.dependsOn variant.javaCompile
def jarJavadocTask = task("jar${variant.name.capitalize()}Javadoc", type: Jar) { description "Generate Javadoc Jar for $variant.name" classifier = 'javadoc' from javadocTask.destinationDir }
jarJavadocTask.dependsOn javadocTask artifacts.add('archives', jarJavadocTask)
def jarSourceTask = task("jar${variant.name.capitalize()}Sources", type: Jar) { description "Generates Java Sources for $variant.name." classifier = 'sources' from variant.javaCompile.source }
jarSourceTask.dependsOn variant.javaCompile artifacts.add('archives', jarSourceTask) }
Сама библиотека: https://bintray.com/ztrap-llc/maven/FormattedEditText/


Ответ

Разобрался (правда не без пары вырванных клоков волос). Косяк действительно допустил я. Но узнать в каком именно месте, мне не удалось, т.к. на просторе GitHub'ов я позаимствовал скрипт, который (О, чудо!) идеально отработал.
Ниже сам скрипт:
task androidJavadocs(type: Javadoc) { source = android.sourceSets.main.java.srcDirs classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) classpath += configurations.compile }
task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { classifier = 'javadoc' from androidJavadocs.destinationDir }
task androidSourcesJar(type: Jar) { classifier = 'sources' from android.sourceSets.main.java.sourceFiles }
artifacts { archives androidSourcesJar archives androidJavadocsJar }

Ошибки в коде при решении уравнения переноса

Обновил содержание вопроса,так как некоторые моменты я сам понял и исправил. И так есть следующие переменные:
hx (шаг по пространству)= 0.1
ht (шаг по времени) = 0.5
Nx (Количество шагов по пространству) = 10;
Nt (Количество шагов по времени) = 12;
wx[i] - массив содержит все шаги по пространству
wt[j] - массив содержит все шаги по времени
wht[j][i]-двумерный массив по которому будет строится результирующий график;

И так найдены несколько проблем:
1) Найдена в коде
for(int i = 0; i < Nx; i++) { wx[i+1] = wx[i] + hx; //массив wht[0][i] = fn(T, i * hx); //i * hx//Исправлено. }
где fn это:
//Функция Хэвисайда - Начальное условие(Граничное условие) а начальное 0-1 public:static double fn(int T, double x) { if (x >= 0) return T; else if(x < 0) return 0; }
Я неправильно задаю начальные условия
Как вино на графике, среди безобразия там где-то видно общее решение "волна", но остальное там неправильно как раз из за того что я в коде неправильно задаю начальные условия
2) Циклы и массивы, а именно:
Идёт обращение к несуществующему элементу массива и следовательно возникают страшные цифры и скачок графика, но я изменить индексы не могу так как есть определённая формула.
for(int j = 0;jЕсли я напишу вместо i = 0, i = 2 или j = 2, то отрисовка графика будет ужасной.
Весь код:
public:static double qx0(double x)//ось пространства { if (x<=0) return 0; else return x; }
public:static double qt0(double t)//ось по времени { if (t<=0) return 0; else return t; }
public:static double fn(int T,double x)//Функция Хэвисайда - Начальное условие { if (x>=0) return T; else if(x<0) return 0; }
public: void drawfunc(double T) { double xmin = -5; double xmax = 10; for(double x = xmin;xSeries["Функция Хэвисайда"]->BorderWidth=3; chart1->Series["Функция Хэвисайда"]->Points->AddXY(x,fn(T,x)); } }
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { ///-------Переменные для работы с разностными схемами double a;//скорость переноса double hx,ht;//шаги по пространству и времени int Nx,Nt;//На сколько частей разбивае отрезок сетки int T;//Входной параметр для искомой функции(Хэвисайд) double wx[20]={0};//массив точек x double wt[20]={0};//массив точек t double wht[20][20]={0};// массив для разностной схемы(сетки) //double res[20][20]={0};//результирующий массив
if(textBox1->Text!="" && textBox2->Text!="" && textBox3->Text!="" && textBox4->Text!="" && textBox5->Text!="" && textBox6->Text!="" && textBox6->Text!="") {
///-----Ввод данных----- a=Convert::ToDouble(textBox1->Text); hx=Convert::ToDouble(textBox2->Text); q=Convert::ToDouble(textBox3->Text); ht=Convert::ToDouble(textBox4->Text); Nx=Convert::ToInt32(textBox5->Text); Nt=Convert::ToInt32(textBox6->Text); T=Convert::ToInt32(textBox7->Text);
//----Построение сетки,узлов for(int i = 0;i for(int j = 0;j ///-----------------Вычисление основых формул с разностной схемой
for(int j = 0;j //----Для записи в простой текстовый файл String^ fileName = "results.txt"; StreamWriter^ sw = gcnew StreamWriter(fileName); for(int j = 0;jWrite("{0} ",wht[j][i]); } sw->WriteLine(); } sw->Close();
//Тестовые функции для отображения drawfunc(T);// Вызов функции для рисования
///---------------Построение графика
for(int j = 0;jSeries["Series2"]->BorderWidth=3; chart2->Series["Series2"]->Points->AddXY(i,wht[j][i]); } } } else MessageBox::Show("Ошибка!Не все поля заполнены!"); }


Ответ

Для того, чтобы ответить, почему не бежит волна на графике, нужно сначала разобраться с численным методом, а лишь потом с кодом на C++. Теория численного анализа не входит в круг вопросов, которые обсуждаются на этом сайте, но краткая справка может пригодиться.
1. Небольшое отступление, посвященное разностным схемам
Итак, мы ищем функцию u(x,t), которая является решением задачи Коши для дифференциального уравнения в частных производных
d u d u --- = - a --- (1) d t d x
с начальным условием
u(x,0) = f(x) (2)
Уравнение (1) называется уравнением переноса, поскольку решением нашей задачи является u(x,t) = f(x-at). Это функция, график которой движется со временем вправо со скоростью a
Подставьте функцию f(x-at) вместо u в уравнение (1) и вычислите частные производные, чтобы проверить, что она действительно является решением.
Преподаватели учат студентов не искать лёгких путей, а решить это уравнение методом конечных разностей. Можно предложить несколько разностных аппроксимаций уравнения (1). Нам предлагается воспользоваться одной из них. Как вскоре выяснится, это очень неудачный выбор.
Итак, рассмотрим схему, в которой производная по t аппроксимируется разностным оператором Dt u

Dt u = (u(x,t+dt) - u(x,t))/dt.
Этот оператор обладает первым порядком аппроксимации.
Производную по x аппроксимируем разностным оператором Dx u

Dx u = (u(x+dx,t) - u(x,t))/dx.
Получим

Dt u = -a Dx u.
Специалистам по численному анализу хорошо известно, что эта схема обладает первым порядком аппроксимации по dt и dx, а также является абсолютно неустойчивой. Это означает, что любое малое возмущение эта схема увеличивает в геометрической прогрессии.
Подставим вместо u(x,t) функцию q^(t/dt) e^(ipx/dx). Подставив, увидим, что если эта функция является решением разностного уравнения, то |q| > 1, если sin p/2 != 0. То есть, любое малое возмущение такой формы будет расти при росте t. Этот способ исследования устойчивости разностных схем называется методом фон Неймана
Итак, эта схема абсолютно неустойчива, следовательно не удовлетворяет условию теоремы Лакса, так что не стоит ожидать сходимости функции, рассчитанной по этой схеме, к решению исходной задачи для уравнения в частных производных.
Интересно, что если мы будем вычислять производную по x по формуле

D'x u = (u(x,t) - u(x-dx,t))/dt,
то получим устойчивую схему.
2. Постановка задачи на ограниченном интервале
Мы хотим искать решение не на всей числовой оси, а на ограниченном интервале [xmin,xmax]. Для того, чтобы функция f(x-at) была решением нашей задачи, необходимо дополнить задачу следующими граничными условиями.
u(xmin,t) = f(xmin - a*t) (3) u(xmax,t) = f(xmax - a*t) (4)
Теперь мы можем перейти к программированию метода решения задачи (1-4) на основе явных схем первого порядка аппроксимации.
3. Программная реализация
Ниже приведена примерная реализация исключительно самого метода. Всё, что касается визуализации, решено отдельно.
Первый блок кода, это определение граничных условий.

#include #include #include
using namespace std;
const double T = 1.0; const double a = 0.5;
inline double f(double x){ if (x>=0) return T; return 0; }
inline double u0(double x){ return f(x); }
inline double u1(double xmin, double t){ return f(xmin - a * t); }
inline double u2(double xmax, double t){ return f(xmax - a * t); }
Следующий блок кода содержит функцию, вычисляющую решение и сохраняющую его в массив. Наша функция в качестве аргументов принимает параметры задачи - координаты границ расчётной области и ссылку на массив, в который нужно сохранить результат.

void run(double xmin,double xmax, double tmax, int N,double u[][M]){ double ht = tmax/N; double hx = (xmax - xmin)/M;
for(int i=0; i for(int j=0; j < N-1; j++){ u[j+1][0] = u1(xmin,j*ht); for(int i=1; iЗдесь реализован вариант с устойчивой схемой -- разностным оператором D'x
4. Результаты
На следующей картинке нарисованы значения функции u(x,t) при a=0.5 и t=0, t=5.0 и t=10.0

Видно, что волна не столько бежит, сколько размазывается в пространстве.
Теперь заменим основной цикл, на цикл, реализующий абсолютно неустойчивую схему, определенную оператором Dx
for(int j=0; j < N-1; j++){ for(int i=0; iРезультат будет выглядеть примерно так

Этот результат совсем не похож на бегущую вправо ступеньку.
5. Заключение
Надеюсь, что этот пример иллюстрирует, что прежде, чем искать ошибки в коде, необходимо изучить свойства алгоритма.