Update Controlbar in bs4dash version 2.00 Shiny - r

I have moved over to the new bs4dash and I am having some issues with updating the control bar.
For each different tab on my sidebar i would like a corresponding control bar. For example, if the sidebar tab is "Home", I would like to the controlbar to consist of multiple selectizeInputs. If however, the sidebar tab is "News", I would like the Control Bar to have different textOutputs.
Here is some of the code I am using
##UI
controlbar = dashboardControlbar(
id = "controlbar",
collapsed = T
)
##Server
observeEvent(input$current_tab,{
if(input$current_tab == "home"){
updateControlbar(id = "controlbar", session = session,
selectizeInput("one", "one", choices = c(1,2,3)
),
selectizeIntput("two", "two", choices = c(1,2,3)
} else if(input$current_tab == "News"){
updateControlbar(id = "controlbar", session = session,
textInput("news1"),
textInput("news2")
}
})
I have also tried many other combos but nothing seems to work.
Thank you for your help

You can combine conditional panels with reactive functions. This code snippet show a very trivial case.
library(shiny)
library(bs4Dash)
shinyApp(
ui = dashboardPage(
header = dashboardHeader(),
sidebar = dashboardSidebar(uiOutput("sidebar")),
body = dashboardBody(),
controlbar = dashboardControlbar(uiOutput("controlbar"))
),
server = function(input, output, session) {
output$sidebar <- renderMenu({
sidebarMenu(id = "main_menu",
menuItem(text = "First page", tabName = "tab1"),
menuItem(text = "Second page", tabName = "tab2")
)
})
output$show_tab1 <- reactive({
!is.null(input$main_menu) && input$main_menu == "tab1"
})
output$show_tab2 <- reactive({
!is.null(input$main_menu) && input$main_menu == "tab2"
})
outputOptions(output, "show_tab1", suspendWhenHidden = FALSE)
outputOptions(output, "show_tab2", suspendWhenHidden = FALSE)
output$controlbar <- renderUI({
div(
conditionalPanel(
condition = "output.show_tab1",
p("Widgets for the first page")
),
conditionalPanel(
condition = "output.show_tab2",
p("Widgets for the second page")
)
)
})
}
)

Related

Reset in Shiny applications

I am trying to clear what ever is written in the text area but looks like it not working. Based on the below applications, when the user clicks on "click" button, the contents (if written) should get cleared. But it is not. Can anyone help me here please........................................
data(mtcars)
library(shiny)
library(shinydashboard)
library(dplyr)
library(DT)
library(shinyjs)
ui <- dashboardPage(
dashboardHeader(title = "Dynamic sidebar"),
dashboardSidebar(sidebarMenu(id = "menu", sidebarMenuOutput("menu"))),
dashboardBody(tabItems
(
tabItem
(tabName = "plots", h2("Dashboard plots"),
fluidRow(column(width = 12, class = "well",
h4("Boxplot"),
plotOutput("bxp")))
),
tabItem(tabName = "dashboard", h2("Dashboard tab content"),
dataTableOutput(outputId = "subdt"),textAreaInput("sd","label1"),textAreaInput("sd1","label2") ,
actionButton("idff","click"))
)
)
)
server <- function(input, output, session) {
output$menu <- renderMenu({
sidebarMenu(
# menuItem("Plots Menu", tabName = "plots", icon = icon("line-chart")),
menuItem("Table Menu", icon = icon("info"),
menuSubItem(
"Dashboard", tabName = "dashboard", icon = icon("calendar")
),
selectInput(
inputId = "mcm", label = "Some label", multiple = TRUE,
choices = unique(mtcars$cyl), selected = unique(mtcars$cyl)
)
)
)
})
observe({
print(input$menu)
})
datsub <- reactive({
mtcars %>%
filter_at(vars("cyl"), all_vars(. %in% input$mcm))
})
output$subdt <- renderDataTable({
datatable(datsub(),selection = if(input$menu == "dashboard"){'single'} else {'none'})
# print(datatable.selection())
})
# datatable(datsub(),selection = if(input$menu == "dashboard"){'single'} else {'none'})
output$bxp <- renderPlot({
hist(rnorm(100))
})
observeEvent(input$idff,{
print("cjec")
shinyjs::reset('sd')
shinyjs::reset('sd1')
})
}
shinyApp(ui, server)
I'd suggest to update the textAreaInput as suggested in the comments. Update the event handler as follows:
observeEvent(input$idff, {
updateTextAreaInput(session = session, inputId = 'sd', value = "")
updateTextAreaInput(session = session, inputId = 'sd1', value = "")
})

sidebarMenu is not storing the right values

I have shainyApp which contains multiple dashboardPages, in each one of them i have sidebarMenu.
I am trying to get the name of the clicked tab.
That's an example code:
ui<-navbarPage("",
tabPanel("tab1",
dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(id="menu1",
menuItem("a1", icon = icon("th"),tabName = "a1",selected = T),
menuItem("a2", icon = icon("th"),tabName = "a2")
)
),
dashboardBody()
)
),
tabPanel("tab2",
dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(id="menu2",
menuItem("b1", icon = icon("th"),tabName = "b1",selected = T),
menuItem("b2", icon = icon("th"),tabName = "b2")
)
),
dashboardBody(
textOutput("text")
)
)
)
)
server <- function(input, output, session) {
output$text<-renderText({
input$menu2
})
}
shinyApp(ui,server)
The problem which I am facing is that input$menu2 has the value 'a1' at the beginning and not 'b1'
Is it a bug or am I doing something wrong here?
Appreciate your help on this
Thanks
Your program is working fine. It displays what was pre-selected in the first instance even when you go to second tab. Once you click on an item in the sidebar, say b2, it will display that until another item is clicked in the sidebar from either tab1 or tab2.
If you wish to display different plots or other information on each tab with its own sidebar, it can be done using a single dashboardPage. Just use conditionalPanel as shown below.
require(shiny)
require(shinydashboard)
require(shinyjs)
### create a simple app
ui <- dashboardPage(
title='Test Menus',
dashboardHeader(
title = 'Loading Menus'
),
dashboardSidebar(
conditionalPanel("input.navbar == 'tab1_val'",
div(id='tab1_sidebar',
#sliderInput('tab1_slider', 'tab1 slider', min=2,max=7,value=2),
sidebarMenu(id="menu1",
menuItem("a1", icon = icon("th"),tabName = "a1",selected = T),
menuItem("a2", icon = icon("th"),tabName = "a2")
)
)
),
conditionalPanel("input.navbar == 'tab2_val'",
div(id='tab2_sidebar',
#sliderInput('tab2_slider', 'tab2 slider', min=2,max=7,value=5),
sidebarMenu(id="menu2",
menuItem("b1", icon = icon("th"),tabName = "b1",selected = T),
menuItem("b2", icon = icon("th"),tabName = "b2")
)
)
)
),
dashboardBody(
useShinyjs(),
tabsetPanel(
id = "navbar",
tabPanel(title="tab1 title",id="tab1",value='tab1_val',
valueBoxOutput('tab1_valuebox'),
uiOutput("text1"),
plotOutput("plot1")
),
tabPanel(title="tab2 title",id="tab2",value='tab2_val',
valueBoxOutput('tab2_valuebox'),
uiOutput("text2"),
plotOutput("plot2")
)
)
)
)
server <- shinyServer(function(input, output, session) {
output$tab1_valuebox <- renderValueBox({
valueBox('1000',subtitle = "blah blah",icon = icon("car"),
color = "blue", print(input$menu1)
)
})
output$tab2_valuebox <- renderValueBox({
valueBox('2000',subtitle = "blah2 blah2",icon = icon("car"),
color = "red"
)
})
output$text1<-renderUI({
print(input$menu1)
})
output$text2<-renderUI({
print(input$menu2)
})
pt1 <- qplot(rnorm(500),fill=I("red"),binwidth=0.2,title="plotgraph1")
pt2 <- qplot(rnorm(600),fill=I("blue"),binwidth=0.2,title="plotgraph2")
output$plot1 = renderPlot({pt1})
output$plot2 = renderPlot({pt2})
#### on click of a tab1 valuebox
shinyjs::onclick('tab1_valuebox',expr={
# move to tab2
updateTabsetPanel(session, "navbar", 'tab2_val')
})
### on click of a tab2 valuebox
shinyjs::onclick('tab2_valuebox',expr={
# move to tab1
updateTabsetPanel(session, "navbar", 'tab1_val')
})
})
shinyApp(ui,server)
This is derived from one of two answers provided by #DeanAttali here. All credit goes to him.

