Multicanvas viewer

🚀 Feature
A napari multicanvas view has been a long-requested feature that could be implemented in different ways.
There are two main approaches that we are interested in:

grid mode: similar to the current grid mode in intent, but by using a grid of viewboxes with individual (optionally linked) cameras
"true" multicanvas: separate Vispy canvas in the same (or different) viewer with potentially different cameras, layer lists and dims, but the ability to share any of the above

This issue serves to discuss the various possibilities for implementation in Napari.
Motivation
Over time in several issues, various motivations have been described for the multicanvas view. To name a few:

comparing side-by-side algorithm performance or accuracy of registration
visualizing multiplexed image channels in separate tiles to avoid loss of information due to color composition in composite images
orthoview

For previous discussions see the following issues:
- #2338 Multicanvas API Thoughts
- #760 Linked multicanvas support
- #662 Linked 2D views
- #561 multicanvas grid display for layers in Napari
Also:
- NAP-3 Spaces
Pitch

Alternatives
Definition of multicanvas
There are several components that may or may not be part of a Multicanvas implementation. Here are some possible features, starting from the simplest in terms of interface, and slowly adding complexity:

A group of canvases that is tightly linked to each other. Cameras are linked, layer list is shared and layers are orderly distributed across canvases. The Dims model is shared (i.e: only one "slicing" is shown)
cameras can be unlinked; users are able (or required) to specify how cameras are linked
layers can be arbitrarily distributed across canvases; users are able (or required) to specify which layers should be shown where.

this could be done by canvases having "subsets" of the layer list, or
by having entirely separate layer lists (which can still share layers)

each canvas has its own dims; users are able (or required) to specify if and which canvases should share dims and which not.

Additionally, there are two main ways to obtain multiple canvases in the GUI:
a. Subdivide a single GL canvas into multiple viewboxes ("virtual" canvases).
b. Create separate canvases
Any combination of the above is possible, and as much customizability is desirable. However, there are two "main use cases" that we think should be handled differently:
Grid Mode
This is the combination of 1 (but possibly also allowing 2 and 3.1. later on). Due to it being easier to implement at the moment, this would be the first to be implemented (see explanation below).
It should be a drop-in replacement of the current grid mode, but instead of translating each layer in world space, a grid of viewboxes is used. Cameras a linked (at least by default), stride and shape can be set (like current grid mode) and a single layer list is used and automatically distributed across viewboxes.
True Multicanvas
This is the combination of 1, 2, 3 (preferably 3.2) and b. This cover every other use case, by putting more power (and more responsibility) in the hands of the user. It should allow (or not disallow) things like

view the same data in multiple viewers/tabs (see NAP-3 Spaces for more discussion on this)
Orthoviews with shared/linked layer list, cameras and dims that are "partially" linked
custom setups such as having a "root" image show up in every canvas, but other combinations of layers for downstream processing in each canvas

Notably, it could be possible (and maybe desirable) to allow a combination of the two implementations above. One might have two "true canvases", where the second one is in Grid Mode and thus split into a grid of mini-canvases.
Current situation
++napari.Canvas and vispy.scene.canvas.SceneCanvas++
Currently the napari.Canvas is a Vispy.scene.canvas.SceneCanvas in the backend which automatically draws the contents of a scene and is able to receive a set of events:

Initialize
Draw
Mouse events including wheel
Key events
Stylus
Touch
Close

One complication is that currently, these events are firstly handled on the Vispy side. The flow of events looks like this:

QT receives event
Canvas creates an event for example mouseEvent
mouseEvent is emitted by EventEmitter
Callback functions listening to a particular event are executed in a particular order
Changes are passed back on to Napari

In order to not surrender control to Vispy we would like to move to the situation of:

QT receives event
Pass it to Napari canvas or canvas like objects
Objects return whether it was under the event
If so, send updates to all linked objects (for example cameras that are linked)

For this please take notion of #5296 Reroute key events.
++Grid mode++
Currently, a grid mode has been implemented in Napari which arranges different layers in a grid that is viewed using one camera. To be able to display all image layers in the grid, the stride parameter is used to control the number of layers displayed in a grid square. While already useful, it's impossible for example to zoom in on a feature and see it on every layer.
Under the hood, this works by setting the World2Grid transform of each layer, which is a simple translation. This results in the layer being "physically" shifted in world space to the new location. (This is also currently buggy if one attempts to roll dimensions because this is not taken into account by the machinery that sets the transform.)
Event coupling issue
One of the first obstacles in this work is caused by the current tight coupling of the Vispy backend and the Napari models when it comes to the canvas. The QtViewer code in particular is hard to disentangle from the Vispy code.
Proposed multicanvas implementations
In general, decoupling the canvas model from the Vispy backend is the first step for a successful implementation. The ViewerModel should hold a new field called canvas which is itself an EventedModel:
class Canvas(EventedModel):
    size: ...
    bg_color: ...

Events from this model would be sent to a wrapper around vispy.SceneCanvas (similarly to our VispyBaseLayer objects) which would take care of translating the model into vispy calls.
Grid Mode
Part of the work for Grid Mode is already done on the Vispy side. It adds a grid to the central widget of the canvas which is then populated by adding a viewbox to each grid tile. Each viewbox has its own camera.  The Vispy implementation also has for each camera a list of which cameras are linked and which properties have to be synced between the different cameras. Cameras are not linked by default. This backend linking could be used by napari, or we could write our own implementation (depending on what fits best).
It should be relatively easy to implement a drop-in replacement of the current grid mode with something like this:
class Grid(EventedModel):
    active: bool = False
    stride: ...
    rows: ...
    columns: ...

class Canvas(EventedModel):
    size: ...
    bg_color: ...
    grid: Grid = Grid()
    ...

The vispy backend could then receive events accordingly, and if Canvas.grid.active = True, generate a grid and reorganize the scenegraph accordingly.
As stated before, each viewbox has its own camera. To me it intuitively seems the most logical to have it as a default that all cameras are linked. There seem to be multiple ways by which this can be achieved.

Use the functionality of the Vispy camera to link cameras.  I think it is not necessary to have each camera linked to each camera. Instead, one 'host' camera would be linked to all cameras, while all the other cameras are linked to the 'host' camera. In this case, QT would receive an event on a grid tile that is propagated to the camera of the viewbox, which then propagates it to the host camera and from there to all the other cameras.
Use eventEmitter on the side of Napari  This implementation would be less dependent on Vispy. In this case, QT would receive an event. Napari determines on which grid tile this event was created. Napari keeps track of the cameras that exist and should be synced and emits the event to all cameras accordingly. Potentially, psygnal could be used for this.

For both cases at a minimum it is required to have a wrapper around vispy.scene.widgets.viewbox.ViewBox. This wrapper is exposed through the grid class (see above). In case of only linked cameras, only 1 camera would have to be exposed on the Napari side, but since a camera list seems to be easy to implement this would not be the first option as a camera list for which it is tracked which ones should be linked is a more generalized solution.
NOTE: The layer._get_value() method might have to be updated to work in viewbox coordinates instead of canvas coordinates.
True Multicanvas
For a True Multicanvas implementation, there are more design and UI/UX considerations to do. For example:

where should multiple Canvas objects live? A list in ViewerModel.canvases?
should each Canvas have its own Dims and Camera? How do we expose them? And if not, where do we put them?

Additional considerations
The current grid mode in Napari makes use of stride in order to control the number of images displayed per grid tile. While this ensures that all image layers can be viewed in grid mode on one canvas, it does create a composite image which can be less informative than looking at grayscale images. In the case of highly multiplexed imaging, the number of markers can exceed 50. In this case, I believe users would like to be able to switch to different 'tabs'. Each tab displays a grid and is only rendered as the tab is activated. Should this be implemented in the Napari core or as a plugin?
In addition to this, a user might like to save the view settings of what is displayed on each grid and how. This configuration could then be imported again in Napari, activating the grid mode and displaying the content according to the configuration.
Additional context
For work on layer lists, it was mentioned during one of the Napari community meetings that @jwindhager has been working on this.
Co-authored by @brisvag

@Czaki @andy-sweet

Thanks for writing this up - I'm excited to see this work being pushed forward and am happy to help out as a reviewer in general on this work.
Still need to collect some general thoughts on this, but here are a few points/questions that come to me first.

Would be good to clarify what some next steps are. You seem to have some solid understanding of what's needed here and there's quite a lot of prior discussion. After reading this, I got the sense that one next step would be implement prototype for the new grid mode described, which sounds like a great idea to me!

For the grid of canvases (in both grid model and "true" multi-canvas), I wouldn't expect to be limited by making a RxC rectangular grid. One example layout I've found useful in the past (for calcium imaging), is two canvases on top (showing 2D videos) and one long canvas on the bottom (to show time series plot). Maybe this is a bit premature, but as we're thinking about public API for grid/canvases here, it's probably worth thinking about how general we want this to be.

Thanks for checking:). I am currently working on it in between coursework, but from next week onwards I can spend more time on it. The initial step is indeed to implement the grid mode as described. This would also get rid of the current transformation being performed when applying the current grid mode. Given that a large part required for this proposed work is already implemented in Vispy @brisvag and I thought this would be the easiest to get started.
Regarding point 2, it seems to me given the different layer dims this would require the implementation of what we now have called true multicanvas. However, I do believe we can make individual grid tiles resizable as these methods are already implemented for viewboxes on the vispy side.

@brisvag, did you already start on this yourself? To me intuitively seems that we could decouple the canvas functionalities one step at the time, for example #5296 and then next decoupling mouse events. The actual decoupling of the canvas would then be easier. What are your thoughts regarding this? Just checking whether I am thinking correctly about this.

I didn't, I'm a bit busy until end of this week, feel free to take a stab at it!
Sure, smaller non-breaking PRs are the best if you can manage :) The main refactor I refer to when I say decoupling would play out like thisin my mind:

create a Canvas(EventedModel) like we said above
create a VispyCanvas object in the _vispy module on the blueprint of the layer/overlay models, and hook it up with the events coming from Canvas evented model similarly to how layers do it
slowly chip away at the mess inside QtViewer by replacing direct calls to vispy.SceneCanvas methods with calls in ViewerModel. This should result in QtViewer doing the bare minimum set up (just like with Layers).

