Long write operations does not seem to work correctly

Summary
I tested the new long write operation commit that has been pushed recently. Tried it in my application and it crashes after the second "long" write operation.
Let me explain a little more my use case. I'm currently sending a rather big file to a BLE device. The file is a firmware in Intel HEX forma. From the defined application exchange protocol, I'm iterating through each line, wrap the line in a application packet format (starts and ends with a predefined byte value), chunk that into multiple packets (20 bytes) and write them one by one to the device by using writeCharacteristic. The callback is then used to trigger the next packet once a line has been fully written, I start sending the next one.
I wanted to test the new long operation as it greatly reduce amount of operation on the queue since a full line using long write operation would used a single operation on the radio queue.
I tried it with the following code:
    getBleConnection().getCharacteristic(characteristicUuid).flatMap(characteristic -> {
      characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);

      return getBleConnection().createNewLongWriteBuilder()
                               .setCharacteristic(characteristic)
                               .setMaxBatchSize(20)
                               .setBytes(bytes)
                               .build();
    }).subscribe(ignore -> {
    }, this::onError, this::onLineWritten);

Where the onLineWritten simply triggers the next line writing operation.
Preconditions

Steps to reproduce actual result
Not clear, but here what I think.

Send multiple lines of data to a device. Each line taking more than 20 bytes.
Use the above code to trigger the line sending one by one and let RxAndroidBLE chunk them as needed.
Run the "upload" operation.

Actual result
There is crash happening, here the log part, the characteristic being written to is the one starting with b4520104 and the b4520107 is some kind of ACK channel that we don't really use.
The second line operation is hanging until a timeout occurs.
02-13 12:28:21.426 D/FlashFirmwareStateMachine: Trying to transition from [FLASH_ACK_RECEIVED (2)] to [FLASH_PROGRESS (3)].
02-13 12:28:21.427 D/FlashFirmwareStateMachine: Writing [AA06063A000000003C4D23343232C223304B802923304B10105CCBAB51EE8C05A6CDD6A0531246B6977D4B49808AE5A6F85A6016D4BFD1DF18A791D803E82330D765D789540F3DCA0B942F3A203D07D16540C306BE7C9C4783F1C3111D7DC9E6516873A4C71C6C876836B1A7E523341F9BEC86DFF644E407AE1963E37AAEF666C6E1DC87AF1C5381F17D0E8E2D9F4382CB1792C3077482233197E21EC36416E53281696CB520F25675F749AD7451326E919660F183C98A250B7E1F1A6D43F81D769481559EDC8FF87480918BFA316A42B969DE118FF1928AF88F7230571E8DE2626D233587A67660BE6EC45049B07BC9CEBC975E30518C8456137AA9B1372779BC2D5BCCBB89B5E3C6D07BBE743FD39C12F33EBB] to device.
02-13 12:28:21.429 D/RxBle#Radio:   QUEUED RxBleRadioOperationCharacteristicLongWrite(91420617)
02-13 12:28:21.430 D/FlashFirmwareStateMachine: Emitting event [1 / 697 (0.14%)].
02-13 12:28:21.430 D/RxBle#Radio:  STARTED RxBleRadioOperationCharacteristicLongWrite(91420617)
02-13 12:28:21.451 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520104-a308-4e56-8a52-536c2ad07147 status=0
02-13 12:28:21.456 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520104-a308-4e56-8a52-536c2ad07147 status=0
02-13 12:28:21.463 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520104-a308-4e56-8a52-536c2ad07147 status=0
02-13 12:28:21.468 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520104-a308-4e56-8a52-536c2ad07147 status=0
02-13 12:28:21.473 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520104-a308-4e56-8a52-536c2ad07147 status=0
02-13 12:28:21.479 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520104-a308-4e56-8a52-536c2ad07147 status=0
02-13 12:28:21.483 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520107-a308-4e56-8a52-536c2ad07147
02-13 12:28:21.484 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520104-a308-4e56-8a52-536c2ad07147 status=0
02-13 12:28:21.497 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520107-a308-4e56-8a52-536c2ad07147
02-13 12:28:21.501 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520104-a308-4e56-8a52-536c2ad07147 status=0
02-13 12:28:21.515 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520107-a308-4e56-8a52-536c2ad07147
02-13 12:28:21.528 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520107-a308-4e56-8a52-536c2ad07147
02-13 12:28:21.530 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520104-a308-4e56-8a52-536c2ad07147 status=0
02-13 12:28:21.543 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520104-a308-4e56-8a52-536c2ad07147 status=0
02-13 12:28:21.553 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520104-a308-4e56-8a52-536c2ad07147 status=0
02-13 12:28:21.558 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520104-a308-4e56-8a52-536c2ad07147 status=0
02-13 12:28:21.560 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520107-a308-4e56-8a52-536c2ad07147
02-13 12:28:21.563 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520104-a308-4e56-8a52-536c2ad07147 status=0
02-13 12:28:21.572 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520107-a308-4e56-8a52-536c2ad07147
02-13 12:28:21.584 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520104-a308-4e56-8a52-536c2ad07147 status=0
02-13 12:28:21.585 V/FlashFirmwareStateMachine: Wrote packet to device, checking if we can write next line.
02-13 12:28:21.586 D/FlashFirmwareStateMachine: Writing [AA06063A000000003C414E559C91B161961B8DCCAA815466E15B9D0EF5726F256F00C65944F8E323302335664F946BBC30C24E91A5DEAC348D62AD8933C0EB1064A470FAC2E00FAB8BE012C5A670A52CFA433F1D6D01ED4F1AF62331D9B2938EBA4A701A524660D361496BA714204B01A9674A5FC6927AA7B3C98C8BFF3658C04F218EF3928329CF006B746A4841BD02BF682ED5C037571C5BDB92DD7F515049FF3DF608FB280784975CDF1D076F5CF1EADD3AE712B4F004E657DA6F21C7449541785223321A6AD1692542CE466C6BC6CCAADF427D99B0F21F98ACB88741592B15F242F5F9154B976E26F0D314C02262359612B240AF867B04CEA587EE6814CDBCCCBBD7F3609F45887562B87C5AB6EFE53EBB] to device.
02-13 12:28:21.590 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520107-a308-4e56-8a52-536c2ad07147
02-13 12:28:21.594 D/RxBle#Radio:   QUEUED RxBleRadioOperationCharacteristicLongWrite(10581863)
02-13 12:28:21.596 D/FlashFirmwareStateMachine: Emitting event [2 / 697 (0.29%)].
02-13 12:28:21.598 D/RxBle#Radio: FINISHED RxBleRadioOperationCharacteristicLongWrite(91420617)
02-13 12:28:21.599 D/RxBle#Radio:  STARTED RxBleRadioOperationCharacteristicLongWrite(10581863)
02-13 12:28:21.604 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520107-a308-4e56-8a52-536c2ad07147
02-13 12:28:21.631 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520104-a308-4e56-8a52-536c2ad07147 status=0
02-13 12:28:21.662 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520107-a308-4e56-8a52-536c2ad07147
02-13 12:28:51.607 D/RxBle#Radio: FINISHED RxBleRadioOperationCharacteristicLongWrite(10581863)
02-13 12:28:51.608 D/FlashFirmwareStateMachine: Finishing with error (Received onError without having requested it).
02-13 12:28:51.613 D/FlashFirmwareStateMachine: Unsubscribing from subscriber(s).
02-13 12:28:51.616 E/BleDebugActivity: co.samsao.directardware.exception.NgmmDeviceStateMachineException: Received onError without having requested it
02-13 12:28:51.616 E/BleDebugActivity:     at co.samsao.directardware.ngmm.StateMachine.finishWithError(StateMachine.java:392)
02-13 12:28:51.616 E/BleDebugActivity:     at co.samsao.directardware.ngmm.StateMachine.onError(StateMachine.java:108)
02-13 12:28:51.616 E/BleDebugActivity:     at co.samsao.directardware.ngmm.StateMachine.access$lambda$10(StateMachine.java)
02-13 12:28:51.616 E/BleDebugActivity:     at co.samsao.directardware.ngmm.StateMachine$$Lambda$11.call(Unknown Source)
02-13 12:28:51.616 E/BleDebugActivity:     at rx.internal.util.ActionSubscriber.onError(ActionSubscriber.java:44)
02-13 12:28:51.616 E/BleDebugActivity:     at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:153)
02-13 12:28:51.616 E/BleDebugActivity:     at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:115)
02-13 12:28:51.616 E/BleDebugActivity:     at rx.internal.operators.OperatorMerge$MergeSubscriber.reportError(OperatorMerge.java:266)
02-13 12:28:51.616 E/BleDebugActivity:     at rx.internal.operators.OperatorMerge$MergeSubscriber.checkTerminate(OperatorMerge.java:818)
02-13 12:28:51.616 E/BleDebugActivity:     at rx.internal.operators.OperatorMerge$MergeSubscriber.emitLoop(OperatorMerge.java:579)
02-13 12:28:51.616 E/BleDebugActivity:     at rx.internal.operators.OperatorMerge$MergeSubscriber.emit(OperatorMerge.java:568)
02-13 12:28:51.616 E/BleDebugActivity:     at rx.internal.operators.OperatorMerge$InnerSubscriber.onError(OperatorMerge.java:852)
02-13 12:28:51.616 E/BleDebugActivity:     at rx.observers.Subscribers$5.onError(Subscribers.java:230)
02-13 12:28:51.616 E/BleDebugActivity:     at rx.observers.Subscribers$5.onError(Subscribers.java:230)
02-13 12:28:51.616 E/BleDebugActivity:     at rx.observers.Subscribers$5.onError(Subscribers.java:230)
02-13 12:28:51.616 E/BleDebugActivity:     at rx.subjects.ReplaySubject$ReplayUnboundedBuffer.drain(ReplaySubject.java:625)
02-13 12:28:51.616 E/BleDebugActivity:     at rx.subjects.ReplaySubject$ReplayState.onError(ReplaySubject.java:470)
02-13 12:28:51.616 E/BleDebugActivity:     at rx.subjects.ReplaySubject.onError(ReplaySubject.java:247)
02-13 12:28:51.616 E/BleDebugActivity:     at com.polidea.rxandroidble.internal.RxBleRadioOperation.onError(RxBleRadioOperation.java:110)
02-13 12:28:51.616 E/BleDebugActivity:     at com.polidea.rxandroidble.internal.operations.RxBleRadioOperationCharacteristicLongWrite.access$400(RxBleRadioOperationCharacteristicLongWrite.java:31)
02-13 12:28:51.616 E/BleDebugActivity:     at com.polidea.rxandroidble.internal.operations.RxBleRadioOperationCharacteristicLongWrite$2.call(RxBleRadioOperationCharacteristicLongWrite.java:111)
02-13 12:28:51.616 E/BleDebugActivity:     at com.polidea.rxandroidble.internal.operations.RxBleRadioOperationCharacteristicLongWrite$2.call(RxBleRadioOperationCharacteristicLongWrite.java:108)
02-13 12:28:51.616 E/BleDebugActivity:     at rx.Completable$29.callOnError(Completable.java:1997)
02-13 12:28:51.616 E/BleDebugActivity:     at rx.Completable$29.onError(Completable.java:1988)
02-13 12:28:51.616 E/BleDebugActivity:     at rx.Completable$10$1.onError(Completable.java:582)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.internal.operators.OnSubscribeRedo$4$1.onError(OnSubscribeRedo.java:326)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.internal.operators.OperatorTakeWhile$2.onError(OperatorTakeWhile.java:85)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.internal.operators.OnSubscribeMap$MapSubscriber.onError(OnSubscribeMap.java:88)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.internal.operators.OnSubscribeMap$MapSubscriber.onError(OnSubscribeMap.java:88)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.internal.operators.OnSubscribeRedo$3$1.onNext(OnSubscribeRedo.java:300)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.internal.operators.OnSubscribeRedo$3$1.onNext(OnSubscribeRedo.java:284)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.internal.operators.NotificationLite.accept(NotificationLite.java:141)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.subjects.SubjectSubscriptionManager$SubjectObserver.emitNext(SubjectSubscriptionManager.java:253)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.subjects.BehaviorSubject.onNext(BehaviorSubject.java:160)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.observers.SerializedObserver.onNext(SerializedObserver.java:91)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.subjects.SerializedSubject.onNext(SerializedSubject.java:67)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.internal.operators.OnSubscribeRedo$2$1.onError(OnSubscribeRedo.java:237)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.observers.SerializedObserver.onError(SerializedObserver.java:152)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.observers.SerializedSubscriber.onError(SerializedSubscriber.java:78)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.internal.operators.OperatorTimeoutBase$TimeoutSubscriber$1.onError(OperatorTimeoutBase.java:187)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.internal.operators.OnSubscribeThrow.call(OnSubscribeThrow.java:44)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.internal.operators.OnSubscribeThrow.call(OnSubscribeThrow.java:28)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.Observable.unsafeSubscribe(Observable.java:10200)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.internal.operators.OperatorTimeoutBase$TimeoutSubscriber.onTimeout(OperatorTimeoutBase.java:200)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.internal.operators.OperatorTimeout$1$1.call(OperatorTimeout.java:41)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.internal.schedulers.EventLoopsScheduler$EventLoopWorker$2.call(EventLoopsScheduler.java:189)
02-13 12:28:51.617 E/BleDebugActivity:     at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
02-13 12:28:51.617 E/BleDebugActivity:     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:428)
02-13 12:28:51.617 E/BleDebugActivity:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
02-13 12:28:51.617 E/BleDebugActivity:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
02-13 12:28:51.617 E/BleDebugActivity:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
02-13 12:28:51.617 E/BleDebugActivity:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
02-13 12:28:51.617 E/BleDebugActivity:     at java.lang.Thread.run(Thread.java:761)
02-13 12:28:51.617 E/BleDebugActivity: Caused by: BleGattCallbackTimeoutException{macAddress=C9:27:49:98:4B:E2, status=-1 (0xffffffff), bleGattOperationType=BleGattOperation{description='CHARACTERISTIC_LONG_WRITE'}}
02-13 12:28:51.617 E/BleDebugActivity:     at com.polidea.rxandroidble.internal.operations.RxBleRadioOperationCharacteristicLongWrite.protectedRun(RxBleRadioOperationCharacteristicLongWrite.java:82)
02-13 12:28:51.617 E/BleDebugActivity:     at com.polidea.rxandroidble.internal.RxBleRadioOperation.run(RxBleRadioOperation.java:44)
02-13 12:28:51.617 E/BleDebugActivity:     at com.polidea.rxandroidble.internal.radio.RxBleRadioImpl$1$1.call(RxBleRadioImpl.java:59)
02-13 12:28:51.617 E/BleDebugActivity:     at com.polidea.rxandroidble.internal.radio.RxBleRadioImpl$1$1.call(RxBleRadioImpl.java:56)
...