How to create a conditional renderUI in Shiny dashboard

I am unable to create a conditional sidebar menu via renderMenu because the if statement fails. "Warning: Error in if: argument is of length zero".
I found conditional RenderUI R shiny and Conditional panel in Shiny dashboard but neither are what I am looking for. A conditional panel might work in this instance but in the long run I will need to be able to do this server side.
if (interactive()) {
library(ggplot2)
library(shiny)
library(shinydashboard)
library(shinipsum)
ui <- dashboardPage(
header = dashboardHeader(),
dashboardSidebar(
sidebarMenuOutput("plotDataVHA"),
sidebarMenuOutput("tabSelector")
),
dashboardBody(tabItems(
tabItem(tabName = "facilities",
fluidRow(box(
uiOutput("selectedFacilityTime")
))),
tabItem(tabName = "service",
fluidRow(box(
uiOutput("selectedFacilityYyCases")
)))
))
)
server <- function(input, output) {
output$renderedSelectedFacilityTime <- renderPlot({
random_ggplot(type = "line")
})
output$selectedFacilityTime <- renderUI({
plotOutput("renderedSelectedFacilityTime")
})
output$renderedFacilityYyCases <- renderPlot({
random_ggplot(type = "bar")
})
output$selectedFacilityYyCases <- renderUI({
plotOutput("renderedFacilityYyCases")
})
output$tabSelector <- renderMenu({
sidebarMenu(id = "test",
menuItem(
text = "Chart data",
menuSubItem(
text = "Facilities",
tabName = "facilities",
selected = TRUE
),
menuSubItem(
text = "Service & Specialty",
tabName = "service",
icon = NULL
)
))
})
output$plotDataVHA <- renderMenu({
if (input$test == "facilities") {
sidebarMenu(
menuItem(
text = "VHA data",
menuSubItem(
text = "None",
selected = TRUE,
icon = NULL
),
menuSubItem(text = "Mean", icon = NULL)
)
)
}
})
}
shinyApp(ui, server)
}
When working properly the menu "VHA data" should only be visible when the submenu "facilities" is selected.
Interesting question. The reason you were getting the argument is of length zero error is because you are rendering both menus on the server side through renderMenu(). So when the app starts, input$test doesn't have a value assigned to it. You can avoid this by using req() which will evaluate the test input$test == "facilities" only after input$test has been initiated.
Now for the menu to only appear when another submenu is selected, you want to create the menu independently of renderMenu(). It is better to evaluate the condition in a normal reactive() and then pass this reactive function as input to renderMenu(). Finally, to remove the menu when input$test == "facilities" is FALSE, you can render an empty html container.
Here is the updated code:
library(ggplot2)
library(shiny)
library(shinydashboard)
library(shinipsum)
ui <- dashboardPage(
header = dashboardHeader(),
dashboardSidebar(
sidebarMenuOutput("plotDataVHA"),
sidebarMenuOutput("tabSelector")
),
dashboardBody(tabItems(
tabItem(tabName = "facilities",
fluidRow(box(
uiOutput("selectedFacilityTime")
))),
tabItem(tabName = "service",
fluidRow(box(
uiOutput("selectedFacilityYyCases")
)))
))
)
server <- function(input, session, output) {
output$renderedSelectedFacilityTime <- renderPlot({
random_ggplot(type = "line")
})
output$selectedFacilityTime <- renderUI({
plotOutput("renderedSelectedFacilityTime")
})
output$renderedFacilityYyCases <- renderPlot({
random_ggplot(type = "bar")
})
output$selectedFacilityYyCases <- renderUI({
plotOutput("renderedFacilityYyCases")
})
output$tabSelector <- renderMenu({
sidebarMenu(id = "test",
menuItem(
text = "Chart data",
menuSubItem(
text = "Facilities",
tabName = "facilities",
selected = TRUE
),
menuSubItem(
text = "Service & Specialty",
tabName = "service",
selected = FALSE,
icon = NULL
)
))
})
make_menu <- reactive({
cat("Current submenu selected: ", input$test, "\n\n")
if (req(input$test) == "facilities") {
sidebarMenu(
menuItem(
text = "VHA data",
menuSubItem(
text = "None",
selected = TRUE,
icon = NULL
),
menuSubItem(text = "Mean", icon = NULL)
)
)
} else {
# return an empty HTML container
div()
}
})
output$plotDataVHA <- renderMenu({
make_menu()
})
}
shinyApp(ui, server)

