Страницы

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

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

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

С помощью vert.x core 3.2.1 написал простенький сервер, который принимает сообщения от подключившегося пользователя, однако хотелось бы реализовать ответ сервера(возврат сообщений пользователя обратно).
Сам код:
import io.vertx.core.Handler; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.core.http.*;
public class serverTest {
public static void main(String[] args) throws Exception {
HttpServer server = Vertx.vertx().createHttpServer(); server.websocketHandler(new Handler() { @Override public void handle(ServerWebSocket webs) { System.out.println("Client connected"); System.out.println("Client's message: "); webs.handler(new Handler() { @Override public void handle(Buffer event) { System.out.println("Received data " + event.toString("ISO-8859-1")); } }); } }); server.listen(8080, "localhost", res -> { if (res.succeeded()) { System.out.println("Server is now listening!"); } else { System.out.println("Failed to bind!"); } }); } }
Через этот интерфейс и метод handle происходит прием сообщений:
@Override public void handle(Buffer event) { System.out.println("Received data " + event.toString("ISO-8859-1")); }
Как я понимаю, нужно туда вкрутить отправщика и поставить какое-то условия, чтобы в случае если сообщение пришло, он высылал его в ответ. Однако я не совсем понимаю как это сделать=(


Ответ

Поковырявшись и потыкав,обнаружил простой метод, благодаря которому можно слать ответы с сервера. Таким образом, метод handle перепишется следующим образом:
public void handle(Buffer event) { System.out.println("Received data: " + event.toString("ISO-8859-1")); webs.writeFinalTextFrame("echo:"+event.toString("ISO-8859-1"));

Создание кнопки на панели в Хром

Подскажите как создать кнопку на панели в хроме? Она должна по клику открывать ссылку в новой вкладке.

Открыть в новой вкладке


Ответ

Чтобы все было ясно, приведу небольшой работающий пример, который помогает реализовать задачу указанную в вопросе.
Создание расширения процесс достаточно простой и понятный. Разумеется для создания сложных расширений требуется более серьезное знание JavaScript.
И так, наше расширение должно уметь открывать в новой вкладке страницу по нажатии на иконку.
Для начала создаем манифест файл, который содержит в себе все необходимые данные о расширении. Файл должен называться manifest.json. Вот его содерживое.
{ "name": "HTML5", "version": "1", "manifest_version": 2, "icons": { "128": "128.png" }, "browser_action": { "default_title": "Нажмите на иконку HTML5", "default_icon" : "128.png" }, "permissions": ["tabs"], "background":{ "scripts": ["background.js"] } }
name - название нашего расширения для Google Chrome. Под этим именен он будет показываться в списке расширений.
version - версия расширения. Указывается на усмотрение разработчика, но в соотвествии с определенными общепринятыми правилами. Об этом можно отдельно почитать тут
manifest_version - версия нашего манифеста. Это значение фиксированное и его менять не надо.
icons - главная иконка нашего расширения размером 128 на 128. Формат файла - png
browser_action - координирует взаимодействие работы с браузером.
default_title - текст, всплывающий при наведении курсора на иконку.
default_icon - иконка для панели расширений (собственно на нее мы будем нажимать чтобы перейти по ссылке)
permissions - указываем действия, на которые наше расширение должно получить доступ. В нашему случае это возможность работать с ТАБ-ами.
background - указываем данные для фоновой страницы. Какие страницы, скрипты итд загружать в фоновом режиме. Мы лишь указываем на файл background.js.
При нажатии на иконку расширения, в фоновом режиме запустится и исполнится код, который лежит в background.js
Содержание файла background.js:
chrome.browserAction.onClicked.addListener(function(activeTab){
chrome.tabs.create({ url: "https://www.w3.org/html/logo/" }); });
Создаем папку и копируем в нее все три файла: manifest.json, background.js, 128.png

Далее переходим в Google Chrome во вкладку Расширения (Extensions) и нажимаем на кнопку "Загрузить распакованное расширение" (Load unpacked extension). Указываем на нашу папку (которая содержит три файла) и расширение будет установлено.

Иконка появится там где ее ждут :-). Кликаем и переходим на нужный адрес.

Невожможно выбрать модификатор доступа класса

Здравствуйте, столкнулся с проблемой следующего рода: есть public класс. При попытке создать наследника с модификатором отличным от public пишет
"modifier ... not allowed here".
Почитал в интернете нашел, что класс наследник может иметь уровень доступа такой же или "шире" чем родителя. При создании третего класса, который не являеться чьим-либо наследником, пишет
"modifier ... not allowed here"
при private. При модификаторе public понятно (в одном java - файле может быть только один private), protected мне не нужен - наследников не будет. Все классы находятся в одном пекедже и одном файле (программа ведь учебная и небольшая). Проблемы нету только с package модификатором.
Объясните, пожалуйста, что не так.
package Animals;
public class Bird {
public static void main(String[] args) { } }
class Parrot extends Bird { }
private class Cat { }


Ответ

Смотрите. В таком виде private или protected классы Parrot и Cat были бы недоступны никому, даже методу main в классе Bird
Без указания конкретного модификатора классы будут иметь package-видимость, то есть видимы для всех в пределах пакета Animals (кстати, пакеты именуют с маленькой буквы).
Для внутренних (inner) классов задание видимости уже имеет смысл: они могут являться деталями реализации внешнего класса, о которых не нужно знать окружающему миру. Т.е. такой код скомпилируется:
public class Bird { private class Cat { }
public static void main(String[] args) { } }
Этот прием достаточно широко используется в классах, входящих в JDK. Например, список LinkedList не показывает наружу деталь реализации - класс узла списка LinkedList.Node, поэтому объявляет его так:
public class LinkedList extends AbstractSequentialList implements List, Deque, Cloneable, java.io.Serializable { private static class Node { ... } }

Как отправить HTTP запрос из Android-приложения?

Что не так с этим кодом?
import java.io.*; import java.net.*;
...
URL url = new URL(e.getText().toString()); HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); InputStream in = new BufferedInputStream(urlConnection.getInputStream());
Если закомментировать последнюю строку, то ничего не происходит. Если же её оставить, то приложение компилируется, но во время выполнения выскакивает сообщение
В приложении "ХХХ" произошла ошибка
и оно аварийно закрывается.


Ответ