Expected result
I think this code should work. Since I write the next line only on the onComplete callback, there is no reason the next line can not be written correctly and that a timeout occurs.
Note that a similar code without using long write operation does work correctly:
        mPacketWriter.write(characteristicUuid, bytes, delay, delayUnit).subscribe(ignore -> {
        }, this::onError, this::onLineWritten);

Where mPacketWriter is a custom chunker that creates all the chunks to write and then concatMap them using the mBleConnection.writeCharacteristic observable as the "synchronization" point.

Hello @maoueh
Thank you for your report. Could you explain a little bit more: what device / OS do you test on?
I see one difference between using the long write operation and your PacketWriter - you use a delay and delayUnit which is not present in the long write - could you give more info about it?

@DariuszAniszewski the delay is not used in "production", it's more when I have to debug stuff with the actual device.
Here the core of the packet writer I usually use:
private Observable<Void> writeToCharacteristic(UUID characteristic,
                                                 byte[] bytes,
                                                 long delay,
                                                 TimeUnit delayUnit,
                                                 int startIndexInclusive,
                                                 int endIndexExclusive) {
    return Observable.fromCallable(() -> Arrays.copyOfRange(bytes, startIndexInclusive, endIndexExclusive))
                     .flatMap(data -> {
                       if (!Delay.isImmediate(delay) && startIndexInclusive == 0) {
                         return Observable.timer(delay, delayUnit).map(ignore -> data);
                       }

                       return Observable.just(data);
                     })
                     .flatMap(data -> {
                       Timber.d("Writing packetize data [%s] to NGMM device.", Bytes.bytesToHex(data));

                       return mBleConnection.writeCharacteristic(characteristic, data).doOnNext((result) -> {
                         onPacketWritten(data);
                       });
                     })
                     .map(ignore -> null);
  }

In production code, the Delay.isImmediate(delay) is always true. So there is no delay usually, the "delay" is usually induced by the mBleConnection.writeCharacteristic(characteristic, data) observable onComplete event.
This is being tested on a LG G5 Android 7.0 phone. The receiving peripheral is backed by a Nordic nRF51822.
I just tried adding a big delay (250ms and also 1s) just before each long operation:
getBleConnection().getCharacteristic(characteristicUuid).flatMap(characteristic -> {
      return getBleConnection().createNewLongWriteBuilder()
                               .setCharacteristic(characteristic)
                               .setMaxBatchSize(20)
                               .setBytes(bytes)
                               .build();
    }).delay(1, TimeUnit.SECONDS).subscribe(ignore -> {
    }, this::onError, this::onPacketWritten);

The operation goes farther, I'm able to write about between 6 and 14 lines but at some point, operation hangs and transfer stops hitting the timeout exception.
I know the transfer is happening since there is a LED blinking on the peripheral when transfer is in progress.
Just not sure why the operation hangs like this.

@dariuszseweryn ^^

It may be possible that that you are experiencing a race condition that happens inside the library. I have seen it though I could not find the cause.
If you could enable RxBleLog on VERBOSE and paste the logs I would get more info.
As a temporary workaround you could delay starting the next long write for about 10 milliseconds after the previous completed.

I activated VERBOSE but the log was unchanged. There is only four occurrences of RxBleLog.v and none impact RxBleRadio. They are all in BleConnectionCompat class.
I tried adding a delay (250ms and 1s), but this changed nothing. In fact, like mentioned, I co a bit farther in the "flashing" but it still hangs.
Do you want me to add verbose statement somewhere in RxAndroidBLE code?

Nevermind, just understood that this is probably exactly what you wanted to check! Here the connect part of the log:
02-13 14:08:59.577 21119-21119 D/RxBle#Radio:   QUEUED RxBleRadioOperationConnect(145097946)
02-13 14:08:59.577 21119-23612 D/RxBle#Radio:  STARTED RxBleRadioOperationConnect(145097946)
02-13 14:08:59.579 21119-21119 V/RxBle#BleConnectionCompat: Connecting without reflection
02-13 14:08:59.580 21119-21119 D/BluetoothGatt: connect() - device: C9:27:49:98:4B:E2, auto: false
02-13 14:08:59.580 21119-21119 D/BluetoothGatt: registerApp()
02-13 14:08:59.580 21119-21119 D/BluetoothGatt: registerApp() - UUID=36f37d3f-bd96-4b06-af12-6ce1a7f6ca5d
02-13 14:08:59.582 21119-23617 D/BluetoothGatt: onClientRegistered() - status=0 clientIf=5
02-13 14:08:59.732 21119-23617 D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=5 device=C9:27:49:98:4B:E2
02-13 14:08:59.735 21119-23617 D/RxBle#BluetoothGatt: onConnectionStateChange newState=2 status=0
02-13 14:08:59.751 21119-23651 I/NgmmDevice$OpenConnectionOnSubscribe: Connection to NGMM device [DEI-7877739 (C9:27:49:98:4B:E2)] established, notifying subscriber about it.
02-13 14:08:59.754 21119-23651 D/RxBle#Radio:   QUEUED RxBleRadioOperationServicesDiscover(188160369)
02-13 14:08:59.760 21119-23612 D/RxBle#Radio: FINISHED RxBleRadioOperationConnect(145097946)
02-13 14:08:59.761 21119-23612 D/RxBle#Radio:  STARTED RxBleRadioOperationServicesDiscover(188160369)
02-13 14:08:59.763 21119-21119 D/BluetoothGatt: discoverServices() - device: C9:27:49:98:4B:E2
02-13 14:08:59.782 21119-21131 D/BluetoothGatt: onSearchComplete() = Device=C9:27:49:98:4B:E2 Status=0
02-13 14:08:59.782 21119-21131 D/RxBle#BluetoothGatt: onServicesDiscovered status=0
02-13 14:08:59.783 21119-23651 D/BluetoothGatt: setCharacteristicNotification() - uuid: b4520107-a308-4e56-8a52-536c2ad07147 enable: true
02-13 14:08:59.787 21119-23651 D/RxBle#Radio:   QUEUED RxBleRadioOperationDescriptorWrite(254820577)
02-13 14:08:59.788 21119-23651 D/BluetoothGatt: setCharacteristicNotification() - uuid: b4520102-a308-4e56-8a52-536c2ad07147 enable: true
02-13 14:08:59.795 21119-23651 D/RxBle#Radio:   QUEUED RxBleRadioOperationDescriptorWrite(154966624)
02-13 14:08:59.796 21119-23651 D/BluetoothGatt: setCharacteristicNotification() - uuid: b4520105-a308-4e56-8a52-536c2ad07147 enable: true
02-13 14:08:59.800 21119-23651 D/RxBle#Radio:   QUEUED RxBleRadioOperationDescriptorWrite(147424987)
02-13 14:08:59.801 21119-23612 D/RxBle#Radio: FINISHED RxBleRadioOperationServicesDiscover(188160369)
02-13 14:08:59.801 21119-23612 D/RxBle#Radio:  STARTED RxBleRadioOperationDescriptorWrite(254820577)
02-13 14:08:59.963 21119-21131 D/RxBle#BluetoothGatt: onDescriptorWrite descriptor=00002902-0000-1000-8000-00805f9b34fb status=0
02-13 14:08:59.967 21119-23612 D/RxBle#Radio: FINISHED RxBleRadioOperationDescriptorWrite(254820577)
02-13 14:08:59.971 21119-23612 D/RxBle#Radio:  STARTED RxBleRadioOperationDescriptorWrite(154966624)
02-13 14:09:00.156 21119-21135 D/RxBle#BluetoothGatt: onDescriptorWrite descriptor=00002902-0000-1000-8000-00805f9b34fb status=0
02-13 14:09:00.159 21119-23612 D/RxBle#Radio: FINISHED RxBleRadioOperationDescriptorWrite(154966624)
02-13 14:09:00.159 21119-23612 D/RxBle#Radio:  STARTED RxBleRadioOperationDescriptorWrite(147424987)
02-13 14:09:00.265 21119-21131 D/RxBle#BluetoothGatt: onDescriptorWrite descriptor=00002902-0000-1000-8000-00805f9b34fb status=0
02-13 14:09:00.270 21119-23612 D/RxBle#Radio: FINISHED RxBleRadioOperationDescriptorWrite(147424987)

Uh, excuse me. You have already had the log. My mistake. If you could add a log in the writeData method and another one on each emission of completed event emission (around line 170) change
                return writeOperationAckStrategy.call(emittingOnBatchWriteFinished.map(bufferIsNotEmpty(byteBuffer)))
                        .takeWhile(bufferIsNotEmpty(byteBuffer));

to something like
                return writeOperationAckStrategy.call(emittingOnBatchWriteFinished
                                                                                .doOnNext(new Action1<Object>() {
                                                                                // I am writing this on a web interface, add a log here - it will be triggered after each batch write has finished
                                                                                })
                                                                                .map(bufferIsNotEmpty(byteBuffer)))
                        .takeWhile(bufferIsNotEmpty(byteBuffer));

