Data array is flattened in numcodecs which reduced the compression ratio that ZFP can provide on multi-dimension arrays

Minimal, reproducible code sample, a copy-pastable example if possible
In ensure_contiguous_ndarray:
if arr.flags.c_contiguous or arr.flags.f_contiguous:
        # can flatten without copy
        arr = arr.reshape(-1, order='A')

Problem description
ZFP is a lossy compressor that expects to get better compression ratio when compressing multi-dimension arrays. Currently in the zfpy.encode, ensure_contiguous_ndarray function flattens the array and feeds to ZFP compressor. In this way, ZFP compressor only can get less expected compression ratio. So I tried to add a switch in ensure_contiguous_ndarray, if the codec is ZFP, I skipped the flattening. However, this only works on C-order array, it doesn't work on F-order array because ZFP decoder only returns C-order array. When the decoder returns C-order multi-dimension array for an original F-order multi-dimension array, ZFP compressor cannot pass the F-order array encode and decode test.
Version and installation information
Please provide the following:

0.9.0 of numcodecs.__version__
Python 3.7, 3.8
Operating system (Linux/Windows)
pip install

@lindstro @jakirkham please add your comments.

I believe there are multiple independent issues here.
First, arrays should not be flattened when used with zfp.  I see no need to even make arrays contiguous as zfp supports strided compression.
Second, it is true that zfp returns decompressed arrays in C order (the default layout in NumPy), regardless of the original layout.  zfp does not capture the original layout, nor is it clear that it should.  For instance, if the array being compressed is not contiguous (think array-of-struct storage), would we really want to return a decompressed array full of holes?  We did consider supporting strided decompression with zfpy.decompress_numpy(), but as I recall there were some issues with this.  That said, I believe one could use zfpy._decompress() to decompress into an existing strided array passed as out argument.
Third, it is an issue if zfp's tests break if given an original array to compress in Fortran order, and I'd be surprised if this were not handled properly.  @halehawk, can you provide a simple example that illustrates such a bug?  If this is indeed the case, then we need to fix the zfp implementation/tests, not numcodecs.

Sounds like we could fix the flattening pretty easily with a new keyword argument here flatten=True
https://github.com/zarr-developers/numcodecs/blob/a81856efbf8dfd8ea925acaac01235a096d285e4/numcodecs/compat.py#L53
All the existing codecs would work the same with the default flatten=True, but we could call it from zfp here
https://github.com/zarr-developers/numcodecs/blob/a81856efbf8dfd8ea925acaac01235a096d285e4/numcodecs/zfpy.py#L58
with flatten=False

But using Ryan's way, it cannot pass the test at test_zfpy.py if the array
is
np.asfortranarray(np.random.normal(loc=1000, scale=1, size=(5, 10, 20))),
because zfp decoder returns a C-order multidimensional array.
On Tue, Feb 8, 2022 at 3:59 PM Ryan Abernathey @.***>
wrote:

Sounds like we could fix the flattening pretty easily with a new keyword
argument here flatten=True
https://github.com/zarr-developers/numcodecs/blob/a81856efbf8dfd8ea925acaac01235a096d285e4/numcodecs/compat.py#L53
All the existing codecs would work the same with the default flatten=True,
but we could call it from zfp here
https://github.com/zarr-developers/numcodecs/blob/a81856efbf8dfd8ea925acaac01235a096d285e4/numcodecs/zfpy.py#L58
with flatten=False
—
Reply to this email directly, view it on GitHub
https://github.com/zarr-developers/numcodecs/issues/303#issuecomment-1033145810,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ACAPEFDTBEMOQUEQCUVP5K3U2GN47ANCNFSM5N3H636A
.
Triage notifications on the go with GitHub Mobile for iOS
https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675
or Android
https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
You are receiving this because you were mentioned.Message ID:
@.***>

`import pytest
import numpy as np
try:
# noinspection PyProtectedMember
from numcodecs.zfpy import ZFPY, _zfpy
except ImportError:  # pragma: no cover
pytest.skip("ZFPY not available", allow_module_level=True)
from numcodecs.tests.common import (
check_encode_decode_array,
check_config,
check_repr,
check_backwards_compatibility,
check_err_decode_object_buffer,
check_err_encode_object_buffer,
)
codecs = [
ZFPY(mode=_zfpy.mode_fixed_rate, rate=-1),
ZFPY(),
ZFPY(mode=_zfpy.mode_fixed_accuracy, tolerance=-1),
ZFPY(mode=_zfpy.mode_fixed_precision, precision=-1),
]
mix of dtypes: integer, float, bool, string
mix of shapes: 1D, 2D, 3D
mix of orders: C, F
arrays = [
np.linspace(1000, 1001, 1000, dtype="f4"),
np.linspace(1000, 1001, 1000, dtype="f8"),
np.random.normal(loc=1000, scale=1, size=(100, 10)),
np.random.normal(loc=1000, scale=1, size=(10, 10, 10)),
np.random.normal(loc=1000, scale=1, size=(2, 5, 10, 10)),
np.asfortranarray(np.random.normal(loc=1000, scale=1, size=(5, 10, 20))),
np.random.randint(-(2 ** 31), -(2 ** 31) + 20, size=1000, dtype="i4").reshape(
100, 10
),
np.random.randint(-(2 ** 63), -(2 ** 63) + 20, size=1000, dtype="i8").reshape(
10, 10, 10
),
]
def test_encode_decode():
for arr in arrays:
if arr.dtype == np.int32 or arr.dtype == np.int64:
codec = [codecs[-1]]
else:
codec = codecs
for code in codec:
check_encode_decode_array(arr, code)
def test_config():
for codec in codecs:
check_config(codec)
def test_repr():
check_repr("ZFPY(mode=4, tolerance=0.001, rate=-1, precision=-1)")
def test_backwards_compatibility():
for code in codecs:
if code.mode == _zfpy.mode_fixed_rate:
codec = [code]
check_backwards_compatibility(ZFPY.codec_id, arrays, codec)
else:
check_backwards_compatibility(
ZFPY.codec_id, arrays[: len(arrays) - 2], codecs
)
def test_err_decode_object_buffer():
check_err_decode_object_buffer(ZFPY())
def test_err_encode_object_buffer():
check_err_encode_object_buffer(ZFPY())`

So why don't we just disallow F order for the zfp codec? I am becoming more and more convinced that it is unnecessary to support it. See discussion in https://github.com/zarr-developers/community/issues/41.

@rabernat I agree with you it is great if we can skip Fortran array test here. I tested xarray.open_dataset with backend netcdf4, it always opens a netcdf file as a c-order data array even the netcdf file was written to f-order originally. I didn't check with hdf5 or scipy backends. If anyone can confirm that hdf5 and scipy are the same cases, then I think it is all right to skip the Fortran array test in the test_zfpy.py.

HDF5 and NetCDF simply do not support F order on disk at all.

I partially agree.  HDF5 imposes C order and (to my knowledge) does not support strided storage, where strides are recorded in the file.  I believe it does not support strides on reads either, e.g., to force F order.  But you can always store F order data in HDF5 by simply reversing the order of dimensions.
zfpy actually examines the NumPy array's strides and passes them on to zfp.  Because zfp uses F order, zfpy reverses the dimensions in anticipation that in most cases, the NumPy order will be the default C order, which promotes good data locality during compression.
Now, the original memory layout is not recorded by zfp, just like how this information is absent from HDF5.  Therefore, if upon decompression the user wants to recover the array in the same order as it was compressed in, that kind of information would have to be stored separately and the data would have to be permuted.
That said, it is not clear to me why it's necessary to ensure that compressed and decompressed data appear in the same order.  Both arrays will agree on the dimensions of the array, just not how it is organized in memory.  Is there a compelling reason to guarantee that both arrays have the same layout?  After all, numcodecs forces both contiguous and flat storage, so the original memory layout is already lost, no?

Ryan's suggestion seems reasonable.
Forget whether we discussed this, but does zfp work with N-D data? If not, what happens if it is fed an array with N greater than what is supported by zfp.
Also how would this work for decompression? Does zfp return an array of the right dimensionality?

Only when 1 <= N <= 4. :-)  For higher-dimensional arrays, you need to consolidate some dimensions (ideally the ones that are least correlated).  This could for instance be done using a reshape operation, though you'd probably want to keep track of the dimensions of the original array.
We're planning to support higher-dimensional arrays in future versions of zfp.  It is unlikely that the compression scheme would support more than four dimensions (it's unusual to have data that is correlated in that many dimensions), but the API would allow you to describe higher-dimensional arrays and to identify the smoothest dimensions along which to compress (may be less than four).
The current zfp C API does not accommodate N > 4; the zfpy module will raise an exception if asked to compress a NumPy array with N > 4.

Thanks for the info Peter :)
Follow up question, when the data is decompressed, will it return the expected N-D array or is it 1-D (IOW up to the user to reshape)?

zfpy will return a decompressed N-D NumPy array of the same shape as the array that was compressed.  However, the way zfpy currently interfaces with numcodecs, it is handed a 1D reshaped array to compress, which is the issue at hand.  In this case, zfpy will also return a 1D decompressed array.  Moreover, compression is severely handicapped by not being able to exploit higher-dimensional correlations.

Side note: In microscopy it is common to have 5-D data (TZYXC or time + 3D spatial + channel).