Another use case: VR can be implemented with two canvases with linked cameras some distance apart.

uuuuuh nice!

This needs to be linked too: https://github.com/napari/napari/issues/1478

I have been a bit swamped and there has been discussion on how to actually open the PRs for this. At first the idea was to make it part of an experimental plug-in, but after some messing around this is actually more complex than implementing it in a hidden fashion in napari. This to first be able to properly test everything without messing up the user experience while at the same time keeping PRs small. End of the month I will have time for this.

Hi all! I’ve been starting to tackle multi-canvas (what’s called “True multicanvas” above) work from a design perspective. The goal at this point is not to reach some prescriptive visual design solution, but to provide ideas on how different answers to the lingering multi-canvas experience questions might actually appear in the viewer so that we can make decisions informed by the user-facing outcomes.
At the time of writing, I’m aware of two similar features/workarounds users (and plugin developers) are using to get around a lack of “true multicanvas” in napari: grid mode and multiple viewers (I’ll call it multi-viewer). Multi-canvas work overlaps with these, but is still distinct to address pain points that continue to exist with grid mode and multi-viewer approaches.
Use cases and pain points
The first thing I want to do is document some of the needs and motivations I see behind a potential multi-canvas feature. NAP-9 and the rest of this issue already do some of this and are included in what I’m describing.
Use cases include

Viewing the same data from different camera angles side by side (ex. orthogonal view)
Viewing the same data with different views side by side (ex. viewing whole data and - slices at once)
Comparing the same data processed differently (ex. running different segmentation models on the same data to observe which produces the desired result)
Viewing different data side by side
Viewing data from the same run acquired with different cameras at once
Taking advantage of multi-canvas and/or its multiple cameras to extend the capabilities away from side by side viewing (ex. @jni’s mention of VR potential above)

Pain points include

For grid mode

Can’t re-grid or adjust grid items individually. It’s all set automatically by initiating grid mode.
Limited scale and zoom controls because they apply to the whole, singular canvas. This can be a big issue with different data of different sizes.
It grids all layers. If there is a labels layer with labels on top of an image layer, they become separate quadrants when grid mode is activated. As far as I’m aware, there’s no way to keep related layers like these as one quadrant in grid mode.
Sliders control all on the singular canvas indiscriminately. So if multiple have a time dimension to their data, the slider controls all the time data in all layers/grid quadrants at once. If multiple have the same dimension with different meaning in the data, it seems it would also all be controlled by one dimension slider.

For multi-viewer

All data is shown in different windows. They need to be manually arranged to monitor size. They may still not all fit with napari minimum window size depending on the monitor (as is the case with mine).
Does not truly show data side by side. The necessary parts of the viewer window—like the left sidebar and window title and such—put space between the data and it is easy to accidentally move windows out of manual configuration in a way a user may not intend.
It allows for as much control is possible in napari viewer normally, but that is not there is no relationship between the data opened. Any changes need to be manually applied to all viewers where it is wanted. Any batch changes would not be possible.

However, there’s also some things that grid mode and multi-viewer seem to be effective at. It’s worth paying attention to these to note what experience we may want to continue in multi-canvas.
The strengths of grid mode are

Shows data side by side immediately. One click and done.
Allows for some amount of multi-layer control with the dimension slider. For example, if you want all data in a timeseries to be at the same frame, you only have to adjust the slider once.
Requires only one viewer to be open. This also means it can work better on smaller monitors.

The strengths of multi-viewer are

Allows for the usual control of data that napari offers. This is a full functionality napari viewer.
Windows can be rearranged, regridded, and otherwise handled at any time manually.
Allows for independent control of all quadrants (by virtue of being totally separate windows)

Spot the difference (feature comparison)
To clarify what’s already supported in napari versus what is requested of multi-canvas, I put features side-by-side (like multi-canvas!?) in a table.

Grid mode (existing)
Multi-Viewer (existing)
Multi-Canvas (proposed)

✅ Shows data side by side in the same window
❌ Shows data side by side in the same window
✅ Shows data side by side in the same window

❌ Can edit grid layout, proportions, order.
✅ Can edit grid layout, proportions, order.
✅ Can edit grid layout, proportions, order.

❌ Can scale/zoom viewer contents
✅ Can scale/zoom viewer contents
✅ Can scale/zoom viewer contents

✅ Can pan viewer contents
✅ Can pan viewer contents
✅ Can pan viewer contents

✅ Grids data automatically
❌ Grids data automatically
❓Not yet determined

✅ Canvas controls (like dimension sliders) control everything on the viewer indiscriminately
✅ Canvas controls (like dimension sliders) control everything on the viewer indiscriminately
❌ Canvas controls (like dimension sliders) control everything on the viewer indiscriminately

❌ User can decide what layers appear/overlap in a single "quadrant"
✅ User can decide what layers appear/overlap in a single "quadrant"
✅ User can decide what layers appear/overlap in a single "quadrant"

Software I’m looking at
For your reference, I’m comparing what has been described for multi-canvas to a few other pieces of software to see what user experiences are like for similar features elsewhere.

JoOkuma’s ortho-view-napari plugin
Gatoniel’s napari-3d-ortho-viewer plugin
Adobe Photoshop
Adobe Illustrator
Figma
I’ve been told Fiji has some amount of multi-canvas-like feature via an orthogonal view, but I have yet to find it.
I’ve been told Blender has a comparable multi-canvas-like feature, but I’ve yet to find it. If you know what I’m missing, please feel free to let me know.

As always, feedback is welcome and encouraged. If this sounds right to you or if you think I misunderstood some part of multi-canvas, that would be very helpful to know. If you have anything else you’d like me to reference or a workflow you are hoping to complete with multi-canvas, feel free to share. Thank you!

A few other examples of multi-canvas viewers.

3DSlicer (or really any clinical imaging visualization tool): https://www.slicer.org/
neuroglancer (browser, geared towards connectomics): see an example with orthogonal slices

