Страницы

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

суббота, 16 марта 2019 г.

git subtree внутри одного репозитория

Как слить содержимое папки ветки 1 в ветку 2 и поддерживать синхронность папки в ветке 1 и ветки 2?
Контекст:
Делаю библиотеку, в т.ч. для выкладывания на github.com, на github принято выкладывать master-ветки без файлов проекта и окружения (файл настроек ide, подтянутые зависимости и т.п.), я же привык всё таскать с собой, чтобы легко было восстановить окружение.
Нужно сделать так:
ветка env: моё рабочее окружение, вместе с подтянутыми зависимостями. Чтобы можно было просто сделать checkout и скомпилировать проект.
ветка master - только непосредственно мои исходники.
Речь идет о репизитории https://github.com/rekby/mbr, сейчас туда загружен вариант с веткой env. Ветка master пуста. В master должно быть содержимое https://github.com/rekby/mbr/tree/env/src/github.com/rekby/mbr
По документации я понял что мне хорошо должен подойти вариант поддеревьев (subtree) - я работаю в своей env-ветке и периодически сливаю изменения в мастер. При необходимости из master подтягиваю их обратно через git diff-tree
В этом месте возникла проблема - git diff-tree работает не так как я этого ожидаю.
Например:
git checkout env git diff-tree -R -r -p master src/github.com/rekby/mbr
Как я понимаю должен мне выдать отличия в src/github.com/rekby/mbr ветки env (текущей) и корнем ветки master (в которой и должен оказаться мой код). Вывод команды пуст.
Попробовал с --relative и еще несколько вариантов - результат тот же.


Ответ

посмотреть отличия в файлах, находящихся в разных каталогах в двух разных ветках можно так:
$ git diff branch1:path/num/1 branch2:path/num/2
в вашем конкретном случае примерно так:
$ git diff master: env:src/github.com/rekby/mbr
если достаточно просто перенести изменения в ветку master, то можно, переключившись в эту ветку, выполнить примерно такую команду:
$ git checkout master $ git diff master: env:src/github.com/rekby/mbr | git apply
если же требуется перенести коммиты (т.е., коммит-сообщения, дату, авторство), то тогда следует ориентироваться не на различия в файлах (получаемые с помощью diff-а), а на различия в списке коммитов. придётся как-то самостоятельно отслеживать — какие коммиты уже перенесены, а какие ещё нет (я, к сожалению, не знаю средств git-а, позволяющих автоматизировать такой процесс — с изменением путей).
получить набор patch-файлов, содержащих коммиты, начиная с заданного, в вашем случае можно примерно так:
$ git checkout env $ git format-patch хэш-последнего-уже-перенесённого-коммита $ git checkout master $ git am -p5 *.patch
обратите внимание на параметр -p5 для команды git am. он указывает отбросить 5 элементов в пути файлов, перечисленных в патче, т.е. вместо a/src/github.com/rekby/mbr/mbr.go получится просто mbr.go
не забудьте после этого удалить сформированные файлы *.patch, чтобы не возникло проблем при следующих переносах.
чтобы сформировать patch-файл для одного коммита, можно передать команде git format-patch параметр -1
$ git format-patch -1 хэш-переносимого-коммита

Если приложение удалено, будут ли деньги сниматься за подписку?

Если приложение удалено, будут ли деньги сниматься за подписку? Что-то нигде в доках не могу этого найти.


Ответ

Да.
Когда пользователь попытается удалить приложение, он получит предупреждение, что имеется активная подписка. Если он проигнорирует предупреждение и продолжит удаление, то подписка останется активной.
Соус:
App uninstallation When the user uninstalls an app that includes purchased subscriptions, the Play Store app will notify the user that there are active subscriptions. If the user chooses to continue with the uninstallation, the app is removed and the subscriptions remain active and recurring billing continues. The user can return to cancel the associated subscriptions at any time in the My Apps screen of the Play Store app. If the user chooses to cancel the uninstallation, the app and subscriptions remain as they were. https://developer.android.com/google/play/billing/billing_subscriptions.html

Javascript: коллбэки, асинхронность и разделение кода