Right, though I suspect there's little correlation across channels.  In radiation transport, we deal with 6D data (3 spatial + 2 angular + energy group) that is correlated in all six dimensions, but there are diminishing returns in compressing more than three dimensions (at least as far as zfp is concerned).  I agree that zfp should handle such data sets, but probably in the API layer and not in the compression algorithm itself.

Peter, I saw your zfpy pip package has Python 3.9 and 3.10 version, does
your 3.9 macos version work on mac? Did you merge my PR for building that
pip package?
On Thu, Feb 10, 2022 at 2:14 PM Peter Lindstrom @.***>
wrote:

Thanks for the info Peter :)
Follow up question, when the data is decompressed, will it return the
expected N-D array or is it 1-D (IOW up to the user to reshape)?
zfpy will return a decompressed N-D NumPy array of the same shape as the
array that was compressed. However, the way zfpy currently interfaces with
numcodecs, it is handed a 1D reshaped array to compress, which is the issue
at hand. In this case, zfpy will also return a 1D decompressed array.
Moreover, compression is severely handicapped by not being able to exploit
higher-dimensional correlations.
Side note: In microscopy it is common to have 5-D data (TZYXC or time + 3D
spatial + channel).
Right, though I suspect there's little correlation across channels. In
radiation transport, we deal with 6D data (3 spatial + 2 angular + energy
group) that is correlated in all six dimensions, but there are diminishing
returns in compressing more than three dimensions (at least as far as zfp
is concerned). I agree that zfp should handle such data sets, but probably
in the API layer and not in the compression algorithm itself.
—
Reply to this email directly, view it on GitHub
https://github.com/zarr-developers/numcodecs/issues/303#issuecomment-1035524967,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ACAPEFFUNFYA5JQ4XBUIILLU2QTFBANCNFSM5N3H636A
.
Triage notifications on the go with GitHub Mobile for iOS
https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675
or Android
https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
You are receiving this because you modified the open/close state.Message
ID: @.***>

I just created a PR #307 , it successfully built and tested on windows/linux, I thought it still skipped the macos tests for numcodecs.zfpy. Hopefully @rabernat @jakirkham can approve the merge soon.

Peter, I saw your zfpy pip package has Python 3.9 and 3.10 version, does your 3.9 macos version work on mac? Did you merge my PR for building that pip package?
…

I'm getting a dlopen() error using the 3.9 macOS package, which I think is something we saw earlier and what your PR addresses.
I wasn't involved in generating these wheels, but it looks like we still have an outstanding PR from you.  I'm sorry for dropping the ball on this.  I think we ran into issues with the PR not being tested and I may have been waiting on this to get resolved.  Since then, we've switched over from Travis to GitHub Actions, though it appears that we're still not testing on Mac.
@da-wad Would you have some time to work with @halehawk on getting her PR tested, ideally by adding testing on macOS?  We're very close to the next zfp release and it would be great to have this worked out before we build Mac wheels for the next version.

Building wheels for Linux and Windows turned out to be way easier in Github Actions than Travis+Multibuild (not to mention faster), so for ease of maintenance that should be used going forwards. Sorry about this, @halehawk , but switching CI actually now invalidates your PR... However, reading the cuibuildwheel docs, I think there is a pretty trivial way to include macOS wheels now. All you should have to do is add corresponding tags from this table to line 27 here: https://github.com/LLNL/zfpy-wheels/blob/master/.github/workflows/wheels.yml#L27

@David Wade @.***> Do you still use config.sh and
.travis.yaml? If you do use config.sh, could you please point me to the
lines in wheels.yaml?
On Mon, Feb 14, 2022 at 8:43 AM David Wade @.***> wrote:

Building wheels for Linux and Windows turned out to be way easier in
Github Actions than Travis+Multibuild (not to mention faster), so for ease
of maintenance that should be used going forwards. Sorry about this,
@halehawk https://github.com/halehawk , but switching CI actually now
invalidates your PR... However, reading the cuibuildwheel docs, I think
there is a pretty trivial way to include macOS wheels now. All you should
have to do is add corresponding tags from this table
https://cibuildwheel.readthedocs.io/en/stable/options/#build-skip to
line 27 here:
https://github.com/LLNL/zfpy-wheels/blob/master/.github/workflows/wheels.yml#L27
—
Reply to this email directly, view it on GitHub
https://github.com/zarr-developers/numcodecs/issues/303#issuecomment-1039150324,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ACAPEFE2MIGXTTFVFLHV25DU3EGOTANCNFSM5N3H636A
.
Triage notifications on the go with GitHub Mobile for iOS
https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675
or Android
https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
You are receiving this because you were mentioned.Message ID:
@.***>

Ah, no those are no longer used. I have removed them and updated the README. It should be no more than adding those tags!
Wheels for Windows are still made in Appveyor, but this should be switched over to Github Actions too and I'd planned to do this with the release of ZFP 0.5.6

@David Wade @.***> There is no /usr/local/lib64 directory on
Mac machine, so I cannot run the cp command in your script successfully.
On Wed, Feb 16, 2022 at 2:38 AM David Wade @.***> wrote:

Ah, no those are no longer used. I have removed them and updated the
README. It should be no more than adding those tags!
Wheels for Windows are still made in Appveyor, but this should be switched
over to Github Actions too and I'd planned to do this with the release of
ZFP 0.5.6
—
Reply to this email directly, view it on GitHub
https://github.com/zarr-developers/numcodecs/issues/303#issuecomment-1041294670,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ACAPEFEBZ3FWY2RA3H46H5LU3NV7VANCNFSM5N3H636A
.
Triage notifications on the go with GitHub Mobile for iOS
https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675
or Android
https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
You are receiving this because you were mentioned.Message ID:
@.***>

Ah, yes. I only said "should be"... of course reality is more complicated.
Take a look at this then:

I updated my PR at zfpy-wheel with a working macos wheel.yml. Please check
it and let me know if you can merge it or not.
On Fri, Feb 18, 2022 at 1:22 AM David Wade @.***> wrote:

Ah, yes. I only said "should be"... of course reality is more complicated.
Take a look at this
https://cibuildwheel.readthedocs.io/en/stable/options/#before-buildthen:
[image: image]
https://user-images.githubusercontent.com/25386679/154644950-99193ee1-2349-436c-9fae-3891b197daac.png
—
Reply to this email directly, view it on GitHub
https://github.com/zarr-developers/numcodecs/issues/303#issuecomment-1044126618,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ACAPEFFFKEF6YEHBAD3H7C3U3X6U7ANCNFSM5N3H636A
.
Triage notifications on the go with GitHub Mobile for iOS
https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675
or Android
https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
You are receiving this because you were mentioned.Message ID:
@.***>

