Sk.builtinFiles.files['src/lib/plotly/plotly.py']="\ndef _mk_unimplemented(name):\n    def f(*args, **kwargs):\n        raise Exception(\"You don't need %s() on Anvil. Set the 'data' property on a Plot component instead\" % name)\n    return f\n\niplot = _mk_unimplemented(\"iplot\")\nplot = _mk_unimplemented(\"plot\")\n";Sk.builtinFiles.files['src/lib/plotly/graph_objects.py']="from .graph_objs import *";Sk.builtinFiles.files['src/lib/plotly/_schema.py']="schema={'bar':{'a':['ErrorX','ErrorY','Hoverlabel','Insidetextfont','Legendgrouptitle','Marker','Outsidetextfont','Selected','Stream','Textfont','Unselected'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['ColorBar','Line','Pattern'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'selected':{'a':['Marker','Textfont']},'unselected':{'a':['Marker','Textfont']}}},'_bar':{'t':['Bar']},'barpolar':{'a':['Hoverlabel','Legendgrouptitle','Marker','Selected','Stream','Unselected'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['ColorBar','Line','Pattern'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'selected':{'a':['Marker','Textfont']},'unselected':{'a':['Marker','Textfont']}}},'_barpolar':{'t':['Barpolar']},'box':{'a':['Hoverlabel','Legendgrouptitle','Line','Marker','Selected','Stream','Unselected'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['Line']},'selected':{'a':['Marker']},'unselected':{'a':['Marker']}}},'_box':{'t':['Box']},'candlestick':{'a':['Decreasing','Hoverlabel','Increasing','Legendgrouptitle','Line','Stream'],'c':{'decreasing':{'a':['Line']},'hoverlabel':{'a':['Font']},'increasing':{'a':['Line']},'legendgrouptitle':{'a':['Font']}}},'_candlestick':{'t':['Candlestick']},'carpet':{'a':['Aaxis','Baxis','Font','Legendgrouptitle','Stream'],'c':{'aaxis':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'baxis':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'legendgrouptitle':{'a':['Font']}}},'_carpet':{'t':['Carpet']},'choropleth':{'a':['ColorBar','Hoverlabel','Legendgrouptitle','Marker','Selected','Stream','Unselected'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['Line']},'selected':{'a':['Marker']},'unselected':{'a':['Marker']}}},'_choropleth':{'t':['Choropleth']},'choroplethmap':{'a':['ColorBar','Hoverlabel','Legendgrouptitle','Marker','Selected','Stream','Unselected'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['Line']},'selected':{'a':['Marker']},'unselected':{'a':['Marker']}}},'_choroplethmap':{'t':['Choroplethmap']},'choroplethmapbox':{'a':['ColorBar','Hoverlabel','Legendgrouptitle','Marker','Selected','Stream','Unselected'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['Line']},'selected':{'a':['Marker']},'unselected':{'a':['Marker']}}},'_choroplethmapbox':{'t':['Choroplethmapbox']},'cone':{'a':['ColorBar','Hoverlabel','Legendgrouptitle','Lighting','Lightposition','Stream'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']}}},'_cone':{'t':['Cone']},'contour':{'a':['ColorBar','Contours','Hoverlabel','Legendgrouptitle','Line','Stream','Textfont'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'contours':{'a':['Impliededits','Labelfont']},'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']}}},'_contour':{'t':['Contour']},'contourcarpet':{'a':['ColorBar','Contours','Legendgrouptitle','Line','Stream'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'contours':{'a':['Impliededits','Labelfont']},'legendgrouptitle':{'a':['Font']}}},'_contourcarpet':{'t':['Contourcarpet']},'densitymap':{'a':['ColorBar','Hoverlabel','Legendgrouptitle','Stream'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']}}},'_densitymap':{'t':['Densitymap']},'densitymapbox':{'a':['ColorBar','Hoverlabel','Legendgrouptitle','Stream'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']}}},'_densitymapbox':{'t':['Densitymapbox']},'funnel':{'a':['Connector','Hoverlabel','Insidetextfont','Legendgrouptitle','Marker','Outsidetextfont','Stream','Textfont'],'c':{'connector':{'a':['Line']},'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['ColorBar','Line'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}}}},'_funnel':{'t':['Funnel']},'funnelarea':{'a':['Domain','Hoverlabel','Insidetextfont','Legendgrouptitle','Marker','Stream','Textfont','Title'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['Line','Pattern']},'title':{'a':['Font']}}},'_funnelarea':{'t':['Funnelarea']},'heatmap':{'a':['ColorBar','Hoverlabel','Legendgrouptitle','Stream','Textfont'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']}}},'_heatmap':{'t':['Heatmap']},'histogram':{'a':['Cumulative','ErrorX','ErrorY','Hoverlabel','Insidetextfont','Legendgrouptitle','Marker','Outsidetextfont','Selected','Stream','Textfont','Unselected','XBins','YBins'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['ColorBar','Line','Pattern'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'selected':{'a':['Marker','Textfont']},'unselected':{'a':['Marker','Textfont']}}},'_histogram':{'t':['Histogram']},'histogram2d':{'a':['ColorBar','Hoverlabel','Legendgrouptitle','Marker','Stream','Textfont','XBins','YBins'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']}}},'_histogram2d':{'t':['Histogram2d']},'histogram2dcontour':{'a':['ColorBar','Contours','Hoverlabel','Legendgrouptitle','Line','Marker','Stream','Textfont','XBins','YBins'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'contours':{'a':['Impliededits','Labelfont']},'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']}}},'_histogram2dcontour':{'t':['Histogram2dContour']},'icicle':{'a':['Domain','Hoverlabel','Insidetextfont','Leaf','Legendgrouptitle','Marker','Outsidetextfont','Pathbar','Root','Stream','Textfont','Tiling'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['ColorBar','Line','Pattern'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'pathbar':{'a':['Textfont']}}},'_icicle':{'t':['Icicle']},'image':{'a':['Hoverlabel','Legendgrouptitle','Stream'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']}}},'_image':{'t':['Image']},'indicator':{'a':['Delta','Domain','Gauge','Legendgrouptitle','Number','Stream','Title'],'c':{'delta':{'a':['Decreasing','Font','Increasing']},'gauge':{'a':['Axis','Bar','Step','Threshold'],'c':{'axis':{'a':['Tickfont','Tickformatstop']},'bar':{'a':['Line']},'step':{'a':['Line']},'threshold':{'a':['Line']}}},'legendgrouptitle':{'a':['Font']},'number':{'a':['Font']},'title':{'a':['Font']}}},'_indicator':{'t':['Indicator']},'isosurface':{'a':['Caps','ColorBar','Contour','Hoverlabel','Legendgrouptitle','Lighting','Lightposition','Slices','Spaceframe','Stream','Surface'],'c':{'caps':{'a':['X','Y','Z']},'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'slices':{'a':['X','Y','Z']}}},'_isosurface':{'t':['Isosurface']},'mesh3d':{'a':['ColorBar','Contour','Hoverlabel','Legendgrouptitle','Lighting','Lightposition','Stream'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']}}},'_mesh3d':{'t':['Mesh3d']},'ohlc':{'a':['Decreasing','Hoverlabel','Increasing','Legendgrouptitle','Line','Stream'],'c':{'decreasing':{'a':['Line']},'hoverlabel':{'a':['Font']},'increasing':{'a':['Line']},'legendgrouptitle':{'a':['Font']}}},'_ohlc':{'t':['Ohlc']},'parcats':{'a':['Dimension','Domain','Labelfont','Legendgrouptitle','Line','Stream','Tickfont'],'c':{'legendgrouptitle':{'a':['Font']},'line':{'a':['ColorBar'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}}}},'_parcats':{'t':['Parcats']},'parcoords':{'a':['Dimension','Domain','Labelfont','Legendgrouptitle','Line','Rangefont','Stream','Tickfont','Unselected'],'c':{'legendgrouptitle':{'a':['Font']},'line':{'a':['ColorBar'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'unselected':{'a':['Line']}}},'_parcoords':{'t':['Parcoords']},'pie':{'a':['Domain','Hoverlabel','Insidetextfont','Legendgrouptitle','Marker','Outsidetextfont','Stream','Textfont','Title'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['Line','Pattern']},'title':{'a':['Font']}}},'_pie':{'t':['Pie']},'sankey':{'a':['Domain','Hoverlabel','Legendgrouptitle','Link','Node','Stream','Textfont'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'link':{'a':['Concentrationscales','Hoverlabel','Line'],'c':{'hoverlabel':{'a':['Font']}}},'node':{'a':['Hoverlabel','Line'],'c':{'hoverlabel':{'a':['Font']}}}}},'_sankey':{'t':['Sankey']},'scatter':{'a':['ErrorX','ErrorY','Fillgradient','Fillpattern','Hoverlabel','Legendgrouptitle','Line','Marker','Selected','Stream','Textfont','Unselected'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['ColorBar','Gradient','Line'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'selected':{'a':['Marker','Textfont']},'unselected':{'a':['Marker','Textfont']}}},'_scatter':{'t':['Scatter']},'scatter3d':{'a':['ErrorX','ErrorY','ErrorZ','Hoverlabel','Legendgrouptitle','Line','Marker','Projection','Stream','Textfont'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'line':{'a':['ColorBar'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'marker':{'a':['ColorBar','Line'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'projection':{'a':['X','Y','Z']}}},'_scatter3d':{'t':['Scatter3d']},'scattercarpet':{'a':['Hoverlabel','Legendgrouptitle','Line','Marker','Selected','Stream','Textfont','Unselected'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['ColorBar','Gradient','Line'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'selected':{'a':['Marker','Textfont']},'unselected':{'a':['Marker','Textfont']}}},'_scattercarpet':{'t':['Scattercarpet']},'scattergeo':{'a':['Hoverlabel','Legendgrouptitle','Line','Marker','Selected','Stream','Textfont','Unselected'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['ColorBar','Gradient','Line'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'selected':{'a':['Marker','Textfont']},'unselected':{'a':['Marker','Textfont']}}},'_scattergeo':{'t':['Scattergeo']},'scattergl':{'a':['ErrorX','ErrorY','Hoverlabel','Legendgrouptitle','Line','Marker','Selected','Stream','Textfont','Unselected'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['ColorBar','Line'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'selected':{'a':['Marker','Textfont']},'unselected':{'a':['Marker','Textfont']}}},'_scattergl':{'t':['Scattergl']},'scattermap':{'a':['Cluster','Hoverlabel','Legendgrouptitle','Line','Marker','Selected','Stream','Textfont','Unselected'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['ColorBar'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'selected':{'a':['Marker']},'unselected':{'a':['Marker']}}},'_scattermap':{'t':['Scattermap']},'scattermapbox':{'a':['Cluster','Hoverlabel','Legendgrouptitle','Line','Marker','Selected','Stream','Textfont','Unselected'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['ColorBar'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'selected':{'a':['Marker']},'unselected':{'a':['Marker']}}},'_scattermapbox':{'t':['Scattermapbox']},'scatterpolar':{'a':['Hoverlabel','Legendgrouptitle','Line','Marker','Selected','Stream','Textfont','Unselected'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['ColorBar','Gradient','Line'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'selected':{'a':['Marker','Textfont']},'unselected':{'a':['Marker','Textfont']}}},'_scatterpolar':{'t':['Scatterpolar']},'scatterpolargl':{'a':['Hoverlabel','Legendgrouptitle','Line','Marker','Selected','Stream','Textfont','Unselected'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['ColorBar','Line'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'selected':{'a':['Marker','Textfont']},'unselected':{'a':['Marker','Textfont']}}},'_scatterpolargl':{'t':['Scatterpolargl']},'scattersmith':{'a':['Hoverlabel','Legendgrouptitle','Line','Marker','Selected','Stream','Textfont','Unselected'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['ColorBar','Gradient','Line'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'selected':{'a':['Marker','Textfont']},'unselected':{'a':['Marker','Textfont']}}},'_scattersmith':{'t':['Scattersmith']},'scatterternary':{'a':['Hoverlabel','Legendgrouptitle','Line','Marker','Selected','Stream','Textfont','Unselected'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['ColorBar','Gradient','Line'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'selected':{'a':['Marker','Textfont']},'unselected':{'a':['Marker','Textfont']}}},'_scatterternary':{'t':['Scatterternary']},'splom':{'a':['Diagonal','Dimension','Hoverlabel','Legendgrouptitle','Marker','Selected','Stream','Unselected'],'c':{'dimension':{'a':['Axis']},'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['ColorBar','Line'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'selected':{'a':['Marker']},'unselected':{'a':['Marker']}}},'_splom':{'t':['Splom']},'streamtube':{'a':['ColorBar','Hoverlabel','Legendgrouptitle','Lighting','Lightposition','Starts','Stream'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']}}},'_streamtube':{'t':['Streamtube']},'sunburst':{'a':['Domain','Hoverlabel','Insidetextfont','Leaf','Legendgrouptitle','Marker','Outsidetextfont','Root','Stream','Textfont'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['ColorBar','Line','Pattern'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}}}},'_sunburst':{'t':['Sunburst']},'surface':{'a':['ColorBar','Contours','Hoverlabel','Legendgrouptitle','Lighting','Lightposition','Stream'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'contours':{'a':['X','Y','Z'],'c':{'x':{'a':['Project']},'y':{'a':['Project']},'z':{'a':['Project']}}},'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']}}},'_surface':{'t':['Surface']},'table':{'a':['Cells','Domain','Header','Hoverlabel','Legendgrouptitle','Stream'],'c':{'cells':{'a':['Fill','Font','Line']},'header':{'a':['Fill','Font','Line']},'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']}}},'_table':{'t':['Table']},'treemap':{'a':['Domain','Hoverlabel','Insidetextfont','Legendgrouptitle','Marker','Outsidetextfont','Pathbar','Root','Stream','Textfont','Tiling'],'c':{'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['ColorBar','Line','Pad','Pattern'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'pathbar':{'a':['Textfont']}}},'_treemap':{'t':['Treemap']},'violin':{'a':['Box','Hoverlabel','Legendgrouptitle','Line','Marker','Meanline','Selected','Stream','Unselected'],'c':{'box':{'a':['Line']},'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'marker':{'a':['Line']},'selected':{'a':['Marker']},'unselected':{'a':['Marker']}}},'_violin':{'t':['Violin']},'volume':{'a':['Caps','ColorBar','Contour','Hoverlabel','Legendgrouptitle','Lighting','Lightposition','Slices','Spaceframe','Stream','Surface'],'c':{'caps':{'a':['X','Y','Z']},'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'hoverlabel':{'a':['Font']},'legendgrouptitle':{'a':['Font']},'slices':{'a':['X','Y','Z']}}},'_volume':{'t':['Volume']},'waterfall':{'a':['Connector','Decreasing','Hoverlabel','Increasing','Insidetextfont','Legendgrouptitle','Outsidetextfont','Stream','Textfont','Totals'],'c':{'connector':{'a':['Line']},'decreasing':{'a':['Marker'],'c':{'marker':{'a':['Line']}}},'hoverlabel':{'a':['Font']},'increasing':{'a':['Marker'],'c':{'marker':{'a':['Line']}}},'legendgrouptitle':{'a':['Font']},'totals':{'a':['Marker'],'c':{'marker':{'a':['Line']}}}}},'_waterfall':{'t':['Waterfall']},'layout':{'a':['Activeselection','Activeshape','Annotation','Coloraxis','Colorscale','Font','Geo','Grid','Hoverlabel','Image','Legend','Map','Mapbox','Margin','Modebar','Newselection','Newshape','Polar','Scene','Selection','Shape','Slider','Smith','Template','Ternary','Title','Transition','Uniformtext','Updatemenu','XAxis','YAxis'],'c':{'annotation':{'a':['Font','Hoverlabel'],'c':{'hoverlabel':{'a':['Font']}}},'coloraxis':{'a':['ColorBar'],'c':{'colorbar':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'geo':{'a':['Center','Domain','Lataxis','Lonaxis','Projection'],'c':{'projection':{'a':['Rotation']}}},'grid':{'a':['Domain']},'hoverlabel':{'a':['Font','Grouptitlefont']},'legend':{'a':['Font','Grouptitlefont','Title'],'c':{'title':{'a':['Font']}}},'map':{'a':['Bounds','Center','Domain','Layer'],'c':{'layer':{'a':['Circle','Fill','Line','Symbol'],'c':{'symbol':{'a':['Textfont']}}}}},'mapbox':{'a':['Bounds','Center','Domain','Layer'],'c':{'layer':{'a':['Circle','Fill','Line','Symbol'],'c':{'symbol':{'a':['Textfont']}}}}},'newselection':{'a':['Line']},'newshape':{'a':['Label','Legendgrouptitle','Line'],'c':{'label':{'a':['Font']},'legendgrouptitle':{'a':['Font']}}},'polar':{'a':['AngularAxis','Domain','RadialAxis'],'c':{'angularaxis':{'a':['Tickfont','Tickformatstop']},'radialaxis':{'a':['Autorangeoptions','Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'scene':{'a':['Annotation','Aspectratio','Camera','Domain','XAxis','YAxis','ZAxis'],'c':{'annotation':{'a':['Font','Hoverlabel'],'c':{'hoverlabel':{'a':['Font']}}},'aspectratio':{'a':['Impliededits']},'camera':{'a':['Center','Eye','Projection','Up']},'xaxis':{'a':['Autorangeoptions','Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'yaxis':{'a':['Autorangeoptions','Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'zaxis':{'a':['Autorangeoptions','Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'selection':{'a':['Line']},'shape':{'a':['Label','Legendgrouptitle','Line'],'c':{'label':{'a':['Font']},'legendgrouptitle':{'a':['Font']}}},'slider':{'a':['Currentvalue','Font','Pad','Step','Transition'],'c':{'currentvalue':{'a':['Font']}}},'smith':{'a':['Domain','Imaginaryaxis','Realaxis'],'c':{'imaginaryaxis':{'a':['Tickfont']},'realaxis':{'a':['Tickfont']}}},'ternary':{'a':['Aaxis','Baxis','Caxis','Domain'],'c':{'aaxis':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'baxis':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}},'caxis':{'a':['Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'title':{'a':['Font','Pad','Subtitle'],'c':{'subtitle':{'a':['Font']}}},'updatemenu':{'a':['Button','Font','Pad']},'xaxis':{'a':['Autorangeoptions','Minor','Rangebreak','Rangeselector','Rangeslider','Tickfont','Tickformatstop','Title'],'c':{'rangeselector':{'a':['Button','Font']},'rangeslider':{'a':['YAxis']},'title':{'a':['Font']}}},'yaxis':{'a':['Autorangeoptions','Minor','Rangebreak','Tickfont','Tickformatstop','Title'],'c':{'title':{'a':['Font']}}}}},'_layout':{'a':['Layout']},'_deprecations':{'a':['Data','Annotations','Frames','AngularAxis','Annotation','ColorBar','Contours','ErrorX','ErrorY','ErrorZ','Font','Legend','Line','Margin','Marker','RadialAxis','Scene','Stream','XAxis','YAxis','ZAxis','XBins','YBins','Trace','Histogram2dcontour']},'_figure':{'a':['Figure']}}";Sk.builtinFiles.files['src/lib/plotly/_cls_overrides.py']="# Classes in plotly that have additional behaviour and features\n\nfrom anvil.util import WrappedObject\n\n_valid_underscore_properties = {\n    \"error_x\": \"error-x\",\n    \"error_y\": \"error-y\",\n    \"error_z\": \"error-z\",\n    \"copy_xstyle\": \"copy-xstyle\",\n    \"copy_ystyle\": \"copy-ystyle\",\n    \"copy_zstyle\": \"copy-zstyle\",\n    \"paper_bgcolor\": \"paper-bgcolor\",\n    \"plot_bgcolor\": \"plot-bgcolor\",\n}\n\n\ndef _get_props(full_path):\n    for under_prop, hyphen_prop in _valid_underscore_properties.items():\n        full_path = full_path.replace(under_prop, hyphen_prop)\n    \n    props = full_path.split(\"_\")\n    for i, prop in enumerate(props):\n        props[i] = prop.replace(\"-\", \"_\")\n    \n    return props\n\ndef _walk_props(self, path, props):\n    res = self\n    for p in props:\n        try:\n            res = WrappedObject.__getitem__(res, p)\n        except TypeError:\n            raise KeyError(path)\n    return res\n\n# support: https://plotly.com/python/creating-and-updating-figures/#magic-underscore-notation\nclass Base(WrappedObject):\n    def __setitem__(self, path, val):\n        if path[0] != \"_\" and \"_\" in path[1:]:\n            props = _get_props(path)\n            res = _walk_props(self, path, props[:-1])\n            WrappedObject.__setitem__(res, props[-1], val)\n        else:\n            return WrappedObject.__setitem__(self, path, val)\n\n    def __getitem__(self, path):\n        if path[0] != \"_\" and \"_\" in path[1:]:\n            props = _get_props(path)\n            return _walk_props(self, path, props)\n        else:\n            return WrappedObject.__getitem__(self, path)\n        \n\n\ndef _not_implemented_wrapper(cls_name, name):\n    def not_implemented(self, *args, **kws):\n        raise NotImplementedError(name + \" is not yet implemented\")\n\n    not_implemented.__name__ = name\n    not_implemented.__qualname__ = cls_name + \".\" + name\n\n    return not_implemented\n\n\nclass Figure(Base):\n    _name = \"Figure\"\n    def __init__(self, data=None, layout=None, **kws):\n        if isinstance(data, Figure):\n            data, layout = data.data, data.layout\n        elif type(data) is dict and (\"data\" in data or \"layout\" in data):\n            # Extract data, layout, and frames\n            data, layout = (\n                data.get(\"data\", None),\n                data.get(\"layout\", None),\n            )\n\n        if data is None:\n            data = []\n        elif not isinstance(data, (list, tuple)):\n            data = [data]\n\n        if layout is None:\n            layout = {}\n        elif isinstance(layout, dict):\n            layout = dict(layout)\n            template = self._initialize_template(layout.get(\"template\", None))\n            if template is not None:\n                layout[\"template\"] = template\n\n        Base.__init__(self, data=data, layout=layout, **kws)\n\n    # some common methods we don't support\n    update_traces = _not_implemented_wrapper(\"Figure\", \"update_traces\")\n    add_trace = _not_implemented_wrapper(\"Figure\", \"add_trace\")\n    for_each_trace = _not_implemented_wrapper(\"Figure\", \"for_each_trace\")\n\n    def update_layout(self, dict1=None, **kws):\n        dict1 = dict1 or {}\n        self.layout.update(dict1, **kws)\n        return self\n\n    _default_template = None\n\n    def _get_template(self, template):\n        return template\n\n    def _initialize_template(self, template):\n        if template is None:\n            template = self._default_template\n        \n        if type(template) is str:\n            return self._get_template(template)\n\n        return template\n\n\n_overrides = {\"plotly.graph_objs._figure.Figure\": Figure}\n";Sk.builtinFiles.files['src/lib/plotly/__init__.py']="import sys as _sys\n\nfrom anvil.server import portable_class as _portable\n\nfrom ._schema import schema as _root_schema\nfrom ._cls_overrides import _overrides, Base\n\n_ModType = type(_sys)\n\n\ndef _cache(fn):\n    cached = {}\n\n    def wrapper(name, module, trace_type=None):\n        args = (name, module, trace_type)\n        seen = cached.get(args)\n        if seen is not None:\n            return seen\n        rv = fn(name, module, trace_type)\n        cached[args] = rv\n        return rv\n\n    return wrapper\n\n\n@_cache\ndef _gen_cls(name, module, trace_type=None):\n    try:\n        cls = _overrides[module + \".\" + name]\n        cls.__module__ = module\n        cls.__name__ = name\n    except KeyError:\n        d = {\"_name\": name, \"_module\": module, \"__module__\": module}\n        if trace_type:\n\n            def __init__(self, d=None, **kws):\n                Base.__init__(self, d, type=trace_type, **kws)\n\n            d[\"__init__\"] = __init__\n        cls = type(name, (Base,), d)\n\n    return _portable(cls)\n\n\nclass _LazyPlotlyMod(_ModType):\n    __slots__ = \"_schema_\"\n\n    def __init__(self, name, schema, package=True):\n        _ModType.__init__(self, name, None)\n        path = name.replace(\".\", \"/\")\n        self.__file__ = path + \"/__init__.py\" if package else path + \".py\"\n        self._schema_ = schema\n        self.__package__ = name  # might be overridden\n\n    def __getattr__(self, attr):\n        if attr == \"__all__\":\n\n            def ignore(x):\n                if x.startswith(\"_\"):\n                    return True\n                defn = self._schema_.get(x)\n                return defn is not None and defn[\"module\"].endswith(\"_deprecations\")\n\n            self.__all__ = sorted(x for x in self.__dir__() if not ignore(x))\n            return self.__all__\n\n        cls_schema = self._schema_.get(attr)\n        if cls_schema is not None:\n            cls = _gen_cls(attr, **cls_schema)\n            setattr(self, attr, cls)\n            return cls\n\n        raise AttributeError(attr)\n\n    def __dir__(self):\n        return sorted(set(_ModType.__dir__(self)) | set(self._schema_.keys()))\n\n\ndef _gen_mod(mod_name, schema, package):\n    trace_types = {cls_name: {\"module\": mod_name, \"trace_type\": cls_name.lower()} for cls_name in schema.get(\"t\", [])}\n    mod_schema = {cls_name: {\"module\": mod_name} for cls_name in schema.get(\"a\", [])}\n    mod_schema.update(trace_types)\n\n    mod = _LazyPlotlyMod(mod_name, mod_schema, package)\n    _sys.modules[mod_name] = mod\n\n    for leaf, s in schema.get(\"c\", {}).items():\n        package = not leaf.startswith(\"_\")  # private modules are not packages (e.g graph_objs._bar)\n        child = _gen_mod(mod_name + \".\" + leaf, s, package)\n        if not package:\n            child.__package__ = mod.__package__\n            mod_schema.update(child._schema_)\n        setattr(mod, leaf, child)\n\n    return mod\n\n\ngraph_objs = _gen_mod(\"plotly.graph_objs\", {\"c\": _root_schema}, True)\n\n# do this after we've created graph_objs\nfrom . import plotly, graph_objects\n";Sk.builtinFiles.files['src/lib/anvil/util.py']="from anvil.server import serializable_type\nimport anvil\n\n\ndef _wrap(value):\n    if isinstance(value, (WrappedObject, WrappedList)):\n        return value\n    elif isinstance(value, dict):\n        return WrappedObject(value)\n    elif isinstance(value, list):\n        wl = WrappedList()\n        for i in value:\n            wl.append(i)\n        return wl\n    else:\n        return value\n\n\n@serializable_type\nclass WrappedObject(dict):\n    _name = None\n    _module = None\n\n    def __init__(self, d=None, **kwargs):\n        if d and isinstance(d, dict):\n            for k in d.keys():\n                self.__setitem__(k, d[k])\n\n        for k in kwargs.keys():\n            self.__setitem__(k, kwargs[k])\n\n    def __getattr__(self, key):\n        return self.__getitem__(key)\n\n    def __setattr__(self, key, value):\n        self.__setitem__(key, value)\n\n    def __setitem__(self, key, value):\n        dict.__setitem__(self, key, _wrap(value))\n\n    def __getitem__(self, key):\n        _sentinel = WrappedObject()\n        r = dict.get(self, key, _sentinel)\n\n        if r is _sentinel:\n            dict.__setitem__(self, key, _sentinel)\n\n        return r\n\n    def update(*args, **new_items):\n        # avoid name conflicts with keys, could use (self, other=(), /, **kws)\n        # but position only args not available in py2/Skulpt\n        if not args:\n            raise TypeError(\"method 'update' needs an argument\")\n        elif len(args) > 2:\n            raise TypeError(\"expected at most 1 argument, got %d\" % (len(args) - 1))\n        elif len(args) == 2:\n            new_items = dict(args[1], **new_items)\n        self = args[0]\n        for k, v in new_items.items():\n            self[k] = v\n\n    def __repr__(self):\n        n = self._name or \"WrappedObject\"\n        m = self._module + \".\" if self._module else \"\"\n        return \"%s%s<%s>\" % (m, n, \", \".join([\"%s=%s\" % (k, repr(self[k])) for k in self.keys()]))\n\n    def __serialize__(self, global_data):\n        return dict(self)\n\n    def __deserialize__(self, data, global_data):\n        self.__init__(data)\n\n    def __copy__(self):\n        return self.__class__(dict.copy(self))\n\n    def __deepcopy__(self, memo):\n        # lazy load this - its only need on the\n        # server and we don't want to load copy on the client\n        from copy import deepcopy\n\n        return self.__class__(deepcopy(dict(self)))\n\n\n@serializable_type\nclass WrappedList(list):\n    def __init__(self, lst=[]):\n        for x in lst:\n            self.append(x)\n\n    def append(self, item):\n        list.append(self, _wrap(item))\n\n    def extend(self, items):\n        for i in items:\n            self.append(i)\n\n    def insert(self, offset, item):\n        list.insert(self, offset, _wrap(item))\n\n    def __serialize__(self, global_data):\n        return list(self)\n\n    def __deserialize__(self, data, global_data):\n        self.__init__(data)\n\n    def __copy__(self):\n        return self.__class__(list.copy(self))\n\n    def __deepcopy__(self, memo):\n        from copy import deepcopy\n\n        return self.__class__(deepcopy(list(self)))\n\n\n";Sk.builtinFiles.files['src/lib/anvil/ext_data/__init__.py']="# This package implements a common interface for providing\n#\nimport json\n\nimport anvil.server\n\ntry:\n    from typing import (\n        TypedDict,\n        Dict,\n        Optional,\n        NewType,\n        Tuple,\n        List,\n        Set,\n    )\n\n    CollectionKey = NewType(\"CollectionKey\", str)\n    LinkDestination = Tuple[CollectionKey]\n    CollectionInfoLink = TypedDict(\n        \"CollectionInfoLink\",\n        {\n            \"to\": CollectionKey,\n            \"multi\": bool,\n        },\n    )\n    CollectionInfoFields = TypedDict(\n        \"CollectionInfoFields\",\n        {\"name\": str, \"client_visible\": bool, \"link\": Optional[CollectionInfoLink]},\n    )\n    CollectionInfoDict = TypedDict(\n        \"CollectionInfoDict\",\n        {\n            \"name\": str,\n            \"fields\": List[CollectionInfoFields],\n            \"summary_fields\": Optional[List[str]],\n        },\n    )\n    RecordIdJson = NewType(\"RecordIdJson\", str)\n\n    GlobalSharedData = TypedDict(\n        \"GlobalSharedData\", {\"spec\": Dict[CollectionKey, CollectionInfoDict]}\n    )\n\n    SendingLocalData = TypedDict(\"SendingLocalData\", {\"sent\": Dict[RecordIdJson, set]})\n\n    ReceivingLocalData = TypedDict(\n        \"ReceivingLocalData\",\n        {\n            \"instances\": Dict[RecordIdJson, \"Record\"],\n            \"collections\": Dict[CollectionKey, \"CollectionInfo\"],\n            \"seen_this_time\": Set[RecordIdJson],\n            \"call_impl\": Optional[\"CallImpl\"],\n        },\n    )\n\n    CompactData = Dict[RecordIdJson, dict]\n    # Field values for single columns are IDs, for multi-link columns arrays of IDs\n    # The empty string \"\" key contains a Capability.\n\nexcept (ImportError, AttributeError):\n    CollectionKey = str\n    LinkDestination = tuple\n    CollectionInfoDict = dict\n    RecordIdJson = str\n    GlobalSharedData = dict\n    SendingLocalData = dict\n    ReceivingLocalData = dict\n    CompactData = dict\n\n\ndef tightjson(data):\n    return json.dumps(data, separators=(',',':'))\n\n\ndef receiving_shared_data(si):\n    # NB we deliberately don't set seen_this_time, becayse every caller *needs* to reset it\n    return si.shared_data(\"anvil.ext_tables\", local_data_factory=lambda: {\"instances\": {}, \"collections\": {}})\n\n\ndef sending_shared_data(si):\n    return si.shared_data(\"anvil.ext_tables\", local_data_factory=lambda: {\"sent\": {}},\n                          transmitted_data_factory=lambda: {\"spec\": {}})\n\n\nclass CallImpl:\n    def __init__(self, schema_name):\n        self.prefix = \"anvil.ext/\" + schema_name\n\n    def load_record_data(self, collection_key, record_caps, request=None):\n        return anvil.server.call(self.prefix+\"/load\", collection_key, record_caps, request=request)\n\n    def update_records(self, collection_key, updates):\n        return anvil.server.call(self.prefix+\"/update\", collection_key, updates)\n\n    def delete_records(self, collection_key, to_delete):\n        return anvil.server.call(self.prefix+\"/delete\", collection_key, to_delete)\n\n\n_model_classes = {}\n\n\nclass CollectionInfo:\n    \"\"\"Information about a collection\"\"\"\n    class FieldInfo:\n        def __init__(self, name, client_visible=True, from_id=False, is_link=False, link_to=None, link_multi=False):\n            self.name = name\n            self.client_visible = client_visible\n            self.is_link = is_link\n            self.link_to = link_to\n            self.link_multi = link_multi\n            self.from_id = from_id\n\n        @staticmethod\n        def load(data, gsdata, collection_cache):\n            link_info = data.get(\"link\")\n            link_to = CollectionInfo.load(link_info[\"to\"], gsdata, collection_cache) if link_info else None\n            link_multi = link_info and link_info[\"multi\"]\n            return CollectionInfo.FieldInfo(data[\"name\"], data.get(\"client_visible\", True), data.get(\"from_id\", False),\n                                            link_info is not None, link_to, link_multi)\n\n    def __init__(self, key, data, fields, call_impl=None):\n        \"\"\"Don't try and make one of these yourself, use the impl package\"\"\"\n        self.schema_name = json.loads(key)[\"s\"]\n        self.key = key\n        self.name = data[\"name\"]\n        self.data = data\n        self.fields = fields\n        self.summary_fields = data.get(\"summary_fields\")\n        self.calls = call_impl or CallImpl(self.schema_name)\n\n    @staticmethod\n    def load(key, gsdata, collection_cache, call_impl=None):\n        c = collection_cache.get(key)\n        if not c:\n            spec = gsdata['spec'].get(key)\n            if spec is None:\n                return None\n            c = collection_cache[key] = CollectionInfo(key, spec, {}, call_impl)\n            # Do this after the collection is in local_data, so circular references work\n            c.fields = {data[\"name\"]: c.FieldInfo.load(data, gsdata, collection_cache) for data in spec['fields']}\n        return c\n\n    def update(self, gsdata):\n        \"\"\"Ingest any fields in this txdata that we didn't get before\"\"\"\n        collection_cache = {}\n        spec = gsdata['spec'].get(self.key)\n        if spec:\n            for fdata in spec['fields']:\n                field = self.fields.get(fdata['name'])\n                if not field or fdata.get(\"link\") and not field.link_to:\n                    self.fields[fdata['name']] = self.FieldInfo.load(fdata, gsdata, collection_cache)\n\n    def save(self, key, gsdata, remote_is_trusted):\n        if key not in gsdata['spec']:\n            if remote_is_trusted:\n                gsdata['spec'][key] = self.data\n            else:\n                gsdata['spec'][key] = {**self.data, \"fields\": [field for field in self.data[\"fields\"]\n                                                               if field[\"client_visible\"]]}\n\n\n@anvil.server.portable_class\nclass Record:\n    def __init__(self, str_id, collection_info=None, cap=None, data=None):\n        \"\"\"Don't make one of these yourself; use schema stuff in the impl package\"\"\"\n        # raise TypeError(\"Cannot instantiate a Record\")\n        self._str_id = str_id\n        self._collection_info = collection_info\n        self._cap = cap\n        if cap:\n            cap.set_update_handler(self._cap_update_handler)\n        self._data = data or {}\n\n    def _cap_update_handler(self, updates):\n        if updates is False:\n            # We've been deleted - clear cache so that\n            # server calls are required for data access (which will then fail)\n            self._data = {}\n        else:\n            # Updates are fleshed-out (ie contain Record objects), so we can just apply them like this\n            self._data.update(updates)\n\n    # USER API\n\n    @property\n    def id(self):\n        return self._cap.scope[2]\n\n    def __eq__(self, other):\n        return isinstance(other, Record) and other._cap.scope == self._cap.scope\n\n    def __hash__(self):\n        return hash(self._cap.scope[1]) ^ hash(tuple(self.id) if type(self.id) is list else self.id)\n\n    def __getitem__(self, field_name):\n        if field_name == \"\":\n            raise KeyError(\"\") # that's where my cap lives\n\n        f = self._collection_info and self._collection_info.fields.get(field_name)\n        if f and f.from_id is not False:\n            if f.from_id is True:\n                return self.id\n            else:\n                return self.id[f.from_id]\n\n        if field_name not in self._data:\n            # Policy decision: Fetch just this field.\n            self._fetch((False, {field_name: True}))\n\n        return self._data[field_name]\n\n    def __iter__(self):\n        # Used to implement dict(record) efficiently\n        all_keys = set(self._data.keys())\n        all_keys.discard(\"\")\n        to_fetch = None\n        if self._collection_info:\n            known_fields = self._collection_info.fields.keys()\n            to_fetch = {field_name: True for field_name in known_fields if field_name not in all_keys}\n            all_keys.update(known_fields)\n\n        def get_key(k):\n            if k not in self._data:\n                self._fetch((False, to_fetch))\n            return self._data[k]\n\n        return iter((k, get_key(k)) for k in all_keys)\n\n    def __setitem__(self, field, value):\n        self.update({field: value})\n\n    def update(self, updates=None, **values):\n        updates = values if updates is None else {**updates, **values}\n        self._calls.update_records(self._cap.scope[1], [(self._cap, updates)])\n\n    def delete(self):\n        self._calls.delete_records(self._cap.scope[1], [self._cap])\n\n    def __repr__(self):\n        info = json.loads(self._cap.scope[1]) if self._cap else {\"s\":\"NO\", \"c\":\"CAP\"}\n        if self._collection_info and self._collection_info.summary_fields:\n            keys = [k for k in self._collection_info.summary_fields if k in self._data]\n            values = \", \".join(k+\"=\"+repr(self._data[k]) for k in keys)\n            if any(k not in self._collection_info.summary_fields for k in self._data.keys()):\n                values += \" ...\" if keys else \"...\"\n        else:\n            values = \", \".join(k+\"=\"+repr(v) for k,v in self._data.items() if k != \"\")\n        return \"<{} {}.{} {} {{{}}}>\".format(\n            type(self).__name__, info[\"s\"], info[\"c\"], (repr(self.id) if self._cap else self._str_id), values\n        )\n\n    # MODELS\n\n    def __init_subclass__(cls, schema=None, collection=None, **kwargs):\n        if type(schema) is not str or type(collection) is not str:\n            raise TypeError(\"If subclassing Record, you must specify schema= and collection= as strings.\")\n        if cls.__init__ is not Record.__init__:\n            raise TypeError(\"If subclassing Record, you may not override __init__\")\n        _model_classes[(schema,collection)] = cls\n\n    # SENDING\n\n    def _compact_ref(self, cdata, gsdata, sldata, collection_info, local_is_trusted, remote_is_trusted):\n        if collection_info.key == self._cap.scope[1]:\n            self._add_to_cdata(cdata, gsdata, sldata, local_is_trusted, remote_is_trusted)\n            return self.id\n        else:\n            return self\n\n    def _add_to_cdata(self, cdata, gsdata, sldata, local_is_trusted, remote_is_trusted):\n        my_data = cdata.get(self._str_id, {})\n        sent_keys = sldata[\"sent\"].setdefault(self.id, set())\n        if \"\" not in sent_keys:\n            my_data[\"\"] = self._cap\n            sent_keys.add(\"\")\n\n        # Only send data if we're on the server side - data from the client will be ignored:\n        if local_is_trusted and (remote_is_trusted or self._collection_info):\n            # If we know about our collection info we can send links compact style\n            fields = {}\n            if self._collection_info and gsdata:\n                self._collection_info.save(self._collection_info.key, gsdata, remote_is_trusted)\n                fields = self._collection_info.fields\n            for key, value in self._data.items():\n                field = fields.get(key)\n                if not remote_is_trusted and field and not field.client_visible:\n                    continue # skip this field\n                if field and field.is_link:\n                    if field.link_multi and type(value) is list:\n                        my_data[key] = [r._compact_ref(cdata, gsdata, sldata, field.link_to, local_is_trusted,\n                                                       remote_is_trusted)\n                                        if isinstance(r, Record) else r for r in value]\n                    elif not field.link_multi and isinstance(value, Record):\n                        my_data[key] = value._compact_ref(cdata, gsdata, sldata, field.link_to, local_is_trusted,\n                                                          remote_is_trusted)\n                my_data[key] = value\n                sent_keys.add(key)\n\n        if my_data:\n            # Only write into cdata if there's any data to add that hasn't been added elsewhere\n            cdata[self._str_id] = my_data\n\n    def __serialize__(self, si):\n        gsdata, sldata = sending_shared_data(si)\n        cdata = {}\n        if self._cap is not None:\n            # NB self._cap is only None if we're dehydrated in a RecordList. If so, we will be rehydreated\n            # before we are reachable, so all the user API assumes _cap is present\n            self._add_to_cdata(cdata, gsdata, sldata, si.local_is_trusted, si.remote_is_trusted)\n        return [self._str_id, cdata]\n\n    # RECEIVING\n\n    @staticmethod\n    def __new_deserialized__(wire_data, si):\n        gsdata, rldata = receiving_shared_data(si)\n        rldata[\"seen_this_time\"] = set()\n        str_id, cdata = wire_data\n        return Record._get_from_data(str_id, cdata, gsdata, rldata, si.remote_is_trusted)\n\n    @staticmethod\n    def _get_from_data(str_id, cdata, gsdata, rldata, remote_is_trusted):\n        instance = rldata[\"instances\"].get(str_id)\n        if not instance:\n            # Icky workaround for Skulpt missing raw_decode\n            try:\n                ck, _ = json.JSONDecoder().raw_decode(str_id)\n            except NotImplementedError:\n                idx = -1\n                while True:\n                    idx = str_id.find(\".\", idx+1)\n                    if idx == -1:\n                        raise ValueError(\"JSON parse failed for str_id: \" + repr(str_id))\n                    try:\n                        ck = json.loads(str_id[:idx])\n                        break\n                    except json.JSONDecodeError:\n                        pass\n            cls = _model_classes.get((ck[\"s\"], ck[\"c\"]), Record)\n            instance = cls(str_id)\n            rldata[\"instances\"][str_id] = instance\n        # Prevent looping:\n        if str_id not in rldata[\"seen_this_time\"]:\n            rldata[\"seen_this_time\"].add(str_id)\n            instance._update_from_txdata(cdata, gsdata, rldata, remote_is_trusted)\n        return instance\n\n    def _fill_out_links(self, data, cdata, gsdata, rldata):\n        \"\"\"We've got collection info, fill out links. Only makes sense if data is trusted.\"\"\"\n        assert self._collection_info\n        for field in self._collection_info.fields.values():\n            if field.is_link and field.name in data:\n                v = data.get(field.name)\n                if field.link_multi:\n                    if type(v) is list:\n                        v = [Record._get_from_data(field.link_to.key+\".\"+tightjson(rid), cdata, gsdata, rldata, True)\n                             if not isinstance(rid, Record) else rid\n                             for rid in v]\n                else:\n                    if not isinstance(v, Record):\n                        v = Record._get_from_data(field.link_to.key+\".\"+tightjson(v), cdata, gsdata, rldata, True)\n\n                data[field.name] = v\n\n    def _update_from_txdata(self, cdata, gsdata, rldata, remote_is_trusted):\n        my_data = cdata.get(self._str_id, None)\n        if my_data is None:\n            return\n\n        if self._cap is None and \"\" in my_data:\n            self._cap = my_data[\"\"]\n            self._cap.set_update_handler(self._cap_update_handler)\n\n        if remote_is_trusted:\n            if gsdata and self._cap:\n                if not self._collection_info:\n                    self._collection_info = CollectionInfo.load(self._cap.scope[1], gsdata, rldata[\"collections\"],\n                                                                rldata.get(\"call_impl\"))\n                    if self._collection_info:\n                        self._fill_out_links(self._data, cdata, gsdata, rldata)\n            if self._collection_info:\n                self._fill_out_links(my_data, cdata, gsdata, rldata)\n            self._data.update(my_data)\n\n    @property\n    def _calls(self):\n        if self._collection_info:\n            return self._collection_info.calls\n        else:\n            coll_dict = json.loads(self._cap.scope[1])\n            return CallImpl(coll_dict[\"s\"])\n\n    @property\n    def _schema_and_collection(self):\n        if self._collection_info:\n            return self._collection_info.schema_name, self._collection_info.name\n        else:\n            ck = json.loads(self._cap.scope[1])\n            return ck[\"s\"], ck[\"c\"]\n\n\n    def _fetch(self, request_spec):\n        dhtd = self._calls.load_record_data(self._cap.scope[1], [self._cap], request=request_spec)\n        cdata, gsdata = dhtd.data\n        rldata = {\"instances\": {}, \"collections\": {}, \"seen_this_time\": set()}\n        if self._collection_info:\n            rldata[\"collections\"][self._collection_info.key] = self._collection_info\n            self._collection_info.update(gsdata)\n        else:\n            self._collection_info = CollectionInfo.load(self._cap.scope[1], gsdata, rldata[\"collections\"])\n        self._update_from_txdata(cdata, gsdata, rldata, True)\n\n\ndef _strip_for_client(s_cdata, s_gsdata, ck_and_ids):\n    if all(all(field[\"client_visible\"] for field in cinfo[\"fields\"])\n           for cinfo in s_gsdata[\"spec\"].values()):\n        # No stripping required\n        return s_cdata, s_gsdata\n\n    c_cdata = {}\n    c_gsdata = {\"spec\": {}}\n    to_transfer = list(ck_and_ids)\n\n    while to_transfer:\n        ck, rid = to_transfer.pop()\n        coll = s_gsdata[\"spec\"].get(ck)\n        if ck not in c_gsdata:\n            c_gsdata[\"spec\"][ck] = {**coll, \"fields\": [field for field in coll[\"fields\"] if field[\"client_visible\"]]}\n        str_id = ck+\".\"+tightjson(rid)\n        if str_id not in c_cdata:\n            c_data = dict(s_cdata[str_id])\n            for field in coll[\"fields\"]:\n                if field[\"name\"] in c_data:\n                    if not field[\"client_visible\"]:\n                        del c_data[field[\"name\"]]\n                    elif field.get(\"link\"):\n                        v = c_data[field[\"name\"]]\n                        link = field[\"link\"]\n                        if not link[\"multi\"]:\n                            to_transfer.append((link[\"to\"], v.id if isinstance(v, Record) else v))\n                        elif type(v) is list:\n                            for record in v:\n                                to_transfer.append((link[\"to\"], record.id if isinstance(record, Record) else record))\n\n            c_cdata[str_id] = c_data\n\n    return c_cdata, c_gsdata\n\n\n\n@anvil.server.portable_class\nclass DehydratedTrustedData:\n    def __init__(self, cdata, gsdata, call_impl):\n        self._cdata = cdata\n        self._gsdata = gsdata\n        self._rldata = {\"instances\": {}, \"collections\": {}, \"seen_this_time\": set(), \"call_impl\": call_impl}\n        self._trusted = True\n        self._records_to_rehydrate = None\n\n    def _rehydrate(self):\n        if self._trusted and self._records_to_rehydrate:\n            for r in self._records_to_rehydrate:\n                r._update_from_txdata(self._cdata, self._gsdata, self._rldata, True)\n            self._records_to_rehydrate = None\n\n    @property\n    def data(self):\n        self._rehydrate()\n        return self._cdata, self._gsdata\n\n    def __serialize__(self, si):\n        return self._cdata, self._gsdata\n\n    def __deserialize__(self, data, si):\n        _, self._rldata = receiving_shared_data(si)\n        self._rldata[\"seen_this_time\"] = set()\n        self._cdata, self._gsdata = data\n        self._trusted = si.remote_is_trusted\n        self._records_to_rehydrate = [r for r in self._rldata[\"instances\"].values() if r._str_id in self._cdata]\n\n\n@anvil.server.portable_class\nclass RecordList(DehydratedTrustedData):\n    def __init__(self, cdata, gsdata, ck_and_ids, call_impl):\n        DehydratedTrustedData.__init__(self, cdata, gsdata, call_impl)\n        self._records = ck_and_ids\n        self._trusted = True\n        self._call_impl = call_impl\n\n    def __serialize__(self, si):\n        cdata, gsdata = self._cdata, self._gsdata\n        if not si.remote_is_trusted:\n            cdata, gsdata = _strip_for_client(cdata, gsdata, self._records)\n        return cdata, gsdata, self._records\n\n    def __deserialize__(self, data, si):\n        DehydratedTrustedData.__deserialize__(self, data[:2], si)\n        self._records = data[2]\n        self._call_impl = None\n\n    def _mk_record(self, record):\n        collection_key, record_id = record\n        str_id = collection_key+\".\"+tightjson(record_id)\n        # If we have an instance in cache, it's complete - there is only one cdata - so we can shortcut\n        instance = self._rldata[\"instances\"].get(str_id)\n        return instance or Record._get_from_data(str_id, self._cdata, self._gsdata, self._rldata, self._trusted)\n\n    def __iter__(self):\n        self._rehydrate()\n        return iter(self._mk_record(record) for record in self._records)\n\n    def __getitem__(self, index):\n        if type(index) is not int:\n            raise TypeError(\"RecordList index must be integers\")\n        self._rehydrate()\n        return self._mk_record(self._records[index])\n\n    def __len__(self):\n        return len(self._records)\n\n    def __bool__(self):\n        return bool(self._records)\n\n    def __repr__(self):\n        return \"<RecordList ({} records)>\".format(len(self._records))\n\n\n@anvil.server.portable_class\nclass LazyIterable:\n    def __init__(self, cap_first_page, first_page=None, cap_second_page=None, get_next_page=None):\n        # Don't create one of these manually; use impl.lazy_iter.LazyIterable\n        self._cap_first_page = cap_first_page\n        self._first_page = first_page\n        self._cap_second_page = cap_second_page\n        self._get_next_page = get_next_page\n\n    def __serialize__(self, si):\n        if si.local_is_trusted:\n            return self.cap_this_page, self._first_page, self._cap_second_page\n        else:\n            return self.cap_this_page, None, None\n\n    def __deserialize__(self, data, si):\n        self._get_next_page = None\n        if si.remote_is_trusted:\n            self._cap_first_page, self._first_page, self._cap_second_page = data\n        else:\n            self._cap_first_page = data[0]\n            self._first_page = self._cap_second_page = None\n\n    def __iter__(self):\n        if self._first_page is not None:\n            return self.Iterator(self._first_page, self._cap_second_page, self._get_next_page)\n        else:\n            return self.Iterator([], self._cap_first_page, self._get_next_page)\n\n    def __repr__(self):\n        return f\"<LazyIterable({self._cap_first_page.scope[1]}): at {self._cap_first_page.scope[2:]} with {len(self._first_page)} items cached, next page = {self._cap_second_page}>\"\n\n    class Iterator:\n        def __init__(self, first_page, next_page_cap, get_next_page):\n            self._page_iter = iter(first_page)\n            self._next_page_cap = next_page_cap\n            self._get_next_page = get_next_page\n\n        def __next__(self):\n            while True:\n                try:\n                    return self._page_iter.__next__()\n                except StopIteration:\n                    if not self._next_page_cap:\n                        raise\n                    if self._get_next_page:\n                        next_data, self._next_page_cap = self._get_next_page(self._next_page_cap)\n                    else:\n                        next_data, self._next_page_cap = anvil.server.call(\"ext.iter:\" + self._next_page_cap.scope[1],\n                                                                           self._next_page_cap)\n                    self._page_iter = iter(next_data)\n\n";