QuPath (https://qupath.github.io) also has this feature. There it's called multiple viewers, but the viewer in QuPath is analogous to the napari canvas.
Here's an old doc, but still accurate:
https://github.com/qupath/qupath/wiki/Multiple-images
What's nice is you can sync the viewers to pan and zoom are shared.

Ilastik: https://www.ilastik.org/gallery#
Fiji:

I’ve circled back to the main questions of multi-canvas that ask us to consider the how of user interactions. These helped me distill what questions we were asking beyond the interface itself and what was needed to have a multi-canvas do foundational the things people have requested it for.
Questions
(Numbered in no particular order, but numbered for easier reference)

How do users activate/initiate multi-canvas?
How do users deactivate/uninitiate multi-canvas?
How do users manage multiple canvases? What information do they need to manage them effectively?
How do existing features work with multiple canvases in a single viewer?
How should multi-canvas relate to the existing grid mode or multiple viewer set ups?
How will users know what canvas they are operating on?
What camera options does a multi-canvas set up allow for?
How are canvases related to each other (ie. totally separate, linked, etc.)? Are they at all?
How can canvases be adjusted within the viewer and with each other?

Primary user flow
I’ve also outlined what I think we need to plan for in order for a user to succeed in any task where they decide to have multiple canvases in a single viewer.

Viewer is open. There is one canvas by default.
Activate multi-canvas.
Orient data within multiple canvases.
Orient multiple canvases within the viewer.
Select a canvas to work on. Could do any steps that can normally be done to a single canvas.
Select a different canvas to work on. Could do any steps that can normally be done to a single canvas.
Deactivate multi-canvas.

Low-fidelity proposals
Based on those questions and that high-level user flow, I’ve come up with a few ideas about where multi-canvas could have a home base in the viewer interface and how one might manage canvases once there is more than one.
All of these options assume a single-canvas mode operates as napari currently does.
Multi-canvas’ home
Replace grid mode

Add mode

Add new canvas

Layer list context menu

New canvas region controls

Layer controls

Canvas tabs

Multi-canvas management
One tree-style layer list

Multiple layer lists

Viewport selection

Thanks for these @isabela-pf! I don't have time to go over every element in detail but for now I just wanted to drop in and say that I really like the idea of tabbed layer lists for the canvases. I was honestly quite confused about how we were going to handle these things. 😅 I like that better because (a) one could break up the layer lists into multiple panels if one has massive amounts of monitor space, and (b) I don't think clicking on a canvas to select it (last option) should be the primary interaction mode because clicking on a canvas typically would have a few side effects, and it's one of those things that makes you think, "if I click on this am I going to also add a point/change a view focus/etc? Or do I need an extra click for that?"

Thanks for the breakdown @isabela-pf!
Strong agree with @jni: we should use dock widgets for layerlists, so we get for free the ability to tile, tab and split out to a new window. I think the same is true for the canvases themselves, so I would go for a combination of "Multiple layer lists" and "Canvas Tabs".
We should discuss about Dims, and the fact that having multiple dims sliders (one per canvas) visible at once might be useful in some cases (like orthoview). In those cases, we might have to show dims sliders somewhere in between canvases, which complicates things quite a bit.
To get more into details:

How do users activate/initiate multi-canvas?
How do users deactivate/uninitiate multi-canvas?

I don't think grid-mode should be replaced. Forgive me if I sound like a broken record on this, but I really think grid mode and "true multicanvas" are solving 2 different problems, and using multicanvas as a stand-in to grid mode would be like using a cannon to kill a fly.
As to where to put the "add canvas" button, I think I prefer the "between layer controls and layer list", as every other place seems off-topic to me. No strong opinions here though.

How should multi-canvas relate to the existing grid mode or multiple viewer set ups?

Grid mode is just an alternative way for a canvas to display its contents (i.e: some canvases may be in grid mode while others aren't). Multiple viewers should be able to accept canvases from other viewers with a simple drag-n-drop. Ultimately, a viewer should be just a container for canvases which takes care of displaying controls, layerlists and dims for them.

How will users know what canvas they are operating on?

Whichever one is selected on the tabs. In case of un-tabbed modes, we should probably have a colored border to highlight the corresponding widget?

What camera options does a multi-canvas set up allow for?
How are canvases related to each other (ie. totally separate, linked, etc.)? Are they at all?

Cameras should be unaffected: each canvas has its own camera which behaves the same as the current. We should offer api (and some simple gui) to link cameras from different canvases, as well other things (like dims).

How can canvases be adjusted within the viewer and with each other?

If we use dock widgets, it should be straightforward!

My comments + notes in response to @isabela-pf's discussion during the community meeting today:
+1 for keeping grid mode. @brisvag has good arguments here. Maybe grid mode can be less of a first class mode (e.g. replace the grid mode button, but still preserve the ability to use grid mode)

@Czaki suggests putting grid mode into the View menu

What types of controls could we imagine for canvases?

link cameras between canvases (e.g. for customizable orthoviews [or non-ortho, but still geometrically linked])

How many canvases do we need to consider supporting eventually? In the limit of tons of canvases napari presumably becomes unusable, so are we thinking like 4, 8, ???
Why is there 1 set of dims controls, shouldn't there be a unique set of dims controls be on each canvas?

@isabela-pf only show dims for the selected canvas
@andy-sweet considering orthoviews, can the behavior of sliders be automatic? Is there a stronger way to keep correspondence between canvases?

@Czaki:

why tabs instead of opening another napari window?
should we think about plugin API first?

@andy-sweet:

is there a notion of a currently selected canvas?
buttons for swapping data dimensions and such should be per canvas
console button should go somewhere else because it doesn't match

Can the layer list reflect the currently selected canvas, and have a button (or smth) that would switch to a "global" layer list?
@Czaki:

an icon on canvas to indicate which one is selected?
ask community on #general on zulip about their multicanvas use cases
add a button: "go back to single canvas", deactivate, etc.

How many canvases do we need to consider supporting eventually? In the limit of tons of canvases napari presumably becomes unusable, so are we thinking like 4, 8, ???

Just a side note: in conversations with @kushalkolar, we were trying to understand our separate vocabularies for napari and fastplotlib, and came up with Viewer <=> Figure and Canvas <=> Subplot. In that mind frame, I think that the number of canvases should be unlimited, or rather limited only by resources (screen size, GPU memory, etc) rather than some arbitrary code limit, and we should think about both automatic and guided layout algorithms for subplots, as well as several "named" layouts such as orthoviews.

Just a side note: in conversations with @kushalkolar, we were trying to understand our separate vocabularies for napari and fastplotlib, and came up with Viewer <=> Figure and Canvas <=> Subplot. In that mind frame, I think that the number of canvases should be unlimited, or rather limited only by resources (screen size, GPU memory, etc) rather than some arbitrary code limit, and we should think about both automatic and guided layout algorithms for subplots, as well as several "named" layouts such as orthoviews.

limited - should mean that we do not care that the interface looks bad over a given number of canvases.

I don't see why we would put a limit. If it looks bad, the solution is easy: reduce the number of canvases or split into separate windows.

* why tabs instead of opening another napari window?

Uses less screen real estate, easier to use the same console, no extra windows to track via window manager. Why browser tabs instead of new windows? :P

* is there a notion of a currently selected canvas?

There should be a notion of active canvas (I think it was in the NAP original proposal), to make it more convenient to work via API (like, no viewer.canvases['some canvas'] but viewer.canvas), as well as via GUI (button to create new layer should put it in the active canvas, and so on).

Can the layer list reflect the currently selected canvas, and have a button (or smth) that would switch to a "global" layer list?

Not sure about a "global" list, what's the intended purpose? But yeah, I think layer list should match the active canvas (and have tabs to switch to others).

From the last round, community meeting feedback narrowed down the general placement of multi-canvas controls and how canvases impacted a layer list. In summary, multi-canvas/adding canvases takes the place of grid mode in the interface (though grid mode is not removed as a feature) and each canvas has its own discrete layer list. Now that we have some agreement on where multi-canvas should go, we can decide how it should behave upon user interaction.
Feedback on any of the following approaches is, as always, welcome! It may be especially good to note

If these mockups have any misunderstandings of multi-canvas features or other code-implausible choices.
If any of these mockups would work well for a use case you want multi-canvas for.

Initiating multi-canvas
Before the user can do anything with multi-canvas, they need to initiate it. In most cases this is adding a new canvas in the same window, and this is how I’ll be interpreting it for napari.
From viewer button

Adding a canvas replaces the current Grid Mode button in the viewer buttons area. It has the same one-click-and-go behavior as the “add layer” button and “toggle grid mode” buttons.

Adding a new canvas begins what we are calling the “multi-canvas” feature. A new layer list appears for the new canvas and a new division appears in the view area with a second canvas.

Return to the viewer buttons to add another canvas. In the community meeting we discussed an early upper limit for canvases that is either 4 or 8 per viewer.

Once again, the layer list and view area update to accommodate another canvas.

Removing canvases (to change the number shown or to return to the single canvas viewer default) can be done from the context menu that appears over the canvas name in the layer list.
From context menu

The same canvas adding behavior could also be completed from a context menu in the view area/over the canvas if that does not conflict with any existing canvas context menus (I did not immediately find any).
From main menu

The same canvas adding behavior could also be completed from the main menu, probably under the View menu, though maybe under an additional main menu if we find reason that canvas actions need their own section.
Over-canvas buttons

Like the canvas context menu option, a designated canvas control area may make the most sense if we want canvas controls to be tightly grouped and in the location where they are most relevant. It bears noting this would be a new area to have buttons in the viewer.
Multi-click option
Having a single-click option to add a canvas has been the route we’ve discussed thus far. Depending on what information is necessary to set up a canvas, we may also need a dialog like the Preferences and some plugins do. I’m providing this to open up the discussion of what we need to successfully add another canvas.

User paths for initiating multi-canvas
Summarizing the above options, multi-canvas would be available from the viewer buttons section, a canvas context menu, and the main menu. But even though they start in different places, they would all have the same behavior beyond that. Different starts, but same path.

I recommend having at least two ways to add a canvas in the viewer. We’ve agreed on the viewer buttons in replacing the current grid mode button, but having one other option can support discoverability and provide a place to group other canvas controls in the future. I would prioritize the main menu over the context menu option if all three do not seem feasible.
Moving grid mode
Feedback was clear that while the place of grid mode in the viewer should become multi-canvas, that grid mode should not be eliminated as a feature. But if it is to be displaced, where should it move? I’ve considered the following options.
To the main menu
The main menu is a great, standard place for listing high-level actions like grid mode. Of the options that already exist, grid mode seems to best fit under the View menu as it changes the visible layout of the canvas but not any of the image data.

Depending on the degree of separation or space conservation we want to prioritize, canvas-related options could also be added to a submenu.

To the main menu separate from canvas options

As has come up in community discussions of grid mode, grid mode only operates on one canvas at a time. While it may solve some overlapping use cases as multi-canvas, it is ultimately only one canvas. If there is a benefit in making this difference clear, I would recommend splitting these actions up in the interface to communicate it.
To a canvas context menu

I mentioned this in a previous section; as far as I can tell napari does not have a canvas context menu at the moment. Considering that grid mode is a whole canvas and all layer related action, a context menu where those things live does seem like a natural grouping.
I recommend a main menu option. The main menu is more discoverable and provides many options for organization depending on how grid mode and canvas controls may need to grow. Still, a context menu has the benefit of bringing the controls to the place they will impact.
What’s next
With decisions about how users can get in and out of multi-canvas modes as well as access other canvas-level controls, we can move on to interactions within or impacted by having multiple canvases. This could include managing canvas layout within a window, managing layers across canvases, moving layers across canvases, and the like.

In summary, multi-canvas/adding canvases takes the place of grid mode in the interface (though grid mode is not removed as a feature) and each canvas has its own discrete layer list

I wasn't in the meetings so I'm probably missing the arguments for this, but I don't see why we would do this. Grid mode is a quick toggle just like 2D-3D and axes swapping, and people are used to having it there. It makes sense to me that it should stay. Even if we thing that multicanvas should also be there, why not just add the button instead of replacing?
Altough I also don't think we should put the "add canvas" button there, to be honest. Can someone write down here a summary of why this was the conclusion at the community meeting?
Most of the other proposed options for how to add a canvas make more sense to me.

When discussing the last mockups at the community meeting, I received feedback that there wasn’t confidence that previous choices were being made based on actual use cases. There was also a discussion about all the possibilities multi-canvas opens up, and an immediate agreement that it’s a powerful concept that’s very easy to go overboard on. Out of this discussion we also agreed it would be helpful to outline the features required to create a fully usable multi-canvas without building for niche features yet.
Feedback that would be especially useful at this juncture includes:

If any use cases or requirements seem to be missing.
Which of these use cases are ones you would want base napari to prioritize, or if any of these use cases seem more suited to plugins?
Does any of the work here create a clear set of next steps to you?
If any of these explorations would work well for a use case you want multi-canvas for.

Use Cases
Use cases are the “why” behind requests for multi-canvas in napari. Earlier in this issue I described use cases found from reading the various issues prior to this one. They are general umbrellas that hold more specific use cases underneath them. I’ll organize this section by similar groupings while also providing examples of more specific use cases.
1. Viewing the same data different ways side by side
This involves loading identical data into different canvases whether it is loaded repeatedly or linked across canvases. Users may want to

View data with orthogonal view layout.
View several slices at once.
Explore the same data at different zoom, along different dim-slider values (such as time), or with other adjustments by linking layers across multiple canvases.

Request for an orthogonal view is one of the use cases I’ve seen most.
2. Comparing the same data processed differently
This involves loading the same data into different canvases and performing different actions on it per canvas. Users may want to

Compare segmentation methods to find which works best for the data.
Compare annotations from different sources on the same data.
Test different plugin alterations to the same data.
Compare registration accuracy.
Compare two tomograms generated different ways.

3. Viewing related data side by side
Data may be gathered as a series, belong to different runs in the same set, or have other relationships. Exploring this data in full can benefit from being viewed side by side as multi-canvas would enable. Users may want to

View a series of images in order of acquisition.
View all camera angles or image types available for data from a single run.
Compare different runs from the same set.

4. Viewing different data side by side
This is loading different data into different canvases. Users may want to

Compare data of the same type of tissue from different runs or data sets.
Compare annotations for the same type of organelle from different data sets.
View a type of sample captured by multiple imaging methods.

Required features
In order for multi-canvas to be fully functional, I propose it needs the following:

Initiate multi-canvas
Return to single canvas
Add a new canvas
Remove a canvas
Minimum two canvases supported in a single window
Adjust canvas layout in view area
Independent canvas controls like pan/zoom
Add layers to canvas
Remove layers from canvas

Based on our discussions, I think the following might also be considered, but I do think we can have some kind of multi-canvas experience without them as well.

Link layers across canvases
Move layers across canvases
Apply plugins to each canvas
Grid mode on each canvas

What’s next
I’d like to make a decision that can help us move into more specific questions and interactions if possible.

100% agree on the must-haves. Ont he others:

Link layers across canvases

Can already be done via link_layers; for anything "better" (sharing layers between canvases) we will need to finish decoupling the slicing state from the layer itself, and so I suggest moving on for now with the limitation of "a layer can only be in a single canvas at a time".

Move layers across canvases

IMO not just a must have, but basically an inevitable implication of "add/remove layers to canvas" and my point above.

Apply plugins to each canvas

There was a discussion about how to transition from "assuming there is a single canvas" to "there are now multiple canvases" and how plugins would interact with that. Our (temporary?) solution was to have the concept of an "active canvas" and for now ensure that any API that worked before (viewer.camera.something) would still work by linking to the active canvas (e.g: viewer.canvases.active.camera.something). See similar discussion in NAP-3 and in my comment above

Grid mode on each canvas

Should come for free :P

Based on the minimum features proposed in my previous comment, I wanted to recommend what I think might be the most direct and minimal path for meeting those features in the viewer.
Relevant feedback here could include:

Have I missed any required features?
Does this seem like an option community members have interest in pursuing?
Does this seem like a technically viable approach?

Preserve as much of the existing viewer interface as possible
Part of aiming for the minimum requirements of a new feature is reflecting minimum changes in the interface. In this scenario, I would recommend an approach that has the default viewer window looking the same. Because we’ve agreed the viewer always starts with one canvas, there is nothing to indicate multi-canvas capabilities within the window itself.

When multiple canvases are open, having multiple canvases in the same viewer window will be the biggest interface change. To manage what is on each canvas, some amount of the layer list interface must also change.

I recommend adding layer list tabs as the minimal approach for the following reasons:

It reuses a component and user experience we already have set in the layer list by simply adding another.
It makes the selected canvas clear without needing to build new canvas selection states in the viewer.
Any of the tree-style-looking options for showing all canvases in one layer list widget would take new work and not follow existing napari patterns I am aware of.

Add canvas controls to the main menu
I believe the shortest path to success for multi-canvas controls would be in the viewers main menu. In this mockup I’ve added Canvas as a menu option in the View menu. The Canvas submenu is where users would

Add a canvas (initiating multi-canvas)
Remove a canvas (returning to single canvas)
Arrange all canvases in the viewport (subject to change, but I do recommend the idea of preset canvas layouts)
Access grid mode (because it is a canvas-level control, though it would still be available in the buttons on the lower right of the viewer as well).

It is worth noting that I think there is still room for adjustment on whether View is the right menu to group canvas controls with, whether canvas controls should be a sub-menu, and other details. But having the controls for multi-canvas in the menu is what I recommend.
What’s next
The fact that community meeting feedback was to circle back to the minimum requirements signaled to me that we were likely trying to solve too many issues for a first pass at a new feature. While I’m open (as always) to feedback on this, I do think focusing on the requirements to make a multi-canvas at all may be a more effective scope considering the time we’ve spent trying to make this decision from pre-NAP days.
Next steps are determining whether or not this seems like a useful and possible approach that the community has interest in pursuing. I will also update this based on feedback of things missing or any other questions that come up.

Adding another comment to bring this up on people's notifications. Feedback on if this minimum approach seems like a good first step to aim for when multi-canvas development starts, isn't certain about this option, if information and/or features are missing are all helpful. Other feedback is welcome as well.
I'm starting work on NAP-6 and will have some split napari attention as the year heads towards its close. It'd be great to find some agreement on direction on multi-canvas work in order to keep inching these efforts forwards. Thank you!

Will we be able to pull a canvas out of the main window (like you can do with dock widgets)? If so, will we also be able to pull the per-canvas layer list out? This might be silly, but I'm thinking about how usable this would be in a dual monitor setup...

@kephale I don't think that's silly! It makes a lot of sense to consider, especially with the frequency I've heard people using napari mention dual monitor setups. As far as I'm aware, napari currently doesn't allow for undocking the single canvas from the main window (presumably because everything else around it can be undocked and it can be alone in the main window as if it were undocked). So this makes me ask
Is the intent that only the additional canvas(es) are undockable from the main window? (Indicated here by the overlapping square icons like those used in napari.)

Or is the intent that all canvases become undockable? Which would also potentially leave the main window empty if all widgets were to be undocked at once.

I don't see why would special case a canvas over another... we should also be able to reorder them, or show them in tabs. So I would say we should just use the qt dock widgets.

At today's community meeting we discussed this last direction of the minimum necessary functionality and interface changes to the viewer to have multi-canvas. So far, there does not seem to be any comments against this direction and multiple in favor of it. I'll be following up in more detail so there is a more comprehensive version of what this approach needs in terms of user interactions.
For now, I wanted to summarize the main points of discussion at the meeting today.

Starting with a minimal approach seems much more favorable from both a PR author and PR reviewer standpoint.
Agreement that starting with a maximum of two canvases per viewer is a good next step.
With two canvases, built in layout options (eg. ortho view, quadrants, etc.) will not be a priority. Using Qt's qspan (I may have linked the wrong one, but this is meant to match the others in napari already) to adjust the vertical split in the middle of the two canvases would be better for now.
Having the same layer on multiple canvases (in the same viewer) at once is not a priority in the minimal approach. While there are many use cases for it, it brings in many interactions that rely on ones in multi-canvas that have yet to be built. It can come later.
At least two people want both canvases to be dockwidgets so they can be undocked, docked, and resized like the other dockwidgets in napari.

Thank you all for following up on multi-canvas!

I don't see why would special case a canvas over another...

I mostly agree, but I think the plan (mainly for API reasons) was to have a concept of a "main" canvas. If this is still the case there may be places it needs to be special-cased. For example will we allow users to close the main canvas? If so, does another canvas become the main? Can users close all of the canvases and have a viewer without a canvas?

I mostly agree, but I think the plan (mainly for API reasons) was to have a concept of a "main" canvas. If this is still the case there may be places it needs to be special-cased. For example will we allow users to close the main canvas? If so, does another canvas become the main? Can users close all of the canvases and have a viewer without a canvas?

By that I meant that I don't think there should be one canvas that's always the "main" and other secondary ones that will always be secondary. I think this would lead us down wrong paths in the implementation, and won't actually save us work in the long run.
Instead, IMO we should aim to achieve this special casing by having an "active" canvas. I would say no, let's prevent at least for now removing all the canvases, that should be easy and save us some pain.
I imagine the implementation path like this (ideally in separate PRs):
- implement most of CanvasModel, without hooking it up
- add a Viewer.canvases container with a single canvas using the CanvasModel, and replace current Viewer.canvas, replacing the current canvas, dims, etc with appropriate properties that point to the new objects in a backward compatible way
- add the ability to add a new canvas, and hook up all the things necessary for this


ISO8601 format currently doesn't work with milliseconds

Just a heads up that ISO8601 formatted dates with milliseconds aren't currently supported. Pretty easy to add:
let ISO8601Format = "yyyy-MM-dd'T'HH:mm:ssZ"
let ISO8601FormatWithMilliseconds = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"

Easy enough to just try the second formatter if the first one fails.

Added feature on latest release


I got the following issue when using wagyu with yew.rs

Caused by:
0: error getting cargo metadata
1: cargo metadata exited with an error:     Updating crates.io index
error: failed to select a version for the requirement aes = "^0.2"
candidate versions found which didn't match: 0.8.2, 0.8.1, 0.8.0, ...
location searched: crates.io index
required by package wagyu-zcash v0.6.3
... which satisfies dependency wagyu-zcash = "^0.6.3" of package wagyu v0.6.3
... which satisfies dependency wagyu = "^0.6.3" of package frontend v0.1.0 (/home/developer/Desktop/Folkseconomy/prototype-12/folkseconomy/frontend)

I get this too


Update attachments-not-tracked-to-dynamics-365-after-office-365-atp-i…

…s-enabled.md
Fixed terms

Hi @chrisda, thanks for your draft. We'll continue to review the updates in private repo PR#4004.


Upgrade snippets to Python3 (using ' instead of ")

It's two years since Python2 was obsoleted. So maybe it's time enough to move on and make the built-in snippets be Python3 compliant

Thanks for the PR.
Changed via https://github.com/orbitalquark/textadept-python/commit/4a7b157c0e27ff15d46a29fb9f8d8cc96223ff7a
We need to keep the '\t' because it respects the user's indentation settings (which will often expand to 4 spaces).


Cannot link to CSS file in Shiny apps

I'm not sure whether this is a bug for here or REditorSupport/vscode-R but it seems like a link issue than an editor problem. In any case here's the problem.
Description
Linking to CSS files in Shiny apps do not work, i.e. I cannot use:
tags$head(
    tags$link(rel = "stylesheet", type = "text/css", href = "style.css")
  )

The file style.css cannot be found. I've already tried multiple different versions of the path like www/style.css or the complete path on my file system. Never worked. The code and the file location should be correct. The exact same code renders fine in RStudio.
At first I thought this is related to RStudio projects, but even if I open a different workspace that does not contain an RStudio project, the problem persists.

Would you like to provide a minimal reproducible example so that we could reproduce it easily?

Hi @renkun-ken,
sorry for the incredibly late reply. I believe I loaded CSS files in R and included them with includeCSS() and then forgot about this issue. Now I run into a similar issue where local links to a PDF seem to be broken when using VSCode instead of RStudio. Here's an reprex that tries linking to different file types. Specifically, the app links to

a dummy pdf file
a gif (a cute bear 🐻), and
a CSS file (makes headlines bold and red-ish)

All files can be found at reprex.zip. Alternatively, if you don't want to use a zip-file from a random dude on the internet, I have provided the links to the files above. Also, here's the code part.
Reprex
app.R
library(shiny)
#> Warning: Paket 'shiny' wurde unter R Version 4.3.2 erstellt

ui <- fluidPage(
  tags$head(
    tags$link(rel = "stylesheet", type = "text/css", href = "style.css")
  ),
  h1('Include pdf via uiOutput() and iframe'),
  uiOutput('pdf'),
  h1('Include Image via uiOutput() and img tag'),
  uiOutput('img_ui'),
  h1('Include Image via imageOutput()'),
  imageOutput('img')
)

server <- function(input, output, session) {
  output$pdf <- renderUI({
    htmltools::tags$iframe(
      src = 'dummy.pdf'
    )

  })
  output$img_ui <- renderUI({
    htmltools::tags$img(
      src = 'hello-bear-waving.gif'
    )
  })
  output$img <- renderImage({
    list(
      src = 'www/hello-bear-waving.gif', ## Needs www/ path
      width = '400px',
      height = '200px',
      alt = "This is alternate text"
    )
  }, deleteFile = FALSE)
}

shinyApp(ui, server)

Shiny applications not supported in static R Markdown documents
Created on 2024-02-16 with reprex v2.1.0

Session info

sessionInfo()
#> R version 4.3.1 (2023-06-16 ucrt)
#> Platform: x86_64-w64-mingw32/x64 (64-bit)
#> Running under: Windows 11 x64 (build 22621)
#>
#> Matrix products: default
#>
#>
#> locale:
#> [1] LC_COLLATE=German_Germany.utf8  LC_CTYPE=German_Germany.utf8
#> [3] LC_MONETARY=German_Germany.utf8 LC_NUMERIC=C
#> [5] LC_TIME=German_Germany.utf8
#>
#> time zone: Europe/Berlin
#> tzcode source: internal
#>
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base
#>
#> other attached packages:
#> [1] shiny_1.8.0
#>
#> loaded via a namespace (and not attached):
#>  [1] cli_3.6.2         knitr_1.45        rlang_1.1.3       xfun_0.41
#>  [5] promises_1.2.1    jsonlite_1.8.8    xtable_1.8-4      glue_1.7.0
#>  [9] htmltools_0.5.7   httpuv_1.6.14     sass_0.4.8        rmarkdown_2.25
#> [13] evaluate_0.23     jquerylib_0.1.4   ellipsis_0.3.2    fastmap_1.1.1
#> [17] yaml_2.3.8        lifecycle_1.0.4   compiler_4.3.1    fs_1.6.3
#> [21] Rcpp_1.0.12       rstudioapi_0.15.0 later_1.3.2       digest_0.6.34
#> [25] R6_2.5.1          reprex_2.1.0      magrittr_2.0.3    bslib_0.6.1
#> [29] tools_4.3.1       withr_3.0.0       mime_0.12         cachem_1.0.8

style.css
h1 {color: #f75990;font-weight:600;}

Expected Output (which I get with RStudio)

Actual Output (in VSCode)

Comments
I've noticed a couple of things:

Using imageOutput() works in both cases. This is due to the fact that renderImage() includes the image via base64 encoding and doesn't link to the file in the www directory. It seems that VSCode can find the file so that renderImage() can do its thing but linking is an issue.
In VSCode the last image is only displayed if I make sure to set my working directory to the one that contains the app.R file. But my R project file structure is actually R_project_directory/reprex/<here is where app.R and the www directory are>. In RStudio this wasn't an issue. Executing app.R in whatever directory immediately made that directory as the working directory while running the Shiny app. I'm not particularly sure what to make out of this but maybe it will give you a hint.


Suddenly Pinia doesn't show up anymore

Vue devtools version
6.5.1
Link to minimal reproduction
http://Icannotshowlinkbecauseitsdevtools.com
Steps to reproduce & screenshots
Just open de devtools and you do not see the Pina Pane
I work with Vite en Vue.

What is expected?
To see the Pinia store
What is actually happening?
I don't see the Pinia store pane
System Info
System:
    OS: Windows 10 10.0.19045
    CPU: (20) x64 12th Gen Intel(R) Core(TM) i7-12700
    Memory: 8.19 GB / 15.77 GB
  Binaries:
    Node: 16.0.0 - C:\Program Files\nodejs\node.EXE
    npm: 7.10.0 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Edge: Chromium (121.0.2277.83)
    Internet Explorer: 11.0.19041.3636

Any additional comments?
No response

https://stackoverflow.com/a/75825663/23150688 was the solution for me


Add possibility to use previous versions of rest api

@yaggg thanks for submitting this! I think this is a good idea, but I wonder if this should instead be set on the instance (in the constructor, still final) instead of being mutable statically? What do you think? That way you could theoretically, if you wanted to, run multiple API versions within the same memory space.

@timols Sure, I strongly agree that final instance variable is much better than mutable static variable, do you think I should overload connect method for passing API version?

Yep, I think that makes sense.


Can't resolve Keyvault reference in App Config with managed identity

Describe the bug
Resolving a keyvault reference through App Config, with a VM managed identity does not work.
Command Name
az appconfig kv list
Errors:
'MSIAuthenticationWrapper' object has no attribute '_token_retriever'

To Reproduce:
Steps to reproduce the behavior.

Create a VM with a managed identity
Create a keyvault, and give VM access policy to get and list secrets
Create an App Config instance
Add a keyvault reference, say testsecret/keyvaultref
From the VM, run az appconfig kv list --name <appconfig_name> --key 'testsecret/*' --resolve-keyvault

Expected Behavior
The value should be resolved from the keyvault.
Environment Summary
Linux-5.4.0-1031-azure-x86_64-with-debian-buster-sid
Python 3.6.10
Installer: DEB

azure-cli 2.14.0

Additional Context
Stacktrace:
msrestazure.azure_active_directory : MSI: Token retrieved
azure.cli.core.util.handle_exception is called with an exception:
Traceback (most recent call last):
  File "/opt/az/lib/python3.6/site-packages/azure/cli/command_modules/appconfig/_kv_helpers.py", line 982, in __resolve_secret
    secret_version=kv_identifier.version)
  File "/opt/az/lib/python3.6/site-packages/azure/keyvault/v7_0/key_vault_client.py", line 1843, in get_secret
    response = self._client.send(request, header_parameters, stream=False, **operation_config)
  File "/opt/az/lib/python3.6/site-packages/msrest/service_client.py", line 336, in send
    pipeline_response = self.config.pipeline.run(request, **kwargs)
  File "/opt/az/lib/python3.6/site-packages/msrest/pipeline/__init__.py", line 197, in run
    return first_node.send(pipeline_request, **kwargs)  # type: ignore
  File "/opt/az/lib/python3.6/site-packages/msrest/pipeline/__init__.py", line 150, in send
    response = self.next.send(request, **kwargs)
  File "/opt/az/lib/python3.6/site-packages/msrest/pipeline/requests.py", line 72, in send
    return self.next.send(request, **kwargs)
  File "/opt/az/lib/python3.6/site-packages/msrest/pipeline/requests.py", line 137, in send
    return self.next.send(request, **kwargs)
  File "/opt/az/lib/python3.6/site-packages/msrest/pipeline/__init__.py", line 150, in send
    response = self.next.send(request, **kwargs)
  File "/opt/az/lib/python3.6/site-packages/msrest/pipeline/requests.py", line 193, in send
    self.driver.send(request.http_request, **kwargs)
  File "/opt/az/lib/python3.6/site-packages/msrest/universal_http/requests.py", line 333, in send
    return super(RequestsHTTPSender, self).send(request, **requests_kwargs)
  File "/opt/az/lib/python3.6/site-packages/msrest/universal_http/requests.py", line 142, in send
    **kwargs)
  File "/opt/az/lib/python3.6/site-packages/requests/sessions.py", line 533, in request
    resp = self.send(prep, **send_kwargs)
  File "/opt/az/lib/python3.6/site-packages/requests/sessions.py", line 653, in send
    r = dispatch_hook('response', hooks, r, **kwargs)
  File "/opt/az/lib/python3.6/site-packages/requests/hooks.py", line 31, in dispatch_hook
    _hook_data = hook(hook_data, **kwargs)
  File "/opt/az/lib/python3.6/site-packages/azure/keyvault/key_vault_authentication.py", line 146, in _handle_401
    security = self._get_message_security(prep, challenge)
  File "/opt/az/lib/python3.6/site-packages/azure/keyvault/key_vault_authentication.py", line 172, in _get_message_security
    scheme))
  File "/opt/az/lib/python3.6/site-packages/azure/keyvault/key_vault_authentication.py", line 61, in _auth_callback_compat
    if len(inspect.getargspec(self._user_callback).args) == 3 \
  File "/opt/az/lib/python3.6/site-packages/azure/cli/command_modules/appconfig/_kv_helpers.py", line 969, in _get_token
    return Profile(cli_ctx=cli_ctx).get_login_credentials(resource)[0]._token_retriever()  # pylint: disable=protected-access