May benefit from copying some changes that are being made to the Numcodecs wheel ( https://github.com/zarr-developers/numcodecs/pull/309 )

In fact, this one is very similar
https://github.com/kivy/kivy/blob/master/.github/workflows/osx_wheels_app.yml
On Fri, Feb 18, 2022 at 10:24 AM jakirkham @.***> wrote:

May benefit from copying some changes that are being made to the Numcodecs
wheel ( #309 https://github.com/zarr-developers/numcodecs/pull/309 )
—
Reply to this email directly, view it on GitHub
https://github.com/zarr-developers/numcodecs/issues/303#issuecomment-1044875318,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ACAPEFCP6LPUDJJYB44AMK3U3Z6DTANCNFSM5N3H636A
.
Triage notifications on the go with GitHub Mobile for iOS
https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675
or Android
https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
You are receiving this because you were mentioned.Message ID:
@.***>

@halehawk Many thanks for your PR, I had to fix it up a bit as it appears that the PyPI upload needs to be running on Linux, so has to be separated out from the wheel building. (See: https://github.com/pypa/gh-action-pypi-publish#non-goals)
Things seem to be working now... at least the job is failing at uploading pre-existing wheels (which it should). I think the existing macOS ones were broken, so we can fix them with 0.5.6 However, I wonder if you could test the 3.10 wheel on Mac?

Sure, I am waiting this wheel to test on my other PR.
Sent from my iPhone

On Feb 24, 2022, at 8:22 AM, David Wade @.***> wrote:

@halehawk Many thanks for your PR, I had to fix it up a bit as it appears that the PyPI upload needs to be running on Linux, so has to be separated out from the wheel building. (See: https://github.com/pypa/gh-action-pypi-publish#non-goals)
Things seem to be working now... at least the job is failing at uploading pre-existing wheels (which it should). I think the existing macOS ones were broken, so we can fix them with 0.5.6 However, I wonder if you could test the 3.10 wheel on Mac?
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.
You are receiving this because you were mentioned.

@David Wade @.***> I just downloaded zfpy-0.5.5-cp310 to my
mac, it was pip install successfully and I can run zfpy and numcodecs.zfpy
from python command line successfully too.
On Thu, Feb 24, 2022 at 8:22 AM David Wade @.***> wrote:

@halehawk https://github.com/halehawk Many thanks for your PR, I had to
fix it up a bit as it appears that the PyPI upload needs to be running on
Linux, so has to be separated out from the wheel building. (See:
https://github.com/pypa/gh-action-pypi-publish#non-goals)
Things seem to be working now... at least the job is failing at uploading
pre-existing wheels (which it should). I think the existing macOS ones were
broken, so we can fix them with 0.5.6 However, I wonder if you could test
the 3.10 wheel on Mac?
[image: image]
https://user-images.githubusercontent.com/25386679/155553406-11a8cd55-523f-4a71-a74b-a1bc8405a2a7.png
—
Reply to this email directly, view it on GitHub
https://github.com/zarr-developers/numcodecs/issues/303#issuecomment-1049969084,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ACAPEFBQNN63FFOUY6XA4PDU4ZEKRANCNFSM5N3H636A
.
Triage notifications on the go with GitHub Mobile for iOS
https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675
or Android
https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
You are receiving this because you were mentioned.Message ID:
@.***>

Excellent! Sounds like this is fixed, and all we need is a new commit-hash from @lindstro of a 0.5.6 tag :-)
I'll look into migrating Windows builds out of Appveyor and into Github Actiosn too...

That's great. Hopefully, we can see zfpy-0.5.6 sooner than we expected.
On Thu, Feb 24, 2022 at 9:07 AM David Wade @.***> wrote:

Excellent! Sounds like this is fixed, and all we need is a new commit-hash
from @lindstro https://github.com/lindstro of a 0.5.6 tag :-)
I'll look into migrating Windows builds out of Appveyor and into Github
Actiosn too...
—
Reply to this email directly, view it on GitHub
https://github.com/zarr-developers/numcodecs/issues/303#issuecomment-1050012636,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ACAPEFDHQCUHRHHZQ3P3D6LU4ZJSLANCNFSM5N3H636A
.
Triage notifications on the go with GitHub Mobile for iOS
https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675
or Android
https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
You are receiving this because you were mentioned.Message ID:
@.***>

@David Wade @.***> did you rebuild zfpy-python38-macos and
zfpy-python39-macos and upload them? Looks like they are not right yet.
On Thu, Feb 24, 2022 at 9:18 AM Peter Lindstrom @.***>
wrote:

It'll be a little while longer, I'm afraid, as I'm on travel this week and
next. It's likely that we will release zfp as version 1.0.0 due to the many
C/C++ ABI incompatibilities we've introduced. The Python interface will not
change, however. Thanks to both of you for helping out with the macOS
wheels.
—
Reply to this email directly, view it on GitHub
https://github.com/zarr-developers/numcodecs/issues/303#issuecomment-1050024008,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ACAPEFHHL6FZIMNK3FTY3I3U4ZK47ANCNFSM5N3H636A
.
Triage notifications on the go with GitHub Mobile for iOS
https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675
or Android
https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
You are receiving this because you were mentioned.Message ID:
@.***>

Yes, they were rebuilt and upload was attempted, as I said previously: "the job is failing at uploading pre-existing wheels (which it should)". Any file uploaded to PyPI cannot be replaced, so that we can't break anything which does work... this is a feature of PyPI I guess you weren't aware of. Unfortunately this means that 0.5.5 is broken forever for Python 3.9 and 3.8 on MacOS...
We could get around this by uncoupling the zfpy version number from the zfp one, but since a 1.0.0 release is imminent I don't know if this is necessary/wise.

It's a pity that zfpy-0.5.5 has broken macos builds for Python 3.8 and 3.9,
and hopefully we don't need to stick with them for a long time. I wasn't
aware of that until you told me now.
On Fri, Feb 25, 2022 at 12:54 AM David Wade @.***>
wrote:

Yes, they were rebuilt and upload was attempted, as I said previously:
"the job is failing at uploading pre-existing wheels (which it should)".
Any file uploaded to PyPI cannot be replaced, so that we can't break
anything which does work... this is a feature of PyPI I guess you
weren't aware of. Unfortunately this means that 0.5.5 is broken forever for
Python 3.9 and 3.8 on MacOS...
We could get around this by uncoupling the zfpy version number from the
zfp one, but since a 1.0.0 release is imminent I don't know if this is
necessary/wise.
—
Reply to this email directly, view it on GitHub
https://github.com/zarr-developers/numcodecs/issues/303#issuecomment-1050617170,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ACAPEFFAOLWUGIUYNNC26E3U44YRVANCNFSM5N3H636A
.
Triage notifications on the go with GitHub Mobile for iOS
https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675
or Android
https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
You are receiving this because you were mentioned.Message ID:
@.***>

@da-wad, one could use *.postX for very simple fixes (IOW non-code changes where packages were just broken). Also it is possible to yank broken packages on PyPI

Yanking the entire 0.5.5 release because of two broken wheels seems a little extreme... @jakirkham!
However, thanks for the nudge to find the proper way to do this. It turns out that there is a build tag in the wheel naming convention for solving exactly this problem: https://packaging.python.org/en/latest/specifications/binary-distribution-format/#file-name-convention
Therefore... I was able to download the artifacts from the zfpy-wheels build, rename the two macosx wheels which weren't uploaded and use twine to pop them onto PyPI manually. Do these work for you now?

Awesome, thanks! Can my PR #303 be merged now?
On Mon, Feb 28, 2022 at 1:08 AM David Wade @.***> wrote:

Yanking the entire 0.5.5 release because of two broken wheels seems a
little extreme... @jakirkham https://github.com/jakirkham!
However, thanks for the nudge to find the proper way to do this. It turns
out that there is a build tag in the wheel naming convention for solving
exactly this problem:
https://packaging.python.org/en/latest/specifications/binary-distribution-format/#file-name-convention
Therefore... I was able to download the artifacts from the zfpy-wheels
build, rename the two macosx wheels which weren't uploaded and use twine to
pop them onto PyPI manually. Do these work for you now?
[image: image]
https://user-images.githubusercontent.com/25386679/155946971-3ade4ba3-1fa0-444b-962f-33dc057b595d.png
—
Reply to this email directly, view it on GitHub
https://github.com/zarr-developers/numcodecs/issues/303#issuecomment-1053992335,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ACAPEFAN3IC5HY2VHN2Y5GDU5MUQBANCNFSM5N3H636A
.
Triage notifications on the go with GitHub Mobile for iOS
https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675
or Android
https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
You are receiving this because you were mentioned.Message ID:
@.***>


Refactor SliverAppBar.medium & SliverAppBar.large to fix several issues

fixes https://github.com/flutter/flutter/issues/121511
fixes https://github.com/flutter/flutter/issues/104493
fixes https://github.com/flutter/flutter/issues/122295
fixes https://github.com/flutter/flutter/issues/115091
fixes https://github.com/flutter/flutter/issues/122530
fixes https://github.com/flutter/flutter/issues/123943

code sample
import 'package:flutter/material.dart';

const Color foregroundColor = Color(0xff00ff00);
const Color backgroundColor = Color(0xff00ffff);
const double elevation = 4.0;
const double scrolledUnderElevation = 6.0;
const Color shadowColor = Color(0xff1212ff);
const ShapeBorder shape = RoundedRectangleBorder(
  borderRadius: BorderRadius.all(Radius.circular(14.0)),
);
const IconThemeData iconTheme = IconThemeData(color: Color(0xffff0000));
const IconThemeData actionsIconTheme = IconThemeData(color: Color(0xff0000ff));
const bool centerTitle = false;
const double titleSpacing = 10.0;
const TextStyle titleTextStyle = TextStyle(
  fontSize: 22.9,
  fontStyle: FontStyle.italic,
  color: Colors.blue,
);

AppBarTheme appBarTheme = const AppBarTheme(
  foregroundColor: foregroundColor,
  backgroundColor: backgroundColor,
  elevation: elevation,
  scrolledUnderElevation: scrolledUnderElevation,
  shadowColor: shadowColor,
  shape: shape,
  iconTheme: iconTheme,
  actionsIconTheme: actionsIconTheme,
  centerTitle: centerTitle,
  titleSpacing: titleSpacing,
  titleTextStyle: titleTextStyle,
);

void main() => runApp(const SliverAppBarExample());

class SliverAppBarExample extends StatefulWidget {
  const SliverAppBarExample({super.key});

  @override
  State<SliverAppBarExample> createState() => _SliverAppBarExampleState();
}

class _SliverAppBarExampleState extends State<SliverAppBarExample> {
  // Parameters
  TextStyle titleTextStyle = const TextStyle(
    color: Colors.deepPurple,
    fontSize: 22,
    fontStyle: FontStyle.italic,
  );
  Widget leading = IconButton(
    icon: const Icon(Icons.menu),
    onPressed: () {},
  );
  PreferredSizeWidget bottomWidget = const TabBar(
    tabs: <Widget>[
      Tab(text: 'Tab 1'),
      Tab(text: 'Tab 2'),
      Tab(text: 'Tab 3'),
    ],
  );

  // Controls
  bool showSliverAppBar = false;
  bool showSliverAppBarMedium = true;
  bool showSliverAppBarLarge = false;
  bool showAll = false;
  bool showLeading = true;
  bool centerTitle = false;
  bool showTitleTextStyle = false;
  bool showTitleSpacing = true;
  bool showAppBarTheme = false;
  bool showBottom = false;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        appBarTheme: showAppBarTheme ? appBarTheme : null,
        useMaterial3: true,
      ),
      home: DefaultTabController(
        length: 3,
        child: Scaffold(
          body: CustomScrollView(
            slivers: <Widget>[
              if (showSliverAppBar || showAll)
                SliverAppBar(
                  leading: showLeading ? leading : null,
                  title: const Text('Sliver App Bar'),
                  titleTextStyle: showTitleTextStyle ? titleTextStyle : null,
                  centerTitle: centerTitle,
                  titleSpacing: showTitleSpacing ? null : 0.0,
                  pinned: true,
                  actions: <Widget>[
                    IconButton(
                        icon: const Icon(Icons.favorite), onPressed: () {}),
                    IconButton(
                        icon: const Icon(Icons.favorite), onPressed: () {}),
                  ],
                  bottom: showBottom ? bottomWidget : null,
                ),
              if (showSliverAppBarMedium || showAll)
                SliverAppBar.medium(
                  leading: showLeading ? leading : null,
                  title: const Text('Medium App Bar'),
                  titleTextStyle: showTitleTextStyle ? titleTextStyle : null,
                  centerTitle: centerTitle,
                  titleSpacing: showTitleSpacing ? null : 0.0,
                  actions: <Widget>[
                    IconButton(
                        icon: const Icon(Icons.favorite), onPressed: () {}),
                    IconButton(
                        icon: const Icon(Icons.favorite), onPressed: () {}),
                  ],
                  bottom: showBottom ? bottomWidget : null,
                ),
              if (showSliverAppBarLarge || showAll)
                SliverAppBar.large(
                  leading: showLeading ? leading : null,
                  title: const Text('Large App Bar'),
                  titleTextStyle: showTitleTextStyle ? titleTextStyle : null,
                  centerTitle: centerTitle,
                  titleSpacing: showTitleSpacing ? null : 0.0,
                  actions: <Widget>[
                    IconButton(
                        icon: const Icon(Icons.favorite), onPressed: () {}),
                    IconButton(
                        icon: const Icon(Icons.favorite), onPressed: () {}),
                  ],
                  bottom: showBottom ? bottomWidget : null,
                ),
              const SliverFillRemaining(
                child: Center(
                  child: Text(
                    'Scroll down to collapse the app bar',
                  ),
                ),
              ),
            ],
          ),
          bottomSheet: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                Wrap(
                  alignment: WrapAlignment.center,
                  runAlignment: WrapAlignment.center,
                  spacing: 5.0,
                  runSpacing: 5.0,
                  children: <Widget>[
                    FilledButton(
                      onPressed: () {
                        setState(() {
                          showSliverAppBar = true;
                          showSliverAppBarMedium = false;
                          showSliverAppBarLarge = false;
                          showAll = false;
                        });
                      },
                      child: const Text('SliverAppBar'),
                    ),
                    FilledButton(
                      onPressed: () {
                        setState(() {
                          showSliverAppBar = false;
                          showSliverAppBarMedium = true;
                          showSliverAppBarLarge = false;
                          showAll = false;
                        });
                      },
                      child: const Text('SliverAppBar.medium'),
                    ),
                    FilledButton(
                      onPressed: () {
                        setState(() {
                          showSliverAppBar = false;
                          showSliverAppBarMedium = false;
                          showSliverAppBarLarge = true;
                          showAll = false;
                        });
                      },
                      child: const Text('SliverAppBar.large'),
                    ),
                    FilledButton(
                      onPressed: () {
                        setState(() {
                          setState(() {
                            showSliverAppBar = false;
                            showSliverAppBarMedium = false;
                            showSliverAppBarLarge = false;
                            showAll = true;
                          });
                        });
                      },
                      child: const Text('All'),
                    ),
                  ],
                ),
                const SizedBox(
                  height: 10.0,
                ),
                Wrap(
                  alignment: WrapAlignment.center,
                  runAlignment: WrapAlignment.center,
                  spacing: 5.0,
                  runSpacing: 5.0,
                  children: <Widget>[
                    // FilledButton.icon(
                    //   onPressed: () {
                    //     setState(() {
                    //       if (textScaleFactor >= 3.0) {
                    //         textScaleFactor = 1.0;
                    //       } else {
                    //         textScaleFactor += 1.0;
                    //       }
                    //     });
                    //   },
                    //   icon: const Icon(Icons.text_increase_rounded),
                    //   label: Text('TextScale: $textScaleFactor'),
                    // ),
                    FilledButton.icon(
                      onPressed: () {
                        setState(() {
                          showLeading = !showLeading;
                        });
                      },
                      label: const Text('Leading'),
                      icon: Icon(showLeading
                          ? Icons.visibility_off
                          : Icons.visibility),
                    ),
                    FilledButton(
                      onPressed: () {
                        setState(() {
                          centerTitle = !centerTitle;
                        });
                      },
                      child: Text('centerTitle: $centerTitle'),
                    ),
                    FilledButton.icon(
                      onPressed: () {
                        setState(() {
                          showTitleTextStyle = !showTitleTextStyle;
                        });
                      },
                      label: const Text('titleTextStyle'),
                      icon: Icon(showTitleTextStyle
                          ? Icons.visibility_off
                          : Icons.visibility),
                    ),
                    FilledButton.icon(
                      onPressed: () {
                        setState(() {
                          showTitleSpacing = !showTitleSpacing;
                        });
                      },
                      label: const Text('titleSpacing'),
                      icon: Icon(showTitleSpacing
                          ? Icons.visibility_off
                          : Icons.visibility),
                    ),
                    FilledButton.icon(
                      onPressed: () {
                        setState(() {
                          showBottom = !showBottom;
                        });
                      },
                      label: const Text('bottom'),
                      icon: Icon(
                          showBottom ? Icons.visibility_off : Icons.visibility),
                    ),
                    FilledButton.icon(
                      onPressed: () {
                        setState(() {
                          showAppBarTheme = !showAppBarTheme;
                        });
                      },
                      label: const Text('AppBarTheme'),
                      icon: Icon(showAppBarTheme
                          ? Icons.visibility_off
                          : Icons.visibility),
                    ),
                    Builder(builder: (BuildContext context) {
                      return FilledButton(
                        onPressed: () {
                          Navigator.push(
                            context,
                            MaterialPageRoute<Widget>(
                              builder: (BuildContext context) =>
                                  const SecondScreen(),
                            ),
                          );
                        },
                        child: const Text('Second Screen'),
                      );
                    }),
                  ],
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class SecondScreen extends StatelessWidget {
  const SecondScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          SliverAppBar.medium(
            title: Text('Second Screen'),
            centerTitle: false,
          ),
          SliverFillRemaining(
            child: Center(
              child: Text(
                'Scroll down to collapse the app bar',
              ),
            ),
          ),
        ],
      ),
    );
  }
}

Description
This PR refactors SliverAppBar.medium & SliverAppBar.large and fixes a bunch of issues.

Refactor to get bottom widget height inside the build context.
Add private variant enum (similar to IconButton)
Move medium and large flexible spaces inside the build to account for bottom height and top padding.
Collapsed title in the flexible space  was a mess, refactored to remove collapsed title from flexible space.
Remove redundant code from flexible space (flexible space only handles expanded title now, which is much cleaner)

Fix text cut off in  SliverAppBar.medium
Before

Preview
Outline

After

Preview
Outline

Fix title disappears with the bottom widget
Before

After

Fix title style and action theme customization (AppBarTheme) and tittle alignment
Before

After

Fix center title alignment
Before

After

Fix automaticallyImplyLeading
Before

After

Pre-launch Checklist

[x] I read the Contributor Guide and followed the process outlined there for submitting PRs.
[x] I read the Tree Hygiene wiki page, which explains my responsibilities.
[x] I read and followed the Flutter Style Guide, including Features we expect every widget to implement.
[x] I signed the CLA.
[x] I listed at least one issue that this PR fixes in the description above.
[x] I updated/added relevant documentation (doc comments with ///).
[x] I added new tests to check the change I am making, or this PR is test-exempt.
[x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

Still working through this - and wow! :)

Is there a reason to not split these changes up? If a customer is broken by one of these changes, all of them would have to be reverted.

The reason It fixes multiple issues and doesn't split the changes, in reality, it's not a lot of changes, in fact, it removes a lot of code if you don't count the tests. Refactoring the constructor itself fixes a bunch of issues and removing collapsed text from the flexible space bar also automatically fixes a lot of redundant parameters.
I could divide the PR into two, 1. refactoring constructors and 2. Removing collapsed text, if you think this will be better.

Let me run it through internal testing. If some failures come up it'll probably be a good signal to split it up.

Let me run it through internal testing. If some failures come up it'll probably be a good signal to split it up.

I can see constructors are const now instead of factory and locally I had to update code sample when switching this branch and master. I suppose this will be taken care by dart fix. Is it a breaking change?

Ran internal test suite and found no breaks. 👍

I want to run 55fb509 through internal testing since it may change something for an existing customer. Firing off another round of tests today. 👍

I want to run 55fb509 through internal testing since it may change something for an existing customer. Firing off another round of tests today. 👍

Thank you so much!

Hm, the update PR button is gone now. Can you rebase this?

(When you are back from OOO) This will need to be rebased again since the Google testing failure is not related to this PR (it picked up another unrelated change in the roll that had a lot of breakages). Can you also check that you have 'allow edits from maintainers' set? Usually there is a button in the UI that allows me to update the branch for you, saving everyone time. :)

Just rebased.

Can you also check that you have 'allow edits from maintainers' set? Usually there is a button in the UI that allows me to update the branch for you, saving everyone time. :)

I remember the team was able to make edits but it was from my personal fork.
According to https://github.com/orgs/community/discussions/5634, it's not possible "if a PR is created from a fork living under an organisation("

Welcome back! Can you rebase once more here? Thank you!

Welcome back! Can you rebase once more here? Thank you!

Thank you!

Ok finally, the CI issues cleared up. 😀
Don't land yet, I should be able to finally get a global test run in to ensure this doesn't break anything.

Woo! Good to go. Thanks for your patience. :)

Woo! Good to go. Thanks for your patience. :)