I added the log and tried other kind of operation. The problem seems to happen way more frequently when a bunch of characteristic changed event arrives after the long write operation has started. Is it possible they are interfering with the way the library check if the characteristic was written correctly?
To add more context, here an overview of how of interact with the peripheral. We write some data to the peripheral and it responds through some notification. Here a different operation than flash that request some data from the device:
02-13 14:48:40.955 17567-17567 D/StateMachine: Writing [AA01040BBB] to device.
02-13 14:48:41.209 17567-18900 D/RxBle#Radio:   QUEUED RxBleRadioOperationCharacteristicLongWrite(253784101)
02-13 14:48:41.211 17567-18663 D/RxBle#Radio:  STARTED RxBleRadioOperationCharacteristicLongWrite(253784101)
02-13 14:48:41.220 17567-17567 D/RxBle#RadioOperationCharacteristicLongWrite: WRITE_DATA: Wrote a [5 bytes] chunk to characteristic with success [true].
02-13 14:48:41.221 17567-17582 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 14:48:41.256 17567-17582 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520102-a308-4e56-8a52-536c2ad07147
02-13 14:48:41.262 17567-18786 V/StateMachine: Received notification data [AA060200BB].
02-13 14:48:41.262 17567-18786 D/StateMachine: Processing complete packet [AA060200BB].
02-13 14:48:41.264 17567-18786 D/StateMachine: Trying to transition from [START (0)] to [ACK_RECEIVED (1)].
02-13 14:48:41.321 17567-17625 D/OpenGLRenderer: endAllActiveAnimators on 0x7d6baebc00 (MenuPopupWindow$MenuDropDownListView) with handle 0x7d6a11abc0
02-13 14:48:41.911 17567-17584 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520102-a308-4e56-8a52-536c2ad07147
02-13 14:48:41.912 17567-18786 V/StateMachine: Received notification data [AA3102FE04FFBB].
02-13 14:48:41.913 17567-18786 D/StateMachine: Processing complete packet [AA3102FE04FFBB].
02-13 14:48:41.931 17567-17581 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520102-a308-4e56-8a52-536c2ad07147
02-13 14:48:41.932 17567-17581 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520102-a308-4e56-8a52-536c2ad07147
02-13 14:48:41.933 17567-18786 V/StateMachine: Received notification data [AA3102FE046EF5040E024445492D424C45200000].
02-13 14:48:41.934 17567-18786 V/StateMachine: Received notification data [0000BB].
02-13 14:48:41.937 17567-18786 D/StateMachine: Processing complete packet [AA3102FE046EF5040E024445492D424C452000000000BB].
02-13 14:48:42.064 17567-17582 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520102-a308-4e56-8a52-536c2ad07147
02-13 14:48:42.070 17567-18786 V/StateMachine: Received notification data [AA3102FEDA1202000FBB].
02-13 14:48:42.071 17567-17582 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520102-a308-4e56-8a52-536c2ad07147
02-13 14:48:42.072 17567-18786 D/StateMachine: Processing complete packet [AA3102FEDA1202000FBB].
02-13 14:48:42.074 17567-17582 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520102-a308-4e56-8a52-536c2ad07147
02-13 14:48:42.074 17567-18786 V/StateMachine: Received notification data [AA3102FEFBFEB80F35F900B485101A5030CCCC2A].
02-13 14:48:42.076 17567-18786 V/StateMachine: Received notification data [43AE5100000000BB].
02-13 14:48:42.077 17567-18786 D/StateMachine: Processing complete packet [AA3102FEFBFEB80F35F900B485101A5030CCCC2A43AE5100000000BB].
02-13 14:48:42.083 17567-17584 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520102-a308-4e56-8a52-536c2ad07147
02-13 14:48:42.087 17567-18786 V/StateMachine: Received notification data [AA01023B00BB].
02-13 14:48:42.088 17567-18786 D/StateMachine: Processing complete packet [AA01023B00BB].
02-13 14:48:42.089 17567-18786 D/StateMachine: Trying to transition from [ACK_RECEIVED (1)] to [RESPONSE_RECEIVED (2)].
02-13 14:48:42.090 17567-18786 D/StateMachine: Finishing with result [[B@77afbd].
02-13 14:48:42.090 17567-18786 D/StateMachine: Emitting event [[B@77afbd].
02-13 14:48:42.090 17567-18786 D/StateMachine: Unsubscribing from subscriber(s).
02-13 14:48:42.910 17567-17582 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520102-a308-4e56-8a52-536c2ad07147
02-13 14:48:42.928 17567-17584 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520102-a308-4e56-8a52-536c2ad07147
02-13 14:48:42.932 17567-17584 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520102-a308-4e56-8a52-536c2ad07147
02-13 14:48:42.936 17567-17584 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520102-a308-4e56-8a52-536c2ad07147
02-13 14:48:42.938 17567-17584 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520102-a308-4e56-8a52-536c2ad07147
02-13 14:48:42.962 17567-17581 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520102-a308-4e56-8a52-536c2ad07147
02-13 14:48:45.815 17567-17584 D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520102-a308-4e56-8a52-536c2ad07147
02-13 14:49:11.233 17567-18944 D/StateMachine: Finishing with error (Received onError without having requested it).
02-13 14:49:11.233 17567-18663 D/RxBle#Radio: FINISHED RxBleRadioOperationCharacteristicLongWrite(253784101)

Note here that the data is written with success (WRITE_DATA) but the ACK never arrived. I validated that the log statements does print correctly when everything is working:
02-13 14:53:42.016 17567-17567StateMachineD/OtherStateMachine: Writing [AA060103E80000BB] to device.
02-13 14:53:42.271 17567-18900StateMachineD/RxBle#Radio:   QUEUED RxBleRadioOperationCharacteristicLongWrite(21173544)
02-13 14:53:42.274 17567-18663StateMachineD/RxBle#Radio:  STARTED RxBleRadioOperationCharacteristicLongWrite(21173544)
02-13 14:53:42.287 17567-17567StateMachineD/RxBle#RadioOperationCharacteristicLongWrite: WRITE_DATA: Wrote a [8 bytes] chunk to characteristic with success [true].
02-13 14:53:42.294 17567-17582StateMachineD/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 14:53:42.297 17567-18988StateMachineD/RxBle#ActionObserver: ACKNOWLEDGE_LONG_CHUNK: Acknowledged!
02-13 14:53:42.299 17567-18663StateMachineD/RxBle#Radio: FINISHED RxBleRadioOperationCharacteristicLongWrite(21173544)

I added a log statement in writeResponseForMatchingCharacteristic.
    private Func1<ByteAssociation<UUID>, Boolean> writeResponseForMatchingCharacteristic() {
        return new Func1<ByteAssociation<UUID>, Boolean>() {
            @Override
            public Boolean call(ByteAssociation<UUID> uuidByteAssociation) {
                RxBleLog.d("MATCHING_CHAR: Checking if matching UUID [%s].", uuidByteAssociation.first);
                return uuidByteAssociation.first.equals(bluetoothGattCharacteristic.getUuid());
            }
        };
    }

When it's not working, even though the onCharacteristicWrite log appears, the writeResponseForMatchingCharacteristic matching function is not invoked somehow
Here a log when not working:
02-13 15:07:44.940 9074-11069D/RxBle#Radio:   QUEUED RxBleRadioOperationCharacteristicLongWrite(257835523)
02-13 15:07:44.943 9074-10958D/RxBle#Radio:  STARTED RxBleRadioOperationCharacteristicLongWrite(257835523)
02-13 15:07:44.956 9074-9074D/RxBle#RadioOperationCharacteristicLongWrite: WRITE_DATA: Wrote a [5 bytes] chunk to characteristic with success [true].
02-13 15:07:44.956 9074-10982D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 15:07:44.987 9074-10982D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520102-a308-4e56-8a52-536c2ad07147
02-13 15:07:44.988 9074-11032V/StateMachine: Received notification data [AA060200BB].
02-13 15:07:44.989 9074-11032D/StateMachine: Processing complete packet [AA060200BB].
02-13 15:07:44.989 9074-10982D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520102-a308-4e56-8a52-536c2ad07147
02-13 15:07:44.990 9074-11032D/StateMachine: Trying to transition from [START (0)] to [ACK_RECEIVED (1)].
02-13 15:07:44.991 9074-11032V/StateMachine: Received notification data [AA01023B00BB].
02-13 15:07:44.992 9074-11032D/StateMachine: Processing complete packet [AA01023B00BB].
02-13 15:07:44.993 9074-11032D/StateMachine: Trying to transition from [ACK_RECEIVED (1)] to [RESPONSE_RECEIVED (2)].
02-13 15:07:44.994 9074-11032D/StateMachine: Finishing with result [[B@841ec62].
02-13 15:07:44.996 9074-11032D/StateMachine: Emitting event [[B@841ec62].
02-13 15:07:44.996 9074-11032D/StateMachine: Unsubscribing from subscriber(s).
02-13 15:07:45.058 9074-9104D/OpenGLRenderer: endAllActiveAnimators on 0x7d6a1cfc00 (MenuPopupWindow$MenuDropDownListView) with handle 0x7d6ddff500
02-13 15:08:14.949 9074-11084D/StateMachine: Finishing with error (Received onError without having requested it).
02-13 15:08:14.952 9074-10958D/RxBle#Radio: FINISHED RxBleRadioOperationCharacteristicLongWrite(257835523)

And one when it works:
02-13 15:07:37.149 9074-11069D/RxBle#Radio:   QUEUED RxBleRadioOperationCharacteristicLongWrite(202844953)
02-13 15:07:37.150 9074-10958D/RxBle#Radio:  STARTED RxBleRadioOperationCharacteristicLongWrite(202844953)
02-13 15:07:37.153 9074-9074D/RxBle#RadioOperationCharacteristicLongWrite: WRITE_DATA: Wrote a [5 bytes] chunk to characteristic with success [true].
02-13 15:07:37.154 9074-9087D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 15:07:37.155 9074-11128D/RxBle#RadioOperationCharacteristicLongWrite: MATCHING_CHAR: Checking if matching UUID [b4520101-a308-4e56-8a52-536c2ad07147].
02-13 15:07:37.156 9074-11128D/RxBle#ActionObserver: ACKNOWLEDGE_LONG_CHUNK: Acknowledged!
02-13 15:07:37.157 9074-10958D/RxBle#Radio: FINISHED RxBleRadioOperationCharacteristicLongWrite(202844953)
02-13 15:07:37.187 9074-9087D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=b4520102-a308-4e56-8a52-536c2ad07147
02-13 15:07:37.188 9074-11032V/StateMachine: Received notification data [AA060200BB].
02-13 15:07:37.188 9074-11032D/StateMachine: Processing complete packet [AA060200BB].

Yup. It seems that this is the exact problem with a race condition. The RxBleGattCallback recieves the notification about finished write but it is not transmitted to the observer (in this situation Long Write Operation). I will need to look into this tomorrow.

In fact, now that you talked about the observer not being notified, I think I might have hit a similar (same?) problem when I first did the "flashing" implementation. At first, what I tried to do was to "subscribe" multiple time to writeCharacteristic without never really waiting between "write" operation.
My idea was that this would fill the queue and the "producer" thread would slowly but steadily remove elements from the queue. However, the queue quickly (maybe after two or three writes) become stalled only queuing more and more operation without removing new entries.
At first I thought it was a problem with threading on my part. But now that we talked about operation not being notified, I think that what happened at that time was the exact same problem as now. The notification was not making it's way to the observer (at that time the RxBleRadioOperationCharacteristicWrite). This was of course making the operation taking control of the thread forever as their was not timeout operation before. This was in returning preventing the thread from popping item from the queue.
Feel free to ping me as I can easily reproduce the problem. I can try solution or give you some detailed log when working and when not working.
Thanks for looking into this.

I think one of the problem (I say one, see below) is that RxBleGattCallback#bluetoothGattBehaviorSubject was not serialized causing it to fail when multiple thread were writing to it. I changed it to:
    private final SerializedSubject<BluetoothGatt, BluetoothGatt> bluetoothGattBehaviorSubject =
            BehaviorSubject.<BluetoothGatt>create().toSerialized();

And it did help since I now see all the ACK when onCharacteristicWrite is being notified. However, it still hangs at some point:
02-13 15:46:54.609 16800-18734 D/FlashFirmwareStateMachine: Writing [AA06063A000000003C4D23343232C223304B802923304B10105CCBAB51EE8C05A6CDD6A0531246B6977D4B49808AE5A6F85A6016D4BFD1DF18A791D803E82330D765D789540F3DCA0B942F3A203D07D16540C306BE7C9C4783F1C3111D7DC9E6516873A4C71C6C876836B1A7E523341F9BEC86DFF644E407AE1963E37AAEF666C6E1DC87AF1C5381F17D0E8E2D9F4382CB1792C3077482233197E21EC36416E53281696CB520F25675F749AD7451326E919660F183C98A250B7E1F1A6D43F81D769481559EDC8FF87480918BFA316A42B969DE118FF1928AF88F7230571E8DE2626D233587A67660BE6EC45049B07BC9CEBC975E30518C8456137AA9B1372779BC2D5BCCBB89B5E3C6D07BBE743FD39C12F33EBB] to device.
02-13 15:46:54.612 16800-18734 D/FlashFirmwareStateMachine: Emitting event [1 / 697 (0.14%)].
02-13 15:46:54.863 16800-18768 D/RxBle#Radio:   QUEUED RxBleRadioOperationCharacteristicLongWrite(86038308)
02-13 15:46:54.864 16800-18631 D/RxBle#Radio:  STARTED RxBleRadioOperationCharacteristicLongWrite(86038308)
02-13 15:46:54.868 16800-16800 D/RxBle#RadioOperationCharacteristicLongWrite: WRITE_DATA: Wrote a [20 bytes] chunk to characteristic with success [true].
02-13 15:46:54.870 16800-16812 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 15:46:54.871 16800-16812 D/RxBle#BluetoothGatt: onCharacteristicWrite Entering subject characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 15:46:54.872 16800-16812 D/RxBle#BluetoothGatt: onCharacteristicWrite Exiting subject characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 15:46:54.874 16800-18736 D/RxBle#RadioOperationCharacteristicLongWrite: MATCHING_CHAR: Checking if matching UUID [b4520101-a308-4e56-8a52-536c2ad07147].
02-13 15:46:54.876 16800-18736 D/RxBle#ActionObserver: ACKNOWLEDGE_LONG_CHUNK: Acknowledged!
02-13 15:46:54.879 16800-16800 D/RxBle#RadioOperationCharacteristicLongWrite: WRITE_DATA: Wrote a [20 bytes] chunk to characteristic with success [true].
02-13 15:46:54.880 16800-16815 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 15:46:54.881 16800-16815 D/RxBle#BluetoothGatt: onCharacteristicWrite Entering subject characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 15:46:54.883 16800-16815 D/RxBle#BluetoothGatt: onCharacteristicWrite Exiting subject characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 15:46:54.885 16800-18768 D/RxBle#RadioOperationCharacteristicLongWrite: MATCHING_CHAR: Checking if matching UUID [b4520101-a308-4e56-8a52-536c2ad07147].
02-13 15:46:54.886 16800-18768 D/RxBle#ActionObserver: ACKNOWLEDGE_LONG_CHUNK: Acknowledged!
02-13 15:46:54.890 16800-16800 D/RxBle#RadioOperationCharacteristicLongWrite: WRITE_DATA: Wrote a [20 bytes] chunk to characteristic with success [true].
02-13 15:46:54.892 16800-16812 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 15:46:54.893 16800-16812 D/RxBle#BluetoothGatt: onCharacteristicWrite Entering subject characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 15:46:54.894 16800-16812 D/RxBle#BluetoothGatt: onCharacteristicWrite Exiting subject characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 15:46:54.897 16800-18736 D/RxBle#RadioOperationCharacteristicLongWrite: MATCHING_CHAR: Checking if matching UUID [b4520101-a308-4e56-8a52-536c2ad07147].
02-13 15:46:54.898 16800-18736 D/RxBle#ActionObserver: ACKNOWLEDGE_LONG_CHUNK: Acknowledged!
02-13 15:46:54.903 16800-16800 D/RxBle#RadioOperationCharacteristicLongWrite: WRITE_DATA: Wrote a [20 bytes] chunk to characteristic with success [true].
02-13 15:46:54.906 16800-16812 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 15:46:54.907 16800-16812 D/RxBle#BluetoothGatt: onCharacteristicWrite Entering subject characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 15:46:54.907 16800-16812 D/RxBle#BluetoothGatt: onCharacteristicWrite Exiting subject characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 15:46:54.910 16800-18768 D/RxBle#RadioOperationCharacteristicLongWrite: MATCHING_CHAR: Checking if matching UUID [b4520101-a308-4e56-8a52-536c2ad07147].
02-13 15:46:54.911 16800-18768 D/RxBle#ActionObserver: ACKNOWLEDGE_LONG_CHUNK: Acknowledged!
02-13 15:46:54.923 16800-16800 D/RxBle#RadioOperationCharacteristicLongWrite: WRITE_DATA: Wrote a [20 bytes] chunk to characteristic with success [true].
02-13 15:46:54.923 16800-16815 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 15:46:54.924 16800-16815 D/RxBle#BluetoothGatt: onCharacteristicWrite Entering subject characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 15:46:54.925 16800-16815 D/RxBle#BluetoothGatt: onCharacteristicWrite Exiting subject characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 15:46:54.926 16800-18736 D/RxBle#RadioOperationCharacteristicLongWrite: MATCHING_CHAR: Checking if matching UUID [b4520101-a308-4e56-8a52-536c2ad07147].
02-13 15:46:54.926 16800-18736 D/RxBle#ActionObserver: ACKNOWLEDGE_LONG_CHUNK: Acknowledged!
02-13 15:46:54.930 16800-16812 D/RxBle#BluetoothGatt: onCharacteristicWrite characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 15:46:54.931 16800-16812 D/RxBle#BluetoothGatt: onCharacteristicWrite Entering subject characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 15:46:54.932 16800-16812 D/RxBle#BluetoothGatt: onCharacteristicWrite Exiting subject characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
02-13 15:46:54.932 16800-16800 D/RxBle#RadioOperationCharacteristicLongWrite: WRITE_DATA: Wrote a [20 bytes] chunk to characteristic with success [true].
02-13 15:47:24.932 16800-18631 D/RxBle#Radio: FINISHED RxBleRadioOperationCharacteristicLongWrite(86038308)
02-13 15:47:24.943 16800-18744 D/FlashFirmwareStateMachine: Finishing with error (Received onError without having requested it).

I see the WRITE_DATA: Wrote a [20 bytes] chunk to characteristic with success [true]. but then never received a onCharacteristicWrite callback, weird.

This issue with no callback from the Android BLE Stack I have heard of - that is why all operations which are expecting a callback have some sort of a timeout. For this you could add a delay between writes and check if that will help.

I don't think it comes from the Android BLE stack. I think it's an event ordering problem. Let's check the last snippet of log more closely (lightly modified to make fit easier in the screen):
15:46:54.926 18736 ActionObserver: ACKNOWLEDGE_LONG_CHUNK: Acknowledged!
15:46:54.930 16812 BluetootGatt: onCharacteristicWrite characteristic=<uuid> status=0
15:46:54.932 16800 LongWriteOperation: WRITE_DATA: Wrote a [20 bytes] chunk to characteristic with success [true].
15:47:24.932 18631 Radio: FINISHED RxBleRadioOperationCharacteristicLongWrite(86038308)

Here, we see the last acknowledgement. Then, before WRITE_DATA has a change to log, we see the onCharacteristicWrite callback being notified. Then 2ms later, we then see the actual WRITE_DATA log statement.
So, somehow, before the ACK checker has been setup correctly, the onCharacteristicWrite is already being notified. When the ACK checker is then ready to process event, the event has already been processed is thus missed.
Clearly some threading issue, not quite sure what is causing this however.

Could you confirm by printing out the number of the batch which the log is referring to?
Back in 2014 when I was developing a FW update functionality for a device I thought I had a similar issue but it was a side-channel ACK as far as I remember - Android BT Stack responded correctly in terms of the sequence.
Here the problem may lay in using the doOnSubscribe which is actually happening before the subscription taking place itself. I will look into creating doAfterSubscribe which could help.
Neverthless could you add a simple counter to be sure about which log is for which batch of the transmission?

Here one log with batch sequence number. The INC_BATCH comes before the bluetoothGatt.writeCharacteristic(bluetoothGattCharacteristic) call while the WRITE_DATA comes after it.
The counter was added to RxBleGattCallback as a static AtomicInteger sCounter. It is incremented only between the two INC_BATCH log statements. Rest of logs are using the value currently set.
 08:24:59.604 8263-9045 D/RxBle#ActionObserver: ACKNOWLEDGE_LONG_CHUNK: Acknowledged!
 08:24:59.606 8263-8263 D/RxBle#RadioOperationCharacteristicLongWrite: INC_BATCH: Value before incrementing batch number is [22].
 08:24:59.607 8263-8263 D/RxBle#RadioOperationCharacteristicLongWrite: INC_BATCH: Value after incrementing batch number is [23].
 08:24:59.609 8263-8263 D/RxBle#RadioOperationCharacteristicLongWrite: WRITE_DATA (23): Wrote a [20 bytes] chunk to characteristic with success [true].
 08:24:59.611 8263-8276 D/RxBle#BluetoothGatt: onCharacteristicWrite (23) characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
 08:24:59.612 8263-8276 D/RxBle#BluetoothGatt: onCharacteristicWrite (23) Entering subject characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
 08:24:59.612 8263-8276 D/RxBle#BluetoothGatt: onCharacteristicWrite (23) Exiting subject characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
 08:24:59.613 8263-9055 D/RxBle#RadioOperationCharacteristicLongWrite: MATCHING_CHAR (23): Checking if matching UUID [b4520101-a308-4e56-8a52-536c2ad07147].
 08:24:59.615 8263-9055 D/RxBle#ActionObserver: ACKNOWLEDGE_LONG_CHUNK: Acknowledged!
 08:24:59.616 8263-8263 D/RxBle#RadioOperationCharacteristicLongWrite: INC_BATCH: Value before incrementing batch number is [23].
 08:24:59.617 8263-8263 D/RxBle#RadioOperationCharacteristicLongWrite: INC_BATCH: Value after incrementing batch number is [24].
 08:24:59.621 8263-8275 D/RxBle#BluetoothGatt: onCharacteristicWrite (24) characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
 08:24:59.621 8263-8275 D/RxBle#BluetoothGatt: onCharacteristicWrite (24) Entering subject characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
 08:24:59.622 8263-8275 D/RxBle#BluetoothGatt: onCharacteristicWrite (24) Exiting subject characteristic=b4520101-a308-4e56-8a52-536c2ad07147 status=0
 08:24:59.623 8263-8263 D/RxBle#RadioOperationCharacteristicLongWrite: WRITE_DATA (24): Wrote a [20 bytes] chunk to characteristic with success [true].

In last batch (i.e 24), we see that counter is incremented, the write characteristic is then called, but the onCharacteristicWrite is notified before the writeData function has finished yet.
I will try the doAfterSubscribe, but I'm not sure it will solve the problem.

Well in fact, there is no doAfterSubscribe operator, so cannot use it.

I have created one - straight forward implementation. The potential fixes are now in the process of code review. I hope to merge them into the master before the end of the day (shortly) so you could test it with a snapshot.

@DariuszAniszewski I checked the subject change and I think you pick the wrong one. The one I think being called by multiple various thread is more likely the bluetoothGattBehaviorSubject which is used in all Gatt callbacks.
Overall, I think all subject in this class should be reviewed as to where they are called by various different thread or not. If it's the case, they would need to be toSerialized also.

Most of the subjects used in the RxBleGattCallback are not subjects to rapid changes. bluetoothGattBehaviourSubject has no critical observers in terms of sequential delivery of events. Adding .toSerialized() on all subjects could add a non-negligible overhead - that is why it is not added everywhere.
A new snapshot should be available. Could you try it out?

I agree, but as you know, they are not thread-safe. Not having rapid changes does not remove the chance that a race condition or dead clock happens in the subject, less likely if there are not much changes but quite possible.
To my eye, the bluetoothGattBehaviourSubject seems problematic as being called by all callbacks. That means that an onCharacteristicWrite and multiple onCharacteristicChanged happening rapidly in the same time window would call the bluetoothGattBehaviourSubject.onNext from various different thread which is an undefined behavior as of RxJava since subjects are not thread safe.
That's why I think this one (bluetoothGattBehaviourSubject) should be toSerialized to prevent problems when multiple stuff happens are the same time.
I will test your branch and report.

Nop, it did not solve the issue (I changed a bit log statement since now we pinned point the problem):
 10:40:06.520 30341-30341 D/ LongWriteOp: INC_COUNTER: Value just after increment is (10).
 10:40:06.521 30341-30341 D/ LongWriteOp: WRITE_DATA: Wrote value with counter (10).
 10:40:06.522 30341-30459 D/BluetoothGatt: onCharacteristicWrite (10) characteristic=<uuid> status=0
 10:40:06.524 30341-30341 D/ LongWriteOp: INC_COUNTER: Value just after increment is (11).
 10:40:06.526 30341-30459 D/BluetoothGatt: onCharacteristicWrite (11) characteristic=<uuid> status=0
 10:40:06.526 30341-30341 D/ LongWriteOp: WRITE_DATA: Wrote value with counter (11).

So it seems that we should somehow synchronise the subscription to the onCharacteristicWrite with writeCharacteristic. Only hackish solutions come to my mind at the moment.

Yeah I know, I thought about using some replay or caching logic, so that the "notification" is held until it can be used, but they would probably prove problematic in some cases.
To work, we would need to cache event happening between just after the subscribe until they are processed ensuring no caching occurs outside the boundaries to avoid false positive.
I tried a bit yesterday night but was not able to do so. I would need to dive deeper to understand at which moment stuff are being done.

I am not in the office anymore. What if you could synchronise this method on rxBleGattCallback:
    private void writeData(byte[] bytesBatch) {
        bluetoothGattCharacteristic.setValue(bytesBatch);
        final boolean success = bluetoothGatt.writeCharacteristic(bluetoothGattCharacteristic);
        if (!success) {
            throw new BleGattCannotStartException(bluetoothGatt, BleGattOperationType.CHARACTERISTIC_LONG_WRITE);
        }
    }

and in the RxBleGattCallback add a synchronized block in the onCharacteristicWrite() callback?

The synchronized block would be needed to used on RxBleGattCallback.this ofcourse.

That would probably work indeed, will test that later today and report.

It seemed it help as through various invocations, I never hit the event being out of order and execution goes farther (batch 109 was my best).  However, it still hang at some point, seems we a chasing multiple problems here :)
Log:
13:44:13.191 14397-14397D/LongWriteOp: INC_COUNTER: Value just after increment is (82).
13:44:13.192 14397-14397D/LongWriteOp: WRITE_DATA: Wrote value with counter (82).
13:44:13.193 14397-14409D/BluetoothGatt: onCharacteristicWrite (82) characteristic=<uuid> status=0
13:44:13.194 14397-15081D/LongWriteOp: ACK_CHECK: Checking for characteristic (82).
13:44:13.195 14397-15081D/LongWriteOp: ACK: Acknowledged (82)!
13:44:13.196 14397-14397D/LongWriteOp: INC_COUNTER: Value just after increment is (83).
13:44:13.199 14397-14397D/LongWriteOp: WRITE_DATA: Wrote value with counter (83).
13:44:13.199 14397-14414D/BluetoothGatt: onCharacteristicWrite (83) characteristic=<uuid> status=0

For batch 83, even if the onCharacteristicWrite happens after the write data correctly, it seems the ACK_CHECK is not invoked as expected.
I will need to dive deeper into Rx scheduler to understand what happen exactly. If you have ideas or want to try stuff, will be happy to check them out.

I think it may still be the same issue. Adding the sychronisation only made the window smaller than before. Ehhh... As a friend of mine said: You have to be this tall [points high in the sky] to write threadsafe code
I will probably have to create some kind of a wrapper and old-fashioned callbacks for writing characteristic with no response setting.
Btw. if you are able to write with response you probably will not face the problem.

An idea just popped inside my head when already in bed:
You could change:
        rxBleGattCallback.getOnCharacteristicWrite()
                .lift(new OperatorDoAfterSubscribe<ByteAssociation<UUID>>(writeNextBatch(batchSize, byteBuffer)))

to something like (exchange lambdas for anonymous classes ofc and pardon pseudocode):
Observable.fromEmitter(emitter -> {
    Subscription s = rxBleGattCallback.getOnCharacteristicWrite().subscribe(emitter);
    emitter.setCancellation(() -> { s.unsubscribe() });
    writeNextBatch();
})

This could help in always subscribing to the notification before writing the batch of data.

@maoueh I have pushed a potential fix for the race condition. You could test it once you will have a moment.

@dariuszseweryn Yup, that fixed the issue, good job!
I also tested by removing our "old" fixes like the synchronized block and the serialized subject and they seems to be not required (I still think bluetoothGattBehaviourSubject should be made SerializedSubject, but that's another topic :)).
So, the code as in the repository right now seem to work correctly for my use case.
Out of scope, but two questions while I have you.
Would you guys accept a PR that would enable the library to execute radio operation out of the main thread? We have a fork where we execute off main thread for most phone (we kept main thread only when manufacturer is Samsung and Android version is 4.3)?
Would you guys accept a PR that would enable to execute my own radio operation? The idea here would be to avoid going on & off of the RxRadio queue. The PR could look like:
RxBleConnection {
  <T> Observable<T> queue(Func3<Scheduler, BluetoothGatt, RxBleGattCallback, RxBleRadioOperation<T>> builder);
}

Of course, this a JavaDoc would explain that usage of the method should be made upon great care.
Anyway, all in all, thanks for the great support!

Glad that one solution finally helped. I will revert all unneeded changes tomorrow.
As for the main thread versus background - I am a bit afraid that there may be more devices that are more stable while using the main thread than we know of. In this situation we would need to keep a list of devices that need a specific solution - which could be a burden.
About the custom operation - I see no particular reason to do it like this. I was thinking about just exposing the RxBleGattCallback and BluetoothGatt for direct usage for optimisation purposes.
Could you elaborate more on your use-case? We would then also have material for internal discussions.

I have added some optimisations to the long write operations. You can check it out. Should use a lot less allocations.
Best Regards

@dariuszseweryn Ok good, I check the changes, don't see a reason for them not to work. But I will test the latest branch nonetheless.
As for the two questions, my use case is simply to optimize the flash firmware operation. With all optimizations in (scheduler off main thread, single operation in the queue), I was able to go from 140s in the worst case (heavy-lifted screen, balanced priority connection) to only 39s in my last try (high priority connection, scheduler off main thread, one operation in the queue).
I will open two issues to keep discussion at the right place for them. I will provide my answer there.


Add benchmarks to buildbot build

As we have benchmarks, we should maintain them, i.e. detect when they don't run anymore.
A way is to add their execution to the buildbot (travis probably cannot afford)
@vigsterkr @lambday any comments?

come to irc

closing as per dicussion


Uncaught TypeError: Cannot read property 'id' of undefined

[Enter steps to reproduce:]

...
...

Atom: 1.41.0 x64
Electron: 4.2.7
OS: Mac OS X 10.14.6
Thrown From: Atom Core
Stack Trace
Uncaught TypeError: Cannot read property 'id' of undefined
At /Users/elliemcgurk/Desktop/Atom.app/Contents/Resources/app/static/<embedded>:11

TypeError: Cannot read property 'id' of undefined
    at extraRenderedScreenLines.forEach (/Users/elliemcgurk/Desktop/Atom.app/Contents/Resources/app/static/<embedded>:11:76051)
    at Map.forEach (<anonymous>)
    at TextEditorComponent.renderLineTiles (/Users/elliemcgurk/Desktop/Atom.app/Contents/Resources/app/static/<embedded>:11:75983)
    at TextEditorComponent.renderContent (/Users/elliemcgurk/Desktop/Atom.app/Contents/Resources/app/static/<embedded>:11:74509)
    at TextEditorComponent.renderScrollContainer (/Users/elliemcgurk/Desktop/Atom.app/Contents/Resources/app/static/<embedded>:11:73969)
    at TextEditorComponent.render (/Users/elliemcgurk/Desktop/Atom.app/Contents/Resources/app/static/<embedded>:11:72748)
    at Object.updateSync (/Users/elliemcgurk/Desktop/Atom.app/Contents/Resources/app/static/<embedded>:14:136093)
    at TextEditorComponent.updateSyncBeforeMeasuringContent (/Users/elliemcgurk/Desktop/Atom.app/Contents/Resources/app/static/<embedded>:11:70606)
    at TextEditorComponent.updateSync (/Users/elliemcgurk/Desktop/Atom.app/Contents/Resources/app/static/<embedded>:11:67993)
    at TextEditorComponent.didMouseWheel (/Users/elliemcgurk/Desktop/Atom.app/Contents/Resources/app/static/<embedded>:11:92801)

Commands
  2x -9:18.2.0 core:paste (div.line.cursor-line)
  2x -8:42.4.0 core:backspace (input.hidden-input)
     -8:19.6.0 core:paste (span.syntax--text.syntax--html.syntax--basic)
     -8:16.3.0 core:backspace (input.hidden-input)
     -8:00.2.0 core:paste (span.syntax--text.syntax--html.syntax--basic)
     -7:57.3.0 core:backspace (input.hidden-input)

Non-Core Packages
pigments 0.40.2

Thanks for reaching out!
We require the template to be filled out on all new issues and pull requests. We do this so that we can be certain we have all the information we need to address your submission efficiently. This allows the maintainers to spend more time fixing bugs, implementing enhancements, and reviewing and merging pull requests.
Thanks for understanding and meeting us half way 😀


Feat/oidc discovery

What kind of change does this PR introduce? (check at least one)

[ ] Bugfix
[X] Feature
[ ] Code style update
[ ] Refactor
[ ] Other, please describe:

Does this PR introduce a breaking change? (check one)

[ ] Yes
[X] No

[X] You consent that the copyright of your pull request source code belongs to Authlib's author.

I forgot to explain what this patch does, sorry: It adds OIDC Discovery. The first step is a new module authlib.specs.oidc.discovery that provides the method get_oid_provider_meta. This method returns a dict with the configuration provided by the endpoint. It also already checks for the REQUIRED keys according to the spec.

I'm going to use rfc8414 instead. They are compatible in most cases.


add: new policy limit config map for serviceaccount

Signed-off-by: eminaktas<EMAIL_ADDRESS>Signed-off-by: Emin Aktas<EMAIL_ADDRESS>Related Issue(s)

None
Description

Adds a new policy for limiting a ConfigMap.
~ kubectl kyverno test other/limit-configmap-for-sa

Executing limit-configmap-for-sa...
applying 1 policy to 2 resources...

│───│────────────────────────│──────────────────────────────────│───────────────────────────────────────────│────────│
│ # │ POLICY                 │ RULE                             │ RESOURCE                                  │ RESULT │
│───│────────────────────────│──────────────────────────────────│───────────────────────────────────────────│────────│
│ 1 │ limit-configmap-for-sa │ limit-configmap-for-sa-developer │ default/ConfigMap/any-configmap-name-good │ Pass   │
│ 2 │ limit-configmap-for-sa │ limit-configmap-for-sa-developer │ default/ConfigMap/any-configmap-name-bad  │ Pass   │
│───│────────────────────────│──────────────────────────────────│───────────────────────────────────────────│────────│

Checklist

[x] I have read the policy contribution guidelines.
[x] I have added test manifests and resources covering both positive and negative tests that prove this policy works as intended.

cc @chipzoller @samj1912 @realshuting

Thanks for this PR! Would you mind explain what use case this solves for you? It appears that it is fairly closely gated (single ConfigMap by name, single ServiceAccount by name, in a single Namespace by name) and so we're curious how this would be consumed.

Yes, that is the case. My motivation is to protect a ConfigMap since users with developer ServiceAccount are allowed to take any actions on ConfigMaps in our environment.
Also, we can extend it with more CofigMap, ServiceAccounts and etc. Should I include the below example with another rule?
    match:
      any:
      - resources:
          kinds:
          - "ConfigMap"
        subjects:
        - kind: ServiceAccount
          name: developer
          namespace: kube-system
      - resources:
          kinds:
          - "ConfigMap"
        subjects:
        - kind: ServiceAccount
          name: another-service-account
          namespace: another-namespace
    preconditions:
      all:
      - key: "{{request.object.metadata.namespace}}"
        operator: In
        value:
        - "any-namespace"
        - "another-namespace"
      - key: "{{request.object.metadata.name}}"
        operator: In
        value:
        - "any-configmap-name-good"
        - "another-namespace"

The above should work.

@chipzoller Updated it. Thanks for the review. 🚀


FEATURE - Add price ticker to broker

Description
This PR adds an endpoint and CLI command (sparkswap info market-stats) that provides the previous data based off of the past 24 hours from the orderbook. Also referred to as "price ticker".
Additionally this call can be used w/ integrations such as CCXT
Price Ticker Information
All values are in quote/counter currency IE LTC

datetime - current datetime stamp (possibly in nano)
high - highest price for the past 24 hours
low - lowest price for the past 24 hours
bid - current best bid
ask - current best ask
vwap - add up price of all trades (fills) and divide by amount of trades made in the same time period
baseVolume - base amount traded in last 24 hours
quoteVolume - counter amount traded in last 24 hours

Changes Include:

added nano-seconds to the broker repo
adding a new cli command sparkswap info market-stats
adding a new grpc service under the InfoService
adding a MarketStats class used for data calculations

Related PRs
List related PRs if applicable
Todos

[ ] Tests
[x] Documentation
[x] Link to Trello

 market summary info (fetchTicker) [ccxt]


integrate stalebot

https://github.com/apps/stale

https://github.com/octomation/go-service/commit/c1e6a708f6ac420de14981d812b03c46ed430aa0


cheatsheet-update

issue:#344
I have also fetched the new updates
Proposed Changes

Additional Info

Any additional information or context

Checklist

[ ] ✅ My code follows the code style of this project.
[ ] 📝 My change requires a change to the documentation.
[ ] 🎀 I have updated the documentation accordingly.
[ ] 🌟 ed the repo

[ ] Bug fix (non-breaking change which fixes an issue)
[ ] New feature (non-breaking change which adds functionality)
[ ] Breaking change (fix or feature that would cause existing functionality to change)

Output Screenshots

Screenshot #1
Screenshot #2

Title goes here
Title goes here

Image goes here
Image goes here

You added the navbar link for cheatsheets before, now it's not there


Michaeltyson master

restore the scroll offset when keyboard hide

Hi! I'd rather not merge this in as it is, because the user may scroll during the edit operation, and if the scroll position is restored to the original after the keyboard is hidden, it may be bewildering to the user. Better to always do the "expected" thing, which is not scrolling to what the user will see as an arbitrary position.
Is this to work around a particular issue?

oh, in my App, the scrollview offset has changed after the keyboard hide, so I saved the original offset and restore it when keyboard hide.

Are you able to reproduce it within the sample app, possibly with some changes?

I think I can try it,  but maybe need some time. I will comment to you when i finished.
Have a nice day ~

Okay, cool - thank you! You too!


Use even more optional chaining in the src/display/api.js file

This slightly shortens the code, in various destroy-methods, which cannot hurt.
Also, use pre-processor checks to simplify PDFDocumentLoadingTask.destroy in the Firefox PDF Viewer since the PDFWorker.fromPort-method isn't used there.

/botio test

Thank you!


Processing hfuns before all global vars are fully populated

Opening this issue per @tlienart 's request on Slack. Also cc'ing @fredrikekre who was involved in the thread.
Currently, process_utils is called before all global variables are fully populated. As such, if an hfun depends on some global variable, it is possible for it to be called with incomplete information. You may see here for the line where process_utils is called but several lines later is when the first actual pass of the files is done.
Below is an MWE:

Make a new site with some tagged articles (I used one of the default themes as is)
Make the following hfun in utils.jl:

function hfun_test_population()
  println(Franklin.globvar("fd_page_tags"))
  return ""
end

Put the following in your table.html file

{{ test_population }}

Call serve()

You will see that the first time hfun_test_population is called (and the {{ test_population }} is processed), the dictionary is only partially complete.

One possible fix is to make a separate "metadata pass" in which all of the static global/local variables (authors, dates, tags, titles, etc.) are precomputed without converting the markdown/html. Then, on the second pass, the util functions will all have access to the complete information when being processed. The downside of this is that the entire site has to be processed twice (but still only converted once), which takes time. It could possibly be integrated into scan_input_dir!.

Just for the context Marco, what were you trying to achieve initially? thanks (and thanks for the detailed issue!)

For context, what I wanted to do was have a section of the side bar that had links to the top 5 tags by post count. I also wanted a "tag landing page" which would be at :site/tag. This was so a user didn't have to search for tags by going through posts and then going to :site/tag/code to see all the pages with the code tag. The hfuns I wrote for these two things are here (please let me know if you see an issue with them, though, other than the bug in this issue, they worked fine):
function hfun_tag_landing_page()
  PAGE_TAGS = Franklin.pagevar("fd_page_tags")
  TAG_COUNT = Franklin.invert_dict(PAGE_TAGS)
  markdown = ""
  for k in sort(collect(keys(TAG_COUNT)))
    markdown *= "* ["*k*"](" * Franklin.joinpath("/tag/", k) * ") (" * string(length(TAG_COUNT[k])) * ")\n"
  end
  return fd2html(markdown, internal=true)
end

function hfun_tag_side_bar()
  PAGE_TAGS = Franklin.pagevar("fd_page_tags")
  TAG_COUNT = Franklin.invert_dict(PAGE_TAGS)
  markdown = ""
  # we want (tag, postcount) tuples to be ordered lexicographically by descending post count and then by
  # ascending alphabetical order.
  for k in sort(collect(keys(TAG_COUNT)), by=x->(-length(TAG_COUNT[x]), x))[1:(min(length(keys(TAG_COUNT)), 5))]
    markdown *= "* ["*k*"](" * Franklin.joinpath("/tag/", k) * ") (" * string(length(TAG_COUNT[k])) * ")\n"
  end
  return fd2html(markdown, internal=true)
end

What I noticed is that pages had only the tag information that was present in the pages that were ancestors of it on the path back up to the root directory. So like the main index.md page had only it's tags in the side bar, but a really nested page would have many more.

Here are some things that I tried to resolve the problem. None of them worked, though that may have just been cause I did it wrong.

I made a FD_ENV :METADATA_PASS variable which acted sort of like FD_ENV :FULL_PASS. Essentially, the very first time that a full pass was completed, METADATA_PASS was set to true. Then, I made all of the statements that actually converted code have FD_ENV[:METADATA_PASS] || <previous code>. Then, I just made serve call fd_full_pass twice and change FD_ENV[:METADATA_PASS] to false after the first one. This didn't work but I can't remember why (I think some hfun variables were being called before they were defined).

I tried to use FD_ENV[:FULL_PASS] to change what the hfuns were outputting. My understanding was that FD_ENV[:FULL_PASS] is set to false after the first full pass is done (at which time all global vars should be fully populated). So, I made my hfun something like

function hfun_test_example()
     !FD_ENV[:FULL_PASS] || return "{{ test_example }}"
    # original code here
end

The idea here was that we should continuously replace "{{ test_example }}" with itself until all the global variables are set before replacing it with the html that we really wanted. Each time that process_utils was called it would reprocess "{{ test_example }}" until the full pass was done. This didn't work as it would just replace it with "{{ test_example }}" once which would appear as plain text in the final page. It is very likely that I just don't understand how html works or how the hfuns are supposed to replace stuff. Nevertheless, it would be a nice feature if we could return nothing from an hfun to delay its processing.

I tried moving around when process_utils and generate_tag_pages but I ran into the same issues from point 1 where it would crash because some variables were being called before their definition.

Thanks a lot for all this careful thinking, I need to take some time to try this myself carefully and see what can be done to better support it; I think your initial analysis of the necessary "double pass" is correct with one pass that solely looks at page var definitions. There may be a way to do this cleverly so that either

there's a parsing phase which ignores everything that's not @def (that should be pretty quick and is probably the easiest option) and then a second phase which looks at everything
there's a single full parsing phase but the ordering of when blocks are processed is done more carefully to ensure that when hfun are processed, all page vars are available, this would require parsing each page, storing the blocks, and then doing a pass where each page is built

The second one has the advantage of a single pass but would require storing a fair bit of stuff for sites which have many pages like julialang (though in the grand scheme of things it's probably very little by modern computing standards).
I think I'll try the first one which is simpler and, assuming it doesn't have too much of an impact on the speed of processing (my hunch is that it won't) then that's probably the easiest option.

Just to say that I ran into this too, also in the context of tags. I wanted to create a page listing the tags and showing their relative popularity, and then have each one link to a summary page for that tag listing all the posts with the tag, which sounds basically exactly the same as @MarcMush was doing.
One possible way to fix it could be to do some dependency analysis like Pluto.jl does, to figure out what order to execute the Julia code. It occurs to me that a website is kind of like a notebook where the cells are scattered across different pages :).

Alright, I think I have a satisfactory first attempt at this which is in branch v010. I would appreciate if you could give it a shot and let me know what you think. It introduces a macro @delay for hfun definition which need the full scope (i.e. the completion of a full pass) to be done properly. When a function is marked as @delay then every page which calls it will be re-built after the first pass.
Here's an example from the OP:
utils.jl
@delay function hfun_test_population()
    all_tags = globvar("fd_page_tags")
    if all_tags === nothing
        return ""
    end
    all_tags = union(values(all_tags)...)
    tagstr = strip(prod("$t " for t in all_tags))
    return "
ALL TAGS: $tagstr
"
end

use in index.md:
@def tags = ["tag1", "tag2"]
{{test_population}}

in menu1.md
@def tags = ["tag2", "tag3"]

upon serve() with no modification:

This is very fast, and, assuming you only have a few such functions, it only requires one or two pages maybe to re-build a second time (so maybe an extra 10ms) which seems reasonable.
Feedback welcome!

I like this approach. delay isn't a bad choice (especially if later usage allows delaying until some global variable matches a condition, like @delay_until(FULLPASS). I will test it out and let you know if I run into issues.

Awesome, thanks!

now released


fix(Anchor): Allow Cards to be hovered inside Anchors

Overview

Fixes a stacking context issue with Anchors that prevented their children from being hovered on their own.
Adds a few extra pixels to the focus outline for interface and standard links.
Adds story

PR Checklist

[ ] Related to designs:
[ ] Related to JIRA ticket: ABC-123
[x] I have run this code to verify it works
[ ] This PR includes unit tests for the code change

📬Published Alpha Packages:@codecademy/gamut-kit@0.3.102-alpha.440178.0@codecademy/gamut-labs@17.0.1-alpha.440178.0@codecademy/gamut@32.18.8-alpha.440178.0<EMAIL_ADDRESS>
🚀 Styleguide deploy preview ready!https://609e9508d93f45f4dee4e976--gamut-preview.netlify.appDeploy Logs

📬Published Alpha Packages:@codecademy/gamut-kit@0.4.5-alpha.a94a11.0@codecademy/gamut-labs@18.3.5-alpha.a94a11.0@codecademy/gamut@33.4.3-alpha.a94a11.0<EMAIL_ADDRESS>
🚀 Styleguide deploy preview ready!https://60b78672e964ca2dc5596b5e--gamut-preview.netlify.appDeploy Logs

📬Published Alpha Packages:@codecademy/gamut-kit@0.4.7-alpha.72f38f.0@codecademy/gamut-labs@18.4.1-alpha.72f38f.0@codecademy/gamut@33.4.4-alpha.72f38f.0<EMAIL_ADDRESS>
🚀 Styleguide deploy preview ready!https://60b7f0f90567b84163322356--gamut-preview.netlify.appDeploy Logs


FFTW MKL failed to create sub dimensional FFT plan

Default provider:
test=Array{ComplexF64}(undef, [[4,4];[4,4]]...);
p1=plan_fft(test,[3,4])
result1=fft(reshape([1:4^4;],4,4,4,4))
result2=p1*reshape([1:4^4;],4,4,4,4)
result1==result2 #false means things are right

But for a MKL provider:
julia> plan_fft!(test,[3,4])
ERROR: FFTW could not create plan
Stacktrace:
 [1] error(s::String)
   @ Base .\error.jl:33
 [2] macro expansion
   @ C:\Users\Baiyi Yu\.julia\packages\FFTW\SDUwi\src\fft.jl:576 [inlined]
 [3] (FFTW.cFFTWPlan{ComplexF64, -1, true, 4})(X::Array{ComplexF64, 4}, Y::Array{ComplexF64, 4}, region::Vector{Int64}, flags::UInt32, timelimit::Float64)
   @ FFTW C:\Users\Baiyi Yu\.julia\packages\FFTW\SDUwi\src\FFTW.jl:49
 [4] #plan_fft!#7
   @ C:\Users\Baiyi Yu\.julia\packages\FFTW\SDUwi\src\fft.jl:695 [inlined]
 [5] plan_fft!(X::Array{ComplexF64, 4}, region::Vector{Int64})
   @ FFTW C:\Users\Baiyi Yu\.julia\packages\FFTW\SDUwi\src\fft.jl:695
 [6] top-level scope
   @ REPL[45]:1

Does MKL not support sub-dimensional FFT?
This kind of FFT is quite ordinary for operator of tensor

Right, this is a documented limitation of MKL, which is not as flexible as FFTW about transforms of slices of multidimensional arrays.
See also e.g. this discussion on discourse and https://github.com/JuliaMath/FFTW.jl/issues/237#issuecomment-1248147936
Not really anything we can do about this.  Complain to Intel, and use the real FFTW library.


Release 0.1.6 to NPM

Fixed by https://github.com/GoogleChrome/omnitone/commit/29a04677778fcbb88db2979914cb7f1233de88cf. Closing.

@hoch thanks !


Exception when deleting an Afferent mapping from the "Cortical Area Details" panel

Repo steps:

have a cortical area that has many different afferent connections
on 3D monitor, click on the cortical area then click pencil
open the connections and start deleting the afferent connections one by one from the list by clicking on the trashcan icon
after confirming the deletion, move on and delete another afferent mapping

Notes:

FEAGI logs did not show any exception but it seems like the api call to delete the mapping was properly received made when failure occurred

Here is the genome I can reliably repo the issue. Use the cortical area called front and start deleting the affarents
response_1730731498395.json

addressed with a work around. We need to find the root cause of these invalid nodes


Login info isn't updatable

If the login info a repo is changed, then if you press the 'push' button, there's no way to update the login info

This was fixed in the big merge from authentication by @dmusican


Isochrones with turn costs

The /isochrone and /spt endpoints currently do not support turn costs. We need to run the algorithm edge-based to support this.
To make things a bit less complicated these endpoints currently can be used also for profiles with turn_costs: false and the turn costs are simply disabled silently, c.f. this discussion: #1967

I already have this on a branch. Coming up.

[ ] /isochrone

[ ] /spt

Finished, up to the fact that for /spt, edge based traversal really is something different than just respecting turn restrictions. You get a different kind of tree, where you get every node several times.
How to make it clear that this happens iff your profile has turn restrictions?
Maybe I can also want this if it has no turn restrictions?

Cool thanks!

You get a different kind of tree, where you get every node several times.

Hm this seems to depend on the requested columns? For example if all I want are the coordinates, times and distances (the default) we should probably use the minima for every node? But if also the (previous) edge_ids etc. are requested we could just return all the entries of the shortest path tree? Or maybe that is what we do already?

How to make it clear that this happens iff your profile has turn restrictions?
Maybe I can also want this if it has no turn restrictions?

This is indeed ugly and here (and maybe only here?) it would make sense to differentiate between edge_based and turn_costs (#1702)? In one case I might be interested in the edge-based tree and in another I might be interested in the node-based tree. But in which case would I be interested in the edge-based tree without turn costs? The calculation is probably not faster when we skip the turn costs, but the routing becomes less accurate (if we neglect OSM turn restrictions this way)?
A few more minor things:

Don't you think there should be an error when ch/lm.disable=false since the speed modes are not supported for /isochrone and /spt?

We now get an internal server error for something like this: /spt?point=xyz. Might be the same as in #1995. Taking into account that we also get 404 when parameters have the wrong type I wonder if we should put all query parameters as strings and do the parsing manually (maybe not so elegant but at least then we can control the error codes). Or maybe this is just a minor bug that can be fixed still using the framework mechanisms.

Should it be allowed to use dashes in profile names, like car-with-turncosts? Right now its only allowed for some legacy reasons where something like -1 (minus one) had to be included, but this will no longer be the case after fixing #1999. See here: https://github.com/graphhopper/graphhopper/pull/1922#discussion_r383033522

Should it be allowed to use dashes in profile names, like car-with-turncosts?

Why not? I don't know the legacy of this, but in my mind, it's just a string, a resource name. I don't want to interpret it in any way.

404 [..] Or maybe this is just a minor bug that can be fixed still using the framework mechanisms.

Will check, but if it isn't -- I want to to as little as possible of this manually, and I want to release control about this and give it to conventions / frameworks. For me, that's the point.

For example if all I want are the coordinates, times and distances (the default) we should probably use the minima for every node? But if also the (previous) edge_ids etc. are requested we could just return all the entries of the shortest path tree? Or maybe that is what we do already?

Noooo, a tree is a tree, it can't suddenly change its structure depending on the columns I request.

Why not? I don't know the legacy of this, but in my mind, it's just a string, a resource name. I don't want to interpret it in any way.

The legacy was that we sometimes had utc-1 in the profile names to indicate infinite u-turn costs. Otherwise you are right a dash is not a problem as a url, yaml or file name, but being a bit more restrictive also sometimes can make things easier. Here I do not see a real reason to allow dash, because one can also just use underscore.

Noooo, a tree is a tree, it can't suddenly change its structure depending on the columns I request. (That it does so depending on the profile is questionable, but depending on the columns -- no.) That would mean that there are meaning-of-the-tree-changing columns and other columns.

Ok I agree changing the columns should better not lead to another result, I was just speculating about what a user expects and came to the conclusion that this might depend on the requested columns. For example if we always return the (edge-based) tree (and the default columns are just the coordinates, times and distances) there are duplicate rows (same coordinates, different times) which I guess is not expected. If on the other hand we remove these 'duplicates' we will be 'missing' some rows when we include the parent edges for example. So maybe for an edge-based tree it just makes no sense to ask for the coordinates of the nodes? If we would list the (road network) edges it would be more clear: Every node of the shortest path tree corresponds to exactly one (directed) edge and every (directed) edge appears at most once in the tree. But sure, what if one asks for 'the' tree including turn costs (not even knowing about edge-based etc.) then things are less clear.

I was just speculating about what a user expects

There seem to be multiple different questions one might ask related to the shortest path tree. Not sure which ones our endpoint is supposed to answer:

Give me 'the' shortest path tree (all the nodes with their distances and times from the center point)

Like 1), but pay respect to turn restrictions

Give me the edge-based shortest path tree (for every road of the graph I want to know the time/distance it takes from the center point, for both directions of the road).

Like 3) but this time I want to ignore turn restrictions


Add constructor to allow Curve to the specified

added new method to permit backward compatibility
replicated the switch statement

Note slight concern that some of func in the switch really should be in mathlib
Signed-off-by: Matthew B White<EMAIL_ADDRESS>

@ale-linux @adecaro @yacovm I'm closing this in favour of #20


"ValueError: Graph disconnected" when trying to create a trainable RNN initial hidden state

Hi guys, I have a set of time-series experiments, and each experiment depends on its initial conditions. I am trying to train the initial hidden state of my RNN using these initial conditions.

Here is the code:
from tensorflow.keras.layers import Input, Dense, LSTM
from tensorflow.keras.models import Model

input_layer = Input(shape=(16,3))
hidden_state_dim = 7

mlp_inp = Input(batch_shape=(hidden_state_dim,1))
mlp_dense_h = Dense(hidden_state_dim, activation='relu')(mlp_inp)
mlp_dense_c = Dense(hidden_state_dim, activation='relu')(mlp_inp)

x = LSTM(7, return_sequences = True, input_shape = (16, 3))(input_layer, initial_state=[mlp_dense_h, mlp_dense_c])

model = Model(input_layer, x)

I receive the error: "ValueError: Graph disconnected: cannot obtain value for tensor Tensor("input_2:0", shape=(7, 1), dtype=float32) at layer "input_2". The following previous layers were accessed without issue: []"
I imagine that the graph is disconnected because there is no back propagation to the mlp_dense_h/c? Any ideas on how to solve this?
Thanks!
I made a post on tensorflow describing it a little bit better: https://stackoverflow.com/questions/59402595/can-i-train-the-initial-hidden-state-of-a-rnn-to-represent-the-initial-condition

What is passed to mlp_inp? You have two inputs, input_layer and mlp_inp. Nothing is given to mlp_inp, and thus cannot be forwarded to your other two dense layers.
That is what the error is saying.

cannot obtain value for tensor Tensor("input_2:0", shape=(7, 1), dtype=float32) at layer "input_2".


Consider: maybe std::function<> is too heavy weight for the callback wrapper

I am about so send a PR with the skeleton for pubsub::SubscriberConnection. This initial version uses std::function<> to type erase the callback provided by the application. This might be too heavy weight, and a lighter weight type erasure might work better.

Do we need to take ownership of the passed callback? If so, then std::function doesn't seem too bad to me.

We do need ownership.  I would also like us to support move-only callables. I could close this bug and open a new one, but I am lazy as the fix would be the same?
I am going to rename it.

After some discussion we decided not to do this.


minimally-nice-maintainer: Any ideas we can use?

The Minimally-nice Open Source Software Maintainer (2017-04-05) has some interesting tips, especially be clear about what you expect.  Is there anything we can import into passing+1 or passing+2?

These are interesting tips, but I doubt we'd get universal agreement on most.  The item "Be clear about what you expect" is something you would get agreement on, but I think we already have that covered.


SMTP email sender without SSL/TLS AUTH fails with javax.mail.MessagingException: Invalid Addresses

What is the bug?
SMTP email sender without AUTH errors with  javax.mail.MessagingException: Invalid Addresses
TLS SMTP AUTH sender works fine
How can one reproduce the bug?
Steps to reproduce the behavior:

Configure sender to use the local Postfix server with default config (not configured for SMTP-AUTH)
Configure email destination using the sender above
Try sending alert to the destination configured above
See error: javax.mail.MessagingException: Invalid Addresses

What is the expected behavior?
The email should be sent successfully
What is your host/environment?

OS: OpenSearch docker container on Ubuntu 18.04
Version: 1.3.2
Alerting plugin version: <IP_ADDRESS>

An attempt to configure the sender without SMTP-AUTH (local Postfix or direct send to MS Office 365 cloud) fails with "javax.mail.MessagingException: Invalid Addresses":
`[2022-05-24T15:49:15,538][DEBUG][o.o.a.r.RestGetDestinationsAction] [opensearch01] GET /_plugins/_alerting/destinations
[2022-05-24T15:49:15,538][DEBUG][o.o.a.t.SecureTransportAction] [opensearch01] User and roles string from thread context: andrija.pantovic@phoenix-systems.ch|admin|own_index,all_access|admin
[2022-05-24T15:49:15,538][DEBUG][o.o.a.t.SecureTransportAction] [opensearch01] Is filterByEnabled: false ; Is admin user: true
[2022-05-24T15:49:23,079][DEBUG][o.o.a.r.RestExecuteMonitorAction] [opensearch01] POST /_plugins/_alerting/monitors/_execute
[2022-05-24T15:49:23,080][DEBUG][o.o.a.t.TransportGetMonitorAction] [opensearch01] User and roles string from thread context: andrija.pantovic@phoenix-systems.ch|admin|own_index,all_access|admin
[2022-05-24T15:49:23,080][DEBUG][o.o.a.MonitorRunner      ] [opensearch01] Running monitor: kore_hsm_syslog_test with roles: [own_index, all_access] Thread: DefaultDispatcher-worker-8
[2022-05-24T15:49:24,090][ERROR][o.o.a.d.f.EmailDestinationFactory] [opensearch01] Exception publishing Message: DestinationType: EMAIL, DestinationName: my_test, Host: phoenixsystems-ch01i.mail.protection.outlook.com, Port: 25, Message: Monitor kore_hsm_syslog_test just entered alert status. Please investigate the issue.

Total hits:
Trigger: severe_events
Severity: 1
Period start: 2022-05-24T15:48:23.079Z
Period end: 2022-05-24T15:49:23.079Z

javax.mail.MessagingException: Invalid Addresses
at org.opensearch.alerting.destination.client.DestinationEmailClient.execute(DestinationEmailClient.java:79) ~[alerting-notification-<IP_ADDRESS>.jar:?]
at org.opensearch.alerting.destination.factory.EmailDestinationFactory.publish(EmailDestinationFactory.java:31) [alerting-notification-<IP_ADDRESS>.jar:?]
at org.opensearch.alerting.destination.factory.EmailDestinationFactory.publish(EmailDestinationFactory.java:18) [alerting-notification-<IP_ADDRESS>.jar:?]
at org.opensearch.alerting.destination.Notification.lambda$publish$0(Notification.java:35) [alerting-notification-<IP_ADDRESS>.jar:?]
at java.security.AccessController.doPrivileged(Native Method) [?:?]
at org.opensearch.alerting.destination.Notification.publish(Notification.java:33) [alerting-notification-<IP_ADDRESS>.jar:?]
at org.opensearch.alerting.model.destination.Destination.publish(Destination.kt:298) [opensearch-alerting-<IP_ADDRESS>.jar:<IP_ADDRESS>]
at org.opensearch.alerting.MonitorRunner$runAction$2.invokeSuspend(MonitorRunner.kt:659) [opensearch-alerting-<IP_ADDRESS>.jar:<IP_ADDRESS>]
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) [kotlin-stdlib-1.3.72.jar:1.3.72-release-468 (1.3.72)]
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:233) [kotlinx-coroutines-core-1.1.1.jar:?]
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594) [kotlinx-coroutines-core-1.1.1.jar:?]
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60) [kotlinx-coroutines-core-1.1.1.jar:?]
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:742) [kotlinx-coroutines-core-1.1.1.jar:?]
[2022-05-24T15:49:24,091][INFO ][o.o.a.m.MonitorRunResult ] [opensearch01] Internal error: javax.mail.MessagingException: Invalid Addresses. See the opensearch.log for details
java.lang.IllegalStateException: javax.mail.MessagingException: Invalid Addresses
at org.opensearch.alerting.destination.factory.EmailDestinationFactory.publish(EmailDestinationFactory.java:36) ~[alerting-notification-<IP_ADDRESS>.jar:?]
at org.opensearch.alerting.destination.factory.EmailDestinationFactory.publish(EmailDestinationFactory.java:18) ~[alerting-notification-<IP_ADDRESS>.jar:?]
at org.opensearch.alerting.destination.Notification.lambda$publish$0(Notification.java:35) ~[alerting-notification-<IP_ADDRESS>.jar:?]
at java.security.AccessController.doPrivileged(Native Method) ~[?:?]
at org.opensearch.alerting.destination.Notification.publish(Notification.java:33) ~[alerting-notification-<IP_ADDRESS>.jar:?]
at org.opensearch.alerting.model.destination.Destination.publish(Destination.kt:298) ~[opensearch-alerting-<IP_ADDRESS>.jar:<IP_ADDRESS>]
at org.opensearch.alerting.MonitorRunner$runAction$2.invokeSuspend(MonitorRunner.kt:659) ~[opensearch-alerting-<IP_ADDRESS>.jar:<IP_ADDRESS>]
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) [kotlin-stdlib-1.3.72.jar:1.3.72-release-468 (1.3.72)]
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:233) [kotlinx-coroutines-core-1.1.1.jar:?]
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594) [kotlinx-coroutines-core-1.1.1.jar:?]
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60) [kotlinx-coroutines-core-1.1.1.jar:?]
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:742) [kotlinx-coroutines-core-1.1.1.jar:?]
Caused by: javax.mail.MessagingException: Invalid Addresses
at org.opensearch.alerting.destination.client.DestinationEmailClient.execute(DestinationEmailClient.java:79) ~[alerting-notification-<IP_ADDRESS>.jar:?]
at org.opensearch.alerting.destination.factory.EmailDestinationFactory.publish(EmailDestinationFactory.java:31) ~[alerting-notification-<IP_ADDRESS>.jar:?]
... 11 more
`
When SMTP AUTH client configured (for example MS Office 365 smtp.office365.com:587 with TLS and credentials set in the keystore) the setup works fine:
2022-05-24T15:59:05,415][DEBUG][o.o.a.r.RestExecuteMonitorAction] [opensearch02] POST /_plugins/_alerting/monitors/_execute [2022-05-24T15:59:05,416][DEBUG][o.o.a.t.TransportGetMonitorAction] [opensearch02] User and roles string from thread context: andrija.pantovic@phoenix-systems.ch|admin|own_index,all_access|admin [2022-05-24T15:59:05,417][DEBUG][o.o.a.MonitorRunner      ] [opensearch02] Running monitor: kore_hsm_syslog_test with roles: [own_index, all_access] Thread: DefaultDispatcher-worker-1 [2022-05-24T15:59:06,923][INFO ][o.o.a.m.d.Destination    ] [opensearch02] Message published for action name: my_test, messageid: Sent, statuscode: 0

Looking into the issue.

Presented same issue too and got some additional errors using different email addresses:
Hotmail account directly → Errors: javax.mail.MessagingException: Can't send command to SMTP host
Hotmail account through postfix (no encrytion) → Errors: javax.mail.MessagingException: Invalid Addresses
Paid hosting email using SSL → Errors: javax.mail.MessagingException: Can't send command to SMTP host
Paid hosting email using TLS → Errors: javax.mail.MessagingException: Could not connect to SMTP host: <SMTP_SERVER_HERE>, port: 465, response: -1
Paid hosting email no ecryption → Errors: javax.mail.MessagingException: 550 Access denied - Invalid HELO name (See RFC2821 <IP_ADDRESS>)
I have confirmed that SMTP works in all my used email addresses and also having set credentials for Alerting module as explained here. Still nothing is sent.

Hello @praveensameneni any news about this?

Hi I was able to replicate this issue on both the docker Version: 1.3.2 image and docker Version: 2.2.0 image.
The fix is as follows:
Change the config in /etc/postfix/main.cf to add the following ( Please append the IP addresses if others exist )
inet_interfaces = <IP_ADDRESS>
mynetworks = <IP_ADDRESS>
In the above case <IP_ADDRESS> is the bridge  gateway and <IP_ADDRESS> is the IPAddress of the container
that you can obtain by docker inspect container ...
Please restart the postfix server
Also please make sure that you put <IP_ADDRESS> as the SMTP sender host using the opensearch dashboard GUI

Thank you @raj-chak! the provided configuration works correctly with my Postfix server.
Still, it would be interesting to get a fix or workaround to use with an email address directly configured into Opensearch (without a Postfix server)


libass soname change in F29

I'm having problems in upgrading to F29 because some packages (vlc and handbrake) still require libass.so.5 while F29 provides libass.so.9.
A rebuild of those packages is needed.

Sorry, I've just seen that unitedrpms repo has Fedora version number hardcoded in its configuration file.
I've changed the configuration to F29 and now it's ok.

@mattiaverga we have a rpm with the repository, please use it... We have support for F27-F30...

@kuboosoft I had the rpm installed, but the unitedrpms.repo file had hardcoded the Fedora version:
baseurl=https://sourceforge.net/projects/unitedrpms/files/28/x86_64/
so running dnf system-upgrade still used the F28 repository. I had to uninstall the unitedrpms rpm and then reinstall it with:
dnf -y install https://github.com/UnitedRPMs/unitedrpms/releases/download/9/unitedrpms-29-9.fc29.noarch.rpm
because before the system upgrade the macros in the command you suggest on your site still translates to F28.
I think you should change the url in the repofile to something like:
baseurl=https://sourceforge.net/projects/unitedrpms/files/$releasever/$basearch/


i have remote ftp problem

Firstly I am working with a framework in php. I am working with some framework files in a way known as blade. For example, when I try to access a file named 'home.wizard.php', it recognizes this file as a folder and prevents me from opening the file with ftp. When I look at the local files, I see a folder called 'home.wizard.php'. Could you fix this problem

Go back to the previous version.
apm uninstall remote-ftp
apm install remote-ftp


Azcopy v10 support in AGC and national clods

Which version of the AzCopy was used?
10.23.1
Note: The version is visible when running AzCopy without any argument
Which platform are you using? (ex: Windows, Mac, Linux)
Windows
What command did you run?
azcopy copy "sourcesas" "destsas"  --recursive --log-level=INFO
Note: Please remove the SAS to avoid exposing your credentials. If you cannot remember the exact command, please retrieve it from the beginning of the log file.
What problem was encountered?
Per our understanding azcopy 10 wasn't supported atleast 4 years back and we were stuck with azcopy 7. Now we can't use azcopy 7 anymore because of lack of support and that itself doesn't support user delegation keys, which force us to move to azcopy 10. I tried to find documentaion for national cloud support (fairfax and mooncake) and also for AGC but couldn't find any. Can you please let me know azcopy support for these clouds?
How can we reproduce the problem in the simplest way?
Not code issue, more of support question.
Have you found a mitigation/solution?
No

Closing due to inactivity.


Add custom validation rule support

https://validatejs.org/#custom-validator
Add decorator / fluent API to cover.

Has any progress been made on this?  Is there a structure that is being proposed?
Quick suggestion would be something in the plugin config that dynamically adds properties to the current validator object, to provide the same api approach with custom validators as built-in ones.  Alternatively, a validators.custom property, that we then extend, if it's preferred to have some kind of division?
I assume the custom validators would need to be configured in the DI somehow, as for example the api lookup type validator mentioned in #29 would need httpClient injected in.

No progress on this one yet PR welcome.  Under the covers the ValidationRule class should probably just have a static method for adding the custom rule that works just like the current rule methods work.

@PWKad - I ended up hacking this together for myself today but I'm not sure I took the right approach. validate.async returns a promise, whereas aurelia-validatejs seems to strongly assume the opposite. I ended up converting all validate return values into promises, then using Promise.all() to wait on them all at once before returning to the original caller. I also publish each error into the reporter when Promise.all() resolves.
I also had to patch validate.js's async so that it doesn't reject if an async function returns an error.  That was stopping me from handling it later on with Promise.all().

👍  I'd like to provide a custom validator with my plugin :)
@PWKad I'm fine with working on this. I need some pointers though, how can this be done?

implemented!


Annotate isDarkMode and isPlatformDarkMode types

latest GetX version.
I'm switching from pedantic to effective_dart, and I got a  unneeded cast warning from dart analysis, removing the cast caused the following warning:

So to avoid this warning I have to make a cast.. and then get a cast not needed warning... and so on. (I wanna head pat dart analysis, good job on this one boy).
Since these getters are public would be nice to have them typed.
Btw, there are other fields to annotate that I can think of too:
currentRoute
previousRoute

Thanks for point this.
It was fixed in the last update.
https://github.com/jonataslaw/getx/commit/08b10f4d340f829c05d52e2c903e452abfb32315#diff-9ee040dd5ee06195d8d527bacfbe1509