AttributeError: 'MSIAuthenticationWrapper' object has no attribute '_token_retriever'

appconfig

Hi @nilsga ,
Thanks for reporting this issue. It is due to a bug in our implementation that blocks the MSI authentication flow to key vault. It currently only works when login with user account. Will send a fix.

The code from appconfig is calling _token_retriever:
https://github.com/Azure/azure-cli/blob/d528de32caf4ba37108571d751312cd44167b27a/src/azure-cli/azure/cli/command_modules/appconfig/_kv_helpers.py#L969
However, _token_retriever is only available for AdalAuthentication which is designed for user credentials. It is not available for managed identity credential MSIAuthenticationWrapper.
https://github.com/Azure/azure-cli/blob/748e1ff040c943697bc4c13aee95f61a8c652801/src/azure-cli-core/azure/cli/core/adal_authentication.py#L21-L24
Also, _token_retriever is a protected member, so calling it from outside is not supported.
There are 2 correct ways to get a raw token:

Call get_raw_token: https://github.com/Azure/azure-cli/blob/2bdd5f259f835fe3faa6974c07f5ba3c2353ff8b/src/azure-cli-core/azure/cli/core/_profile.py#L640
(The track 2 approach) Get the credential with get_login_credentials, then call get_token: https://github.com/Azure/azure-cli/blob/748e1ff040c943697bc4c13aee95f61a8c652801/src/azure-cli-core/azure/cli/core/adal_authentication.py#L68