Thank you for running the tests!

Wow @TahaTesser this an impressive amount of fixes in one go, congrats on getting it merged! 🥳 👍🏻

Hi. When could this fix be available on a release on the stable channel? Thanks.

Wow @TahaTesser this an impressive amount of fixes in one go, congrats on getting it merged! 🥳 👍🏻

It's team work. Not easy to land such PRs without @Piinks help!

I'm having this issue, please how can I implement your solution?

I'm having this issue, please how can I implement your solution?

This is currently available on the beta channel and it should be available in the major stable release


python3 unicode error

Hi, I'm running Windows 10 with a miniconda3 (python3)
I installed gooey (v1.0.2) and pyinstaller (v3.4) today following the 'packaging' instructions here: https://chriskiehl.com/article/packaging-gooey-with-pyinstaller
I only changed this line to be added in my python script
from this nonbuffered_stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
to this nonbuffered_stdout = os.fdopen(sys.stdout.fileno(), 'w')
because of python3 needs (see this stackoverflow topic  )
But I've got the following error.
> pip install Gooey
> pip install pyinstaller
> cd c:\mybuildingdir
> python test.py
# this runs successfully
> pyinstaller build.spec
69 INFO: PyInstaller: 3.4
69 INFO: Python: 3.7.3
71 INFO: Platform: Windows-10-10.0.17134-SP0
73 INFO: UPX is not available.
Traceback (most recent call last):
  File "c:\users\giannico\appdata\local\continuum\miniconda3\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "c:\users\giannico\appdata\local\continuum\miniconda3\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Users\giannico\AppData\Local\Continuum\miniconda3\Scripts\pyinstaller.exe\__main__.py", line 9, in <module>
  File "c:\users\giannico\appdata\local\continuum\miniconda3\lib\site-packages\PyInstaller\__main__.py", line 111, in run
    run_build(pyi_config, spec_file, **vars(args))
  File "c:\users\giannico\appdata\local\continuum\miniconda3\lib\site-packages\PyInstaller\__main__.py", line 63, in run_build
    PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs)
  File "c:\users\giannico\appdata\local\continuum\miniconda3\lib\site-packages\PyInstaller\building\build_main.py", line 838, in main
    build(specfile, kw.get('distpath'), kw.get('workpath'), kw.get('clean_build'))
  File "c:\users\giannico\appdata\local\continuum\miniconda3\lib\site-packages\PyInstaller\building\build_main.py", line 784, in build
    exec(text, spec_namespace)
  File "<string>", line 7
SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \UXXXXXXXX escape

Any suggestion?

Please post a runnable code example demonstrating the problem.

Sorry, here it is. It's just a very basic script, it just show the interface and print "Done" on screen.
(of course rename the attached files deleting the .txt extension)
build.spec.txt
test.py.txt
Uh I just solved the 'unicode error' changing this 'build.spec' lines
from this
a = Analysis(['test.py'],
             pathex=['C:\mypythontest\test_gooey'],

to this
a = Analysis([r'test.py'],
             pathex=[r'C:\mypythontest\test_gooey'],

because python3 needs it (see this stackoverflow post )
But I still have a 'Fatal Error Detected: Failed to execute script' windows popup message when I try to execute the .exe
Do you have any suggestion? (should I start a different issue?)

Uh I solved this one too!
Thanks to this issue here https://github.com/chriskiehl/Gooey/issues/295
I changed the build.spec file line console=False, to console=True, and it works!
I'll add a step-by-step guide to the wiki here, if you think it could be useful

You. Are. Amazing!
I've long been bugging people to add their packaging experiences / knowledge to the wiki. You are the first! Thanks for the wiki contribution!

All Possible solution added here [Solved] SyntaxError: (unicode error) ‘unicodeescape’ codec can’t decode bytes in python3


Reopen "Make Wrapper::Inner not require clone, only have to_inner require Clone"

Reopens #152

Codecov Report
Base: 73.3% // Head: 73.8% // Increases project coverage by +0.5% :tada:

Coverage data is based on head (c5cf9a2) compared to base (65985ee).
Patch has no changes to coverable lines.

Additional details and impacted files
@@           Coverage Diff            @@
##           master    #157     +/-   ##
========================================
+ Coverage    73.3%   73.8%   +0.5%
========================================
  Files          33      34      +1
  Lines        5482    5636    +154
========================================
+ Hits         4018    4160    +142
- Misses       1464    1476     +12

Impacted Files
Coverage Δ

src/wrapper.rs
86.7% <0.0%> (-0.2%)
:arrow_down:

apfloat/src/ieee.rs
90.7% <0.0%> (ø)

src/confinement.rs
87.5% <0.0%> (ø)

derive/src/wrapper.rs
78.5% <0.0%> (+0.5%)
:arrow_up:

src/lib.rs
16.9% <0.0%> (+1.7%)
:arrow_up:

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

:umbrella: View full report at Codecov.
:loudspeaker: Do you have feedback about the report comment? Let us know in this issue.

Thank you. I have created v4.0 branch and merged this PR into there - and will release the first 4.0-alpha.1 version from that branch. Once we will be done with testing and do a full 4.0 release this will get merged automatically into master.

Published v4.0.0-alpha.1 - so you can use it


exception 'MongoDB\Driver\Exception\AuthenticationException' with message 'Authentication failed.'

$client = new MongoDB\Client("mongodb://localhost:27017/database", ['username' => 'user', 'password' => 'passwd', 'db' => 'admin']);

manual: http://mongodb.github.io/mongo-php-library/api/source-class-MongoDB.Client.html#15-167

If you are expecting to authenticate against the "admin" database, I would suggest removing both "/database" from the URI string and the db key from the options. The driver already defaults to authenticate against the "admin" database. If you do wish to specify a different database, you can either do so via the URI string (where you're currently indicating that you want to auth against the database named "database") or the authSource option (specified as either a query string parameter in the URI string or via the options array).
I realize this does differ from the legacy driver's MongoClient constructor options, where we previously accepted a "db" option. The driver and library documentation for MongoDB\Driver\Manager and MongoDB\Client, respectively, now refer to the Connection string documentation, which I cite below.

/database: Optional. The name of the database to authenticate if the connection string includes authentication credentials in the form of<EMAIL_ADDRESS>If /database is not specified and the connection string includes credentials, the driver will authenticate to the admin database.

Source: Standard Connection String Format.

authSource: Specify the database name associated with the user’s credentials, if the users collection do not exist in the database where the client is connecting. authSource defaults to the database specified in the connection string.
MongoDB will ignore authSource values if the connection string specifies no user name.

Source: Authentication Options.
In your case, you are specifying a username via the array options, so you need not worry about the last line of the authSource docs (if you decide to use that option).

I actually did the same thing at first when I was going from the legacy driver to the new one. However, with the relatively new changes to the documentation (and the link to the MongoDB docs) it's pretty clear what options are available. So, I'm pretty sure this issue can be closed now.

I have the problem with mongo verion 3.4.9
No suitable servers found (serverSelectionTryOnce set): [connection refused calling ismaster on '{IP:27017']
Please me give advanace

@kahovn: Please keep the conversation to PHPC-1025, which I moved over from the original issue you opened on the SERVER project. "No suitable servers found" is a very generic error that only implies that the driver was unable to select a server based on its view of the topology. The actual cause for that failure can be very different case to case.


Fast register in new flytekit

Also fix bug with register refactor where workflow template nodes weren't properly having project/domain/version substituted.
https://github.com/lyft/flyte/issues/605

@wild-endeavor @kumare3

https://flyte-org.slack.com/archives/CREL4QVAQ/p1609272942221400 for more info.

@wild-endeavor yes. i'll add an example to flytesnacks next


Issue with Duplicate Detection in Headless Notifications Despite Unique IDs

Hello and thank you for developing this amazing library!
I have successfully implemented the headless notification feature as per the documentation. Here's how I'm currently pushing notifications:
push.success<HeadlessNotificationProps>({
    id: arg.id,
    props: {
        title: arg.title,
        content: arg.content,
    },
});

In my configuration, I have set avoidDuplicates to true. However, I'm encountering an issue where subsequent notifications are not displayed even when I specify unique IDs for each. This problem does not occur when avoidDuplicates is set to false.
Question: How can I ensure that each headless notification is treated as unique even when avoidDuplicates is enabled? Is there a specific property or approach I should be using to differentiate each notification?
Any guidance or insights would be greatly appreciated!

Hi @FR31NDSDEV, notifications are considered duplicates if their title, message and type values are equal.
To avoid unnecessary overhead, Notivue doesn't compare props. Also, there's no need to define an id as this is done internally for you after calling push.
title and/or message should be defined outside of props also when using Custom Components. They're part of the notification core whereas props instead, is just an object that can be optionally used to forward some additional arbitrary data.
When title and message are not defined (like the snippet you pasted), their value will fallback to an empty string. So when you try to push a second notification, and their value is undefined again, it will be detected as a duplicate as there already are two notification with same title and message.
To conclude, simply create the notification like this:
push.success<HeadlessNotificationProps>({
   title: arg.title,
   message: arg.message,
});

or this:
push.success({
message: arg.message,
});

Hi @FR31NDSDEV, notifications are considered duplicates if their title, message and type values are equal.
To avoid unnecessary overhead, Notivue doesn't compare props. Also, there's no need to define an id as this is done internally for you after calling push.
title and/or message should be defined outside of props also when using Custom Components. They're part of the notification core whereas props instead, is just an object that can be optionally used to forward some additional arbitrary data.
When title and message are not defined (like the snippet you pasted), their value will fallback to an empty string. So when you try to push a second notification, and their value is undefined again, it will be detected as a duplicate as there already are two notifications with same title and message.
To conclude, simply create it like this:
push.success<HeadlessNotificationProps>({
   title: arg.title,
   message: arg.message,
});

or this:
push.success<HeadlessNotificationProps>({
   message: arg.message,
});

Cheers and enjoy!


feat: quest username quest fix #130

[ ] issue #130
[ ] follows contribution guide
[ ] code change includes tests
[ ] breaking change

Username quest that award reward if user has claim a username
The quest contract implemented IQuest interface
Which

allow for claiming of reward,
get claim reward
check a user is eligible for claim rewards

this is the function am trying to test,
fn is_claimable(
            self: @ContractState, user: ContractAddress, calldata: Span<felt252>
        ) -> bool {
            if self.claimed.read(user) {
                return false;
            }

            let username_store_main = IUsernameStoreDispatcher {
                contract_address: self.username_store.read()
            };

            let claim_username: felt252 = username_store_main.get_username(user);

            if claim_username == 0 {
                return false;
            }

            return true;
        }

this is the test a wrote,
#[test]
fn username_quest_test() {
    let username_store_address = deploy_username_store_contract();
    println!("username store contract address inside test: {:?}", username_store_address);

    let username_quest_contract_address = deploy_username_quest(username_store_address);

    let art_peace = IArtPeaceDispatcher {
        contract_address: deploy_with_quests_contract(
            array![].span(), array![username_quest_contract_address].span()
        )
    };

    let username_store_dispatcher = IUsernameStoreDispatcher {
        contract_address: username_store_address
    };

    snf::start_prank(CheatTarget::One(art_peace.contract_address), utils::PLAYER1());

    username_store_dispatcher.claim_username(username);

    let initial_username = username_store_dispatcher.get_username(utils::PLAYER1());
    println!("initial username: {}", initial_username);

    println!("username address before claim_main_quest: {:?}", utils::PLAYER1());

    art_peace.claim_main_quest(0, utils::EMPTY_CALLDATA());

    println!("username address after claim_main_quest: {:?}", utils::PLAYER1());

    assert!(initial_username == username, "Username not claim after main quest ");
    snf::stop_prank(CheatTarget::One(art_peace.contract_address));
}

art_peace.claim_main_quest(0, utils::EMPTY_CALLDATA());

    0x5175657374206e6f7420636c61696d61626c65 ('Quest not claimable')

this function keep returning 0 when call from inside is_claimable
fn get_username(self: @ContractState, address: ContractAddress) -> felt252 {
self.user_to_username.read(get_caller_address())
}
i suspect the user calling the function inside the test function is different from the user calling the function inside is_claimable function  @b-j-roberts @ptisserand can you help here

What is this line returning in your example :
println!("initial username: {}", initial_username);?
I think the issue is that you are pranking the art_peace contract instead of the username store contract when doing claim_username

What is this line returning in your example : println!("initial username: {}", initial_username);?
I think the issue is that you are pranking the art_peace contract instead of the username store contract when doing claim_username

I think the same, you have to prank both contracts:
    snf::start_prank(CheatTarget::Multiple(array![art_peace.contract_address, username_store_address]), utils::PLAYER1());

instead of
snf::start_prank(CheatTarget::One(art_peace.contract_address), utils::PLAYER1());


[ISSUE #4618] Add HTTP source connector

Fixes #4618.
Motivation
Add Http source connector.
Modifications

Add Http source connector
Add unit tests for Http source connector

Documentation

Does this pull request introduce a new feature?  yes
If yes, how is the feature documented? docs. Please refer to http-protocol-binding
If a feature is not applicable for documentation, explain why?
If a feature is not documented yet in this PR, please create a followup issue for adding the documentation

Would you be willing to write a document(#4601 (comment)) for this connector? If you are willing, they can be written in this PR or in a new PR.

Of course. I'll write it in a new PR.

Maybe this question shouldn't be asked here, but I still want to know why most sourceConnectors don't implement the commit() method.

Would you be willing to write a document(#4601 (comment)) for this connector? If you are willing, they can be written in this PR or in a new PR.

Of course. I'll write it in a new PR.

@Fungx In the future, community will mainly maintain documents in eventmesh-site. Therefore, if it is convenient for you, please write the new English documents in this directory of eventmesh-site, and Chinese documents in the directory.

Sure. Leave it to me.


Can you create a PR and merge it to the official repo?

https://github.com/projectdiscovery/nuclei-templates

Created the PR https://github.com/projectdiscovery/nuclei-templates/pull/3160 and closing the issue. Reopen if necessary!


Refreshing API definition interacts strangely with CLI flags and CachedTransport

Yesterday restish failed to refresh an API definition, and it took me an hour to figure out what happened.
I'll go through the debugging story and make a few suggestions on how this could be avoided.
Because these suggestions might be controversial, I've chosen to open this card to discuss, rather than make a PR.
I can make a PR for whatever direction we chose to go (if any).
The issue happened as follows:

I tried to make a restish call with an extra Content-Type header passed in as a CLI flag
Restish checked the API definition cache, noticed it was expired and decided to refresh it by loading the definition from the server
Restish applied the Content-Type header to the call to /openapi.json
My upstream honoured the Content-Type header and sent down the definition in the requested (not json) format
Restish stored the response in its file based CachedTransport
Restish failed to parse the definition

When I ran restish again, without the extra header, it would fail again, because it would serve the response from the CachedTransport (I suppose the headers are not part of the cache invalidation key).
If you run with debug logging on this is invisible: there's no way to tell that restish did not in fact run the request, but straight up loaded the response from the cache.
This lead me to spend a considerable amount of time looking at my upstream server to figure out why content-negation was broken.
I fixed restish by explicitly passing --rsh-no-cache.
Clearly this is an esoteric edgecase with a simple workaround, so I understand if we chose not to fix it.
However, I would suggest the following changes to prevent this and similar issues:

I think we should not apply headers passed in from the CLI to the remote call fetching the definition. We should only use the one's defined in the API config. The headers are almost always going to passed to modify the behaviour of the API call, not the service discovery call. In the best case they are ignored by the upstream, but they can lead to unintended consequences like this.
I don't think we need 2 caches. We already cache the resulting parsed API definition, which eliminates most calls to the upstream to fetch the openapi document. The additional cached transport doesn't add any extra value, but it can break things. Especially if restish failed to parse the spec, it should not reuse the a cached response from the server.

Nice find BTW. I agree on both points.


⚠ Bofrost.de has degraded performance

In 96957c6, Bofrost.de (https://www.bofrost.de) experienced degraded performance:

HTTP code: 200
Response time: 990 ms

Resolved: Bofrost.de performance has improved in eab81ae after 31 minutes.


RHODS: add API-level testing role

/cc @kpouget

tested in https://github.com/openshift-psap/ci-artifacts/pull/496, merging.


Why does this network ask to enter any spectrogram at the last stage?

Hello, could you please tell me why does the network ask to enter any spectrogram at the time of the outputting the result?
I mean this command
python inference.py -p [checkpoint path] -i [input mel path]
Usually , GAN networks generate random noise by themselves, so why does network need mel to output the result ?

Not in the case of Vocoder GAN like melgan, vocgan or TFGAN. In these GAN we take melspec as input and directly upsample to mels to hop size times to get audio wav, we don't condition noise we directly use mel spectrogram.

@etimsijs Not in the case of Vocoder GAN like melgan, vocgan or TFGAN. In these GAN we take melspec as input and directly upsample to mels to hop size times to get audio wav, we don't condition noise we directly use mel spectrogram.

So, this network for audiophiles ? The network can increase the sampling rate from 22 kHz to 41 kHz, let's say? Is it not for generating audio?


windows_dns_client resource

Description
This adds a windows resource for configuring a servers interface dns settings. It allows assigning list of static IP's for DNS search servers and/or a list of DNS domain suffixes to append to short names when searching.
Check List

[ ] All tests pass. See https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/TESTING.MD
[ ] New functionality includes testing.
[ ] New functionality has been documented in the README if applicable
[ ] All commits have been signed for the Developer Certificate of Origin. See https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD

@tas50 here is that dns_client resource I mentioned at chef conf for possible integration with core chef as well.

@tas50 not sure why the integration tests are failing. They pass on my local machine. I was having issues with timing for the second check. The sleep command helped fix it locally.

These tests are boggling me. Is appveyor possibly overriding my DNS settings changes?

@Xorima I know you were busy around the time I created this, wondering if you have a chance to look at the test now. They pass on my local machine but don't seem to pass in testing here.


Add names

Issue #460.

Travis tests has failed
Hey Gary Pang,
Please read the following log in order to understand why the tests failed.
It'll be awesome if you fix what's wrong and commit the changes.
npm test
><EMAIL_ADDRESS>test /home/travis/build/bluzi/name-db
> mocha

  name files
    1) should contain valid JSON
    2) should contain a lowercase name, same as the filename
    3) should not have duplicate names
    4) should have ISO-639-3 language codes
    5) should have correct structure

  Translations
    6) should be lowercase

  Sex
    7) should be "m", "f" or "u"
    8) should be lowercase

  0 passing (99ms)
  8 failing

  1) name files
       should contain valid JSON:
     Error: Error in name file "bruce.json": Invalid JSON file