Здравствуйте.
Есть cordova приложение. Есть плагин, который я могу вызвать со стороны javascript, чтобы получить данные извне, например, через такой враппер:
CordovaWrapper.getRawData(successCallback, errorCallback);
Данные, которые я получу из cordova (они придут как аргументы successCallback), я бы хотел использовать в HTML приложении.
Конечно, можно во всех местах, где нужны данные из successCallback, использовать этот CordovaWrapper, чтобы получить данные и сразу же использовать:
CordovaWrapper.getRawData(function(JSONString) { var data = JSON.parse(JSONString) for (var i in data) { data[i].formattedValue = ''+data[i].value+''; }
// здесь мы используем эти полученные и отформатированные данные
}, function(e) { console.log(e) });
Но мне это не кажется хорошей идеей. Кроме того, хорошо бы было закешировать распаршенный JSON с примененным к нему форматированием.
Я мало знаком с Javascript, но мне хотелось бы реализовать какой-нибудь провайдер данных, к которому я смогу обращаться, чтобы получать закешированные и отформатированные данные из cordova (используя этот гипотетический CordovaWrapper). И в случае работы приложения в браузере, а не на девайсе, отдавать какие-нибудь захардкоженые данные.
if (standaloneMode) { // какие-то тестовые данные return [{ value: 'test1', options: [...], }, { value: 'test2', options: [...], }]; } else { return dataFromCordova; }
Проблема в том, что получение данных - асинхронное.
Если делать асинхронно, получается коллбэк на коллбэке:
Объявление:
DataProvider.getData = function(callback) { var format = function (arr) { for (var i in arr) { arr[i].formattedValue = ''+arr[i].value+''; } return arr; };
if (standaloneMode) { var testData = [{ value: 'test1', options: [...], }, { value: 'test2', options: [...], }];
callback(format(testData)); return; }
if (this.cache) { callback(this.cache); } else { var successCallback = function(JSONString) { data = JSON.parse(JSONString); callback(format(data)); }; CordovaWrapper.getRawData(successCallback, errorCallback); } }
И использование:
DataProvider.getData(function (data) { // здесь мы используем эти полученные и отформатированные данные });
Были мысли загружать данные в провайдер до использования. Но, опять же, нет гарантий, что момент, когда эти данные будут нужны, не наступит раньше, чем эти данные будут получены из cordova.
Как правильно сделать? Нормально ли это, хотеть отдельный класс/объект, который будет предоставлять данные? Нормально ли иметь столько коллбэков из-за асинхронности? Как делать такого рода кеширование? Как не дублировать строчки вида
callback(format(data));
?


Ответ

JavaScript это ивентво ориентированный язык, то есть лапша из колбеков это обычное дело. К сожелению текущая версия JavaScript не позволяет упростить работу с колбеками, и для этого вам необходимо подобрать библиотеку для упрощения логики работы с событиями.
Замечу что если у вас в приложении действительно много колбеков то возможно стоит ознакомиться с Функциональным реактивным программированием. Вот очень мотивирующи доклад к изучению FRP.
Но в большинстве случаев FRP будет излишним, и можно воспользоваться Promise (на самом деле это частный случай FRP). Промисы будут достепны в ES6 а пока вы можете воспользоваться реализацией промисов из какой-нибудь библиотеки например jquery
Promise - это специальный объект который выпонит успешный callback или callback с ошибкой и гарантирует что один из этих колбеков будет выполнен и выполнен только один раз. На основании этих условий есть разные средства для комбинирования промисов, например метод when из jquery. Если вам нужно больше вариантов для комбинирования промисов, посмотрите библиотеку Q
По поводу вашего вопроса с кешированием ответа я приведу пример с использованием jquery, в других библотеках решение не должно сильно отличаться.
В jquery есть класс Deferred который помогает создавать промисы.
Вам нужно создать объект Deferred var deferred = new $.Deferred() например в вашем врапере и вернуть промис deferred.promise() В вашем врапере в момент получения данных необходимо вызвать метод resolve если получение данных было успешным или reject в противном случае. У обекта который вы получите в результате метода deferred.promise() будут методы done и fail которые принимают callback. Обратите внимание что колбек вызовится в любом случае, даже если получение данных произошло до добавления колбеков в методы done и fail
Таким образом вы можете создать 1 объект Deferred для каждого запроса в функции получения данных и возвращать промис каждый раз при обрашении к функции. В итоге вы получите кеширование данных и избавитесь от лапшы колбеков.
Примеры Deferred
Статья про промисы

Чтение данных с arduino uno через COM порт

Доброе время суток! Возникла проблема: код на arduino нормально работает, во встроенном мониторе порта данные правильно отображаются. Но в приложении на C#, особенно очень часто в самом начале приходит непонятных мусор вместо значений. Типичные значения во встроенном мониторе:
145 0 145 0
Значения в программе на C#:
SSH(??j - откуда берутся эти строки? 145 143 ??j
Код программы
public partial class MainWindow : Window { SerialPort sp = new SerialPort("COM3", 115200, Parity.None, 8, StopBits.One);
public MainWindow() { InitializeComponent();
sp.DataReceived += new SerialDataReceivedEventHandler(OnDataReceived); sp.Open(); }
private void OnDataReceived(object sender, SerialDataReceivedEventArgs e) { Dispatcher.BeginInvoke(new Action(delegate() { this.console.Text += sp.ReadExisting(); }));
}
private void ReadPort(object source, ElapsedEventArgs e) {
}
private void readButton_Click(object sender, RoutedEventArgs e) {
} }
}


Ответ

Много работал с компортом и ардуиной. Тагер(для лезертага) делал и прочее. Как я понял мусор в компорте - это вообще норма. Собственно для этого и существуют различные протоколы передачи данных. В простейшем случае, ты должен сначала слать идентификатор начала данных. Это может быть что угодно. Допустим [StartData]. Следом шлешь данные. А после идентификатор конца данных. [StopData]. Не плохо бы еще прикрутить контрольную сумму(гугли по CRC) и длину данных. Тогда в с# ты будешь сначала искать в потоке компорта идентификатор начала пакета. Потом читать ответ до идентификатора конца пакета.
Реализовывать чтение можно по-байтово. Считываем байт - если равен '[', то читаем дальше, если следующий 'S' то продолжаем. Нет - отбрасываем, начинаем сначала.

Ввод данных с клавиатуры - Rust

Здравствуйте! Как я могу считать данные вводимые пользователем с клавиатуры? Здесь также задан вопрос, но предложенные способы очень неудобны. Можно ли как-то считать строку в стиле Python (input()) или C++/Си (cin/scanf())? А если нет, то как сделать это более удобным способом?
UPD
Нашел это. Подключаю к проекту:
[dependencies.text_io] version = "*" features = ["nightly"]
Но к сожалению уверенно отказывается компилироваться quasi v0.3.0


Ответ

Написал небольшую функцию:
fn read_string(comment:&str) -> String { println!("{}", comment); let mut string: String = String::new();
std::io::stdin().read_line(&mut string) .ok() .expect("Error read line!");
return string; }
Если вместо return string написать return string.trim().parse::().unwrap(); можно получить тип i32, а по аналогии - все остальные. Теперь можно писать так: let number:i32 = read_i32("Input number: "); Пока не знаю, как выполнить чтение на одной строке с желаемым тектом, т.е при использовании примера выше:
Input number: (здесь вводится текст)
UPD
Чтобы текст вводился на одной строке с комментарием к нему модифицируйте функцию:
use std::io::Write; use std::io;
fn read_string(comment:&str) -> String { print!("{}", comment); io::stdout().flush();
let mut string: String = String::new();
io::stdin().read_line(&mut string) .ok() .expect("Error read line!");
return string; }

Объединение объектов в массиве по ключу

У меня имеется массив с разными данными , который выглядит примерно так:
[ { "_id": "556c978be20c7cd0087c6f10", "username": "ivan", "music": [ "Metallica" ] }, { "_id": "556c978be20c7cd0087c6f10", "username": "ivan", "interests": [ "Music", "Djent" ] }, { "_id": "556c978be20c7cd0087c6f13", "username": "alina", "interests": [ "Music", "Literature" ] }, { "_id": "556c978be20c7cd0087c6f13", "username": "alina", "music": [ "Skyharbor" ] } ]
Как с объединить объекты в массиве по ключам ('_id') следующим образом (приоритет lodash):
[ { "_id": "556c978be20c7cd0087c6f10", "username": "ivan", "music": [ "Metallica" ], "interests": [ "Music", "Djent" ] }, { "_id": "556c978be20c7cd0087c6f13", "username": "alina", "music": [ "Skyharbor" ] "interests": [ "Music", "Literature" ] } ]


Ответ

Сгруппировать по идентификаторам можно с помощью groupBy, а затем объединить пары с помощью merge
var users = [{ "_id": "556c978be20c7cd0087c6f10", "username": "ivan", "music": [ "Metallica" ] }, { "_id": "556c978be20c7cd0087c6f10", "username": "ivan", "interests": [ "Music", "Djent" ] }, { "_id": "556c978be20c7cd0087c6f13", "username": "alina", "interests": [ "Music", "Literature" ] }, { "_id": "556c978be20c7cd0087c6f13", "username": "alina", "music": [ "Skyharbor" ] }]; console.log( _.map( _.groupBy( users, function (u) { return u._id } ), function (g) { return _.merge.apply(this, g) } ) );
P. S. Прошу ногами не бить, в первый раз в жизни вижу lodash.

Ошибка SOAP looks like we got no XML document.Как исправить?

Добрый вечер.
Начал разбираться с SOAP,набросал простенький сервис новостей и клиент под него и получил ошибку.
Что есть:
сервис новостей,находится в папке news (все это крутится на OpenServre`e) soap-server,находится в папке news/soap wsdl файл news.wsdl,находится в папке news/soap soap-client,находится в папке localhost
Что я делаю:
Запускаю OpenServer,перехожу на localhost - вылетает
Операция Client вернула ошибку: looks like we got no XML document
Проверил кодировки и BOM-символы,все в порядке.
soap-server.php
setClass("NewsService"); // Запуск сервера $server->handle();
soap-client.php
getNewsCount(); echo "

Всего новостей: $result

"; // Сколько новостей в категории Политика? $result = $client->getNewsCountByCat(1); echo "

Всего новостей в категории Политика:$result

"; // Покажем конкретную новость $result = $client->getNewsById(5); $news = unserialize(base64_decode($result)); var_dump($news); }catch(SoapFault $e){ echo 'Операция '.$e->faultcode.' вернула ошибку: '.$e->getMessage(); }
news.wsdl







Где,я ошибся? Что исправить?
Признателен за уделенное время.


Ответ

Добавте
ob_clean(); ob_start();
Перед
$server->handle();