How to add floating button in shinydashboard

I am working on something where I need a floating button in shinydashboard. Below is a code to get a floating button using shinyMaterial package.
library(shiny)
library(shinymaterial)
# Wrap shinymaterial apps in material_page
ui <- material_page(title = "Basic Page",
tags$h1("Page Content"),
material_floating_button(
input_id = "example_floating_button",
icon = "live_help",
depth = 5,
color = "red lighten-3"
)
)
server <- function(input, output) {
}
shinyApp(ui = ui, server = server)
When I am trying to use the floating button from shinymaterial library in shinydashboard, it doesn't work. Any help is appreciated, all I want if a floating button on every page..using any library.
library(shiny)
library(shinydashboard)
library(dplyr)
library("shinymaterial")
ui <- dashboardPage(
dashboardHeader(dropdownMenuOutput("notificationMenu")),
dashboardSidebar(sidebarMenu(menuItem("Page 1", tabName = "page1"),
menuItem("Page 2", tabName = "page2"))),
dashboardBody(tabItems(
tabItem(tabName = "page1", h4("This is Page 1"),
material_floating_button(
input_id = "example_floating_button",
icon = "live_help",
depth = 5,
color = "red lighten-3"
)),
tabItem(tabName = "page2",
textInput("text", "Enter News:", "New News."),
actionButton("save", "Save"))
)))
server <- function(input, output, session){
raw_news <- reactiveValues()
# Intial Header News: 1 Message from Admin
raw_news$news <- data_frame(from = "Admin", text = "this is a message")
# The notifications in header
output$notificationMenu <- renderMenu({
raw_news <- raw_news$news
dropdownMenu(
messageItem(raw_news$from[1], raw_news$text[1])
)
})
# save a new notification
observeEvent(input$save, {
raw_news$news <- data.frame(from = "User", text = input$text)
})
}
shinyApp(ui = ui, server = server)
Just use an actionButton in a fixedPanel instead.
tabItem(tabName = "page1", h4("This is Page 1"),
fixedPanel(
actionButton("test", label = "test"),
right = 10,
bottom = 10
)
),