SyntaxError: Unexpected token } in JSON at position 172
      at Context.it (test/test.js:16:23)

  2) name files
       should contain a lowercase name, same as the filename:
     SyntaxError: Unexpected token } in JSON at position 172
      at JSON.parse (<anonymous>)
      at Context.it (test/test.js:24:31)

  3) name files
       should not have duplicate names:
     SyntaxError: Unexpected token } in JSON at position 172
      at JSON.parse (<anonymous>)
      at Context.it (test/test.js:35:31)

  4) name files
       should have ISO-639-3 language codes:
     SyntaxError: Unexpected token } in JSON at position 172
      at JSON.parse (<anonymous>)
      at Context.it (test/test.js:47:31)

  5) name files
       should have correct structure:
     Error: Error in name file "bruce.json":
SyntaxError: Unexpected token } in JSON at position 172
      at Context.it (test/test.js:106:23)

  6) Translations
       should be lowercase:
     SyntaxError: Unexpected token } in JSON at position 172
      at JSON.parse (<anonymous>)
      at Context.it (test/test.js:116:31)

  7) Sex
       should be "m", "f" or "u":
     SyntaxError: Unexpected token } in JSON at position 172
      at JSON.parse (<anonymous>)
      at Context.it (test/test.js:131:31)

  8) Sex
       should be lowercase:
     SyntaxError: Unexpected token } in JSON at position 172
      at JSON.parse (<anonymous>)
      at Context.it (test/test.js:145:31)