If you only need to create a keyvault client, you may simply use the client factory from keyvault command module:
https://github.com/Azure/azure-cli/blob/1eed07797b9877fac1703555d25ead43b295376b/src/azure-cli/azure/cli/command_modules/keyvault/_client_factory.py#L128
It has been proved to work with both user credential and managed identity credential and has better error handling logic. + @bim-msft for awareness.

Fixed by https://github.com/Azure/azure-cli/pull/15826
Will take effect at our upcoming release train (Nov 17).


Any plan to make trace id and span id UUID?

Hi,
I'd like to see if there is any plan to make trace id and span id UUID
thanks
William

No, there are no concrete plans. When Zipkin was first designed at Twitter, 64 bits was a well thought-out id length, it's a balance between size and chance of collision.

just opened this as a constrained proposal to only address the trace id as 128bit https://github.com/openzipkin/zipkin/issues/1262


Use InMemory data storage on top of SqLite

Fixes issue #56
/cc @sebastienros

Thank you. Can you also add a test class like the Sqlite one?
Also, the change doesn't compile (see CI)

When you add the test class, also update the appveyor.yml file to opt in for this test. Look at the end of the file, this will be obvious.

There was a tiny issue before, I fix it and added the test too, nothing but the CI shows an error after adding the test
Any Idea?