Generic button for go to next and previous tabItem Shiny

I know this is pretty close to previously aked questions, but after thorough study of those examples I haven't found a solution for my particular problemm yet.
I have a shiny App using Shiny Dashboard with this structure (*1). I can make a next or previous page button this way:
next_btn <- actionButton( inputId ="Next1",
label = icon("arrow-right"))
with an observer :
observeEvent(input$Next1, {
updateTabItems(session, "tabs", "NAME")
})
where NAME is the tabItem ID. This version is simpler than the expamples I've found that use switch and or simply Navigate to particular sidebar menu item in ShinyDashboard?
However, this only works to switch from pagename1 to pagename2 with a specific button for it.
I have however, 10-20 tabItems in my app : ** <<- the reason for my problem**
The approach mentioned about would require me to write a actionbutton(next1, ... ac but next 2 , next 3 etc. 1 for each page, and also an separate observer for each.
What I am trying to make is this:
1 generic action button called "NEXTPAGE"
with an observer that does updateTabItems(session, tabs, "current page +1"
to to the current page +1 in whatever way I'm lost. I could imagine making a list parameter of all tab names, find the current tabname in that list, grab it's position, shift one position up (previous), or down (next) for example.
However, I do not know how to get a list variable of all tabItems present in my app, other than some very laborious manual typing of a list of strings.
*1 app structure:
library(shiny)
library(shinydashboard)
### create general button here like:
### write a function that looks at what (nth) tabItem we are, and creates a ### uiOutput for a next_n button (I can do this myself I think)
dashboardHeader(title = "FLOW C.A.R.S."),
dashboardSidebar(
sidebarMenu(id = "tabs",
menuItem("Home", tabName = "Home", icon = icon("home")),
menuItem("My Page", tabName = "MyPage", icon =icon("download")),
menuItem("Do math", tabName = "Math", icon=icon("folder-open")),
menuItem("Results of something", tabName="Results", icon=
icon("file-text-o")),
menuItem("Short Manual", tabName = "Manual", icon = icon("book"))
)
),
dashboardBody(
tabItems(
tabItem(tabName = "Home", class = 'rightAlign',
actionButton( inputId ="Next1", label = icon("arrow-right"))),
tabItem(tabName = "MyPage", class = 'rightAlign',
actionButton( inputId ="Next2", label = icon("arrow-right")),
actionButton( inputId ="Previous2", label = icon("arrow-left"))),
tabItem(tabName = "Math", class = 'rightAlign',
actionButton( inputId ="Next3", label = icon("arrow-right")),
actionButton( inputId ="Previous3", label = icon("arrow-left"))),
tabItem(tabName = "tabName", class = 'rightAlign',
actionButton( inputId ="Next4", label = icon("arrow-right")),
actionButton( inputId ="Previous4", label = icon("arrow-left"))),
tabItem(tabName = "Maual", class = 'rightAlign',
actionButton( inputId ="Previous5", label = icon("arrow-left")))
))
server:
shinyServer = function(input, output, session) {
observeEvent(input$Next1, {
updateTabItems(session, "tabs", "MyPage)
})
observeEvent(input$Previous2, {
updateTabItems(session, "tabs", "Home")
})
observeEvent(input$Next2, {
updateTabItems(session, "tabs", "Math)
})
### repeat for next2 and previous 2 , 3 etc
}
Summary, I'm looking for a code that will give us the name of the Tab coming after of before the current tab, so that we can stuff the outcome of that query into updateTabItems(session, "tabs" .......)
so that we can make a more general observer that says for instance;
if Next[i] button is clicked go to tabItem[i+1]
but like I said, I can imagine myself writing such a code, if only if I knew how to access the list of tabItems with function (obviously I have the names in the ui page since I labelled all of them, but I'm trying to avoid all the redunant repetition of code by typing it all out for each page/button/observer)
only thing I discoverd so far is that paste(input$tabs) inside an observer will give you the current tab, but then what...
thanks for anny help!
If it's unclear, please feel free to contact me
I will admit that this is not fully generalized. It requires that you place a vector in your server that has the names of the tabs from the UI. But, you really only need two buttons to make it work (not two buttons per tab). You only need to make sure that the tab_id vector has the correct names in the same order as the UI. You can probably get away with something like this if it is a small scale project where the tabs and tab names are not changing a lot.
library(shiny)
library(shinydashboard)
library(shinyjs)
### create general button here like:
### write a function that looks at what (nth) tabItem we are, and creates a ### uiOutput for a next_n button (I can do this myself I think)
shinyApp(
ui =
dashboardPage(
dashboardHeader(title = "FLOW C.A.R.S."),
dashboardSidebar(
useShinyjs(),
sidebarMenu(id = "tabs",
menuItem("Home", tabName = "Home", icon = icon("home")),
menuItem("My Page", tabName = "MyPage", icon =icon("download")),
menuItem("Do math", tabName = "Math", icon=icon("folder-open")),
menuItem("Results of something", tabName="Results", icon=
icon("file-text-o")),
menuItem("Short Manual", tabName = "Manual", icon = icon("book"))
)
),
dashboardBody(
hidden(actionButton(inputId ="Previous", label = icon("arrow-left"))),
hidden(actionButton(inputId ="Next", label = icon("arrow-right")))
)
),
server =
shinyServer(function(input, output, session){
tab_id <- c("MyPage", "Math", "Results", "Manual")
observe({
lapply(c("Next", "Previous"),
toggle,
condition = input[["tabs"]] != "Home")
})
Current <- reactiveValues(
Tab = "Home"
)
observeEvent(
input[["tabs"]],
{
Current$Tab <- input[["tabs"]]
}
)
observeEvent(
input[["Previous"]],
{
tab_id_position <- match(Current$Tab, tab_id) - 1
if (tab_id_position == 0) tab_id_position <- length(tab_id)
Current$Tab <- tab_id[tab_id_position]
updateTabItems(session, "tabs", tab_id[tab_id_position])
}
)
observeEvent(
input[["Next"]],
{
tab_id_position <- match(Current$Tab, tab_id) + 1
if (tab_id_position > length(tab_id)) tab_id_position <- 1
Current$Tab <- tab_id[tab_id_position]
updateTabItems(session, "tabs", tab_id[tab_id_position])
}
)
})
)
As i wrote in the comment:
The easiest would be for sure to rewrite the code and have an array: tabItemNames = c("Home", "MyPage",....) and then name the tabs accordingly tabItem(tabName = tabItemNames[1],...), tabItem(tabName = tabItemNames[2],... etc. That i wouldnt call redundant repition of code,...(see also Benjamin´s answer.
However, I appreciated the JS challenge and gave it a shot:
You could use JS to read the tabItemNames. That would fulfill the bonus requirement of not having to hardcode them in the code.
observe({
runjs("
function getAllElementsWithAttribute(attribute){
var matchingElements = [];
var allElements = document.getElementsByTagName('*');
for (var i = 0, n = allElements.length; i < n; i++){
if (allElements[i].getAttribute(attribute) !== null){
matchingElements.push(allElements[i]);
}
}
return matchingElements;
};
ahref = getAllElementsWithAttribute('data-toggle');
var tabNames = [];
var tabName = '';
for (var nr = 0, n = ahref.length; nr < n; nr++){
tabName = ahref[nr].hash.split('-')[2]
if(tabName != 'Toggle navigation') tabNames.push(tabName)
}
Shiny.onInputChange('tabNames', tabNames);
")
})
The assumption i make that you do not have any further element having a 'data-toggle' attribute. If this would not be fulfilled one would have to integrate further conditions in the code.
In the following a running example, build by the code above combined with the code provided by Benjamin:
library(shiny)
library(shinydashboard)
library(shinyjs)
app <- shinyApp(
ui =
dashboardPage(
dashboardHeader(title = "FLOW C.A.R.S."),
dashboardSidebar(
useShinyjs(),
sidebarMenu(id = "tabs",
menuItem("Home", tabName = "Home", icon = icon("home")),
menuItem("My Page", tabName = "MyPage", icon =icon("download")),
menuItem("Do math", tabName = "Math", icon=icon("folder-open")),
menuItem("Results of something", tabName="Results", icon=
icon("file-text-o")),
menuItem("Short Manual", tabName = "Manual", icon = icon("book"))
)
),
dashboardBody(
actionButton(inputId ="Previous", label = icon("arrow-left")),
actionButton(inputId ="Next", label = icon("arrow-right"))
)
),
server =
shinyServer(function(input, output, session){
global <- reactiveValues(tab_id = "")
tab_id <- c("Home", "MyPage", "Math", "Results", "Manual")
Current <- reactiveValues(
Tab = "Home"
)
observeEvent(
input[["tabs"]],
{
Current$Tab <- input[["tabs"]]
}
)
observeEvent(
input[["Previous"]],
{
tab_id_position <- match(Current$Tab, input$tabNames) - 1
if (tab_id_position == 0) tab_id_position <- length(input$tabNames)
Current$Tab <- input$tabNames[tab_id_position]
updateTabItems(session, "tabs", input$tabNames[tab_id_position])
}
)
observeEvent(
input[["Next"]],
{
tab_id_position <- match(Current$Tab, input$tabNames) + 1
if (tab_id_position > length(input$tabNames)) tab_id_position <- 1
Current$Tab <- input$tabNames[tab_id_position]
updateTabItems(session, "tabs", input$tabNames[tab_id_position])
}
)
observe({
runjs("
function getAllElementsWithAttribute(attribute){
var matchingElements = [];
var allElements = document.getElementsByTagName('*');
for (var i = 0, n = allElements.length; i < n; i++){
if (allElements[i].getAttribute(attribute) !== null){
matchingElements.push(allElements[i]);
}
}
return matchingElements;
};
ahref = getAllElementsWithAttribute('data-toggle');
var tabNames = [];
var tabName = '';
for (var nr = 0, n = ahref.length; nr < n; nr++){
tabName = ahref[nr].hash.split('-')[2]
if(tabName != 'Toggle navigation') tabNames.push(tabName)
}
Shiny.onInputChange('tabNames', tabNames);
")
})
})
)
runApp(app, launch.browser = TRUE)
The javascript function to read the elements I used from here: Get elements by attribute when querySelectorAll is not available without using libraries?

Resources