npm ERR! Test failed.  See above for more details.

Thanks @CodeWritingCow!
merged #1


Add option to use String fields for picklists instead of enums

This change helps decoupling Salesforce picklist values from code using the Camel Salesforce component. This allows writing custom business logic to handle any discrepancies (e.g. extra/missing picklist values) instead of getting deserializing exceptions.
Thus, when a new picklist value is added in Salesforce, running code will not break just because the new value is not part of the corresponding enum.
Similarly, (feature toggled) business logic can be added to handle new picklist values which have not yet been added to the corresponding Salesforce object, e.g. due to different progressions in various staging environments (true story).
Signed-off-by: Sune Keller<EMAIL_ADDRESS>

Ping @davsclaus

Will need to extend this one to work with multi-select picklist fields too...

Can you create a new PR for new code changes as this has been merged and should be closed.

@davsclaus Will do


Visualize figure 2

Hello. Thank you for sharing your amazing work. I wanted to reproduce the results and the figures in your paper. I don't know how to draw the t-sne plot for sensor embedding in figure 2 in your paper. Can you please provide information on how to draw this figure?

Hello. Did you find the solution? i encounter the same issue.

Hello. Thank you for sharing your amazing work. I wanted to reproduce the results and the figures in your paper. I don't know how to draw the t-sne plot for sensor embedding in figure 2 in your paper. Can you please provide information on how to draw this figure?

Hello. Did you find the solution? i encounter the same issue.

Hello. Did you find the solution? i encounter the same issue.


Hyphen in snippet prefix de-indents snippet

Does this issue occur when all extensions are disabled?: Yes

VS Code Version: 1.63.0
OS Version: Windows_NT x64 10.0.19043

Steps to Reproduce:

Configure VSCode to use the attached snippets file
Indent some spaces
Insert the "Foo- Bar" snippet by typing "bar" <TAB>

The snippet is inserted with one space fewer indentation than the current indent level.
If the snippet is inserted by typing "foo" - the snippet inserts normally.
Seems to be to do with a hyphen being in the snippet prefix, followed by a space.
Behaviour not present in 1.62.3

test_snippets.zip

Can you try this with VS Code Insiders?

Thanks, not sure if I'm missing something with installing Insiders. Downloaded from the link provided, but the build seems 4 days old, and the commit that solves #138707 is after the commit referenced in the Help > About box.
Help > Check for updates tells me there are currently no updates available
Version: 1.64.0-insider
Commit: 065b450db9f555f177161748e8f2911ebb5677f9
Date: 2021-12-10T05:14:44.789Z
Electron: 13.5.2
Chromium: 91.0.4472.164
Node.js: 14.16.0
V8: 9.1.269.39-electron.0
OS: Windows_NT x64 10.0.19043
For what it's worth, behaviour still present here.

Latest insiders is on 745ef8b8264e12b2a704f6b2b60a2ce2cabfcda3

Updated insiders to 745ef8b8264e12b2a704f6b2b60a2ce2cabfcda3
Behaviour still exists.
Snippet here, for ease:
{
    "FooBar": {
        "prefix": "Foo- Bar",
        "body": [
            "Foo",
        ],
    }
}

I do reproduce. Thanks for clarifying so quickly

The root cause is the (still good) fix for https://github.com/microsoft/vscode/issues/123860. To fix the aforementioned issue we changed that snippet prefix matching isn't "locked" to word starts anymore. In this case it means the Foo- Bar snippet is freely aligned with  bar (e.g the bar-word plus its leading whitespace)

There seems to be some related fun here with camelCase here too:
{
	"FooBar": {
		"prefix": "FooBar Baz",
		"body": [
			"Foo",
		],
	}
}

Calling this snippet with bar casuses the 1 space de-indent


[Feature] Custom different values for handheld and docked, globally or per game

For example when I use a charger, or use my switch in docked mode, I would want to use 60 fps lock, but when it's in handheld without any charging - I would like to play at 30 or 45 fps to preserve power. I do this but manually. Is there a way to automatically change fps lock depending on switch mode?

If we are talking about doing detection on game's level, then it's perfectly doable to do docked/handheld detection.
But charger detection is not doable from game's level.

I would also really like this feature, since I don't always want to be at 60fps while using my switch in handheld. Right now it requires disabling the custom FPS target every time I play Handheld, which is a minor inconvenience.

This is very essential, especially after the amazing feature you added for refresh rate sync. Most TVs don't support anything other than 60hz. I have to personally go and reset the limit everytime I connect to the TV. I would love to have/implement this feature. Could you point out which files are relevant for this modification @masagrator?

especially after the amazing feature you added for refresh rate sync

It would be fantastic if the Nintendo Switch controlled the refresh rate of the TV. Oh, the dreams. Although, knowing what talented and enthusiastic developers there are in the Switch scene, I wouldn't be surprised if even this happens one day.


Babylon protocol

Will BakeChain be updated for the Babylon Protocol?

Yes it will - we will be publishing updates for our software shortly to help with this.


skillcalculator: Add multiplier input

Adds a multiplier input to the skill calculator, bound to [1,100].
No Multiplier:

With Multiplier:

With Multiplier + Bonuses:

"Experience Multiplier" gets cut off in the label, so couldn't be consistent there with the label name

Per feedback from Discord, let's cap this at 32x maximum, since multipliers larger than that do not exist.
Also, we should add a x suffix, eg. 2x (reference config units for how this can be achieved), and add a spinner so it can be increased or decreased without typing.

I had to make the formatter factory public to use here, and didn't try too hard to refactor.
LMK if that's an issue

Added in b0c7cb6401aba08078d35078cd1940904734a454 and e249333917767ab3d114a2d197aede752c095699


Feat 53 gestion etab secondaires

:tada: This PR is included in version 0.1.0 :tada:
The release is available on GitHub release
Your semantic-release bot :package::rocket:


Add compileSrc option to InjectManifet webpack plugin

R: @philipwalton
CC: @bailnl
Fixes #2383
When compileSrc is set to false, the swSrc file won't be run through the webpack compilation process. That allows for the use case described in #2383, where the manifest ends up injected into an arbitrary file that might not be something that should be processed by webpack.
The default behavior has not changed.

thanks ~  @jeffposnick


cannot get continuous trajectory in /tagslam/odom/body_rig

try to run my own bag
use msckf_vio  to generate continuous vio trajcetory
but I cannot get continuous trajectory in /tagslam/odom/body_rig
I want to know whether this situation is correct?
note these codes:
  void TagSlam::publishBodyOdom(const ros::Time &t) {
    for (const auto body_idx: irange(0ul, nonstaticBodies_.size())) {
      const auto body = nonstaticBodies_[body_idx];
      Transform pose;
      if (graph_utils::get_optimized_pose(*graph_, t, *body, &pose)) {  // here is condition
        auto msg = make_odom(t, fixedFrame_, body->getOdomFrameId(), pose);
        odomPub_[body_idx].publish(msg);
        if (writeToBag_) {
          outBag_.write<nav_msgs::Odometry>(
            "/tagslam/odom/body_" + body->getName(), t, msg);
        }
      }
    }
  }