I will test this locally, we might need to set the ReuseConnection argument to true, or the data is lost after each session.

Strange!! It was working with the same ConnestionString before, have a look to the old commit https://github.com/sebastienros/yessql/commit/1d643b1f89b60592e1e6e2852bd31dc0b46e688d

The new unit test class is failing.

I'm getting no such table: Identifiers any idea?!!

I just pushed the fixes that you need. I tried to create it myself and all tests pass.
You just have to rebase on master, then add your extension method and don't forget to pass true for sharedConnection. Then it will work.

Well done!! thanks @sebastienros

I update the PR to make sharedConnection as optional parameter


Bring back symbol!

In https://github.com/stellar/rs-soroban-sdk/pull/879 the symbol! macro was replaced with Symbol::short for short integer forms of symbols and Symbol::new for larger host stored symbols.
Even though Symbol::short is a const function, there's no guarantee it will be executed at compile time and for most uses by contract developers, and most uses in generated code, the function logic will be embedded in the resulting .wasm file and the conversion from string to integer will occur at runtime.
This is the reason we originally added symbol! in https://github.com/stellar/rs-soroban-sdk/pull/488. We had discovered that const functions in Rust are preferred to be executed at runtime unless they are called within a const context. The symbol! macro ensured that the conversion occurred in a const context. Because the function does conversion of the string, if it is included in the .wasm for each call, that's ~50-200 bytes of extra wasm per call.
The macro was that was removed in #879 was as below:
#[proc_macro]
pub fn symbol(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as LitStr);
    match Symbol::try_from_str(&input.value()) {
        Ok(_) => quote! {{
            const symbol: soroban_sdk::Symbol = soroban_sdk::Symbol::from_str(#input);
            symbol
        }}
        .into(),
        Err(e) => Error::new(input.span(), format!("{}", e))
            .to_compile_error()
            .into(),
    }
}

Given that Symbols can be short or long now, where the latter requires an Env, we need to rethink the macro rather than just copy and paste it back. Some ideas:

Add the macro back as it is, just for use with short symbols, and name it symbol_short!.
// 🟢
symbol_short!("SHORT");

// 🟢
Symbol::new(env, "LONGLONGLONG");

// 🔴 with friendly compiler error
symbol_short!("LONGLONGLONG");

// 🤷🏻
Symbol::new(env, "SHORT");

Add a new macro symbol! that optionally takes an Env and does a compile-time const conversion if the Symbol is short enough, otherwise it uses the Env. In the event someone calls symbol! with a value too long without an Env it is trivial to display a user-friendly compiler error saying the Env is required for symbols over a certain length.
// 🟢
symbol!("SHORT");

// 🟢
symbol!(env, "LONGLONGLONG");

// 🔴 with friendly compiler error
symbol!("LONGLONGLONG");

// 🤷🏻
symbol!(env, "SHORT");

I think (2) would be preferred as gives them one tool to use, and helps them use it the right way.
cc @graydon @dmkozh

Could we also have something similar for string? And what is the difference for devs between the two?


modifier is not tracked

I have a problem with modifier, sometimes it's updated with user sometime it's blank, all this can happen on the same record. I tried to add an after_save callback to history_tracker class to set the modifier manually form current_user but seems like it's not triggering this callback

Hi,
I have the same problem. I'm using the tracker in RoR engine with Mongoid::Userstamp.
I've tried
Mongoid::History.modifier_class_name = 'MyEngine::User'
but didn't help. User or Modifier is not passed in params when I check console. But updated_by_id is.
But this does work from console
user = MyEngine::User.first
page = MyEngine::Page.create(title: 'Test', user: user)

and then every update is tracked with the same modifier, even if it's updated by different user.
Any ideas?
Thanks!
J

This should be MyEngine::Page.create(title: 'Test', updated_by: user).

This is old, closing. Please reopen if you can reproduce.


[cluster-test] added instances_for_group api