Запрос отправляется при вызове getInputStream();
Скорее всего, ошибка, которую вы видите говорит вам о том, что вы делаете HTTP запрос в главном потоке Android приложения (если это не так, дополните вопрос).
Интернет запросам свойственно занимать много времени, а главный поток предназначен прежде всего для обработки и отображения пользовательского интерфейса, который должен реагировать на действия пользователя быстро. Поэтому, необходимо создать новый поток:
Thread t = new Thread(new Runnable(){ public void run(){ //Ваш код для запроса } }).start();
Или, вы можете использовать AsyncTask. Подробнее о нем и вообще о потоках тут: https://habrahabr.ru/post/124484/
Учтите, что Вы не сможете ничего делать с элементами интерфейса не из главного потока. Для того, чтобы выполнить код в главном потоке, используйте Activity.runOnUiThread

Инициализация статического члена в main

Как инициализировать неконстантный статический член класса до создания экземпляра класса в функции main?
Например:
class A { protected: static int x; A(){} public: }; class B: public A { };
int main() { // нужно инициализировать x здесь B b; }


Ответ

Добавьте статическую функцию, которая будет присваивать значение x и вызывайте её:
class A { protected: static int _x; A() {} public: static void InitX(int x) { _x = x; } };
В main
int main() { A::InitX(5); B b; }
Если нужна именно инициализация, то Вы не можете контролировать то, когда она будет выполнена, но она обязательно будет выполнена до main.
В Вашем коде, кстати, как раз не хватает инициализации, а без неё код не соберётся. Добавьте в глобальной области видимости следующее:
int A::x = 0;

Как повернуть группу точек в 2D относительно произвольной точки?

Попробовал сделать по формулам :
И так как поворачивать нужно относительно произвольной точки, то от x и y предварительно отнимается расстояние этой точки от начала координат, а затем добавляется. Вот код(С++) :
void rotate(int &x, int &y, const double &cosVal, const double &sinVal, const int &cx = 0, const int &cy = 0) { const double _x = x - cx; const double _y = y - cy; x = round( _x * cosVal - _y * sinVal); y = round( _x * sinVal + _y * cosVal); x += cx; y += cy; }
Но получается вот это (точка относительно которой крутится - центр треугольника) :
(гифка записана с момента когда треугольник уже начал деформироваться и "уезжать" от своего центра).


Ответ

Вы работаете с математикой с плавающей точкой, при этом используя переменные типа int! Естественно, [накапливающиеся] ошибки округления дают совершенно нелепые результаты!
Используйте для координат переменные типа double, а в int их переводите только для вывода графики (и то можно неявно...)
void rotate(int &x, int &y, const double &cosVal, const double &sinVal, const int &cx = 0, const int &cy = 0)
должна превратиться в
void rotate(double &x, double &y, double cosVal, double sinVal, double cx = 0.0, double cy = 0.0)

Как отправить данные в уже запущенный Service?

Как отправить данные в уже работающий сервис?
activity_main.xml




MainActivity.java
package com.example.my.myapplication; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle;
import android.view.View; import android.widget.EditText;
public class MainActivity extends Activity {
public final static String BROADCAST_ACTION = "com.example.my.myapplication";
BroadcastReceiver br; EditText EditText1; EditText EditText2;
/** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
EditText1 = (EditText) findViewById(R.id.editText1); EditText2 = (EditText) findViewById(R.id.editText2);
// создаем BroadcastReceiver br = new BroadcastReceiver() { // действия при получении сообщений public void onReceive(Context context, Intent intent) { int result = intent.getIntExtra("result", 0); String re = Integer.toString(result); EditText2.setText(re); } }; // создаем фильтр для BroadcastReceiver IntentFilter intFilt = new IntentFilter(BROADCAST_ACTION); // регистрируем (включаем) BroadcastReceiver registerReceiver(br, intFilt);
Intent intent;
// Создаем Intent для вызова сервиса, // кладем туда параметр времени и код задачи int s = Integer.parseInt(EditText1.getText().toString()); intent = new Intent(this, MyService.class).putExtra("time", s); intent.putExtra("time", s); // стартуем сервис startService(intent); }
@Override protected void onDestroy() { super.onDestroy(); // дерегистрируем (выключаем) BroadcastReceiver unregisterReceiver(br); }
public void onClickStart(View v) { Intent intent; int s = Integer.parseInt(EditText1.getText().toString()); intent = new Intent(this, MyService.class).putExtra("time", s); intent.putExtra("time", s); }
}
MyService.java
package com.example.my.myapplication;
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import android.app.Service; import android.content.Intent; import android.os.IBinder;
public class MyService extends Service {
ExecutorService es;
public void onCreate() { super.onCreate(); es = Executors.newFixedThreadPool(1); }
public void onDestroy() { super.onDestroy(); }
public int onStartCommand(Intent intent, int flags, int startId) {
int time = intent.getIntExtra("time", 1); MyRun mr = new MyRun(startId, time); es.execute(mr);
return super.onStartCommand(intent, flags, startId); }
public IBinder onBind(Intent arg0) { return null; }
class MyRun implements Runnable {
int time; int startId;
public MyRun(int startId, int time) { this.time = time; this.startId = startId; }
public void run() { Intent intent = new Intent(MainActivity.BROADCAST_ACTION); while (true) { try { // начинаем выполнение задачи TimeUnit.SECONDS.sleep(time); // сообщаем об окончании задачи intent.putExtra("result", time * 100); sendBroadcast(intent); } catch (InterruptedException e) { e.printStackTrace(); } } // stop(); }
void stop() { stopSelfResult(startId); } } }
Что я хочу от приложения: при запуске стартует сервис, ему отправляется число. Он это число умножает на 100 и отправляет результат в активити во второе текстовое поле (причём продолжает работать дальше). Далее я хочу отправить сервису новое число, не останавливая его работу, ввожу новое число в первое тестовое поле, и при нажатии на кнопку надо отправить сервису это число. А он должен его также умножить на 100 и отправить обратно в активити в первое текстовое поле. Не могу разобраться, как передавать данные уже запущенному сервису. Подскажите.


Ответ

Запущенный сервис будет работать пока у него не вызван stopSelf(). Передавать данные в сервис можно так же с помощью startService(intent), новый сервис запускаться при этом не будет, а у запущенного сервиса будет вызван onStartCommand
Таким образом, вам надо убрать бесконечный цикл из MyRun.run(), реализовать логику ваших умножений, убрать stopSelfResult из MyRun.stop() и добавить startService(intent); в onClickStart вашей активити.
Чтобы таки потом остановить сервис, запустите его с другим intent'ом, в onStartCommand обработайте его: остановите ваш пул или подождите пока он не отработает (см. тут). Затем вызовите stopSelf

Python. Перевести байт-код в человекочитаемый вид в элементе списка

Изначально имеется строка
>>> string = '50.6,383,149,1.9,786, 4 -4, [Ne]3s²3p², DIA,5.43'
которая была разбита в лист по разделителю ","
>>> print(re.split(r',', string)) ['50.6', '383', '149', '1.9', '786', ' 4 -4', ' [Ne]3s\xc2\xb23p\xc2\xb2', ' DIA', '5.43']
Элемент [Ne]3s²3p² был переведен в байт код '[Ne]3s\xc2\xb23p\xc2\xb2'.
Его можно успешно принтовать в человеческом виде
>>> print('[Ne]3s\xc2\xb23p\xc2\xb2'.decode('utf-8')) [Ne]3s²3p²
А вот возможно перевести его в человекочитаемый вид и вписать обратно в список?


Ответ

У вас не байт-код (содержимое *.pyc файлов), а просто текстовое представление объекта типа str в Питоне, возвращаемое функцией repr()
Вы его видите, потому что по умолчанию при печати списка в Питоне вызывается repr() для каждого элемента списка.
Если вы хотите другой результат, то форматируйте список, возвращаемый функцией re.split() самостоятельно, например, чтобы напечатать каждый элемент списка на отдельной строчке:
for элемент in ваш_список: print(элемент)

Дополнительно, результат намекает что вы используете Питон 2. В этом случае, либо добавьте на самом верху from __future__ import unicode_literals или явно используйте u"" префикс, чтобы создать Юникодную строчку (из константы в исходном коде) вместо использования байт, иначе вы можете кракозябы получить при печати

Как получить файл (кириллица в имени) с FTP?

Python 3.5, ftplib
В каком виде ftp.nlst() получает имена файлов? И как их привести к нормальному виду?
filelist = ftp.nlst() - получаем список имен файлов print (filelist[3]) - выводим имя 4-ого файла и получаем иероглифы
@jfs >>> print(ascii(filelist[6])) '\xc8\xed\xf1\xf2\xf0\xf3\xea\xf6\xe8\xff.pdf'
Спасибо за подробный ответ)


Ответ

Изначально (RFC 765, 959), FTP только 7-бит ASCII поддерживал, RFC 2640 расширяет поддержку до других кодировок, RFC 3659 уточняет, что команды такие как MLST могут вернуть пути либо в UTF-8 кодировке, либо это может быть произвольная каша байтов—за некоторыми исключениями такими как CRLF (новая строка, b'\x0d\x0a'), одинокий Telnet IAC (b'\xff').
На POSIX имена файлов могут быть произвольной последовательностью байтов за исключением b'\x2f' и b\x00' (слэш и ноль).
В Питоне 3, ftplib формально использует latin-1 кодировку по умолчанию, которая произвольную последовательность байт позволяет в Unicode декодировать.
В: В каком виде ftp.nlst() получает имена файлов?
ftp.nlst() возвращает список текстовых (Unicode) строк.
В: И как их привести к нормальному виду?
Если вы знаете, что сервер использует единственную кодировку для имён файлов в вашем случае (вероятно, utf-8, если вывод команды feat её показывает) и нет непредставимых имён (PEP 383), то правильные имена можно получить декодированием:
filename = filename.encode(ftp.encoding).decode(your_encoding)
Можно передать 'surrogateescape' обработчик ошибок в .decode(), чтобы поддерживать и непредставимые имена (чтобы была возможность без потерь восстановить изначальные байты, одновременно позволяя печатать представимые имена в «нормальном виде»).

Судя по результату ascii(), в вашем случае ftp-сервер возвращает имена в cp1251 кодировке (ANSI codepage на русской Винде):
>>> print(ascii(filelist[6])) '\xc8\xed\xf1\xf2\xf0\xf3\xea\xf6\xe8\xff'
В этом случае, your_encoding='cp1251', чтобы получить исходное имя:
filename = filelist[6].encode(ftp.encoding).decode('cp1251') # -> 'Инструкция'
Чтобы зря не перекодировать, можно перед вызовом ftp.nlst() выставить ftp.encoding = 'cp1251', если известно что все имена файлов в этой кодировке представимы. Тогда ftp.nlst() сразу вернёт правильно декодированные имена.

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

Можно ли как-то сделать так (как-то настроить shell), что бы можно было в терминале набирать выражения вида a * b, a + b, a - b, a / c, где a и b- числа, и что бы это выражение вычислялось?
Т.е. что бы можно было делать вот так:
dzmitry@mycomp:~$ 12 * 45
А не запуская, например, питон:
dzmitry@mycomp:~$ py Python 3.4.3 (default, Oct 14 2015, 20:28:29) [GCC 4.8.4] on linux Type "help", "copyright", "credits" or "license" for more information. >>> 12 * 45 540 >>>
Т.е. я не пользуюсь калькулятором, а использую командную оболочку с запущенным питоном, и хочу использовать командную оболочку как калькулятор, минимизируя промежуточные шаги


Ответ

Можно ли как-то сделать так (как-то настроить shell)
увы, «настроить» невозможно. оболочка предназначена для выполнения команд, а не для вычисления арифметических выражений.
для таких вычислений нужна специализированная на этом программа. например (из самых распространённых) bc, dc и т.п.
bc
по умолчанию округляет результат до целых чисел. с помощью команды scale=число можно задать количество знаков после запятой. чтобы каждый раз не вводить эту команду, имеет смысл записать её в конфигурационный файл ~/.bcrc
dc
в этом калькуляторе используется обратная польская нотация и, соответственно, стек. пример:
5 k #задать количество знаков после запятой 2 3 / p # поместить в стек 2 и 3, выполнить деление /, напечатать верхушку стека p .66666 # это результат

Слияние веток в Git-е: непонятный конфликт строк

Всем доброго времени суток.
Изучаю Git. Использую гуй SourceTree. Репозиторий лежит на BitBucket. Создал два аккаунта, чтоб воспроизвести совместную разработку. Когда делаю слияние изменений в одной ветке - в блок HEAD помещается только конфликтные строки. Когда делаю слияние изменений из разных веток - в этот блок попадают все строки.
Например, два автора меняют одну и ту же строку в файле index.php в ветке master. Мой воображаемый "напарник" успешно пушит свои изменения. А вот я уже должен выполнить слияние, перед тем как отправить свои изменения. Делаю пул. Файл принимает следующее состояние:
<<<<<<< HEAD echo "This is my master branch"; ======= echo "This is test branch"; >>>>>>> 18baca2cbbf6685dbe946554f436312e93bd4ff3 exit();
// I don't have new ideas... (((
Тут всё понятно. Строка echo... является конфликтной и я самостоятельно решаю что мне с ней сделать. А теперь представим тот же файл index.php, но из разных веток. Отличия между ними лишь в том, что в ветке test появляется две строки: одна из них пустая, а вторая содержит комментарий. Как мне подумалось, слияние должно вообще пройти без проблем в автоматическом режиме, ведь нет никаких разных изменений в одной и той же строке. Однако, здравствуйте. Содержимое файла index.php при попытке слияния:
<<<<<<< HEAD echo "This is master branch"; exit();
// I don't have new ideas... ((( ======= // This is my test branch
echo "This is master branch"; exit();
// I don't have new ideas... ((( >>>>>>> test
И в конце файла ещё одна пустая строка (после строки >>>>>>> test).
На этом моменте я завис. Не могу понять откуда вообще появились конфликтные строки. Их быть не должно. Ведь в тесте всего лишь 2 новые строки, не более. Кто может мне объяснить, где я чего не понял? Это так и должно быть, или я, криворукий, где-то допустил ошибку, которая приводит к такому результату?
Заранее благодарю за помощь. С уважением, Юрий.


Ответ

Если у двух строк разные окончания - то они считаются гитом различными. Поэтому важно правильно договариваться об окончаниях строк внутри команды.
Также есть вариант принудительно настроить окончания строк для репозитория, это делается в файле .gitattributes
Пример настройки в этом файле:
*.cs text eol=crlf
Здесь написано, что все файлы с расширением .cs надо считать текстовыми, хранить в репозитории с LF окончаниями строк - а в рабочей копии загружать с окончанием строк CRLF.
Или вот другой пример:
*.xml text eol=lf
Здесь во всех xml-файлах окончания строк всегда будут LF.

Немного о том, что вообще такое "окончания строк". Окончание строки - это набор невидимых символов, которые отделяют в файле одну строку от другой. Исторически, имеется два разных символа, которые пришли к нам еще с пишущих машинок и телетайпов:
CR - возврат каретки, этот символ возвращал каретку в начало текущей строки LF - перевод строки, этот символ переводил каретку к следующей строке, не смещая ее
Для электрических печатных машинок или матричных принтеров это были две разные команды (а у машинок - еще и две разные кнопки). Но когда встала задача обработки текстов на компьютере, два разных символа оказалось избыточно, поэтому некоторые системы пошли по пути упрощения.
В современном UNIX-мире сейчас принято разделение строк при помощи одного символа LF, на старых маках использовался символ CR - ну а DOS и потом винда остались на CRLF.
Тем не менее, все нормальные текстовые редакторы сейчас уже умеют автоматически определять окончания строк или даже работать со смешанными окончаниями строк в одном файле - поэтому вы про них ничего и не знали.
Но git работает не с текстом, а с байтами - поэтому в гите важно приводить окончания строк для файла к одному виду.

Проброс реального ip-адреса в виртуальную машину за nat

Есть вэб-сервер на виртуальной машине.
Нужно сделать так, чтобы весь трафик по 80 и 443 портам заворачивался на эту виртуальную машину без подмены ip-адреса клиента.
Мой iptables:
iptables -F iptables -t nat -F iptables -t mangle -F iptables -X
iptables -t nat -A POSTROUTING -s 192.168.0.0/16 -o vmbr0 -j SNAT --to-source 'x.x.x.x iptables -t nat -A POSTROUTING -o vmbr1 -j SNAT --to-source 192.168.0.1
iptables -t nat -I PREROUTING -p udp -m udp --dport 60000:61000 -j DNAT --to 192.168.0.200:60000-61000
iptables -A PREROUTING -t nat -i vmbr0 -p tcp -d 'x.x.x.x --dport 18180 -j DNAT --to 192.168.0.200:22 iptables -A PREROUTING -t nat -i vmbr0 -p tcp -d 'x.x.x.x --dport 17172 -j DNAT --to 192.168.0.102:22 iptables -A PREROUTING -t nat -i vmbr0 -p tcp -d 'x.x.x.x --dport 17171 -j DNAT --to 192.168.0.101:22 iptables -A PREROUTING -t nat -i vmbr0 -p tcp -d 'x.x.x.x --dport 3000 -j DNAT --to 192.168.0.101:3000 iptables -A PREROUTING -t nat -i vmbr0 -p tcp -d 'x.x.x.x --dport 443 -j DNAT --to 192.168.0.200:443 iptables -A PREROUTING -t nat -i vmbr0 -p tcp -d 'x.x.x.x --dport 80 -j DNAT --to 192.168.0.1:80
iptables -A PREROUTING -t nat -i vmbr0 -p tcp -s y.y.y.y -d 'x.x.x.x --dport 8080 -j DNAT --to 192.168.0.102:80 iptables -A PREROUTING -t nat -i vmbr0 -p tcp -s y.y.y.y -d 'x.x.x.x --dport 8081 -j DNAT --to 192.168.0.102:8081
iptables -A INPUT -p TCP --dport 80 -j ACCEPT iptables -A OUTPUT -p TCP --dport 80 -j ACCEPT iptables -A INPUT -p TCP --dport 443 -j ACCEPT iptables -A OUTPUT -p TCP --dport 443 -j ACCEPT
iptables -A INPUT -s y.y.y.y -j ACCEPT iptables -A INPUT -i lo -j ACCEPT iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT #iptables -I INPUT 1 -p udp --dport 60000:61000 -j ACCEPT #iptables -A INPUT -p icmp --icmp-type echo-request -j REJECT --reject-with icmp-host-prohibited iptables -P INPUT DROP


Ответ

как я понял, подразумевается трафик, приходящий на интерфейс vmbr0 на адрес x.x.x.x
вот эти правила надо «привести к общему знаменателю»:
iptables -A PREROUTING -t nat -i vmbr0 -p tcp -d 'x.x.x.x --dport 443 -j DNAT --to 192.168.0.200:443 iptables -A PREROUTING -t nat -i vmbr0 -p tcp -d 'x.x.x.x --dport 80 -j DNAT --to 192.168.0.1:80
если целевая виртуальная машина имеет ip-адрес 192.168.0.200, то и во втором правиле должен фигурировать этот ip-адрес. а это правило надо убрать:
iptables -t nat -A POSTROUTING -o vmbr1 -j SNAT --to-source 192.168.0.1 на целевой виртуальной машине шлюзом по умолчанию должен быть назначен ip-адрес, который присвоен сетевому интерфейсу (на машине, правила netfilter-а которой приведены в вопросе), «смотрящему» в локальную сеть. насколько я понял — 192.168.0.1

ORDER BY по INTEGER, но представить, что отрицательные числа больше положительных

Здравствуйте! Как составить такой запрос, чтобы сначала шли положительные числа по возрастанию, а потом все отрицательные? (В моей таблице только -1, другие отрицательные числа не нужны)
Например, для ряда 4, 3, 5, -1, 8, 2, -1 ORDER BY по столбцу с числами выведет строки, упорядочив их таким образом: -1, -1, 2, 3, 4, 5, 8, а хотелось бы 2, 3, 4, 5, 8, -1, -1, это возможно?


Ответ

select id from table order by case when id>0 then 0 else 1 end, id

Проблема с дополнительным шрифтом

Я указываю шрифт для кнопки a_Simpler
Если это шрифт не добавлен в библиотеку шрифтов:

То она пишет обычным шрифтом Microsoft Sans Serif
Можно ли сохранить шрифт a_Simpler вместе с .exe? или как решить проблему?


Ответ

Компиляция из ответов на en.SO:
Трюк состоит в том, чтобы положить шрифт в глобальную PrivateFontCollection, и использовать его оттуда. (Саму коллекцию, судя по всему, нужно положить в главный класс приложения или другое общедоступное место.)
Если он уже там у вас есть, и коллекция определена как PrivateFontCollection pfc, используйте такую конструкцию:
b.Font = new Font(pfc.Families[0], <тут указываете размер>);
Ещё нужно установить в свойствах UI-элемента UseCompatibleTextRendering в true
Вместо индекса 0 может понадобиться другой, если вы кладёте в коллекцию несколько шрифтов.

Как можно добавить шрифт в коллекцию? Для этого используются методы AddFontFile и AddMemoryFont. Если вы таскаете шрифт в файле, то всё совсем просто: pfc.AddFontFile(<тут путь к вашему файлу со шрифтом>);
Если вы решили положить шрифт в ресурсы, понадобится более сложный код.
var fontdata = Properties.Resources.Simpler; // Simpler - имя, которое вы дали шрифту var length = fontdata.Length; // в ресурсах var unsafeData = Marshal.AllocCoTaskMem(length); Marshal.Copy(fontdata, 0, unsafeData, length); pfc.AddMemoryFont(unsafeData, length); Marshal.FreeCoTaskMem(unsafeData);

Источники: [1], [2], [3], [4]

Создание таймера до момента во времени [закрыт]

Помогите создать таймер, вот с таким дизайном:

Кода на JavaScript нету, поскольку, я не знаю этого языка. Проект большой, могу только скрин выложить. Не хватает только этого таймера.
function startTimer() { var my_timer = document.getElementById("my_timer"); var time = my_timer.innerHTML; var arr = time.split(":"); var h = arr[0]; var m = arr[1]; var s = arr[2]; if (s == 0) { if (m == 0) { if (h == 0) { alert("Время вышло"); window.location.reload(); return; } h--; m = 60; if (h < 10) h = "0" + h; } m--; if (m < 10) m = "0" + m; s = 59; } else s--; if (s < 10) s = "0" + s; document.getElementById("my_timer").innerHTML = h + ":" + m + ":" + s; setTimeout(startTimer, 1000); }

15:48:27



Ответ

В принципе можно так:
function timer() { time_rest = ((time_rest < 0) ? 0: time_rest - 1); var hours = Math.floor(time_rest / 3600); var minutes = Math.floor((time_rest - (hours * 3600)) / 60); var seconds = Math.floor((time_rest - ((hours * 3600) + (minutes * 60)))); if(hours < 10) { hours = "0" + hours; } if(minutes < 10) { minutes = "0" + minutes; } if(seconds < 10) { seconds = "0" + seconds; } document.getElementsByClassName("hours")[0].innerHTML = hours; document.getElementsByClassName("minutes")[0].innerHTML = minutes; document.getElementsByClassName("seconds")[0].innerHTML = seconds; if(time_rest == 0) { //location.reload(); // обновляем страницу, если время вышло (скрыл для теста) } } var time_now = new Date().getTime() / 1000; // текущее время в формате timestamp var time_to = new Date("21 June 2016 22:33:44").getTime() / 1000; // финальное время в формате timestamp var time_rest = Math.floor(time_to - time_now); // сколько осталось секунд до финального времени в формату timestamp // делим на 1000, т.к. ответит приходит в миллисекундах timer(); setInterval(function() { timer(); }, 1000); .timer { width: 300px; text-align: center; color: #98001A; font-size: 30px; font-family: Arial; } .timer .title { font-size: 15px; color: #000; } .timer .hours, .timer .minutes, .timer .seconds { display: inline; padding: 1.6px; } .timer .colon { display: inline; }

До конца акции осталось:
00
:
00
:
00

Как в регулярном выражении исключить слово?

Я знаю про x(?!y) - находит x, только если за x не следует y. Но мне нужно исключать слово вне зависимости от того где оно стоит.
Найти букву А но исключить такие слова: арбуз, абандон и т.д.


Ответ

Относительно
Найти букву А но исключить такие слова: арбуз, абандон и т.д.
В Notepad++ используйте захватывающую подмаску с чередованиями и условный шаблон замены:
(\b(?:арбуз|абандон)\w*)|а
Заменить на
(?1$1:я)
Т.е. с помощью (\b(?:арбуз|абандон)\w*)|а мы найдем и сохраним все слова исключения (с окончаниями или без с помощью \w*) в группе №1, и при совпадении эти слова будут восстановлены в тексте с помощью ?1$1 (если первая подмаска найдена, восстанавливаем), а буква а будет изменена/удалена во всех остальных случаях (:я).
Относительно использования параметра Match case решайте сами.

Entity Framework. таблица ссылающаяся на себя

Коллеги, помогите пожалуйста.
EF, Code First. Есть таблица, в которой я хочу хранить генеалогическую информацию о лошадях (ссылки на мать и отца, если они известны). Насколько я это себе представляю, каждая запись таблицы может содержать от 0 до 2 внешних ключей, ссылающихся на первичный ключ другой записи этой же таблицы.
1. Для меня проще использовать DataAnnotations, поэтому начал я так
public class Horse { public int Id { get; set; }
[ForeignKey("Father")] public int? FatherId { get; set; } public virtual Horse Father { get; set; }
[ForeignKey("Mother")] public int? MotherId { get; set; } public virtual Horse Mother { get; set; } }
Во время создания миграции получаю ошибку. Horse_Mother_Target: : Multiplicity is not valid in Role 'Horse_Mother_Target' in relationship 'Horse_Mother'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.. Тут я не понял проблемы, поясните пожалуйста что не так?
2. Добавляю к классу св-во Children, описывающее вторую сторону связи.
public class Horse { public int Id { get; set; }
[ForeignKey("Father")] public int? FatherId { get; set; } public virtual Horse Father { get; set; }
[ForeignKey("Mother")] public int? MotherId { get; set; } public virtual Horse Mother { get; set; }
public virtual ICollection Children { get; set; } }
Миграция создается без ошибок, но выглядит так:
AddColumn("dbo.Horses", "Horse_Id", c => c.Int()); CreateIndex("dbo.Horses", "FatherId"); CreateIndex("dbo.Horses", "MotherId"); CreateIndex("dbo.Horses", "Horse_Id"); AddForeignKey("dbo.Horses", "Horse_Id", "dbo.Horses", "Id"); AddForeignKey("dbo.Horses", "FatherId", "dbo.Horses", "Id"); AddForeignKey("dbo.Horses", "MotherId", "dbo.Horses", "Id");
Два требуемых внешних ключа создались, смотрят куда надо, однако что это за столбец Horse_Idи почему он автоматически генерируется, непонятно...
3. Решил попробовать FluentApi. Убрал DataAnnotations в классе, написал такое:
modelBuilder.Entity() .HasOptional(h => h.Father) .WithMany(x => x.Children) .HasForeignKey(x => x.FatherId) .WillCascadeOnDelete(false);
modelBuilder.Entity() .HasOptional(h => h.Mother) .WithMany(x => x.Children) .HasForeignKey(x => x.MotherId) .WillCascadeOnDelete(false);
По смыслу похоже на правду. По итогу получил следующую ошибку: Sequence contains no matching element. Тут вообще никаких мыслей нет, что произошло...
4. Решил попробовать создать только 1 внешний ключ. Убрал кусок, связанный с MotherId (DataAnnotations выкинул еще до этого), оставил только
modelBuilder.Entity() .HasOptional(h => h.Father) .WithMany(x => x.Children) .HasForeignKey(x => x.FatherId)
И неожиданно получил миграцию, которую хотел увидеть изначально:
CreateIndex("dbo.Horses", "FatherId"); CreateIndex("dbo.Horses", "MotherId"); AddForeignKey("dbo.Horses", "FatherId", "dbo.Horses", "Id"); AddForeignKey("dbo.Horses", "MotherId", "dbo.Horses", "Id");
После таких приключений я окончательно запутался. Прошу, поясните по пунктам, где именно я некорректно прописывал требования к EF и как это надо было делать правильно. Как следует конфигурировать связи в общем случае, когда в одной таблице 2 и более внешних ключа, указывающих на одну и ту же таблицу.


Ответ

Ваша проблема - в соответствии между навигационными свойствами. Свойства, ведущие в две стороны, идут парами. Вы разбиение на пары не указывали - отсюда и странности.
Ваша первая попытка сделала два свойства - Father и Mother - встречными друг другу (они стали такими автоматически). Разумеется, это глупо и даже сама EF это поняла, о чем и сказала, пусть и в такой странной манере:
Horse <-> Horse ----------------- Father <-> Mother
Во втором варианте EF не смогла объединить свойства в пары - и они стали независимыми:
Horse <-> Horse ------------------- Father -> Mother -> <- Children
В третьем варианте вы попробовали сопоставить свойство Children два раза. EF так не умеет:
Horse <-> Horse ------------------- Father <-> Children Mother <-> Children
В четвертом варианте вам только кажется что все правильно. На самом деле вы сопоставили Father и Children, а Mother осталась без пары:
Horse <-> Horse ------------------- Father <-> Children Mother ->

Теперь как делать правильно. Способ первый. Отказываемся от общего свойства Children:
class Horse { // ...
public virtual Horse Father { get; set; } public virtual Horse Mother { get; set; } [InverseProperty("Father")] public virtual ICollection FatherChildren { get; set; } [InverseProperty("Mother")] public virtual ICollection MotherChildren { get; set; } }
Более красивый способ - использовать отдельный класс-связку:
class Horse { // ...
public virtual ICollection Parents { get; set; } public virtual ICollection Children { get; set; } }
class HorseParent { public int ParentId { get; set; }
[Key, Column(Order = 0)] public int ChildId { get; set; }
[Key, Column(Order = 1)] public bool IsFather { get; set; }
[ForeignKey("ParentId"), InverseProperty("Children")] public virtual Horse Parent { get; set; }
[ForeignKey("ChildId"), InverseProperty("Parents")] public virtual Horse Child { get; set; } }
Здесь я использовал составной первичный ключ для того, чтобы ограничить число родителей.
PS если у вас возникает проблема с каскадным удалением - уберите конвенцию OneToManyCascadeDeleteConvention из ModelBuilder или переходите c DataAnnotations на FluentApi.

Но это еще не идеал. Дело в том, что в текущем виде лошадь может быть одновременно отцом для одного ребенка и матерью - для другого. Этого можно избежать путем включения пола в первичный ключ:
class Horse { [Key, Column(Order = 0)] public int Id { get; set; }
[Key, Column(Order = 1)] public bool IsMale { get; set; }
public virtual ICollection Parents { get; set; } public virtual ICollection Children { get; set; } }
class HorseParent { [Key, Column(Order = 0)] public int ChildId { get; set; } [Column(Order = 1)] public bool IsChildMale { get; set; } // Не нужно семантически, но нужно для внешнего ключа
[Column(Order = 2)] public int ParentId { get; set; } [Key, Column(Order = 3)] public bool IsFather { get; set; }
public virtual Horse Parent { get; set; } public virtual Horse Child { get; set; } }
protected override void OnModelCreating(DbModelBuilder b) { b.Conventions.Remove();
b.Entity().HasMany(h => h.Parents).WithRequired(h => h.Child) .HasForeignKey(p => new { p.ChildId, p.IsChildMale }); b.Entity().HasMany(h => h.Children).WithRequired(h => h.Parent) .HasForeignKey(p => new { p.ParentId, p.IsFather });
b.Entity(); }
Теперь сама СУБД будет отслеживать, что пол родителя соответствует его роли, а родители каждой лошади - разнополые.

c# сделать функцию параметром функции

Есть множество функций типа flipImageV. До и после кода в этих функциях должны быть одинаковые строки кода. Что бы в каждой функции типа flipImageV их не писать, хочу сделать одну, куда буду передавать нужную функцию на выполнение...
Вот универсальная функция, куда передаю выбранную функцию типа flipImageV:
protected void editImage(delegate func) { currentImage.ImageUrl = @"..\images\img0.jpg"; func(); photo.Save(@"~\" + imagePath); }
Функция типа flipImageV:
protected void flipImageV(object sender, EventArgs e) { photo.FlipVertical(); }
Использование того шаблона:
editImage(flipImageV);
или
protected void flipImageV(object sender, EventArgs e) { editImage(photo.FlipVertical()); }
Что должно быть вместо delegate func? Как это лучше сделать?


Ответ

Используйте просто Action
protected void editImage(Action func) { currentImage.ImageUrl = @"..\images\img0.jpg"; func(); photo.Save(@"~\" + imagePath); }
Вызывать как-то так:
editImage(() => photo.FlipVertical());

Если вам нужно непременно передавать внутрь функцию наподобие flipImageV, которая получает два игнорируемых аргумента, можно так:
editImage(() => flipImageV(null, EventArgs.Empty));

C# рефлексия. Получение значения приватного поля экземпляра класса?

Есть экземпляр класса Class1, каким образом можно получить его aValue поле? Вопрос крайне глупый, понимаю... и все же. Получается получить только статические поля, а для экземпляров как быть?
public class Class1{
private int aValue; public Class1(int a){ this.aValue = a; } }
Class1 cls = new Class1(10);


Ответ

Нужно указать маску:
Class1 cls = new Class1(10); FieldInfo fieldInfo = typeof(Class1).GetField("aValue", BindingFlags.Instance | BindingFlags.NonPublic); int a = (int)fieldInfo.GetValue(cls);

Пользователи на смартфоне

Можно ли как-нибудь получить доступ к пользователям смартфона(либо создать новый)?


Ответ

Для получения данных о пользователях устройства (не путать с аккаунтами на устройстве) вы можете использовать UserManager(доступен с API 17)
UserManager um = (UserManager) context.getSystemService(USER_SERVICE); List userHandles = um.getUserProfiles(); //метод доступен с API 21
Возможно, для работы с этим классом нужно разрешение

Которое, к сожалению, доступно только для системмных приложений.

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

Доброго времени суток. NetBeans при компиляции запускает все файлы .java в рамках одного проекта. Можно ли как то запустить только один .java файл? Выбирал "Выполнить файл", но все равно прогоняет все.
Вот я работаю со вторым файлом, при компиляции запускает и первый, хоть он и закрыт в редакторе.


Ответ

Каждая программа имеет свою точку запуска главный класс с методом main, с которого запускается главный поток приложения. Если же в приложении имеются несколько таких точек, то главный класс можно указать явно несколькими способами. Для старта подойдет смена главного класса на уровне IDE.
Чтобы выбрать главный класс для приложения с несколькими классами, содержащих стартовый метод main, в IDE NetBeans нужно:
Выбрать проект в списке и нажать на правую кнопку мыши

Высветится контекстное меню, там выбери Свойства

Далее откроется окошко Свойств, там перейди в Выполнение

Далее в пункте Главный класс имеется кнопка Обзор, на ней и нажми, и выбери нужный тебе класс. Зафиксируй кнопкой Выбрать главный класс и нажми Ок

Готово!

Плагин JS для отсеивания по версии браузера

К примеру, есть задача отсеять браузеры, с которых заходит пользователь, чтобы дать предупреждение о том, что всё поедет, в случае если пользователь зашёл с древнего браузера. К примеру, имеем такой список отсеивания: http://caniuse.com/#feat=flexbox.
Существует ли поддерживаемый плагин для голого JS или jQuery, чтобы влепить попап вроде такого?

На скриншоте плагин http://jreject.turnwheel.com, но он, к сожалению, последний раз обновлялся в 2014 году — нету поддержки мобильных браузеров.


Ответ

Как правильно прокомментировали - эта задача делится на две. Первая - определить, что браузер пользователя не поддерживается сайтом. Вторая - отобразить окно, максимально совместимое со всеми древними браузерами.
Вторая задача по прежднему прекрасно решается плагином http://jreject.turnwheel.com . Для первой задачи, как написал @Alexey Ten , необходимо проверить доступность критичных фич.
К примеру решение по вопросу (попап при отсутсвии поддержки flexbox):
var tst = document.createElement("div"); var flexSupportCaps = [ tst.style.flex, tst.style.flexWrap, tst.style.flexFlow, tst.style.flexGrow, tst.style.alignContent, tst.style.alignItems, tst.style.alignSelf, tst.style.justifyContent, tst.style.order ]; if (flexSupportCaps.indexOf(undefined)!=-1){ $(document).ready(function(){ $.reject({ reject: { all: true }, // Reject all renderers for demo header: 'Браузер не поддерживается', // Header Text paragraph1: 'Вы используете устаревший браузер.', // Paragraph 1 paragraph2: 'Для корректной работы портала vashsite.ru рекомендуем установить один из следущих браузеров, или обновить ваш до последней версии.', closeLink: 'Закрыть окно', closeMessage: 'Я согласен с тем, что отображение сайта может быть некорректно.', imagePath: '/externals/jReject-master/images/', closeCookie: true, browserInfo: { msie: { text: 'Microsoft Edge', url: 'https://www.microsoft.com/ru-ru/windows/microsoft-edge' } } }); }); } delete tst;
Выявляется поддержка flexbox, если её нет, то выплёвывается попап плагина jReject. Выплёвывается он единожды, о чём говорит параметр closeCookie: true .

XMLHttpRequest: Как возобновить закачку

Тут я пытался что то навалять примерно так:
var slice = file.slice(10, 100); // прочитать байты с 10 го по 99 й
xhr.send(slice); //и отправить эти байты в запросе.
Но такая модель не жизнеспособна!
Как отослать на сервер не весь файл, а только нужную часть его?
Или поставить на паузу закачку а потом либо отменить либо продолжить.
С помощью javascript как можно это сделать?
Спасибо.


Ответ

Для загрузки нам нужно точно знать количество загруженных байт. Это может сообщить только сервер.
Алгоритм возобновляемой загрузки
Загрузкой файла будет заведовать объект Uploader, его примерный общий вид:
function Uploader(file, onSuccess, onFail, onProgress) {
// fileId уникальным образом идентифицирует файл // можно добавить идентификатор сессии посетителя, но он и так будет в заголовках var fileId = file.name + '-' + file.size + '-' + +file.lastModifiedDate;
// сделать из fileId число (хеш, алгоритм неважен), мы будем передавать его в заголовке, // в заголовках разрешены только ASCII-символы fileId = hashCode(fileId);
var errorCount = 0;
// если количество ошибок подряд превысит MAX_ERROR_COUNT, то стоп var MAX_ERROR_COUNT = 6;
var startByte = 0;
var xhrUpload; var xhrStatus;
function upload() { console.log("upload: check status"); xhrStatus = new XMLHttpRequest();
xhrStatus.onload = xhrStatus.onerror = function() {
if (this.status == 200) { startByte = +this.responseText || 0; console.log("upload: startByte=" + startByte); send(); return; }
// что-то не так if (errorCount++ < MAX_ERROR_COUNT) { setTimeout(upload, 1000 * errorCount); // через 1 сек пробуем ещё раз } else { onError(this.statusText); }
};
xhrStatus.open("GET", "status", true); xhrStatus.setRequestHeader('X-File-Id', fileId); xhrStatus.send(); }
function send() {
xhrUpload = new XMLHttpRequest(); xhrUpload.onload = xhrUpload.onerror = function() { console.log("upload end status:" + this.status + " text:" + this.statusText);
if (this.status == 200) { // успешное завершение загрузки onSuccess(); return; }
// что-то не так if (errorCount++ < MAX_ERROR_COUNT) { setTimeout(resume, 1000 * errorCount); // через 1,2,4,8,16 сек пробуем ещё раз } else { onError(this.statusText); } };
xhrUpload.open("POST", "upload", true); // какой файл догружаем /загружаем xhrUpload.setRequestHeader('X-File-Id', fileId);
xhrUpload.upload.onprogress = function(e) { errorCount = 0; onProgress(startByte + e.loaded, startByte + e.total); }
// отослать, начиная с байта startByte xhrUpload.send(file.slice(startByte)); }
function pause() { xhrStatus && xhrStatus.abort(); xhrUpload && xhrUpload.abort(); }
this.upload = upload; this.pause = pause; }
// вспомогательная функция: получение 32-битного числа из строки
function hashCode(str) { if (str.length == 0) return 0;
var hash = 0, i, chr, len; for (i = 0; i < str.length; i++) { chr = str.charCodeAt(i); hash = ((hash << 5) - hash) + chr; hash |= 0; // Convert to 32bit integer } return hash; };
Аргументы для new Uploader:
file
Объект File API. Может быть получен из формы, либо как результат Drag’n’Drop. onSuccess, onFail, onProgress Функции-коллбэки, которые будут вызываться в процессе (onProgress) и при окончании загрузки. Подробнее про важные данные, с которыми мы будем работать в процессе загрузки:
fileId
Уникальный идентификатор файла, генерируется по имени, размеру и дате модификации. По нему мы всегда сможем возобновить загрузку, в том числе и после закрытия и открытия браузера.
startByte
С какого байта загружать. Изначально – с нулевого.
errorCount / MAX_ERROR_COUNT
Текущее число ошибок / максимальное число ошибок подряд, после которого загрузка считается проваленной. Алгоритм загрузки:
Генерируем fileId из названия, размера, даты модификации файла. Можно добавить и идентификатор посетителя. Спрашиваем сервер, есть ли уже такой файл, и если да – сколько байт уже загружено? Отсылаем файл с позиции, которую сказал сервер. При этом загрузку можно прервать в любой момент, просто оборвав все запросы.
Вы можете скачать пример и запустить локально для полноценной демонстрации:

Простая анимация фрагментов

Пытаюсь задать простую анимацию смены фрагментов. При помещении xml - файлов анимации в папку /anim/ выдает исключение:
Caused by: java.lang.RuntimeException: Unknown animation name: objectAnimator
Если же поместить файлы анимации в папку /animator/, то метод setCustomAnimation() ругается и говорит что необходим ресурс анимации из папки /anim/. Подскажите, как же все таки нужно сделать, чтобы это работало.
Файл R.anim.slide_in_left.xml:

Файл R.anim.slide_in_right.xml:


Файл mainActivity.java:
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button;
public class MainActivity extends AppCompatActivity { Fragment1 f1; Fragment2 f2; FragmentTransaction fm;
@Override protected void onCreate( Bundle savedInstanceState ) { super.onCreate( savedInstanceState ); setContentView( R.layout.activity_main );
f1 = new Fragment1(); f2 = new Fragment2(); fm = getSupportFragmentManager().beginTransaction(); fm.setCustomAnimations( R.anim.slide_in_left, R.anim.slide_in_right ); fm.replace( R.id.fragCont, f1 ); fm.addToBackStack( null ); fm.commit();
Button btn = ( Button ) findViewById( R.id.btn ); btn.setOnClickListener( new View.OnClickListener() { @Override public void onClick( View v ) { fm = getSupportFragmentManager().beginTransaction(); fm.setCustomAnimations( R.anim.slide_in_left, R.anim.slide_in_right ); if ( f1.isVisible() ) { fm.replace( R.id.fragCont, f2 ); } else { fm.replace( R.id.fragCont, f1 ); } fm.commit(); } } ); } }


Ответ

Судя по всему, FragmentTransaction из библиотеки поддержки ( android.support.v4.app.FragmentTransaction ) работают только с ресурсами из каталога anim, начиная с версии Android 3.1 XML ресурсы анимации должны размещаться в каталоге animator, с которыми не работает android.support.v4.app.FragmentTransaction. Для работы с этими ресурсами необходимо использовать стандартный android.app.FragmentTransaction. Поменял классы фрагментов на android.app.* и все заработало.

git как начать заново

У меня есть папка в java проектом, ранее пыталась ее залить на github, но ничего не вышло. Создала новый репозиторий на github, и пробую залить все сначала, но папка уже настроена на старый репозиторий. Команда git add . не добавляет ничего, git push пытается залить в старое место. Подскажите как все очистить и начать и нуля?


Ответ

git remote set-url origin (и тут url вашего нового репозитория на гитхабе) git push
Если git push не проходит - в данном случае допустимо сделать git push -f

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

возникла мысль заменить два запроса к базе одним, возможно ли такое сделать?
SELECT `label` AS `from` FROM `city` WHERE `code` = 'moscow' SELECT `label` AS `to` FROM `city` WHERE `code` = 'irkutsk'
Результат который нужно получить одним запросом должен быть:


Ответ

Не совсем понятна БД, которая у вас. При объединении может получиться нежелаемый результат, поэтому запросы могут быть не совсем корректны.
Как вариант, можно объединить 2 запроса через UNION (1 столбец, строки друг под другом):
SELECT `label` AS `from` FROM `city` WHERE `code` = 'moscow' UNION SELECT `label` AS `to` FROM `city` WHERE `code` = 'irkutsk'
Можно сделать так, чтобы было 2 столбца label - to и from
SELECT * FROM (SELECT `label` AS `from` FROM `city` WHERE `code` = 'moscow') c1, (SELECT `label` AS `to` FROM `city` WHERE `code` = 'irkutsk') c2

MySQL процедуры для чайников

Имею две таблицы с товарами интернет магазина. В одну попадают только товары от различных поставщиков с указанием ID поставщика. Во вторую попадают все цены и наличие по каждому товару первой таблице, по каждому складу поставщика.
Так как SQL недавно появился в моей жизни в таких масштабах, приходится просить помощи, не во всем сам могу разобраться.
Кратко о данных в таблицах:
Таблица с товарами выглядит вот так

Таблица с ценами так

Как видно на изображениях, на один товар может приходиться несколько различных цен на различных складах. Написал процедуру для усреднения цен по складам каждого поставщика.
CREATE PROCEDURE `average`(IN `v_id` INT, IN `v_in_id` INT, IN `v_sup_id` INT) BEGIN DECLARE vPrice INT; DECLARE vAmount INT;
SET vPrice = (SELECT (SUM(buy_price*amount)/SUM(amount)) FROM td_prices WHERE buy_price > 0 AND amount > 0 AND item_id = v_in_id and sup_id = v_sup_id); SET vAmount = (SELECT SUM(amount) FROM td_prices WHERE item_id = v_in_id and sup_id = v_sup_id);
UPDATE td_items SET buy_price = vPrice, amount = vAmount WHERE id = v_id; END;;
Не могу сказать что хорошо написал, опыта не хватает, возможно и заглючит при нулевой цене или количестве, но пока работает.
Процедуру выполняю в PHP скрипте - делаю выборку всех id,in_id,sup_id из таблицы items и подставляю их в мою процедуру, вызывая ее в цикле перебора этой самой выборки. Грубо говоря
$data = $sql->get('SELECT * FROM td_items'); foreach($data as $item) { $sql->query('call avarage(_ids_from_$item_here)'); }
Да, идея банальная и не самая производительная..
После выполнения процедуры таблица заполняется вполне корректно

Собственно, вопрос: Сейчас на 10 тысяч имеющихся в таблице items записей выполнение всего моего скрипта занимает аж 10 минут (на ноутбуке). Это никуда не годится, я прекрасно понимаю что если объеденить foreach PHP и SQL в одной единой процедуре, процесс пойдет намного быстрее. Но опыта не хватает. Подскажите, пожалуйста, методы оптимизации всей этой "выборки". Второй день бьюсь с sql курсорами и переменными, результата и понимания 0


Ответ

Использовать курсоры и любые циклы при работе с SQL надо в очень редких, особо тяжелых, случаях. Практически любую работу в SQL можно выполнить одним запросом. Ваш цикл по td_prices и вызов процедуры для обновления каждой отдельной строки можно заменить таким запросом:
UPDATE td_items I JOIN (SELECT item_id, sup_id, SUM(IF(buy_price > 0 AND amount > 0,buy_price*amount,0)) /SUM(IF(buy_price > 0 AND amount > 0,amount,0)) as buy_price, SUM(amount) as amount FROM td_prices GROUP BY item_id, sup_id ) P ON I.in_id=P.item_id AND I.sup_id=P.sup_id SET I.buy_price=P.buy_price, I.amount=P.amount
IF пришлось применить т.к. у вас почему то используются немного разные выборки для количества (берущие вообще все записи) и цен (берущие большие нуля записи). Вообще стоит подумать о дополнительных признаках по которым решать какие записи надо обновлять, а какие нет. Например вести поле timestamp в прайсах и менять только записи для которых в БД изменились какие либо цены с момента последнего обновления. Или вообще менять средние цены автоматом в триггере на изменение таблицы с прайсами.

Как копировать файлы с заменой в Linux тем же методом, что и в Windows? (без учёта регистра)

У меня есть Morrowind и куча модов к нему. Я хочу эти моды установить. Как вам известно, Morrowind писался под винду и моды к нему соответственно тоже, но я использую кроссплатформенный движок OpenMW, что позволяет нативно запускать игру в линуксе.
Так вот в чём моя проблема: установка модов обычно сводится к распаковке файлов из архива мода в директорию игры с заменой. Беда в том, что если оригинальная папка называется "Sound", а в архиве находится папка "sound", то никакой замены не произойдёт (аналогично и с файлами)! У меня просто будет 2 разных папки/файла, потому что линукс чувствителен к регистру. В итоге мод установится криво (а таких модов очень много и вручную я всё проследить не могу).


Ответ

специализированного средства для исправления подобной эксклюзивной «кривизны», конечно, нет.
но такое средство несложно написать на любом подходящем языке программирования, или даже обойтись оболочкой и утилитами из gnu/coreutils

например, у нас есть «базовый» каталог 1
$ tree 1 1 └── Sound ├── File └── File2
и есть распакованный (или любым другим образом полученный) каталог 2, в котором есть некоторые файлы/каталоги, отличающиеся от аналогичных файлов/каталогов из каталога 1 регистром имени:
$ tree 2 2 └── sound ├── file └── file3
фактически, нам надо привести имена таких файлов/каталогов к тому же регистру, что и в каталоге 1. т.е., sound/file переименовать в sound/File и sound переименовать в Sound
сохраним имя «базового» каталога в переменной base, а имя «переименовываемого» каталога — в ren
$ base=1 ren=2 составим список файлов/каталогов, совпадающих при преобразовании их в нижний регистр (с таким же успехом можно было и в верхний):
$ comm -1 -2 \ <(cd "$base"; find -mindepth 1 | tr '[:upper:]' '[:lower:]' | sort) \ <(cd "$ren"; find -mindepth 1 | tr '[:upper:]' '[:lower:]' | sort)
получаем:
./sound ./sound/file в цикле будем читать имена, находить исходные (без преобразования регистра) имена, сравнивать их и, если не совпадают, переименовывать и сообщать об этом:
$ comm -1 -2 \ <(cd "$base"; find -mindepth 1 | tr '[:upper:]' '[:lower:]' | sort) \ <(cd "$ren"; find -mindepth 1 | tr '[:upper:]' '[:lower:]' | sort) | \ while read n; do \ c1=$(cd "$base"; find -iwholename "$n"); \ c2=$(cd "$ren"; find -iwholename "$n"); \ if [[ "$c1" != "$c2" ]]; then \ echo "переименовываем $ren/$c2 в $ren/$c1"; \ mv "$ren/$c2" "$ren/$c1"; \ fi; \ done
получаем:
переименовываем 2/./sound в 2/./Sound переименовываем 2/./Sound/file в 2/./Sound/File
а внутри каталога 2 — имена в нужном регистре:
$ tree 2 2 └── Sound ├── File └── file3

итоговый скрипт:
#!/bin/bash base=$1 ren=$2 comm -1 -2 \ <(cd "$base"; find -mindepth 1 | tr '[:upper:]' '[:lower:]' | sort) \ <(cd "$ren"; find -mindepth 1 | tr '[:upper:]' '[:lower:]' | sort) | \ while read n; do c1=$(cd "$base"; find -iwholename "$n") c2=$(cd "$ren"; find -iwholename "$n") if [[ "$c1" != "$c2" ]]; then echo "переименовываем $ren/$c2 в $ren/$c1" mv "$ren/$c2" "$ren/$c1" fi done
принимает два параметра — «базовый» и «переименовываемый» каталоги.

Таймер в RabbitMQ

Как в RabbitMQ на python сделать отправку сообщений в очередь так, чтобы оно пришло в очередь только через определенное время, например, 4 часа ?


Ответ

RabbitMQ не поддерживает такую "родную" функцию.
Предложение приведенное выше проблематично так как требует базы данных и постоянную обработку сообщений. Такое решение намного более "рискованно". Не говоря уже о том что просто дополнительное обрабатывающее средство + база данных ну просто ни к чему.
Но функцию возможно эмулировать. При этом сообщение будет отослано и будет находиться на сервере до тех пор пока не наступит время сообщение доставить. Следующая версия NServiceBus.RabbitMQ транспорта будет поддерживать Native Delays при помощи Topic Exchanges.
Имплементация не зависит от языка посылающей аппликации.
Идея заключается в создании header exchanges где каждый уровень представляет бит из задержки. Если бит 0, exchange направляет сообщение на следующий уровень. Если бит 1, то в queue с TTL соответствующий задержке на этом уровне. Каждый queue с DLQ binding к следующему exchange.
Схематически, это будет выглядеть так:

Заметка: можно также имплементировать с Header Exchanges
С 32-ух битной задержкой (32 уровня exchanges) задержка получится от 1 до 2^31 секунд.

Проверка строки с датой/временем на корректность в Ruby

Нужно в Ruby проверить строку вида '12.01.2016 14:26', корректные ли в ней дата/время.
Предполагаю, что это проще всего сделать при помощи регулярного выражения
Если регулярным выражением, то каким? Если не регулярным выражением, то как тогда?


Ответ

Некоторые люди, столкнувшись с проблемой, думают: "Точно, я воспользуюсь регулярными выражениями". Теперь у них две проблемы. — Джейми Завински
Вам не нужны регулярные выражения для решения этой задачи.
Решение есть в стандартной библиотеке Ruby. Это Date.strptime, принимающий строку и разбирающий её по strftime-подобной маске
DateTime.strptime('12.01.2016 14:26', '%d.%m.%Y %H:%M') # => #
В случае некорректности даты/времени прилетит исключение ArgumentError

phpDocumentor и метод с неизвестным числом аргументов

Есть метод с неизвестным заранее числом аргументов, причем первый и второй аргументы обязательны и должны иметь определённые значения. Я хочу задокументировать это, но не знаю как:
/** * @param string $name * @param string $type * @param string $param_1-$param_x */ public function some_method() { $args = func_get_args(); }
Или я в корне не прав, допуская такой способ передачи аргументов и нужно передавать переменное количество аргументов массивом: some_method($name, $type, array $param)?


Ответ

Начиная с PHP 5.6 используется новый синтаксис для неизвестного количества аргументов, без использования функции func_get_args(). В этом случае можно все подробности описать в рамках директивы @param для аргумента ...$args
/** * @param string $name ... * @param string $type ... * @param mixed $args ... */ public function some_method($name, $type, ...$args) { // foreach($args as $arg) { ... }; }

Как установить bash на Windows 10 home edition?

Все мануалы говорят, что после активации режима разработчика нужно включить в optionalfeatures.exe Windows Subsystem for Linux. Но на HomeEdition такого нет.


Ответ

Установить linux подсистему в Windows 10 можно только в том случае, если пришло обновление anniversary update. Оно скорее всего в августе 2016 года должно было само прийти. Если нет - можно попробовать его поставить ручками - https://support.microsoft.com/en-us/help/12387/windows-10-update-history

global в функции это нормально?

есть класс, который осуществляет работу с БД есть функция, которая возвращает определенную строку, в т.ч. с помощью класса
использовать класс внутри функции получилось только с помощью global пример кода
$db = new TestClass();
function getContent($param1, $param2){ global $db; return $db->blabla('SELECT ... ', $param1, $param2); }
это нормально? или лучше использовать что-то другое для определения $db внутри функции?


Ответ

Идеальным ответом является комментарий от Vladimir Gamalian:
Для небольших скриптов вполне нормально, польза от отказа от global ощущается с увеличением сложности программной системы.
От себя я бы определил так:
Если, как в данном случае, код пишется процедурно, то ничего плохого в таком использовании global нет.
Вообще, global ругают по двум причинам. Первая - это действительно страх и ужас, когда этот оператор используется не по назначению, для передачи локальных переменных в функцию, что катастрофически запутывает программу. Допустим, у нас есть функция
function f1() { global $var $var++; }
и где-то в коде программы встречается вот такой кусок:
$var = 1; f1();
Что произошло с переменной $var, что делала функция f1() - из этого кода решительно не понятно. Такого кода надо избегать всегда. Вместо global в данном случае надо всегда писать так:
function f1($var) { return $var++; }
и использовать
$var = 1; $var = f1($var);
Вторая причина - это, условно говоря, невозможность подменить $db на лету. В более сложных программных системах иногда возникает необходимость подменять тот или иной сервис в зависимости от задачи. К примеру, вместо mysql использовать, скажем, MongoDB. Для одной и той же задачи, но в зависимости от контекста. И в этом случае global станет помехой, и нам нужно будет изобретать более сложные способы передачи сервисов в функцию.
Но до тех пор пока наша программа достаточно простая, не использует ООП, и при этом мы используем этот оператор для действительно глобальных сервисов, использование global вполне оправдано.

Каким образом в функции может сохраняться значение переменной?

Изучаю JS на http://learn.javascript/, сейчас читаю подраздел «Замыкание функции изнутри» раздела «Замыкания, область видимости». В пункте «Возврат функции» описывается пример с вложенной функцией.
Я, собственно, не понимаю, как counter при каждом запуске вспоминает переменную currentCount, учитывая написанное в том же разделе, что LexicalEnviroment при каждом завершении функции стирается из памяти, а при каждом новом запуске создается заново.
Не пойму, где хранится currentCount, если лексическое окружение стирается каждый раз?


Ответ

Такие вопросы вызывают у меня скупую слезу на бороду.
Всё просто - LexicalEnvironment действительно уничтожается после окончания работы вызова. Но в примере работа не закончена, т. к. возвращаемая функция сохранила ссылку на родительский [makeCounter] объект переменных.
То есть пока возвращенная функция будет жива, родительский LE обязан сохранится, вдруг при выполнении нужно обратится к родительской функции за переменными (что и происходит: в возвращённой функции нет переменной currentCount)?
Сборщики мусора работают по алгоритму ссылок (Mark and sweep), в общих чертах это как-то так:
Находятся корни, т. е. то, что всегда будет существовать (в браузерах это объект window, его же нельзя удалить). После каждого пробуждения, он [сборщик] рекурсивно обходит корни и помечает всё, до чего может дотянутся; это считается как нужное и полезное. Всё остальное считается недостижимым и память из-под них возвращается среде.
А теперь вспомним, что возвращённая функция, условно сохранённая в window, ссылается на родительский LexicalEnvironment через скрытое свойство [[Scope]] Сборщик просто не может удалить его - window -> counter -> [[Scope]]
Это объясняет почему новый вызов makeCounter создал девственно чистый счётчик - каждый вызов функции выдаёт ей кристально новый LexicalEnvironment

Замыкания - вообще очень интересная вещь, которая может быть очень мощной, а может в конец запутать, если не знать принципов работы замыканий.

Как писать коментарии в json-конфиге?

Есть конфиг файл в формате json. Нужно закоментировать одну строку и попробовать другое значение. Ну и сопроводиловку для будущего себя накатать. Какой знак за это отвечает?


Ответ

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

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

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


Ответ

Ознакомьтесь со статьей на MSDN: Добавление и редактирование ресурсов (Visual C#)
Для добавления ресурсов в проект необходимо щелкнуть правой кнопкой мыши узел Свойства в проекте в Обозревателе решений, щелкнуть Открыть, а затем на странице Ресурсы в Конструкторе проектов нажать кнопку Добавить ресурс. Ресурсы можно добавить в проект в качестве связанных ресурсов (внешние файлы) или как внедренные ресурсы (внедренные непосредственно в файл RESX).
При добавлении связанного ресурса в файле RESX со сведениями о ресурсах проекта будет указан только относительный путь на файл ресурса на диске. Если в качестве связанных ресурсов добавить изображения, видео или другие сложные файлы, их можно будет изменять в редакторе по умолчанию, сопоставленном с соответствующим типом файла в конструкторе ресурсов. В случае внедренных ресурсов, данные хранятся непосредственно в файле ресурсов проекта (RESX). Строки могут храниться только как внедренные ресурсы.
После добавления файлов в ресурсы, добавленные файлы помещаются в папку Resources, находящуюся в корне проекта.
Также можно задать действие при построении:
None — файл не включается в выходную группу проекта и не компилируется в процессе построения. Примером такого файла является текстовый файл документации, например файл Readme. Compile — файл компилируется в выходные файлы построения. Эта настройка используется для файлов кода. Content — файл не компилируется, но включается в выходную группу "Содержимое". Этот вариант используется по умолчанию для файлов HTM и других веб-файлов. Embedded Resource — файл внедряется в основные выходные файлы построения проекта в виде DLL или исполняемого файла. Обычно это значение используется для файлов ресурсов.
Для задания свойства Действие при построении (Build Action) или свойства Копировать в выходной каталог(Copy to Output Directory) необходимо зайти в свойства у файла ресурсов и изменить необходимое свойство.
Собственно говоря, Вас интересует свойство Действие при построении (Build Action) - которое необходимо указать под Ваши нужды.
Полезные ссылки для изучения:
Свойства файла Связанные и внедренные ресурсы Ресурсы в файле формата .Resx Ресурсы в приложениях Упаковка и развертывание ресурсов

Создание корневой файловой системы без получения прав суперпользователя в Linux

Я на своем ПК под управлением Linux создаю корневую файловую систему для встроенной системы под управлением Linux. Ее архитектура не 386. (Microbalze). Она должна быть в 2-х вариантах: как файл образа(rootfs.img) с файловой системой Ext4, этот файл будет затем записан во flash на целевой встроенной системе, и как каталог, доступный по сети через NFS. Вопрос: как назначить всем файлам этой корневой ФС владелцем root, не получая прав root на моем ПК, на котором я ее собираю? В книге "Linux from scratch" предлагается делать это с помощью chroot, т.е. создать в отдельной папке мини-rootfs со всеми нужными программами(bash, gcc итд), сделать в нее chroot и затем работать в ней с правами суперпользователя. Но у этого варианта очевидные недостатки: 1. У меня уже все программы установлены, зачем их устанавливать по второму разу? 2. Файл rootfs.img принадлежит мне, но для его редактирования я должен зачем-то получать права root. 3. В конце концов, возможна ситуация, когда пользователю не разрешено получение root прав на его ПК. Спасибо всем ответившим.


Ответ

Вопрос: как назначить всем файлам этой корневой ФС владелцем root, не получая прав root на моем ПК, на котором я ее собираю?
обновлённый вариант ответа
в уже собранном образе можно «похозяйничать» с помощью, например, программы guestfish из пакета libguestfs-tools. для ускорения работы требуется, чтобы пользователь входил в группу kvm (это в debian gnu/linux, в других дистрибутивах она, возможно, будет называться иначе).
пример с файлом, содержащим образ файловой системы (знаком > в начале строки отмечены команды, выполняемые «внутри» псевдо-оболочки, которая запускается программой guestfish):
$ guestfish -a образ > run
смотрим список файловых систем — там присутствует только одна, та, что находится внутри файла с образом, который указан с помощью опции -a):
> list-filesystems /dev/sda: ext2
монтируем эту файловую систему в качестве корня:
> mount /dev/sda /
можно посмотреть файлы (здесь, для примера, в файловой системе присутствует только один файл):
> ls / lost+found файл
изменить принадлежнось можно встроенной командой chown (и пользователя и группу надо указывать в цифровом виде):
> chown 0 0 /файл
как я понял, рекурсивно эта команда, увы, не работает. так что если надо поменять принадлежность большого количества файлов, то придётся автоматизировать процесс. в man guestfish есть примеры, которые помогут в такой автоматизации.
завершить сеанс псевдо-оболочки можно либо командой exit, либо нажатием ctrl+d
про создание образа с помощью virt-make-fs
кстати, в уже упомянутом пакете libguestfs-tools есть программа virt-make-fs, с помощью которой можно создать образ с файловой системой из архива:
$ virt-make-fs архив.tar образ
ну а поместить в архив файлы с нужной принадлежностью можно, как обычно, с помощью fakeroot. например, находясь в каталоге, являющимся «корнем» создаваемой файловой системы:
$ fakeroot bash $ chown -R пользователь:группа * $ tar -cf архив.tar * $ exit
если пользователь и группа — это root, то вызов chown может и не потребоваться, ведь «внутри» окружения, созданного программой fakeroot текущий пользователь выглядит «как бы root-ом», и принадлежащие ему файлы/каталоги выглядят «как бы принадлежащими root-у». см. вывод $ ls -l
старый вариант ответа, про genext2fs
но можно для самой сборки образа воспользоваться, например, программой genext2fs (ext2 filesystem generator for embedded systems) из одноимённого пакета
пример (всё выполняется от имени рядового пользователя):
создаём «корневой» каталог для нашей файловой системы, а в нём файл:
$ mkdir корень; touch корень/файл создаём образ с файловой системой ext2 размером в 1024 блока, с подменой пользователя (опция -U):
$ genext2fs -U -b 1024 -d корень образ

проверяем. тут уже (для монтирования) потребуются права суперпользователя:
$ mkdir точка.монтирования $ sudo mount образ точка.монтирования
и видим, что созданный файл принадлежит пользователю root
$ ls -l точка.монтирования total 52 drwx------ 2 root root 52224 Sep 28 18:26 lost+found -rw-r--r-- 1 root root 0 Sep 28 18:11 файл
не забываем отмонтировать:
$ sudo umount точка.монтирования

p.s. в принципе, и для монтирования можно, в крайнем случае, обходиться без дополнительных прав, воспользовавшись программой fuse-ext2 из пакета fuseext2
$ fuse-ext2 образ точка.монтирования
программа выдаст много строчек с информацией, из которой в данном случае полезной является только уведомление о том, что файловая система смонтирована в режиме «только для чтения».
не забываем отмонтировать:
$ fusermount -u точка.монтирования

полезная информация:
Creating SD image without root privileges Mount an image file without root permission?

Что происходит с пользователями, которые скачали бета-версию приложения?

Такой вопрос, например, сейчас приложение находится на бета-тестировании в Google Play, что произойдет с пользователями, когда приложение выйдет в release? У них обновится приложения до версии, которая в release? Пользователи, которые скачали бету-версию будут показываться, как пользователи, которые скачали приложение?


Ответ

Тут будут 2 варианта, которые на самом деле между собой мало отличаются в плане результата:
Например, у вас в БЕТА была версия 3. В релиз вы выпускаете версию 4. В этом случае все, кто пользовался БЕТА 3 обновятся до РЕЛИЗ 4 (т. к. это одно и то же приложение, с одним и тем же пакетом) Например, у вас в БЕТА была версия 3, и вы ее же переносите в релиз. Никто ни до чего не обновится, но всем станет доступна версия 3.
В любом случае, приложение всегда обновляется до последней доступной версии.
Разница будет в другом случае: Если у вас в релизе версия 4, и вы выпустили в БЕТА версию 5, то версия 4 будет доступна всем, а версия 5 - только бета-тестерам.