def smooth_savitzky_golay_ipy(obj, **kwargs): wdict = {} window_length = OddIntSlider(value=3, step=2, min=3, max=max(int(obj.axis.size * 0.25), 3)) polynomial_order = ipywidgets.IntSlider(value=3, min=1, max=window_length.value - 1) # Polynomial order must be less than window length def update_bound(change): polynomial_order.max = change.new - 1 window_length.observe(update_bound, "value") differential_order = ipywidgets.IntSlider(value=0, min=0, max=10) color = ipywidgets.ColorPicker() close = ipywidgets.Button( description="Close", tooltip= "Close widget and remove the smoothed line from the signal figure.") apply = ipywidgets.Button( description="Apply", tooltip="Perform the operation using the selected range.") link((obj, "polynomial_order"), (polynomial_order, "value")) link((obj, "window_length"), (window_length, "value")) link((obj, "differential_order"), (differential_order, "value")) # Differential order must be less or equal to polynomial_order link((polynomial_order, "value"), (differential_order, "max")) link((obj, "line_color_ipy"), (color, "value")) box = ipywidgets.VBox([ labelme("Window length", window_length), labelme("polynomial order", polynomial_order), labelme("Differential order", differential_order), labelme("Color", color), ipywidgets.HBox((apply, close)) ]) wdict["window_length"] = window_length wdict["polynomial_order"] = polynomial_order wdict["differential_order"] = differential_order wdict["color"] = color wdict["close_button"] = close wdict["apply_button"] = apply def on_apply_clicked(b): obj.apply() apply.on_click(on_apply_clicked) def on_close_clicked(b): obj.close() box.close() close.on_click(on_close_clicked) return { "widget": box, "wdict": wdict, }
def point1d_roi_ipy(obj, **kwargs): wdict = {} value = ipywidgets.FloatText(description="value") wdict["value"] = value link((obj, "value"), (value, "value")) return { "widget": value, "wdict": wdict, }
def image_constast_editor_ipy(obj, **kwargs): wdict = {} left = ipywidgets.FloatText(disabled=True) right = ipywidgets.FloatText(disabled=True) help = ipywidgets.HTML( "Click on the histogram figure and drag to the right to select a" "range. Press `Apply` to set the new contrast limits, `Reset` to reset " "them or `Close` to cancel.", ) wdict["help"] = help help = ipywidgets.Accordion(children=[help]) help.set_title(0, "Help") close = ipywidgets.Button( description="Close", tooltip="Close widget and remove span selector from the signal figure." ) apply = ipywidgets.Button( description="Apply", tooltip="Perform the operation using the selected range.") reset = ipywidgets.Button( description="Reset", tooltip="Reset the contrast to the previous value.") wdict["left"] = left wdict["right"] = right wdict["close_button"] = close wdict["apply_button"] = apply wdict["reset_button"] = reset # Connect link((obj, "ss_left_value"), (left, "value")) link((obj, "ss_right_value"), (right, "value")) def on_apply_clicked(b): obj.apply() apply.on_click(on_apply_clicked) def on_reset_clicked(b): obj.reset() reset.on_click(on_reset_clicked) box = ipywidgets.VBox([ labelme("vmin", left), labelme("vmax", right), help, ipywidgets.HBox((apply, reset, close)) ]) def on_close_clicked(b): obj.close() box.close() close.on_click(on_close_clicked) return { "widget": box, "wdict": wdict, }
def test_no_traits(self, A=_A): a = A() class B: value = 3 b = B() with pytest.raises(ValueError): l = link((a, "value"), (b, "value")) with pytest.raises(ValueError): l = link((b, "value"), (a, "value"))
def get_scalable_fixed_patter_widget(obj, **kwargs): cdict = get_component_widget(obj, display=False) wdict = cdict["wdict"] container = cdict["widget"] interpolate = Checkbox(description='interpolate', value=obj.interpolate) wdict["interpolate"] = interpolate link((obj, "interpolate"), (interpolate, "value")) container.children = (container.children[0], interpolate) + \ container.children[1:] return { "widget": container, "wdict": wdict, }
def point_2d_ipy(obj, **kwargs): wdict = {} x = ipywidgets.FloatText(description="x") y = ipywidgets.FloatText(description="y") wdict["x"] = x wdict["y"] = y link((obj, "x"), (x, "value")) link((obj, "y"), (y, "value")) container = ipywidgets.HBox([x, y]) return { "widget": container, "wdict": wdict, }
def span_roi_ipy(obj, **kwargs): wdict = {} left = ipywidgets.FloatText(description="Left") right = ipywidgets.FloatText(description="Right") link((obj, "left"), (left, "value")) link((obj, "right"), (right, "value")) wdict["left"] = left wdict["right"] = right container = ipywidgets.HBox([left, right]) return { "widget": container, "wdict": wdict, }
def fit_component_ipy(obj, **kwargs): wdict = {} only_current = Checkbox() iterpath = enum2dropdown(obj.traits()["iterpath"]) def disable_iterpath(change): iterpath.disabled = change.new only_current.observe(disable_iterpath, "value") wdict["only_current"] = only_current wdict["iterpath"] = iterpath help_text = HTML( "Click on the signal figure and drag to the right to select a" "range. Press `Fit` to fit the component in that range. If only " "current is unchecked the fit is performed in the whole dataset.", layout=ipywidgets.Layout(width="auto")) wdict["help_text"] = help_text help = Accordion(children=[help_text], selected_index=None) set_title_container(help, ["Help"]) link((obj, "only_current"), (only_current, "value")) link((obj, "iterpath"), (iterpath, "value")) fit = Button(description="Fit", tooltip="Fit in the selected signal range") close = Button( description="Close", tooltip="Close widget and remove span selector from the signal figure." ) wdict["close_button"] = close wdict["fit_button"] = fit def on_fit_clicked(b): obj._fit_fired() fit.on_click(on_fit_clicked) box = VBox([ labelme("Only current", only_current), labelme("Iterpath", wdict["iterpath"]), help, HBox((fit, close)) ]) def on_close_clicked(b): obj.span_selector_switch(False) box.close() close.on_click(on_close_clicked) return { "widget": box, "wdict": wdict, }
def test_callbacks(self, A, B): """Verify two linked traitlets have their callbacks called once.""" a = A(value=9) b = B(count=8) # Register callbacks that count. callback_count = [] def a_callback(name, old, new): callback_count.append('a') a.on_trait_change(a_callback, 'value') def b_callback(name, old, new): callback_count.append('b') b.on_trait_change(b_callback, 'count') # Connect the two classes. c = link((a, 'value'), (b, 'count')) # Make sure b's count was set to a's value once. assert ''.join(callback_count) == 'b' del callback_count[:] # Make sure a's value was set to b's count once. b.count = 5 assert ''.join(callback_count) == 'ba' del callback_count[:] # Make sure b's count was set to a's value once. a.value = 4 assert ''.join(callback_count) == 'ab' del callback_count[:]
def test_link_broken_at_target(self, A, B): a = A() b = A() dl = dlink((a, "value"), (b, "value"), transform=lambda x: x**2) l = link((a, "value"), (b, "value")) with pytest.raises(t.TraitError): b.value = 2
def _set_microscope_parameters(obj, **kwargs): traits = obj.traits() widgets = [] wdict = {} for trait_name in obj.editable_traits(): if trait_name in ("mapping", "signal"): continue trait = traits[trait_name] widget = float2floattext(trait, get_label(trait, trait_name)) widgets.append(widget) wdict[trait_name] = widget.children[1] link((obj, trait_name), (widget.children[1], "value")) store_button = ipywidgets.Button(description="Store", tooltip="Store the values in metadata") store_button.on_click(obj.store) wdict["store_button"] = store_button container = ipywidgets.VBox([ipywidgets.VBox(widgets), store_button]) return {"widget": container, "wdict": wdict}
def get_component_widget(obj, **kwargs): """Creates interactive notebook widgets for all component parameters, if available. """ wdict = {} active = Checkbox(description='active', value=obj.active) wdict["active"] = active link((obj, "active"), (active, "value")) container = VBox([active]) for parameter in obj.parameters: pardict = parameter.gui(toolkit="ipywidgets", display=False)["ipywidgets"] wdict["parameter_{}".format(parameter.name)] = pardict["wdict"] container.children += pardict["widget"], return { "widget": container, "wdict": wdict, }
def get_eelscl_widget(obj, **kwargs): """Create ipywidgets for the EELSCLEDge component. """ wdict = {} active = Checkbox(description='active', value=obj.active) fine_structure = Checkbox(description='Fine structure', value=obj.fine_structure_active) fs_smoothing = FloatSlider(description='Fine structure smoothing', min=0, max=1, step=0.001, value=obj.fine_structure_smoothing) link((obj, "active"), (active, "value")) link((obj, "fine_structure_active"), (fine_structure, "value")) link((obj, "fine_structure_smoothing"), (fs_smoothing, "value")) container = VBox([active, fine_structure, fs_smoothing]) wdict["active"] = active wdict["fine_structure"] = fine_structure wdict["fs_smoothing"] = fs_smoothing for parameter in [obj.intensity, obj.effective_angle, obj.onset_energy]: pdict = parameter.gui(toolkit="ipywidgets", display=False)["ipywidgets"] container.children += pdict["widget"], wdict["parameter_{}".format(parameter.name)] = pdict["wdict"] return { "widget": container, "wdict": wdict, }
def show_preferences_widget(obj, **kwargs): ipytabs = {} wdict = {} for tab in obj.editable_traits(): tabdict = {} wdict["tab_{}".format(tab)] = tabdict ipytab = [] tabtraits = getattr(obj, tab).traits() for trait_name in getattr(obj, tab).editable_traits(): trait = tabtraits[trait_name] widget = TRAITS2IPYWIDGETS[type(trait.trait_type)](trait, get_label( trait, trait_name)) ipytab.append(widget) tabdict[trait_name] = widget.children[1] link((getattr(obj, tab), trait_name), (widget.children[1], "value")) ipytabs[tab] = ipywidgets.VBox(ipytab) titles = ["General", "GUIs", "EELS", "EDS"] ipytabs_ = ipywidgets.Tab( children=[ipytabs[title.replace(" ", "")] for title in titles], titles=titles) for i, title in enumerate(titles): ipytabs_.set_title(i, title) save_button = ipywidgets.Button(description="Save", tooltip="Make changes permanent") wdict["save_button"] = save_button def on_button_clicked(b): obj.save() save_button.on_click(on_button_clicked) container = ipywidgets.VBox([ipytabs_, save_button]) return { "widget": container, "wdict": wdict, }
def fit_component_ipy(obj, **kwargs): wdict = {} only_current = Checkbox() wdict["only_current"] = only_current help = HTML( "Click on the signal figure and drag to the right to select a" "range. Press `Fit` to fit the component in that range. If only " "current is unchecked the fit is performed in the whole dataset.", layout=ipywidgets.Layout(width="auto")) wdict["help"] = only_current help = Accordion(children=[help]) help.set_title(0, "Help") link((obj, "only_current"), (only_current, "value")) fit = Button(description="Fit", tooltip="Fit in the selected signal range") close = Button( description="Close", tooltip="Close widget and remove span selector from the signal figure." ) wdict["close_button"] = close wdict["fit_button"] = fit def on_fit_clicked(b): obj._fit_fired() fit.on_click(on_fit_clicked) box = VBox( [labelme("Only current", only_current), help, HBox((fit, close))]) def on_close_clicked(b): obj.span_selector_switch(False) box.close() close.on_click(on_close_clicked) return { "widget": box, "wdict": wdict, }
def line2d_roi_ipy(obj, **kwargs): wdict = {} x1 = ipywidgets.FloatText(description="x1") y1 = ipywidgets.FloatText(description="x2") link((obj, "x1"), (x1, "value")) link((obj, "y1"), (y1, "value")) container1 = ipywidgets.HBox([x1, y1]) x2 = ipywidgets.FloatText(description="x2") y2 = ipywidgets.FloatText(description="y2") link((obj, "x2"), (x2, "value")) link((obj, "y2"), (y2, "value")) container2 = ipywidgets.HBox([x2, y2]) linewidth = ipywidgets.FloatText(description="linewidth") link((obj, "linewidth"), (linewidth, "value")) container = ipywidgets.VBox([container1, container2, linewidth]) wdict["x1"] = x1 wdict["x2"] = x2 wdict["y1"] = y1 wdict["y2"] = y2 wdict["linewidth"] = linewidth return { "widget": container, "wdict": wdict, }
def interactive_range_ipy(obj, **kwargs): # Define widgets wdict = {} axis = obj.axis left = ipywidgets.FloatText(disabled=True) right = ipywidgets.FloatText(disabled=True) units = ipywidgets.Label() help_text = ipywidgets.HTML( "Click on the signal figure and drag to the right to select a signal " "range. Press `Apply` to perform the operation or `Close` to cancel.", ) help = ipywidgets.Accordion(children=[help_text], selected_index=None) set_title_container(help, ["Help"]) close = ipywidgets.Button( description="Close", tooltip="Close widget and remove span selector from the signal figure." ) apply = ipywidgets.Button( description="Apply", tooltip="Perform the operation using the selected range.") wdict["left"] = left wdict["right"] = right wdict["units"] = units wdict["help_text"] = help_text wdict["close_button"] = close wdict["apply_button"] = apply # Connect link((obj, "ss_left_value"), (left, "value")) link((obj, "ss_right_value"), (right, "value")) link((axis, "units"), (units, "value")) def on_apply_clicked(b): if obj.ss_left_value != obj.ss_right_value: obj.span_selector_switch(False) for method, cls in obj.on_close: method(cls, obj.ss_left_value, obj.ss_right_value) obj.span_selector_switch(True) apply.on_click(on_apply_clicked) box = ipywidgets.VBox([ ipywidgets.HBox([left, units, ipywidgets.Label("-"), right, units]), help, ipywidgets.HBox((apply, close)) ]) def on_close_clicked(b): obj.span_selector_switch(False) box.close() close.on_click(on_close_clicked) return { "widget": box, "wdict": wdict, }
def test_connect_same(self, A, B): """Verify two traitlets of the same type can be linked together using link.""" a = A(value=9) b = B(value=8) # Conenct the two classes. c = link((a, 'value'), (b, 'value')) # Make sure the values are the same at the point of linking. assert a.value == b.value # Change one of the values to make sure they stay in sync. a.value = 5 assert a.value == b.value b.value = 6 assert a.value == b.value
def test_connect_same_trait_target_undefined_source_trait( self, A=_A, B=_A): """Verify two traitlets of the same type can be linked together using link.""" a = A(value=9) b = B() # b.value is Undefined # Conenct the two classes. c = link((a, 'value'), (b, 'value')) assert b.value == 9 # Change one of the values to make sure they stay in sync. a.value = 5 assert a.value == b.value b.value = 6 assert a.value == b.value del b.value # Reset trait (to Undefined in this case) assert a.value is t.Undefined
def test_link_different(self, A, B): """Verify two traitlets of different types can be linked together using link.""" a = A(value=9) b = B(count=8) # Conenct the two classes. c = link((a, 'value'), (b, 'count')) # Make sure the values are the same at the point of linking. assert a.value == b.count # Change one of the values to make sure they stay in sync. a.value = 5 assert a.value == b.count b.count = 4 assert a.value == b.count
def test_unlink_link(self, A, B): """Verify two linked traitlets can be unlinked.""" a = A(value=9) b = B(value=8) # Connect the two classes. c = link((a, 'value'), (b, 'value')) a.value = 4 c.unlink() # Change one of the values to make sure they don't stay in sync. a.value = 5 assert a.value != b.value c.link() a.value = b.value a.value += 1 a.value = b.value
def rectangular_roi_ipy(obj, **kwargs): wdict = {} left = ipywidgets.FloatText(description="left") right = ipywidgets.FloatText(description="right") link((obj, "left"), (left, "value")) link((obj, "right"), (right, "value")) container1 = ipywidgets.HBox([left, right]) top = ipywidgets.FloatText(description="top") bottom = ipywidgets.FloatText(description="bottom") link((obj, "top"), (top, "value")) link((obj, "bottom"), (bottom, "value")) container2 = ipywidgets.HBox([top, bottom]) container = ipywidgets.VBox([container1, container2]) wdict["left"] = left wdict["right"] = right wdict["top"] = top wdict["bottom"] = bottom return { "widget": container, "wdict": wdict, }
def circle_roi_ipy(obj, **kwargs): wdict = {} x = ipywidgets.FloatText(description="x") y = ipywidgets.FloatText(description="y") link((obj, "cx"), (x, "value")) link((obj, "cy"), (y, "value")) container1 = ipywidgets.HBox([x, y]) radius = ipywidgets.FloatText(description="radius") inner_radius = ipywidgets.FloatText(description="inner_radius") link((obj, "r"), (radius, "value")) link((obj, "r_inner"), (inner_radius, "value")) container2 = ipywidgets.HBox([radius, inner_radius]) container = ipywidgets.VBox([container1, container2]) wdict["cx"] = x wdict["cy"] = y wdict["radius"] = radius wdict["inner_radius"] = inner_radius return { "widget": container, "wdict": wdict, }
def test_tranform(self, A, B): """Test transform link.""" # Create two simple classes with Int traitlets. a = A(value=9) b = B(value=8) # Conenct the two classes. c = link((a, 'value'), (b, 'value'), transform=(lambda x: 2 * x, lambda x: int(x / 2.))) # Make sure the values are correct at the point of linking. b.value = 2 * a.value # Change one the value of the source and check that it modifies the target. a.value = 5 b.value = 10 # Change one the value of the target and check that it modifies the # source. b.value = 6 a.value = 3
def test_connect_same_trait_source_undefined(self, A=_A, B=_B): """Verify two traitlets of the same type can be linked together using link.""" a = A() # a.value is Undefined b = B(value=8) # Conenct the two classes. c = link((a, 'value'), (b, 'value')) # Linking doesn't change b.value because a.value is undefined assert b.value == 8 # Change one of the values to make sure they stay in sync. a.value = 5 assert a.value == b.value b.value = 6 assert a.value == b.value del a.value # Reset trait (to Undefined in this case) if has_traitlets(b): # linking sets b.value to 0 if it has traitlets assert b.value == 0 else: assert b.value is t.Undefined
def smooth_butterworth(obj, **kwargs): wdict = {} cutoff = ipywidgets.FloatSlider(min=0.01, max=1.) order = ipywidgets.IntText() type_ = ipywidgets.Dropdown(options=("low", "high")) color = ipywidgets.ColorPicker() close = ipywidgets.Button( description="Close", tooltip= "Close widget and remove the smoothed line from the signal figure.") apply = ipywidgets.Button( description="Apply", tooltip="Perform the operation using the selected range.") link((obj, "cutoff_frequency_ratio"), (cutoff, "value")) link((obj, "type"), (type_, "value")) link((obj, "order"), (order, "value")) wdict["cutoff"] = cutoff wdict["order"] = order wdict["type"] = type_ wdict["color"] = color wdict["close_button"] = close wdict["apply_button"] = apply box = ipywidgets.VBox([ labelme("Cutoff frequency ration", cutoff), labelme("Type", type_), labelme("Order", order), ipywidgets.HBox((apply, close)) ]) def on_apply_clicked(b): obj.apply() apply.on_click(on_apply_clicked) def on_close_clicked(b): obj.close() box.close() close.on_click(on_close_clicked) return { "widget": box, "wdict": wdict, }
def smooth_tv_ipy(obj, **kwargs): wdict = {} smoothing_parameter = ipywidgets.FloatSlider(min=0.1, max=1000) smoothing_parameter_max = ipywidgets.FloatText( value=smoothing_parameter.max) color = ipywidgets.ColorPicker() close = ipywidgets.Button( description="Close", tooltip= "Close widget and remove the smoothed line from the signal figure.") apply = ipywidgets.Button( description="Apply", tooltip="Perform the operation using the selected range.") link((obj, "smoothing_parameter"), (smoothing_parameter, "value")) link((smoothing_parameter_max, "value"), (smoothing_parameter, "max")) link((obj, "line_color_ipy"), (color, "value")) wdict["smoothing_parameter"] = smoothing_parameter wdict["smoothing_parameter_max"] = smoothing_parameter_max wdict["color"] = color wdict["close_button"] = close wdict["apply_button"] = apply box = ipywidgets.VBox([ labelme("Weight", smoothing_parameter), labelme("Weight max", smoothing_parameter_max), labelme("Color", color), ipywidgets.HBox((apply, close)) ]) def on_apply_clicked(b): obj.apply() apply.on_click(on_apply_clicked) def on_close_clicked(b): obj.close() box.close() close.on_click(on_close_clicked) return { "widget": box, "wdict": wdict, }
def smooth_lowess_ipy(obj, **kwargs): wdict = {} smoothing_parameter = ipywidgets.FloatSlider(min=0, max=1) number_of_iterations = ipywidgets.IntText() color = ipywidgets.ColorPicker() close = ipywidgets.Button( description="Close", tooltip= "Close widget and remove the smoothed line from the signal figure.") apply = ipywidgets.Button( description="Apply", tooltip="Perform the operation using the selected range.") link((obj, "smoothing_parameter"), (smoothing_parameter, "value")) link((obj, "number_of_iterations"), (number_of_iterations, "value")) link((obj, "line_color_ipy"), (color, "value")) box = ipywidgets.VBox([ labelme("Smoothing parameter", smoothing_parameter), labelme("Number of iterations", number_of_iterations), labelme("Color", color), ipywidgets.HBox((apply, close)) ]) wdict["smoothing_parameter"] = smoothing_parameter wdict["number_of_iterations"] = number_of_iterations wdict["color"] = color wdict["close_button"] = close wdict["apply_button"] = apply def on_apply_clicked(b): obj.apply() apply.on_click(on_apply_clicked) def on_close_clicked(b): obj.close() box.close() close.on_click(on_close_clicked) return { "widget": box, "wdict": wdict, }
def _get_axis_widgets(obj): widgets = [] wd = {} name = ipywidgets.Text() widgets.append(labelme(ipywidgets.Label("Name"), name)) link((obj, "name"), (name, "value")) wd["name"] = name size = ipywidgets.IntText(disabled=True) widgets.append(labelme("Size", size)) link((obj, "size"), (size, "value")) wd["size"] = size index_in_array = ipywidgets.IntText(disabled=True) widgets.append(labelme("Index in array", index_in_array)) link((obj, "index_in_array"), (index_in_array, "value")) wd["index_in_array"] = index_in_array if obj.navigate: index = ipywidgets.IntSlider(min=0, max=obj.size - 1) widgets.append(labelme("Index", index)) link((obj, "index"), (index, "value")) wd["index"] = index value = ipywidgets.FloatSlider( min=obj.low_value, max=obj.high_value, ) wd["value"] = value widgets.append(labelme("Value", value)) link((obj, "value"), (value, "value")) link((obj, "high_value"), (value, "max")) link((obj, "low_value"), (value, "min")) link((obj, "scale"), (value, "step")) units = ipywidgets.Text() widgets.append(labelme("Units", units)) link((obj, "units"), (units, "value")) wd["units"] = units scale = ipywidgets.FloatText() widgets.append(labelme("Scale", scale)) link((obj, "scale"), (scale, "value")) wd["scale"] = scale offset = ipywidgets.FloatText() widgets.append(labelme("Offset", offset)) link((obj, "offset"), (offset, "value")) wd["offset"] = offset return {"widget": ipywidgets.VBox(widgets), "wdict": wd}
def ipy_navigation_sliders(obj, **kwargs): continuous_update = ipywidgets.Checkbox(True, description="Continous update") wdict = {} wdict["continuous_update"] = continuous_update widgets = [] for i, axis in enumerate(obj): axis_dict = {} wdict["axis{}".format(i)] = axis_dict iwidget = ipywidgets.IntSlider(min=0, max=axis.size - 1, readout=True, description="index") link((continuous_update, "value"), (iwidget, "continuous_update")) link((axis, "index"), (iwidget, "value")) vwidget = ipywidgets.BoundedFloatText(min=axis.low_value, max=axis.high_value, step=axis.scale, description="value" # readout_format=".lf" ) link((continuous_update, "value"), (vwidget, "continuous_update")) link((axis, "value"), (vwidget, "value")) link((axis, "high_value"), (vwidget, "max")) link((axis, "low_value"), (vwidget, "min")) link((axis, "scale"), (vwidget, "step")) name = ipywidgets.Label(str(axis), layout=ipywidgets.Layout(width="15%")) units = ipywidgets.Label(layout=ipywidgets.Layout(width="5%"), disabled=True) link((axis, "name"), (name, "value")) link((axis, "units"), (units, "value")) bothw = ipywidgets.HBox([name, iwidget, vwidget, units]) # labeled_widget = labelme(str(axis), bothw) widgets.append(bothw) axis_dict["value"] = vwidget axis_dict["index"] = iwidget axis_dict["units"] = units widgets.append(continuous_update) box = ipywidgets.VBox(widgets) return {"widget": box, "wdict": wdict}