Motivation
added instances_for_group api
Have you read the Contributing Guidelines on pull requests?
(Write your answer here.)
Test Plan
(Share your test plan here. If you changed code, please provide us with clear instructions for verifying that your changes work.)
Related PRs
(If this PR adds or changes functionality, please take some time to update the docs at https://github.com/libra/website, and link to your PR here.)

@bors-libra r=andll

:pushpin: Commit 0832e08 has been approved by andll

@bors-libra r=andll

:bulb: This pull request was already approved, no need to approve it again.

There's another pull request that is currently being tested, blocking this pull request: #5119

:pushpin: Commit 0832e08 has been approved by andll

:hourglass: Testing commit 0832e08bc5773f9aa24b9bb2d266a26b8912b77c with merge 4902c45d88becf15dea0961117bea99f8aaae90f...

:sunny: Test successful - checks-actions_land_blocking_test, checks-circle_commit_workflow
Approved by: andll
Pushing 4902c45d88becf15dea0961117bea99f8aaae90f to master...


EfficientNet loading slowly from SavedModel format

Please make sure that this is an issue related to performance of TensorFlow.
As per our
GitHub Policy,
we only address code/doc bugs, performance issues, feature requests and
build/installation issues on GitHub. tag:performance_template
System information

Have I written custom code (as opposed to using a stock example script provided in TensorFlow): No
OS Platform and Distribution (e.g., Linux Ubuntu 16.04): Linux Ubuntu 18.04.5 LTS (see colab notebook for details)
Mobile device (e.g. iPhone 8, Pixel 2, Samsung Galaxy) if the issue happens on mobile device: No
TensorFlow installed from (source or binary): binary
TensorFlow version (use command below):  v2.3.0-0-gb36436b087 2.3.0
Python version: 3.6.9
Bazel version (if compiling from source): -
GCC/Compiler version (if compiling from source): -
CUDA/cuDNN version: -
GPU model and memory: -

Describe the current behavior
When saving an instance of the EfficientNet to disk in SavedModel format and loading the same model again the loading routine takes (depending on the variation of EfficientNet) ~20 to ~120 seconds. As (please correct me if I am mistaken here) the SavedModel format is supposed to replace the frozen graphs in TensorFlow 2.0 I assume that this format is encouraged to deploy models for inference using a GPU and should be loadable quickly. It especially seems strange to me that loading the model takes orders of magnitude longer than building it from scratch. Please see the exact loading times for the EfficientNet architectures in this colab notebook.
As an alternative I had a look at the TensorFlow Lite format which, sadly, does not feature support for NVidia GPUs. My investigation on the loading times, however, show that EfficientNet models in TensorFlow Lite format are loaded much faster (<<< 1 second) than from SavedModel format. Please see this colab notebook for TFLite loading times.
I would appreciate any advice here as the loading times are essential in our use cases. Thank you!
Describe the expected behavior
The model is created at least comparably fast from SavedModel format as it takes to build it from scratch.
Standalone code to reproduce the issue
https://colab.research.google.com/gist/soyers/49c40641d97e91aa3191733f123ac799/efficientnetloadingtimessavedmodel.ipynb

@soyers,
I was able to reproduce the issue with TF v2.3. However with TF-nightly, the load time is reduced by half. Please check the attached gist for reference. Thanks!

Hi @amahendrakar,
thank you for your efforts! I am glad that the coming realease of TensorFlow will introduce significant improvements in this respect.
It still strikes me a bit that even in the nightly build the loading time from SavedModel is ~5x as long as building the model from scratch.
Maybe there are further improvements prossible, but I guess that's the way it is currently. Are there any for improvements for inference (maybe an option to export a frozen graph as SavedModel) such that low latency inference with GPUs is possible as it was in TF 1?
Thanks again for having a look and sharing your insights! I would be very grateful about an answer to the question above but apart from that please feel free to close this issue!

I was able to reproduce the issue with TF 2.8. Please check the attached gist for reference. Thanks!

@soyers,
I tried to reproduce the mentioned code on tf-nightly(2.13.0-dev20230301) and observed that when compared to previous executions, the time taken was comparatively better.

Version EfficientNet-B0 was built within 5.970604181289673 loaded within 12.36282753944397 seconds
Version EfficientNet-B1 was built within 2.764843702316284 loaded within 17.881444454193115 seconds
Version EfficientNet-B2 was built within 2.9328582286834717 loaded within 18.624332189559937 seconds
Version EfficientNet-B3 was built within 4.0417070388793945 loaded within 19.903307676315308 seconds
Version EfficientNet-B4 was built within 5.190731525421143 loaded within 25.772964000701904 seconds
Version EfficientNet-B5 was built within 4.886446714401245 loaded within 30.365610122680664 seconds
Version EfficientNet-B6 was built within 7.293424129486084 loaded within 35.94611573219299 seconds
Version EfficientNet-B7 was built within 8.17107605934143 loaded within 43.748724699020386 seconds

Kindly find the gist of it here and also EfficientNet model was the heavy model where the load time might be more compare to other models and also the time interval might be depends on the GPU which we are trying to execute. Thank you!

@soyers,
Closing this as stale. Please reopen if this is still a valid request. Thank you!


Instructions in README not working

The demo in this repo works because it's nested in this repo and as a result, the reference to ..index here resolves. But when you step through the README, it fails with the following error:
❯ marp -s -c marp.config.js

[ ERROR ] Failed converting Markdown. (Cannot find module '../index'

What should it say instead of ../index?

Nvm. The following did the trick:
    engine: ({ marp }) => marp.use(require('@kazumatu981/markdown-it-kroki'), {


new technique requests

@tgbugs : we would like to add the following instances. Would you agree?
(some of them might only not exist in our list, but you have them already)
"NEW" TECHNIQUES SUGGESTIONS:

calcium imaging
fiber photometry
pupillometry
electrooculography
video-oculography
eye-attached tracking
ultrasound imaging
virus transfection OR virus-mediated transfection
neuronal tracing
retrograde tracing
voltammetry
cryopreservation
cryofixation
manual sectioning (if tissue was cutted by hand with a knife to smaller pieces)

Note: 4. electrooculography already exists as a controlledTerm/technique
Continuation of @lzehl's list:

3D computer graphic modeling
3D scanning
beta-galactosidase staining
connectivity based parcellation technique
drifting grating visual stimulation
electromyography
figure-ground visual stimulation
headpost implantation surgery
high-speed video recording
immunoprecipitation
implant surgery
injection
intracranial electroencephalography
mass spectrometry
morphometry
multi-compartement modeling
natural image visual stimulation
natural sound stimulation
non-rigid motion correction
perfusion fixation technique
perturbational complexity index analysis
photon stimulation technique
pressure (micro) injection
rule-based modeling
scattered light imaging
seed-based correlation analysis
sonography
static grating visual stimulation
stimulation
structural covariance analysis
tetrode extracellular electrophysiology
video tracking
voxel-based morphometry

Some additional ones that may be up for discussion:

(ligand) binding affinity measurement
communication profiling
dye filling
light extinction measurement
nonlinear image registration

@tgbugs Any comments? ;)

A bunch of these are already in the ontology, will need to do a more thorough check (this format is not easy to review).

I'll close this issue for now. We have added (I think) all of them for now (https://github.com/HumanBrainProject/openMINDS_controlledTerms/pull/48) but can be changed later on if necessary.


Fix issue #2810

修复在不符合可处理的JSON格式时未做处理导致校验结果错误的问题。

 Thank you for your submission, we really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.You have signed the CLA already but the status is still pending? Let us recheck it.

 Thank you for your submission, we really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.You have signed the CLA already but the status is still pending? Let us recheck it.


Android Kotlin Gradle plugin compatibility with other libraries

Bug description:

Hello,
When building for production, I'm getting the following warning/error:
The Kotlin Gradle plugin was loaded multiple times in different subprojects, which is not supported and may break the build.
This might happen in subprojects that apply the Kotlin plugins with the Gradle 'plugins { ... }' DSL if they specify explicit versions, even if the versions are equal.
Please add the Kotlin plugin to the common parent project or the root project, then remove the versions in the subprojects.
If the parent project does not need the plugin, add 'apply false' to the plugin line.
See: https://docs.gradle.org/current/userguide/plugins.html#sec:subprojects_plugins_dsl
The Kotlin plugin was loaded in the following projects: ':react-native-mlkit-ocr', ':react-native-webview'

I also have the following in build.gradle in order for both libraries to use the same version:
kotlinVersion="1.4.32"

Related library: https://github.com/agoldis/react-native-mlkit-ocr/issues/5
Environment:

OS: Android
OS version: Any
react-native version: 0.62.2
react-native-webview version: 11.4.0

Hello,
I have the same problem with another library and react native webview:
The Kotlin plugin was loaded in the following projects: ':react-native-ios-context-menu', ':react-native-webview'
what is the problem? what we can do?

Same problem here


Disk size selector is empty for custom disk offerings

Steps to reproduce:

Go to Storage
Click on new volume creation button
Choose a custom disk offering in a selector

Expected result: Minimum value is selected by default
Actual result: empty field
Connected feature ID: storage_disk_create

Tested on Master


add sprint 3 features

add export data package and validate table
rearrange /backlog
delete /sprint directories as almost done

all acceptance tests for first 5 sprints done


⚠ ClamAV has degraded performance

In 21ee791, ClamAV (https://spamassassin.apache.org/) experienced degraded performance:

HTTP code: 200
Response time: 179 ms

Resolved: ClamAV performance has improved in a41d6f2.


Chore: Next.js Starter files Bootstrapped

A screenshot of the project up and running will be appreciated next time. Kindly check the contributing guide. Thanks @mrolaleyeisrael

Well done

Alright.


恕我直言，多类型实体类实现过于复杂！虽然item多样式，但后台返回外层json类型是一个，不可能根据你item的不同拆分bean的不同，不如MultiAdapter库。

What kind of issue is this?

[ ] Question. This issue tracker is not the place for questions. If you want to ask how to do
something, or to understand why something isn't working the way you expect it to, use Stack
Overflow. https://stackoverflow.com/questions/tagged/MultiType

[ ] Bug report. If you’ve found a bug, spend the time to write a failing test. Please provide
      your device name, device OS version, and describe the reproduction steps.

[ ] Feature Request. Start by telling us what problem you’re trying to solve. Often a solution
already exists! Don’t send pull requests to implement new features without first getting our
support. Sometimes we leave features out on purpose to keep the project small.

Info:

MultiType version:
Device OS version:
Device Name:

Description:
Reproduction Steps:
My thoughts:
What did I do:

@censhengde 恕我直言.....您应该好好看看人家库的文档...你说的这情况不就是oneToMany的方式处理不就完了么...你不想拆分你的bean那就按你实现的去做type区分呗

楼上说的对，使用一个Bean 内部使用type去区分，典型的就是聊天记录展示，这点我觉得你可能没理解到@censhengde


fix editor colors

@AntoineKM
Changed the colors a little bit so that they look good in both dark and white backgrounds.

Hi @shivamhwp,
Thanks for your pull request! We will review it today!
In the meantime if you can give us a star it would be cool ahah
Have a nice day, we'll be back to you soon!

where can I find the onThemeChange code, I'm trying to make two files for the themes but am unable to find the place where the theme code is written. Please help me with this.

@AntoineKM @jerembdn @YounesBessa
Please merge the request.

@AntoineKM @jerembdn @YounesBessa Please merge the request.

we're just waiting for @AntoineKM, it would be merged in some hours.

@AntoineKM @jerembdn @YounesBessa Please merge the request.

we're just waiting for @AntoineKM, it will be merged in a few hours.

thank you very much.
it's my first open-source contribution.

@AntoineKM @jerembdn @YounesBessa Please merge the request.

we're just waiting for @AntoineKM, it will be merged in a few hours.

thank you very much. it's my first open-source contribution.

you did good ! we really appreciate !
if you want to follow closer the advancement of the project, you can join your discord server, all links are on the readme.
thanks :D


Working examples would be useful

I like your package, but it would be better if you could provide a complete working example that shows how to create the form with several fields, submit it and collect the data.   Right now I'm trying to figure out the values for $formType and $mappedEntity in the $formBuilder->create($formType, $mappedEntity) call.
Also, examples of how to use it with Twig would be helpful.
I can figure out the details eventually, but having clear working examples will make people more likely to start using your package.  The webmozart/standalone-forms package has a good working form example that you might be able to adapt.

Hello, thanks for feedback!
Thought examples in readme file was enough. Will update them.
As for your question
$formType is any symfony form entity. For example Form Classes
$mappedEntity is optional parameter. Its just your class which you want to populate with form data. As described [here]http://symfony.com/doc/current/forms.html#creating-a-simple-form
Ill try to add docs with twig integration bit later.
Hope everything will work for you.
Good luck!

The example in the README.md serves its purpose. @lfjeff If you want to read more about how to build forms and retrieve the data, you should check out the Symfony Form documentation: https://symfony.com/doc/current/forms.html
@lostedboy Nice job, works great for me. Maybe you should add a link to the official documentation for the forms package, but I do not think that more examples are necessary.

Nevermind, links are already in the README. I'm just blind.


Account deletion should cancel stripe subscription + delete customer io user

Describe the bug
When people delete their account, it doesn't delete their info from all places. Only from internal db's. It sometimes messes with certain behaviours and makes things hard.
Expected behavior
Should delete elsewhere

Did not cancel stripe sub, only deleted customer io user


let hdfs segment kill be a success when segment file does not exist

Why? sometimes we get into a corrupted hdfs state where things from hdfs got deleted but not from metadata store (happened on a dev cluster during some migration). Then we want to be able to fix the situation by doing a kill task over respective dataSource and interval, so that those entries get deleted from metadata store. currently kill task fails and we have to manually [selectively] clean the db.
so relaxing the behavior to print a warning in that situation instead of failing.

:+1:

:+1: after travis


Update demo notebook (habitat.utils.common import).

Motivation and Context
The Jupyter notebooks with Habitat API and Habitat Sim demos raise an import error (line from habitat_sim.utils import d3_40_colors_rgb) as of 31 March 2020. Demo links (docs):

https://aihabitat.org/docs/habitat-api/habitat-api-demo.html
https://aihabitat.org/docs/habitat-api/habitat-sim-demo.html

It looks like this import was for an older API version and there were breaking changes since last demo update.
How Has This Been Tested
Tried out the notebooks locally, and there are no more import errors. Note that I only fixed it in docs, these pages have a link to download the Jupyter notebook, which hasn't been changed (I do not have access to it). Please reflect changes of this PR to update two files (so users download the corrected version):

https://dl.fbaipublicfiles.com/habitat/notebooks/habitat-sim-demo.ipynb
https://dl.fbaipublicfiles.com/habitat/notebooks/habitat-api-demo.ipynb

Types of changes

Docs change / refactoring / dependency upgrade
Bug fix (non-breaking change which fixes an issue)

Checklist

[x] My code follows the code style of this project.
[ ] My change requires a change to the documentation.
[x] I have updated the documentation accordingly.
[x] I have read the CONTRIBUTING document.
[x] I have completed my CLA (see CONTRIBUTING)
[ ] I have added tests to cover my changes.
[ ] All new and existing tests passed.

Thanks @kdexd!
@erikwijmans / @mathfac -- this is a good test-case. I know we decided to not keep the .ipynb files in github (because they don't render nicely), but this prevents open-source contributors from fixing things within them. Thoughts?

@mathfac -- FYI -- the .ipynb files still have the error in them.


Truncate sensor.rest to 255 characters. Parse JSON and store in attributes.

Description:
Truncates the state to 255 characters, to comply with https://github.com/home-assistant/home-assistant/pull/9696
Tries to automatically parse REST output as JSON, and if there are no parsing issues, stores all data inside attributes (even if the variable is templated).
Supporting documentation for this is a separate PR. I will reference it as soon as I get an ID.
Checklist:
If user exposed functionality or configuration variables are added/changed:

[ ] Documentation added/updated in home-assistant.github.io -- examples for clarity

If the code communicates with devices, web services, or third-party tools:

[ ] Local tests with tox run successfully. Your PR cannot be merged unless tests pass
[ ] New dependencies have been added to the REQUIREMENTS variable (example).
[ ] New dependencies are only imported inside functions that use them (example).
[ ] New dependencies have been added to requirements_all.txt by running script/gen_requirements_all.py.
[ ] New files were added to .coveragerc.

If the code does not interact with devices:

[ ] Local tests with tox run successfully. Your PR cannot be merged unless tests pass
[ ] Tests have been added to verify that the new code works.

Relevant documentation PR:https://github.com/home-assistant/home-assistant.github.io/pull/3941

I don't like this. First we modify data and last the json attributes can produce state change and fill database if they have changed value.
The correct solution is a note on documentation they help to trim this with templates function:
 | truncate(250)
Thanks for contribute. Would be nice if you can add this to documentation and help other with this problem.

The truth is this PR has two independent changes.
Regarding truncating data to 255 your suggestion could be fine. I only thought it would prevent the sensor from failing and leaving users in the blind. That commit can be omitted if this is desired.
Regarding parsing json as attributes: Normally I would say that is fine, but there are cases where you are not allowed to poll the same resource 7 times to extract 7 items from the same response. You could be limited by back-end technology (in my case I need to inject libraries in a running process to extract the data and doing it too often can cause crashes), or by API policy (x requests/day).
I do agree that probably saving attributes in the database will cause it to grow (maybe that's why my database grew by 330MB in 2 months!), but this could be addressed with a method do periodically expire data older than X days (user configurable).
Until now I've been doing it with a custom component, but other users seem to want this as well, so I figured pushing it to rest.py trying not to break previous functionality would be ok.
Would you be more open to having the parsed attributes merged in if I added a configuration option to explicitly parse the JSON and store it as attributes?
Thanks

There's definitely a place for this for rate-limited APIs.  I think this would be useful with some modifications.

instead of exposing all attributes in the response payload, take a list of particular JSONPath strings and expose those
have the state of the sensor return something like a response code rather than a partial string of the JSON data

I could really use something similar to the origin commit to avoid making multiple REST calls for each sensor value.

I tried making a PR for something that would allow saving JSON as a state and referencing it later but it was rejected
https://github.com/home-assistant/home-assistant/pull/10515

I'd like to have a discussion to see what is the best way to integrate this functionality into the standard HA components.
My approach was elegant (IMHO), but was rejected because it could potentially store a lot of fast changing attribute data which would cause the DB to grow. I've tested it with attributes larger than 255 characters and they were stored correctly. Accessing data from attributes should be easy in automations and elsewhere (template sensors), without the need to parse it again. The only limitation would be the fact that only JSON is parsed this way, so if you want to parse - for example - an XML output, this wouldn't help you (but I figure it could be added if needed with a try/catch statement).
So, my next proposal is to do the attribute parsing only on demand (use a configuration attribute to specify which sensor should be parsed - leave it to the user).
@cribbstechnologies's suggestion of parsing only relevant sections of data could be useful, but I'm not sure how exactly to model that in the configuration (I'm thinking of complex JSON data structures as input).
I'd like to clear it with the main developers on how this should be handled to submit a suitable PR.

For my use case, I have a REST call out to an API provided by my Solar panels.  It returns about 20 elements, 5 of which I want to use as sensors.  Given the rate limit of the API I would prefer to not make 5 calls every minute (instead of 1).  Providing a way to specify in the config a value template and and an attribute list (which I can then use template sensor on) would be perfect.

@tvfoodmaps can you show me an example query and reply JSON? I'd like to try to find a way to parse specific sections of it.

@mad-ady
Here is the JSON response:
{ "system_id": 585444, "modules": 38, "size_w": 9500, "current_power": 167, "energy_today": 740, "energy_lifetime": 38508985, "summary_date": "2017-11-15", "source": "microinverters", "status": "normal", "operational_at":<PHONE_NUMBER>, "last_report_at":<PHONE_NUMBER>, "last_interval_end_at":<PHONE_NUMBER> }

I modified the REST sensor to dynamically generate sensor entities based on configuration
https://github.com/cribbstechnologies/home-assistant/blob/62b6f9a49f28883dd8a299805aca506575f7e96c/homeassistant/components/sensor/rest.py
Example config:
sensor:
  - platform: rest
    resource: https://raw.githubusercontent.com/cribbstechnologies/ha_config/master/www/test_launch.json
    name: launch window
    sensors:
      sensor_1:
        json_path: 'launches[0].name'
        value_template: 'True'
      sensor_2:
        json_path: 'launches[0].vidURLs[0]'
        value_template: 'False'

I asked for feedback on the commit in the devs channel on discord but nobody responded. I still need to figure a way to have the parent sensor be able to whittle down the response JSON and then have the child sensors use that data rather than the full payload. I'll probably mess around with that today.


docs: add consumption budgets naming rules

Naming restrictions from the portal

Scope
budgets can be defined at the subscription or resource group scope
At subscription scope:

At resource group scope

References

Azure template reference: https://docs.microsoft.com/en-us/azure/templates/microsoft.consumption/budgets?tabs=json

@GlennChia : Thanks for your contribution! The author(s) have been notified to review your proposed change.

@GlennChia - thanks for adding this missing resource type.
#sign-off


Create: 209 Minimum Size Subarray Sum

File(s) Modified: 0209-minimum-size-subarray-sum.java
Language(s) Used: java
Submission URL: https://leetcode.com/problems/minimum-size-subarray-sum/submissions/937850242/

Thanks!


Is there any method like most.defer() and most.create()?

I did not find most.defer() and most.create() in the API docs.
I need to defer a function call until it is subscribed.
most.defer(() => {
  result = getResult();
  return most.of(result);
})

How do I do to achieve my goal?

create() is a separate package now, as it's a non-standard use case:
https://github.com/mostjs/create

Ok, thanks.
Is there a package like @most/defer? Or should I need to use most.create() to send a stream and then flatten()?

Hi @xareelee.  Can you help me understand the use case for a function like defer?  It seems that you'd like create a stream lazily.  All most streams are already lazy, so I'm just guessing that perhaps you'd like to use something like defer when initial construction of the stream is somehow expensive?
If that's the case, then it should be fairly simple to make your own.  There are several ways.  Here's one using continueWith.  You could do something similar, as you suggested with just and chain, or just, map and switchLatest.
import { empty, continueWith, just } from 'most'

// Let's make our own defer() function
const defer = f => continueWith(f, empty())

// Use it
defer(() => just(getResult()))

Hope that helps. If I haven't understood your question correctly, we'll probably need a bit more detail on what exactly you expect defer() to do.  Thanks!

Can you help me understand the use case for a function like defer?

// without `defer`
function foo(options) {
  // has side-effect or inner dependency; would be triggered before the returned stream is subscribed
  const settings = setup_settings(options);
  return most.of(settings);
}

// with `defer`
// we could wrap the whole implementation in the `defer`
function foo(options) {
  // defer the execution until subscribed
  return defer(() => {
    // only be triggered when the this stream is subscribed.
    const settings = setup_settings(options);
    return most.of(settings);
  });
}

Using defer to keep the impure function to be called only when it is subscribed. It's important if the timing matters.

import { empty, continueWith, just } from 'most'

// Let's make our own defer() function
const defer = f => continueWith(f, empty())

// Use it
defer(() => just(getResult()))

I did not try this, but it seems OK if the function f passed to the continueWith() only be called when subscribed. Thanks for your help.

if the function f passed to the continueWith() only be called when subscribed

Yep, that's correct.  Closing since I believe this answers the original question.
Cheers!


Add customizable sorting for sidepanel view

From #22
We should let the user customize the sort order for the targets in the sidepanel view.

Merged, so closing.


Fix #192 ExpressReceiver support for rawBody for signature verification

Summary
This pull request fixes issue #192 which prevents Bolt running on Google Cloud Platform.
I've extracted verifySlackRequest method from ExpressReceiver as ExpressSignatureVerifier and modified it a litle. Also, I changed the body parser parseBody in ExpressReceiver to handle rawBody. I'll add line comments to explain the intention further.
I haven't added unit tests for this change yet but I made sure the change works on real GCP environment. ~My example app on GCP managed to respond to url_verification requests.~
UPDATE: My example app on GCP responded to url_verification requests and handled events as I expect.
~Separately from that, it seems that we still have another issue after the body parsing step. My app on  GCP didn't work for event subscription (probably other requests, too) due to ack timeout errors. I've not figured out the root cause yet, but it seems to be hanging here.~
^ UPDATE: Never mind. It was just my personal projects' quota issue...
Requirements (place an x in each [ ])

[x] I've read and understood the Contributing Guidelines and have done my best effort to follow them.
[x] I've read and agree to the Code of Conduct.

This pull request is now ready to be reviewed. I avoided doing force-push and pushed several commits. Please squash them into one when merging it.

@seratch This is really thorough and impressive. I have some comments and questions regarding the design, so I left them in this review. I did not look too closely at the tests because I think you might agree with some of the feedback, and those tests might chance along with the design. Happy to hear your thoughts.

@aoberoi Thank you very much for your generous review. I've updated the PR again.
Update summary:

I merged verifySlackRequest and parseBody into unified RequestHandler named verifySignatureAndParseBody. One thing I should notice you is that I exported the function because I wanted to have tests for it. If you have suggestions or alternatives, please let me know.
I added logger as an optional arg to ExpressReceiverOptions and ExpressReceiver's constructor args + use it to output warnings/errors
The function verifyRequestSignature is not ready to be extracted as a separate module but it's not exposed to external. Therefore, we can freely change the interface when extracting it as a reusable module.

This looks so good! Thanks especially for designing a testing solution for Express-related concerns, that looked tricky.