so can I get continuous trajectory of tagslam/odom/body_rig??

Combining msckf_vio odom with tag observations should definitely work, and give you a reasonably continuous trajectory (subject to possible jumps in the odometry, and jumps on loop closure, but both of these can be worked on).
Can you post more information on what's going wrong? First of all: is your mskf_vio working? Can you post an rviz graph of the msckf odom? Is that trajectory smooth?
Once that works: are there any areas where you can run tagslam without the odometry (maybe in places where there are plenty of tags)? Maybe just run it on a single tag? That will give you a very jittery trajectory, with occasional jumps, but at least you can tell if basic parameters like intrinsic calibration etc are correct.
When you combine odometry and tags, suppress all tags except for one (which must have a defined pose in the world). Does the trajectory look smooth then? If not, where does it jump?
Other things worth posting so I can give you better feedback:

some camera images showing the tags (so I can tell the quality of the images)
tagslam.yaml and cameras.yaml
rviz screen shot of where the trajectory jumps, showing odometry and tag poses (enable "TF")

A couple of clarifications and hints

I just tested for the first time to run sync_and_detect live, with odometry as well, and it works. Except that it couldn't handle the case of raw (uncompressed) images. I have fixed that and just pushed it. Please do 'git pull origin master' to update.
The syncing actually happens at the camera: that's when the header.stamp is set. So long as left and right camera have identical header.stamp, everything should work: the time stamps should flow through msckf_vio, arrive at sync_and_detect, and have identical header.stamp. The sync_and_detect then runs the tag detector, and produces the detected tags, again with matching header.stamp. Sync_and_detect does not re-publishes the odom messages, it just filters the images based on it, i.e. it only runs the tag detector when it has a left images, a right image, and an odom message, all with the same time stamps. Only then does it publish the tags.
If things don't work, carefully step through all your ros nodes, and run "rosnode info" on every one of them. Do they they subscribe to valid topics? Topic mismatch is the most common problem.

Here is the relevant snippet from my sync-and-detect.launch
  <arg name="images_are_compressed" default="false"/>
  <arg name="annotate_images" default="false"/>
  <!-- for list of valid tag families, see apriltag_detector.h
       0 = 36h11
       1 = 25h9
       2 = 16h5
  -->
  <arg name="tag_family" default="0"/>
  <node pkg="tagslam" type="sync_and_detect_node" name="sync_and_detect"
    output="$(arg output)" clear_params="True">
    <rosparam param="image_topics">
      ["/ovc/cam_0/image_raw",
       "/ovc/cam_1/image_raw"]
    </rosparam>
    <rosparam param="image_output_topics">
      ["/annotated_images/cam_0/compressed",
       "/annotated_images/cam_1/compressed" ]
    </rosparam>
    <rosparam param="odometry_topics">
      ["/vio/odom" ]
    </rosparam>
    <rosparam param="tag_topics">
      ["/ovc/cam_0/tags", "/ovc/cam_1/tags"]
    </rosparam>

I think my topics  are correct.
1.by typing below commands, I cannot get continuous trajectory.
roslaunch msckf_vio our.launch
roslaunch tagslam sync_and_detect.launch
roslaunch tagslam tagslam.launch config_dir:=./ run_online:=true

2.But if I type likes below operation, it works.
roslaunch msckf_vio our.launch
roslaunch tagslam sync_and_detect.launch

After running sync_and_detect.launch, I can get  _output.bag in .ros.
rosbag play _output.bag
roslaunch tagslam tagslam.launch config_dir:=./ run_online:=true

This time, it can get continuous trajectory.
so I really confuse about this situation.

How does the non-continuous trajectory look like? Does rviz show any odometry? Does the tagslam node publish any odometry?
Can you run rosbag info on the "_output.bag" and post the output? That way I can see what topics are in there, and maybe guess which ones are missing in the other case (if this even is the problem).
The only other guess I have is that it has to do with time stamps. I usually do "rosbag play --clock foo.bag" when playing back from a bag. Also, note that in this case you should use "rosparam set use_sim_time true", which you must set before you run rviz (and any other ros node that relies on clock). In the scenario 1) above, do you also play from bag, or is that data then directly coming from the camera?
Can you collect a bag with the original data (collect the "compressed" image topic), just maybe a minute or so, and send it to me (bernd.pfrommer@gmail.com), along with the cameras.yaml, camera_poses.yaml and tagslam.yaml?

Is this still an issue?

I have sent the data to your email, just a moment ago. hope that you can fix it

I had intense difficulty getting the odometry to work right, in the end I got it kinda working, and I did not see the jumps in the tagslam output that you mentioned.
The first thing to check for jumps is the raw odometry itself. There are occasionally jumps in the msckf_vio, when it loses features, because that is when it is compounding all the visual feature tracks into the state update.
If the odometry looks good, then the only reason for jumps should be when tagslam tries unsuccessfully to close the loop. When the gap is too big you will get subgraph error warnings, and a jump in trajectory. But that did not seem to be the problem in this case.

I finally find the problem.
When I play the bag slowly, it can get continuous trajectory.
rosbag play -r 0.8 my.bag

But when playing the bag in normal speed, the trajectory is non-continuous.
I check the odometry from vio and the /tagslam/odom_raw/body_rig.
It shows the odometry from vio is continuous, but /tagslam/odom_raw/body_rig is non-continuous, which causes the final error result.
so I think whether the computing consume of  tagslam  is large , which causes that it cannot get the odometry from vio timely.
When running online, tag detection, vio and tagslam are running simultaneously.
If we get the _output.bag firstly,  and run tagslam later,  it can work well, because only tagslam is running without tag detection and vio generation.


Non-escaped characters

Hello,
I wanted to report this simple issue: here is what happens when the message I'm encrypting contains an exclamation point:
keybase encrypt valentin -m "what's going on?!"
-bash: !": event not found

Should we escape it instead?
I'm running version 1.0.18-20161116190722+95f8303.

This is not a Keybase issue, typically ! needs to be quoted.
From the bash manpage

When the command history expansion facilities are being used (see HISTORY EXPANSION below), the history expansion character, usually !, must be quoted to prevent  history  expan‐
sion.

Example
bash-4.2$ history
    1  history
    2  echo 'command1'
    3  echo 'command2'
    4  echo 'command1'
    5  history

bash-4.2$ !3
echo 'command2'
command2

bash-4.2$ echo "Example !2"
echo "Example echo 'command1'"
Example echo 'command1'

bash-4.2$ echo "Example2 $(!2)"
echo "Example2 $(echo 'command1')"
Example2 command1


Multiple instances of activity open on clicking Service notification.

Multiple instances of activity open on clicking Foreground Service notification.
Steps to reproduce
Click the Pomodoro App notification multiple times while it is running. At this moment, the service is only started on starting the app. For better understanding, increase the TIME_PERIOD of the counter in MainActivity to prolong the duration of notification. Multiple instance are evident when back button is pressed.
Expected behaviour
Ideally, a single instance of activity should be open. If no instance is in memory, a new one should be created but if it is memory, it should be reopened instead of creating a new activity.
Actual behaviour
Every time the notification is clicked a new instance of the activity is created.

@kartikohri1712
For now, the serviceIntent has been moved to the Start/Stop button.
This issue can still be reproduced if that button is hit multiple times, but it will solved when the work / break cycle logic is implemented (issue for which is currently being written)

Moreover, in my opinion will not be wise to interfere with activity lifecycle for this matter. Please let me know if you think otherwise.


chore(docs): Improve documentation accessibility

resolves #2067
Before

After

Nice! Could we make the menu selection colour a bit more darker? It's hard to see that it's selected.


Null Pointer Exception

After I had installed the plugin, I went to the Tools | Options | Editor area to check it out, and during the process this error popped up. Thank you for the plugin.
java.lang.NullPointerException
at lukazitnik.jshint.annotations.LintingThread.(LintingThread.java:22)
at lukazitnik.jshint.annotations.JSHintDocumentListener.updateAnnotations(JSHintDocumentListener.java:32)
at lukazitnik.jshint.annotations.EditorRegistryListener.addDocumentListenerAndAnnotations(EditorRegistryListener.java:87)
at lukazitnik.jshint.annotations.EditorRegistryListener.updateOpenDocuments(EditorRegistryListener.java:64)
at lukazitnik.jshint.Installer.updateChangeListenersOnEditorRegistry(Installer.java:46)
at lukazitnik.jshint.Installer.access$000(Installer.java:13)
at lukazitnik.jshint.Installer$1.preferenceChange(Installer.java:35)
[catch] at java.util.prefs.AbstractPreferences$EventDispatchThread.run(AbstractPreferences.java:1496)

What a nasty stack trace! I am truly sorry you've encountered it. It looks like the editor module doesn't behave as I expected. I would like to know more about the environment in which the plugin is ran. If it's not too much to ask, could you please send me your IDE log file? You can get it by going to Main Menu -> View -> IDE Log and then Output Window -> IDE Log -> Ctrl+S.

Version 1.1.2 of the plugin bears a fix for this issue. It can be downloaded from the NetBeans Plugin Portal. Thank you for this report.