6 CSS for Shiny
In the previous part, we saw how to create, manipulate HTML tags with shiny and htmltools, as well as importing external web dependencies, especially CSS files. This is however far from being enough to develop apps that stand out from the pack. As introduced in <IP_ADDRESS>, CSS is a web language allowing a deep customization of the appearance. This part aims at providing an acceptable overview of CSS capabilities in the shiny context, so that you may start to seamlessly customize your apps in few times.
6.1 How to include CSS?
There are three ways to include CSS in a web page:
- Point to an external file
<link rel="stylesheet" href="style.css"/>
. - Insert the style in the
head
. Not recommended for complex projects since hard to maintain. - Insert the style at the tag level, through the
style
attribute, also known as inline CSS, and not recommended since hard to maintain.
<!DOCTYPE html>

<meta charset="utf-8" />
<link rel="stylesheet" href="style.css" />
<title>CSS</title>

Hello World

Some text

Plop

We advise to follow the first method as much as you can so that you modify the CSS in only one place! At the end of the day, your CSS script will look like the below example:
All of the above methods apply to shiny:
-
External CSS file
tags$link(rel = "stylesheet", type="text/css", href="www/style.css")
. -
Internal CSS
tags$head(tags$style("p {color: red;}"))
. -
Inline CSS
p(style = "color:red;", "Red text")
.
However, if you correctly followed the previous part about HTML dependencies, the best way in Shiny is to create a dependency, and attach it to a tag:
css_dep <- function() {
htmlDependency(
name = "css dep",
version = "1.0",
src = path_to_css,
stylesheet = filename
)
}
tagList(tag, css_dep)
Following this method, you make the file accessible on the server, thereby easing the debugging process. When should we apply the above method? Well, it does not make a lot of sense for tiny CSS modifications, where you could use one of the three other methods listed above. Moreover, it is also fine for an external dependency for which you don’t need to debug or modify the code.
6.2 CSS selectors
CSS selectors define on which elements to apply CSS rules. Below, we review the most common patterns.
6.2.1 Basics
To apply CSS, we select a tag, choose the property we want to change and give it a value:
For instance, to set the color blue to the p
tag, we would do:
Now, how would we apply the same property to multiple tags? We separate tags by a comma, also called grouping selector:
See below an example with a Shiny app:
6.2.2 Select by class, id
The method shown above applies to all selected tags. This is not necessarily what we want as we probably would like to filter. We first add a class
to the first p
tag. Best practice is to give it a meaningful name:
On the CSS side, we prefix the class by a .
:
To style unique elements, we may use id
:
As another example, the result is shown in Figure 6.1:
### RUN ###
# OSUICode::run_example(
# "css/selector-class-id"
# "package = "OSUICode"
# )
### APP CODE ###
library(shiny)
ui <- fluidPage(
tags$style(
".first-p {
color: red;
}
#element {
color: red;
}
"
),
p(class = "first-p", "Hello World"),
p("Another text"),
div(id = "element", "A block")
)
server <- function(input, output) {}
shinyApp(ui, server)
The second p
tag is not selected.
6.2.3 Apply CSS to single elements
Let’s consider the following example:
How would you change the color of the World
word? We could not select the whole p
element, as it would apply to the
whole tag. There exists specific tags like div
and span
which you can apply. As stated in chapter 1.3, span
may be used inside containers to surround words:

Hello World! What's up?

6.2.4 Advanced selectors
Until now, we’ve seen how to select an element by the tag name, a class and an id. Yet, this is not enough. How would you select the below tag?
<IP_ADDRESS> Select by attributes
To select by attribute, we use tag[attribute]
Tag
Tag
Tag
The below CSS code selects all a
tags having a data-toggle
attribute:
while the following code, will only select the first a
tag:
The reason is that we exactly match the dropdown
value!
We could be less specific:
*
checks whether the word dropdown
is there but not the position. You may use ^
and $
like you do with regular expressions to check if the value starts or ends by the specified word, respectively.
<IP_ADDRESS> Direct descendants
Let’s consider a navbarPage()
with nested navigation. This is accomplished with the navbarMenu()
function:
navbarPage(
"App Title",
tabPanel("Plot"),
navbarMenu(
"More",
tabPanel("Summary"),
"----",
"Section header",
tabPanel("Table")
)
)
The resulting HTML code is as follow:

Plot

More

Summary

Section header

Table

There are two ul
menus with multiple li
and a
inside. Applying our previous CSS selector as depicted in Figure 6.4 selects all links.
What if we only want to select the direct a
children of the outer menu, meaning we exclude the inner menu links? Using the child combinator >
, we can select direct children and not all descendant that could contain grand-children.
Result is displayed in Figure 6.5:
### RUN ###
# OSUICode::run_example(
# "css/selector-descendant"
# "package = "OSUICode"
# )
### APP CODE ###
library(shiny)
ui <- navbarPage(
"App Title",
tabPanel(
"Plot",
tags$style(
HTML(
".navbar-nav > li > a {
font-size: 20px;
font-weight: bold;
}
"
)
)
),
navbarMenu(
"More",
tabPanel("Summary"),
"----",
"Section header",
tabPanel("Table")
)
)
server <- function(input, output) {}
shinyApp(ui, server)
Well, what if we want to be even more specific and get only the very first nav link element? We have to introduce pseudo classes.
<IP_ADDRESS>.1 Pseudo-classes
A pseudo class starts with the :
symbol. For instance, a:active
styles active links and button:disabled
applies for disabled buttons.
There exists many pseudo class types, particularly the structural ones. Those are useful to select specific children like element:first-child
. Going back to the navbarPage()
example, we could refine our CSS selector adding :first-child
to the li
element as we want to only select the first item:
As expected, only the first link is styled, as demonstrated in Figure 6.6.
### RUN ###
# OSUICode::run_example(
# "css/selector-pseudoclass"
# "package = "OSUICode"
# )
### APP CODE ###
library(shiny)
ui <- navbarPage(
"App Title",
tabPanel(
"Plot",
tags$style(
HTML(
".navbar-nav > li:first-child > a {
font-size: 20px;
font-weight: bold;
}
"
)
)
),
navbarMenu(
"More",
tabPanel("Summary"),
"----",
"Section header",
tabPanel("Table")
)
)
server <- function(input, output) {}
shinyApp(ui, server)
<IP_ADDRESS>.2 Pseudo-elements
Pseudo elements are preceded by ::
. The most famous ones are ::before
and ::after
, that respectively apply before and after the selected element.
For instance .navbar-nav > li:first-child > a::before
will insert an element before the very first navbar link.
### RUN ###
# OSUICode::run_example(
# "css/selector-pseudoelement"
# "package = "OSUICode"
# )
### APP CODE ###
library(shiny)
ui <- navbarPage(
"App Title",
tabPanel(
"Plot",
tags$style(
HTML(
".navbar-nav > li:first-child > a {
font-size: 20px;
font-weight: bold;
}
.navbar-nav > li:first-child > a::before {
content: '✌'
}
"
)
)
),
navbarMenu(
"More",
tabPanel("Summary"),
"----",
"Section header",
tabPanel("Table")
)
)
server <- function(input, output) {}
shinyApp(ui, server)
As an exercise, you may change a::before
to a::after
and notice how the emoji behave in the above example.
6.3 Best practices
6.3.1 DRY principle
DRY stands for “Don’t repeat yourself”. This methodology not only applies to structural languages like R and JavaScript but also to declarative languages like CSS. Below is an example of badly managed CSS code. Both .class-1
and .class-2
have the same color and border radius. Only the padding and font size change. This type of code does not follow the DRY rule and increases the risk of having contradictory CSS properties.
.class-1{
color: #33BEFF;
padding: 10px 16px;
font-size: 12px;
border-radius: 3px;
}
.class-2{
color: #33BEFF;
padding: 5px 10px;
font-size: 12px;
border-radius: 3px;
}
We could gather all common properties in one generic class:
.generic {
color: #33BEFF;
border-radius: 3px;
}
.specific-1 {
padding: 10px 16px;
font-size: 18px;
}
.specific2 {
padding: 5px 10px;
font-size: 12px;
}
On the HTML side, we add classes from the most generic to the most specific like:
As an even more concrete example, take a look at the bulma button:
Notice how easy it is to predict the style of the button. It will be large and take the maximum width. It is for sure more meaningful than seeing a .class1
!
6.3.2 Selector specificity
What happens in case multiple different selectors target the same element? Which style is really applied? Consider the following example:
with the following CSS rules:
Can you guess what would be the element text color? Well, this is not obvious. You must understand that web browsers apply rules to select the more specific rules:
- Inline style is the most specific. This is style directly attached to the HTML tag.
-
id
applies to unique objects. -
class
,pseudoclasses
, attributes. - elements and pseudo-elements.
Going back to our previous example, the most specific selector is #element
, therefore the text color will be red. What happens in case of equality? The last written selector is applied:
Only the second selector is applied to the tag. To apply class1
, you must move it after the class2
style definition.
Best practice is to keep the lowest specificity as possible, thereby making .class
the first choice.
6.3.3 Block element modified (BEM)
The BEM methodology will help you to write meaningful CSS, easier to manage.
A block is a standalone entity having a self explanatory name like header
, checkbox
. An elements is part of the block but not standalone like menu items.
A modifier indicates a specific state of an element, for instance if a button is disabled, active, … The general scheme is defined below:
Following this methodology guaranties to have documented and meaningful classes.
6.4 Modify CSS with the HTML inspector
6.4.1 Add inline properties
- Run the following app:
ui <- fluidPage(
tags$style("p { color: red;}"),
p("Hello World")
)
server <- function(input, output, session) {}
shinyApp(ui, server)
Right click the
p
element and open the inspector. In theStyles
tab, notice theelement.style
section. This is to define inline new CSS rules for the selected item.Let’s add 2 rules by clicking inside the
element.style
container:
-
border-style: dashed
. Indicates we want a box with dashed border -
border-color: ...
. To set a border color
After typing enter, the inline CSS is automatically added in the tag element.
You probably noticed the auto suggestion feature while typing a property, as shown in Figure 6.8, being particularly handy when learning CSS.
6.4.2 View local changes
Whenever playing around with a web page style or a shiny app, it may be good to have an overview of all changes when you are satisfied about the new design.
- Run the previous shiny app example and open the inspector
- In the Styles tab, add some new CSS properties to the first p element set of rules
- Once done press enter and click on the file name located at the top-right corner of the property box
- This opens the Sources tab. In the left sidebar, right click on the file name (index) and select
Local Modifications
- This opens a
Git
like diff panel calledChanges
where you can review any change and see the previous values.
To get a deeper understanding of the different CSS options please refer to the Google documentation.
6.5 CSS in action
We review the most commonly used CSS properties such as text styling, shadows, color and background color, …
6.5.1 Text Styling
<IP_ADDRESS> Fonts
Fonts control the text appearance and may be changed as below:
In practice, we enter multiple font values, in case the end user does not have the same
font. The last values are composed of generic polices like serif
and monospace
.
For instance, Bootstrap 3 utilizes the default sans-serif
police. A neat tool to inspect the current text fonts is the HTML inspector CSS Overview tab, as shown Figure 6.10.
Custom fonts may be downloaded with @font-face
but there are few prerequisites to make them render properly:
- The file format must be correctly handled by the end user web browsers. There are currently
.ttf
(work on almost all web browser),.woff
(work on almost all web browser),.svg
(iPhone and iPad),.eot
(IE only) and.otf
(don’t work on IE). - Those files have to be downloaded which may take time.
- Most fonts are not open source.
Importantly, the font files must be accessible to the CSS file where they are called from. As another example, the below code means that the fonts
folder is located one level above the CSS file:
@font-face {
font-family: 'Framework7 Icons';
font-style: normal;
font-weight: 400;
src: url("../fonts/Framework7Icons-Regular.eot");
src: url("../fonts/Framework7Icons-Regular.woff2") format("woff2"),
url("../fonts/Framework7Icons-Regular.woff") format("woff"),
url("../fonts/Framework7Icons-Regular.ttf") format("truetype");
}
Chapters 9 and 8 exposes convenient methods to seamlessly handle Shiny app’s font.
<IP_ADDRESS> Size
To change the text size, we use the font-size
property. From there, you have two choices:
-
Relative size (first choice) like
small
,medium
, … You may also find notations like1em
(default size),1.8em
being bigger and0.5em
being smaller; as well as percentages. - Absolute size: 16px, 20px, …
In the following example, the second h1
tag is smaller than the default one, so is p
:
### RUN ###
# OSUICode::run_example(
# "css/font-size"
# "package = "OSUICode"
# )
### APP CODE ###
library(shiny)
ui <- fluidPage(
tags$style(
".smaller--h1 {
font-size: 0.75em;
}
.smaller--p {
font-size: 80%;
}
"
),
h1("Default
"),
h1(class = "smaller--h1", "Smaller
"),
p("Normal
"),
p(class = "smaller--p", "Smaller
")
)
server <- function(input, output) {}
shinyApp(ui, server)
6.5.2 Colors
We have already mentioned this property before in the previous examples. In CSS, there are four ways to apply colors to a text or to the background:
- Using the hexadecimal notation (HEX). For instance
#FFFFFF
corresponds to the white color. Given a color code, unless you already know it, the result is quite hard to predict. Could you guess what is the result of#4b0082
? - Using the rgb code. If you ever followed art courses, this is the classic system uses in painting, by mixing colors.
rgb
stands for red, green and blue. Each scale goes from 0 to 255 (256 choices), which gives a weight to each color! Why 255? Since 256256256 gives about 16 millions color, the maximum number of colors that actual screen can display. - Using the hsl convention.
hsl
stands for hue, saturation and lightness. Saturation and lightness are expressed in percentage from 0 to 100. The hue goes from red (0) to 360 (a sort of red) each time incrementing by 15. The yellow color is 60. - Using the color name like
ghostwhite
,maroon
,red
…
While rgb
and hsl
give an unlimited number of possibilities, HTML color names are not infinite.
There are many tools allowing to get each of those codes like, notably color pickers:
6.5.3 Borders and shadows
These effects may be applied to text and block elements. The easiest way to set up a border is to leverage the border
property which accepts three parameters:
- The border width in px.
- The border color with any valid CSS color like
rgb()
,red
, … - The border type, which corresponds to the border style (
none
,solid
,dotted
,dashed
,double
,groove
,ridge
,inset
andoutset
). In practice, we mostly usesolid
.
There exists other properties such as border-radius which controls the shape of the corners from top left to bottom left. The higher the value the most rounded is the corner.
If for any reason, you want to fine tune the border position, there are four properties: border-top, border-bottom, border-left and border-right.
Finally, shadows are controlled by two properties:
- text-shadow which applies a shadow to a text element (rarely used).
- box-shadow for styling blocks.
For instance:
The box-shadow
property takes four main parameters:
- The horizontal offset in px.
- The vertical offset in px.
- The blur radius value in px. The higher the more blurred.
- The shadow color.
Do you remember the shinydashboard box that we imported inside a simple shiny app in Chapter 4.3? This box has been included in the {OSUICode}
side package. Let’s add it some border and shadows:
### RUN ###
# OSUICode::run_example(
# "css/custom-box/start"
# "package = "OSUICode"
# )
### APP CODE ###
library(shiny)
library(OSUICode)
library(shinyWidgets)
ui <- fluidPage(
useShinydashboard(),
br(),
box2(
title = "Box with border",
background = "blue",
height = "400px"
)
)
server <- function(input, output) {}
shinyApp(ui, server)
The box
class is styled as follows and shown Figure 6.11:
The border-radius
of 3px indicates that the box is slightly rounded on all corners.
There is a top solid border which color is gray as well as a tiny shadow.
Let’ increase the border-radius
to 10px, change the top border to border-left
with an orange color and slightly increased thickness:
.box {
border-radius: 10px;
border-left: 6px solid #e28810;
box-shadow: 0 1px 1px rgb(0 0 0 / 10%);
}
We would like to increase the shadow effect only on mouse hover, with reasonable values. To proceed we leverage the pseudo format elements like :hover
:
The easiest way to modify the shadow style is directly inside the HTML inspector, as demonstrated on Figure 6.12. Next to the property text, there is a button to open the shadow editor. We click on it, which opens a box with input to control the shadow offset, the blur and spread parameter. We leave the effect outside the box, that is outset
unchanged. To change the color, we click on the color widget next to the rgb value which opens Figure 6.13.
We finally include this new CSS rule inside the previous app. Optionally, we may change the color of the text header to be white, to improve the contrast with the box background (See Figure 6.14):
### RUN ###
# OSUICode::run_example(
# "css/custom-box/end"
# "package = "OSUICode"
# )
### APP CODE ###
library(shiny)
library(OSUICode)
library(shinyWidgets)
ui <- fluidPage(
useShinydashboard(),
tags$style(
".box {
border-top: none;
border-radius: 10px;
border-left: 6px solid #e28810;
box-shadow: 0 1px 1px rgb(0 0 0 / 10%);
}
.box:hover {
box-shadow: 0px 8px 8px 0px rgb(0, 0, 0, 0.2);
}
.box-header {
color: #fff;
}
"
),
br(),
box2(
title = "Box with border",
background = "blue",
height = "400px"
)
)
server <- function(input, output) {}
shinyApp(ui, server)
6.5.4 Animations
Properly utilized, CSS animations are a powerful way to highlight a specific part of your app, without any line of JavaScript code. For instance, assume you have an application which requires to click on a run button after filling some parameters. You may want to indicate the user that they can click on it. However, I would recommend to play the animation once or add a disable option, as it might cause more frustration if people visit your app quite frequently.
To create an animation, one has to leverage the @keyframes
rule. This basically describes what happens and when during the animation. For instance:
Alternatively, you may also use percentages, which is more flexible as you may introduce multiple changes. The percentage is calculated based on the overall animation duration, that is, if the animation lasts 4 seconds, 50% corresponds to 2s:
@keyframes my-animation {
0% {property: value1;}
25% {property: value2;}
50% {property: value3;}
/* ... */
100% {property: value4;}
}
We try below in a simple Shiny app, where we simply change the text color from black to red:
### RUN ###
# OSUICode::run_example(
# "css/animations/basic-broken"
# "package = "OSUICode"
# )
### APP CODE ###
library(shiny)
ui <- fluidPage(
tags$head(
tags$style(
"@keyframes my-animation {
from {color: auto;}
to {color: red;}
}
h1 {
color: grey;
}
"
)
),
h1("Hello World")
)
server <- function(input, output) {}
shinyApp(ui, server)
Nothing happens. Could you spot why?
We forgot to attach the animation to the element. You may use the animation
super property or multiple properties as shown below:
element {
animation: name, duration, delay, count, ...;
/* OR */
animation-name: ...,
animation-duration: ...,
/* ... */
}
If you want to keep the last state of the animation active, use animation-fill-mode: forwards;
.
You also may want to give time to the user to open the page before playing the animation, especially if the later has a short duration. Therefore, it is often advised to specify a delay with animation-delay
.
Let’s try again below.
### RUN ###
# OSUICode::run_example(
# "css/animations/basic"
# "package = "OSUICode"
# )
### APP CODE ###
library(shiny)
ui <- fluidPage(
tags$head(
tags$style(
"@keyframes my-animation {
from {color: grey;}
to {color: red;}
}
h1 {
color: grey;
animation: my-animation 3s 2s forwards;
}
"
)
),
h1("Hello World")
)
server <- function(input, output) {}
shinyApp(ui, server)
To close this section, I propose to create a very simple Shiny app that calculates the sum of 2 numbers. It relies on a run button to update the result. The goal is to make it blink one seconds after the app starts, for 3 seconds. We first design the animation, calling it blink
. We decide to utilize the background-color
property which fills the button with green. To add more effect to the button border, we also leverage box-shadow
. Finally, we change the button text color to white, to improve the color contrast. The animation consists in one steps, that is, at 50% of the animation, we apply a green background and add box shadow to the element. As an exercise, you may add more steps with extra colors for a smoother transition. The code is found below.
@keyframes blink {
50% {
background-color: #16a520;
box-shadow: 0 0 10px 2px #16a520;
color: white;
}
}
We apply the animation with a delay of second, each cycle lasts one second, repeated three times:
Notice the fourth parameter which corresponds to the animation-timing-function
property. It controls the animation speed curve. Passing it the linear
value ensures a smoother transition than using the default ease
. The whole code is shown below.
### RUN ###
# OSUICode::run_example(
# "css/animations/blink"
# "package = "OSUICode"
# )
### APP CODE ###
library(shiny)
ui <- fluidPage(
tags$head(
tags$style(
"@keyframes blink {
50% {
background-color: #16a520;
box-shadow: 0 0 10px 2px #16a520;
color: white;
}
}
.blink-green {
animation: blink 1s 1s 3 linear;
}
"
)
),
numericInput("number_1", "Number 1", 1),
numericInput("number_2", "Number 2", 1),
actionButton("calculate", "Click", class = "blink-green"),
textOutput("sum")
)
server <- function(input, output) {
output$sum <- renderText({
input$calculate
isolate({
input$number_1 + input$number_2
})
})
}
shinyApp(ui, server)
6.5.5 Layout
As mentioned in section 1.3, there exists block
and inline
tags. While block elements are displayed under each other, inline elements are added next to each others, as shown in Figure 6.15.
CSS allows deep customization of block elements like setting up the width, height and margin. Let’s review them below.
<IP_ADDRESS> Style blocks
As shown Figure 6.16, a block tag may be seen as a box. CSS allows to set internal and external margins. Internal margins, also called padding, is the space between the block border and the content, in all directions. External margins also known as margin are all spaces between blocks in all directions. A block is also defined by a width and height as well as optional minimal width and height. Width and height may be set either using absolute unites (px) or relative unites(%) but minimal values are always absolute. Minimal values are useful in case the end user resizes the windows.
The corresponding CSS properties are found below:
Padding and margins are called CSS super properties. Indeed, setting padding: 10px
guarantees to have 10px in all directions. If you need custom values, you will have to specify the directions:
There exists a shortcut margin: 5px 0 5px 2
that means 5px on the top, 0 px on the right, 5 px on the bottom and 2px on the left. To remember about the good order, it is clockwise (top, right, bottom, left). Specifying only 2 values margin: 5px 2.5px
means 5px top and bottom, 2.5px left and right. All of the above obviously applies to padding!
Using margin allows to center a block when margin: auto
is applied in combination with a given width.
What happens when the content inside a block is bigger than the block itself?
We apply the overflow super property that acts either horizontally or vertically. To have only vertical overflow, choose overflow-y
. The overflow property has four possible values:
- visible shows the content.
- hidden hides the content that goes outside the block.
- scroll shows scrolling bars in all directions to see the hidden content.
- auto let the web browser decide.
Let’s apply our newly acquired knowledge to a simple shiny app.
### RUN ###
# OSUICode::run_example(
# "css/layout/blocks"
# "package = "OSUICode"
# )
### APP CODE ###
library(shiny)
ui <- fluidPage(
tags$style(
".block {
border-color: #00000;
border-style: solid;
background-color: lightblue;
text-align: center;
margin: 10px;
min-height: 200px;
width: 200px;
}
span, a {
background-color: orange;
}
"
),
div(
class = "block",
"Block 1",
br(),
span("Inline text 1"), span("Inline text 2")
),
div(
class = "block",
"Block 2",
br(),
lapply(1:2, a, href = "https://www.google.com/", "Link")
),
div(
class = "block",
"Block 3",
lapply(1:5, span, "Inline text")
)
)
server <- function(input, output) {}
shinyApp(ui, server)
Well, is that all? I could to better by combining fluidRow
and column
! Indeed, those two functions are part of the grid system built on top of flexbox. Let’s talk about this in the next section.
<IP_ADDRESS> Flexbox
The flexbox (“flexible boxes”) model is a game changer in layout development as it allows to seamlessly:
- Align items in a container.
- Ensure those items fill the same space.
The first step is to define the main container and give the flex value to the display property:
Once done, we have to define the direction, that is flex-direction with four choices, as shown Figure 6.17:
- row
- row-reverse
- column
- column-reverse
Below is an example involving shiny. We first define the container CSS where display: flex
and flex-direction: row
set the flexbox display. We also add a border to better see the container limits:
Then, we define the style for container elements, that are p
tags. We give them a width and height to better see the blocks. Each child has a given background color with the :nth-child(n)
pseudo class. As an exercise, you may try to replace the flex-direction
by any of the four values and see how blocks move in the main container:
### RUN ###
# OSUICode::run_example(
# "css/layout/flexbox"
# "package = "OSUICode"
# )
### APP CODE ###
library(shiny)
ui <- fluidPage(
tags$style(
".container {
display: flex;
flex-direction: row-reverse;
border: red dashed 2px;
}
p {
width: 200px;
height: 200px;
text-align: center;
color: white;
font-size: 50px;
}
.container :nth-child(1) {
background-color: green;
}
.container :nth-child(2) {
background-color: orange;
}
.container :nth-child(3) {
background-color: purple;
}
"
),
div(
class = "container",
p("A"),
p("B"),
p("C")
)
)
server <- function(input, output) {}
shinyApp(ui, server)
The flex-wrap property may be useful to control how blocks are arranged:
- nowrap (default) put all items on the same row.
- wrap put items on multiple lines from top to bottom.
- wrap-reverse put items on multiple lines from bottom to top.
Interestingly, both flex-wrap
and flex-direction
may be merged with flex-flow: direction wrap mode
.
Items may be aligned either on the principal axis defined in the container CSS or on the secondary axis, called cross-axis:
-
justify-content that may take the following values
flex-start
(default),flex-end
,center
,space-between
,space-around
andspace-evenly
. -
align-items whose values can be
stretch
(default),flex-start
,flex-end
,center
andbaseline
.
justify-content
and align-items
are applied at the container level and not on individual items! Whenever the container has multiple line, as a result of a flex-wrap: wrap
or flex-flow: ... wrap
, we use align-content
to align on the cross-axis (flex-start, flex-end, center, stretch by default, space-between, space-around).
flexbox is a mono dimensional system.
<IP_ADDRESS> Grid model
As mentioned above, fluidRow
and column
leverage the Bootstrap grid system, that uses flexbox. This is unfortunately rather complex and out of the scope of this book.
6.5.6 Responsive design: media queries
At the very beginning of the web, there was no smart phones or tablets. All websites were mostly designed to be display on fix computer screens. Everything has changed now, which leads to several problems for non responsive sites.
Media queries are convenient to solve this issue. They allow to setup rules depending on various conditions. The structure is defined as follows:
For instance, assuming you want to increase the text size, only for mobile devices:
all
stands for all screen sizes and the second request target devices having a width
of 480px, at most.
In a shiny app this would give:
### RUN ###
# OSUICode::run_example(
# "css/media-queries/basic"
# "package = "OSUICode"
# )
### APP CODE ###
library(shiny)
ui <- fluidPage(
tags$style(
"@media all and (max-device-width: 480px) {
p {
font-size: 1.5em;
}
}
"
),
p("Hello World")
)
server <- function(input, output) {}
shinyApp(ui, server)
As shown on Figure 6.18, the developer tools have a responsive mode,
which you can enable by clicking on the blue button next to the Elements
tabs.
The responsive mode lets you define the viewport dimensions, that is the height and width of the web browser page, so as to test the media queries. We set the width to 480 so that the text size appears increased. You may try with 481px and see that this text becomes smaller. Be careful, the responsive mode tool does not display the web browser navigation bars, nor the status bar (the bar containing the battery icon and various indicators). Be sure to select the ...
icon to enable the show media queries
and show rulers
options. The media query option provides a better visualization of the media query range versus the current screen width, while the ruler helps to fine tune the design.
Let’s consider another example, involving shiny::modalDialog
. This function displays
a Bootstrap 3 modal, whose design is partly controlled by media queries. We run the app below and open the developer tools:
### RUN ###
# OSUICode::run_example(
# "css/media-queries/modal"
# "package = "OSUICode"
# )
### APP CODE ###
library(shiny)
shinyApp(
ui = fluidPage(
actionButton("show", "Show modal dialog")
),
server = function(input, output) {
observeEvent(input$show, {
showModal(
modalDialog(
title = "Important message",
"This is an important message!"
)
)
})
}
)
The corresponding CSS rules are located in the Bootstrap (3) CSS file:
@media (min-width: 768px) {
.modal-dialog {
width: 600px;
margin: 30px auto;
}
.modal-content {
-webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
}
.modal-sm {
width: 300px;
}
}
@media (min-width: 992px) {
.modal-lg {
width: 900px;
}
}
The first query fixes a width of 600px for all modals having the .modal-dialog
class (default), as long as the screen size is at least 768px. Moreover, if the modal has the modal-sm
class, its width is set to 300px. Finally, as soon as the screen width is higher or equal to 992 px, all modals having the .modal-lg
class have a width set to 900px.
Figure 6.19 illustrates the modal responsiveness.
In Figure 6.20, we changed the modal size from s
to l
(top and bottom, respectively).
This has strong implications for the modal size on mobiles. As long as the screen size is lower than 768px, the size parameter is ignored!


CUROLOGY
HOME
SHOP
LEARN
CONTACT
CART
0
Contact us
353 Sacramento St
San Francisco, CA 94111
<EMAIL_ADDRESS>First Name
Email address
We'll never share your email with anyone else.
Subject
Message
SEND


|
QSense Sidecar Library
1.0.0
Developed for QSense
|
This class contains a number of static methods to convert between big-endian and little-endian integers of various sizes. More...
#include <ByteOrder.h>
Static Public Member Functions | |
| static int16_t | flipBytes (int16_t value) |
| static uint16_t | flipBytes (uint16_t value) |
| static int32_t | flipBytes (int32_t value) |
| static uint32_t | flipBytes (uint32_t value) |
| static int64_t | flipBytes (int64_t value) |
| static uint64_t | flipBytes (uint64_t value) |
| static int16_t | toBigEndian (int16_t value) |
| static uint16_t | toBigEndian (uint16_t value) |
| static int32_t | toBigEndian (int32_t value) |
| static uint32_t | toBigEndian (uint32_t value) |
| static int64_t | toBigEndian (int64_t value) |
| static uint64_t | toBigEndian (uint64_t value) |
| static int16_t | fromBigEndian (int16_t value) |
| static uint16_t | fromBigEndian (uint16_t value) |
| static int32_t | fromBigEndian (int32_t value) |
| static uint32_t | fromBigEndian (uint32_t value) |
| static int64_t | fromBigEndian (int64_t value) |
| static uint64_t | fromBigEndian (uint64_t value) |
| static int16_t | toLittleEndian (int16_t value) |
| static uint16_t | toLittleEndian (uint16_t value) |
| static int32_t | toLittleEndian (int32_t value) |
| static uint32_t | toLittleEndian (uint32_t value) |
| static int64_t | toLittleEndian (int64_t value) |
| static uint64_t | toLittleEndian (uint64_t value) |
| static int16_t | fromLittleEndian (int16_t value) |
| static uint16_t | fromLittleEndian (uint16_t value) |
| static int32_t | fromLittleEndian (int32_t value) |
| static uint32_t | fromLittleEndian (uint32_t value) |
| static int64_t | fromLittleEndian (int64_t value) |
| static uint64_t | fromLittleEndian (uint64_t value) |
| static int16_t | toNetwork (int16_t value) |
| static uint16_t | toNetwork (uint16_t value) |
| static int32_t | toNetwork (int32_t value) |
| static uint32_t | toNetwork (uint32_t value) |
| static int64_t | toNetwork (int64_t value) |
| static uint64_t | toNetwork (uint64_t value) |
| static int16_t | fromNetwork (int16_t value) |
| static uint16_t | fromNetwork (uint16_t value) |
| static int32_t | fromNetwork (int32_t value) |
| static uint32_t | fromNetwork (uint32_t value) |
| static int64_t | fromNetwork (int64_t value) |
| static uint64_t | fromNetwork (uint64_t value) |
This class contains a number of static methods to convert between big-endian and little-endian integers of various sizes.
|
inlinestatic |
|
inlinestatic |
|
inlinestatic |
|
inlinestatic |
|
inlinestatic |
|
inlinestatic |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |


Simple Buddha Bowl
A Simple Plant-Based Protein-Iron Bowl with Vitamin C for more effectivity!
INGREDIENTS
1/2 cup Squash - boiled
10 Sweet Potato Leaves - boiled
1/4 cup Soy Bean Sprouts - boiled
1 cube Tofu - cubed into 27 cubes
1 small can of Button Mushrooms - sliced into halves
1/4 cup Black Beans
2 Tomatoes - chopped
10 Chinese Celery Leaves
1 cup Rice
FOR TOFU SAUCE:
> 30g Oyster Sauce
> 1/2 tbsp Lemon/Calamansi Juice
> 1 tbsp Honey


|
Name
|
Type
|
Description
|
| taskId | xsd:string |
Unique identifier of the task this progress report is for.
|
| vsanDataEfficiencyConfig | VsanDataEfficiencyConfig |
The data efficiency config for vSAN.
|
| vsanDataEncryptionConfig | VsanHostEncryptionInfo |
The data encryption config that will be used to bootstrap single node
vSAN cluster.
Right now only vSAN encryption with AWS KMS running in VMware Cloud
on AWS is supported. This is for VMware internal use. Caller needs
to specify the KMS server address "arn:aws:kms" to indicate AWS KMS
is used for vSAN encryption and credentials will be automatically
configured by vSAN when running in VMC.
Since vSAN API VMC M5
|
| vsanDiskMappingCreationSpec | VimVsanHostDiskMappingCreationSpec |
If set, this is used to call InitializeDiskMappings() to create vSAN disk
groups. If not set, Vcsa Deployer will skip claiming disks.
|
|
Properties inherited from DynamicData |
| None |


These release notes cover new developer and user-facing incompatibilities, important issues, features, and major improvements.
I'm trying to use ElasticsearchSink with Flink 0.10.2 and Elasticsearch 2.2.0, and I'm having the following error:
java.lang.NoClassDefFoundError: org/elasticsearch/common/settings/ImmutableSettings at org.apache.flink.streaming.connectors.elasticsearch.ElasticsearchSink.open(ElasticsearchSink.java:177) at org.apache.flink.api.common.functions.util.FunctionUtils.openFunction(FunctionUtils.java:36) at org.apache.flink.streaming.api.operators.AbstractUdfStreamOperator.open(AbstractUdfStreamOperator.java:89) at org.apache.flink.streaming.runtime.tasks.StreamTask.openAllOperators(StreamTask.java:286) at org.apache.flink.streaming.runtime.tasks.StreamTask.invoke(StreamTask.java:213) at org.apache.flink.runtime.taskmanager.Task.run(Task.java:584) at java.lang.Thread.run(Thread.java:745)
The problem seems to be the use of the class ImmutableSettings, that has been removed since Elastisearch 2.0. I imagine that with previous versions of Elasticsearch (i.e: 1.7.1) it will work correctly.
Reference: https://github.com/elastic/elasticsearch/issues/13151
Thanks in advanced,
Carlos


Covid-19 has changed many lives. More and more people are working from home and studying from home through the internet. Social medias and other applications have become the norm. I decided to take computer engineering as I found it evolving everyday. It is interesting to note computers are here to stay. I am a confident young man who has a strong interest in aeroplanes. Besides that, I have an interest in music and I can play the piano. I am currently taking the grade 8 piano exam. I strongly believe that I possess good leadership qualities and communication skills since young as I have been assigned with various leadership roles through my schooling years. Over the years, I grew to become a better leader and I believe I have the ability and maturity to guide my peers. Also, I am able to speak in 3 languages namely English, Tamil and Malayalam.
It is a premium program that allows scope for engineering academics. Through this program, I will be able to gain new skills and create new innovations for the world to enjoy. It will not be a routine work and one can take pride in building a better place for the world. Every problem in engineering is a challenge which gives one to grow out from it. Hence, I take this opportunity to join this program to improve myself to be a better person.


--- layout: post title: How I Shot The Time-Lapse date: 2010-07-16 03:40:00.000000000 -07:00 type: post published: true status: publish categories: [] tags: [] meta: {} author: ---
I've always wanted to do a time-lapse but didn't want to shell out the money for the intervalometer from Canon. So what, i did was just hook up my Canon 5D Mk II to my laptop and used Canon's EOS Utility, which pretty much allows you to do the same thing. I had it shoot continuously from 7:30pm to about 9:30pm in 5 second intervals. I ended up with around 1450 shots. I first tried putting together the video at 15fps, which ended up being kind of choppy. 24fps yielded one minute of footage but wasn't fluid enough, so I went with 30fps.
One thing I did learn though, was to not use auto-focus. You can notice a shift in the focusing when it starts to get darker. Overall though, I'm happy with the results and will definitely give this another shot sometime soon.
.


microscopes.irm.model.
state
¶The underlying state of an Infinite Relational Model.
You should not explicitly construct a state object.
Instead, use initialize()
.
Notes
This class is not meant to be sub-classed.
assignments
(self, int domain)¶empty_groups
(self, int domain)¶entity_data_positions
(self, int domain, int eid, relations)¶get_domain_hp
(self, int domain)¶get_relation_hp
(self, int relation)¶get_suffstats
(self, int relation, gids)¶groups
(self, int domain)¶groupsize
(self, int domain, int gid)¶isactivegroup
(self, int domain, int gid)¶models
(self)¶ndomains
(self)¶nentities
(self, int domain)¶ngroups
(self, int domain)¶nrelations
(self)¶score_assignment
(self, int domain)¶score_likelihood
(self, rng r)¶serialize
(self)¶set_domain_hp
(self, int domain, dict d)¶set_relation_hp
(self, int relation, dict d)¶microscopes.irm.model.
initialize
(model_definition defn, data, rng r, **kwargs)¶Initialize state to a random, valid point in the state space
| Parameters: | defn : model definition data : list of relation dataviews rng : random state |
|---|
microscopes.irm.model.
bind
(state s, int domain, relations)¶microscopes.irm.model.
deserialize
(model_definition defn, bytes)¶Restore a state object from a bytestring representation.
Note that a serialized representation of a state object does not contain its own structural definition.
| Parameters: | defn : model definition bytes : bytestring representation |
|---|


Portfolio - Handbags
Chain Gang:
Miss Manor:
Sail Away:
Graphic Totes:
Glow:
Puffer:
Home
Resume
Portfolio
Handbags
Shoes
Press
Artwork
Awards
Styling
Contact Me
Contact:
Charis
© Copyright 2005-2009. All rights reserved.


Before Change
combined[:, :other.signal_length] -= other.audio_data
else:
combined = np.copy(other.audio_data)
combined[:, :self.signal_length] -= self.audio_data
return AudioSignal(audio_data_array=combined)
def _verify_audio(self, other, op):
After Change
return self.add(other)
def __sub__(self, other):
return self.subtract(other)
def _verify_audio(self, other):
if self.num_channels != other.num_channels:
raise Exception("Cannot do operation with two signals that have a different number of channels!")


COALITION TO PROTECT CONTRACTORS (MOTTO: RESTORATION OF EQUITY AND JUSTICE) 108 COLLEGE ROAD, HARROW MIDDLESEX, ENGLAND HA1 2DB FAX: 44-70401-22568, TEL: 44-70401-22568, E-mail<EMAIL_ADDRESS>Sir, RE: YOUR OUTSTANDING PAYMENT The Coalition to Protect Contractors is a Non-Government Organization (NGO) formed in March 2006 by a group of activists, patriots and like-minds to protect the rights of Foreign Contractors in Africa. We have also extended our scope to include pursuit of payments for money inherited from the deceased. We are operating from United Kingdom at the moment for tactical reasons and have resolved to ensure justice is done for the money being owed you for long because of the unscrupulous activities, misdeeds, irregularities, exploitation, extortion, mess and disappointments by many questionable and unscrupulous characters in these African countries. Many Foreigners are being owed or purported to be owed in African countries for Contracts they have satisfactorily completed or for funds they have inherited from the deceased. The processes of claiming the unpaid sums have been very tortuous, stressful and frustrating. Your payment is pending. All manner of people have contacted you. We will ens ure all people that exto Stop any form of correspondence with any office/official with immediate effect and never pay one cent to any person again. Reply immediately providing/reconfirming the following information to facilitate our work - How much are you purported to be owed? State the origin, e.g. executed contract, inheritance e.t.c. Where is your money coming from; South Africa, Nigeria, Togo, Ghana, Ivory Coast, e.t.c? What is the Contract Amount or Reference Number of Transaction? Provide your Receiving Bank Information. Have you been made to travel in the course of pursuing your payment? Have you received any part payment at all? Have you received any bogus Draft, Cheque or in deed any other instrument? Was there any attempt to pay you with the so-called defaced cash? How long have you been pursuing your payment? How much money have they extorted from you? Do you have any pending case in court to this effect? Provide your direct telephone and fax numbers. It will be practically impossible t o make an y progress on your case Yours Sincerely, Chief Anthony Enahoro. JP Coordinator, Coalition to protect Contractors/Inheritances beneficiaries


Legato's goal is to simplify IoT development. We're hoping you'll find the dev environment and app framework so easy to use, you won't need the docs too much. But when you do need to refer to the docs, this info might be useful:
We have a less is more approach to docs' conventions. We abbreviate, use contractions, and focus on key words. Our formatting is clean and simple. Our language is informal and direct.
Copyright (C) Sierra Wireless Inc. Use of this work is subject to license.


Purpose
Some nets cannot be checked because they are too small to be shrunk, or limitations of the algorithm caused the process to abort.
Function
To report nets that could not be processed, and should be checked manually or with the bottleneck test.
Activation
Set positive value to Over Etch parameter.
Known Limitations


Supporting Rust by using Rust
An exploration of great command line tools
Melbourne Rust Meetup
Tue 26 Sep 2017
Rust is great
What is a Rust tool?
Why Rust tools are great
-
Performance
Fast and efficient with resources -
No runtime
Few runtime dependencies -
Cross Platform
Supports all major platforms
Why Rust tools are great
-
Easy to install
Package manager orcargo install
-
Usable
Provide a nice interface
Demos
watchexec
Executes commands in response to file modifications
ripgrep
The usability of The Silver Searcher with the raw speed of [GNU] grep
.
You can build tools too!
- If you use a tool that is frustrating to install due to runtime requirements or dependency issues, perhaps it's a candidate for a Rust version.
- Maybe you use a tool that is error prone or could benefit from fearless concurrency.
Conclusion
- You can help spread Rust by using tools written in Rust
- There's already a stack of great tools out there
- Lots of opportunity to write your own tools


Admin 4B is an open source admin template built on top of Bootstrap 4. The source code can be found on the GitHub repo.
This template uses many bootstrap features, so you need to have some knowledge in this toolkit. Before you continue, please, take a look at the bootstrap documentation.
The admin4b.min.*
is a template bundle that already includes jQuery, Bootstrap, Popper and Admin 4B theming and plugins.
For the template icons you can use Simple Line Icons or Font Awesome.
For the template work properly you need to add Bootstrap dependencies manually: jQuery and Popper. Also, you need to add Font Awesome CSS file.
Copy-paste the stylesheet <link>
into your <head>
after the font stylesheets to load our CSS.
Place the following <script>
tags near the end of your pages, right before the closing
<body>
tag.
An example code of the initial setup can be seen below.
All components (including bootstrap) are automatically initialized by the template.


--- layout: page title: Introducing OpenElections Developer Geoff Hing date: 2014-02-11 22:31:42.000000000 -05:00 type: page parent_id: '0' published: true password: '' status: publish categories: [] tags: [] meta: _edit_last: '43578620' _wp_page_template: default _publicize_pending: '1' author: login: openelections email<EMAIL_ADDRESS>display_name: openelections first_name: '' last_name: '' ---
The OpenElections team is very pleased to welcome Geoff Hing as our newest staff member. In his role as OpenElections Developer, Geoff will be working closely with Derek and Serdar on the core architecture of the project, as well as overseeing and assisting volunteer coders as they help wrangle election data from across the country.
Geoff is a technologist and cultural worker who lives in Chicago. He works developing technologies that intersect with community information needs, civic data and participatory governance. His work reflects connections with engineering, journalism and do-it-yourself culture. He joins us from recent work for Floodlight Project and The Work Department. In the past he has done data-driven technology projects with Food Genius and Metro Chicago Information Center. @geoffhing
Welcome aboard, Geoff!


This document provides detailed information for developers that wish to compile and make changes to the Openfire source code.
For additional developer resources, please visit: http://www.igniterealtime.org. The Openfire build process is based on Ant. Visit the Ant website for more information. There is no need to download and install Ant - a version of it is included in this distribution.
This documentation is divided into three sections:
You can get the Openfire source code by downloading a source distribution or by checking out the source code from CVS. Instructions for both options can be found on the source page.
Getting your machine ready for development requires a few steps. Wherever possible, instructions are provided for both Unix/Linux and Windows users.
Important! -- the Openfire build tool needs to know where Java is installed on your system. You must configure the "JAVA_HOME" environment variable to point to the correct directory. Instructions on how to set this variable for various platforms are as follows:
export JAVA_HOME=/usr/local/jdk1.5
The value "/usr/local/jdk1.5" should be replaced with your actual Java directory. Be sure there are no spaces after the end of the directory name. Do not add an extra slash after the directory name.
source .profile
The JAVA_HOME variable should now be configured correctly.
set JAVA_HOME=c:\jdk1.5
The value "c:\jdk1.5" should be replaced with your actual Java directory. Be sure there are no spaces between the "=" sign or after the end of the directory name. Do not add an extra slash after the directory name.
The Openfire build process uses Ant, so that tool must be installed and configured on your computer. First download Ant from: http://ant.apache.org. Next, follow the installation instructions.
Linux/Unix users only:You must make the ant script
executable. From the build directory, type:
chmod u+x ant
|
Now, invoke the build tool to compile the Openfire source code
Windows: ant
Unix/Linux: ./ant
If the build tool is invoked correctly and Openfire compiles, you've correctly configured your copy of the Openfire source distribution.
Finished!
The list of common build tasks is below. All build commands should be
run from the "build" directory of your Openfire distribution.
For a full list of the commands and a brief description from the command line, type
ant -projecthelp
. For more complete help on several commands,
read the documentation below.
To execute a build task, type ant [options] targetname
where "targetname" is
one of the targets listed below:
Each task is documented with a syntax guide and description. Optional paramaters for each task are enclosed with braces. If you would like to permanently set the value of a property, add it to build/build.xml file.
ant
Description:
Equivalent of calling "ant openfire".
ant openfire
Description:
Builds Openfire into the target/openfire directory. You can then launch Openfire using the scripts in target/openfire/bin.
ant plugins
Description:
Builds all plugins into the target/openfire/plugins directory.
ant clean
Description:
Cleans all artifacts of the build process.


SLATE
Your personal docket
CREATE AN ACCOUNT
Username
Email
Password
Sign Up
send
Already have an account ?. Click here to log in.


[1]
Cheap, small, great sound; Problems with large audio book tracks
[2]
sound quality, size, screen, price; side earphone plug in
[3]
Excellent sound, frequent firmware updates, MTP or MSC mode; Doesn't update playcount on device


{% extends "master.html" %} {% block title %} Most Viewed Reports on EveryCRSReport.com {% endblock %} {% block head %} {% endblock %} {% block body %}
These are the top reports viewed on EveryCRSReport.com each week, updated every Monday.
{% for week in most_viewed_reports %}{{loop.index}}. {{report.versions[0].title}} {{report.number}}


Reminder: The Pokémon Sword And Shield Maximus Cup Is Now Live In Tetris 99
Secure that theme
by Liam DoolanUpdate: As a reminder, the ninth Tetris Maximus Cup is now live, giving players the chance to earn a lovely Pokémon Sword And Shield theme. More details below.
Original Article (Fri 1st Nov, 2019 01:15 GMT): This month sees the release of Pokémon Sword and Shield on the Nintendo Switch. Before you enter the Galar Region on 15th November, Nintendo will be hosting a special Pokémon Maximus Cup in its online battle royale title, Tetris 99.
Here's the official announcement from the Nintendo Versus Twitter account:
This event starts next week on 7th November and will run until 11th November. If you participate and earn 100 event points, you'll unlock the special Sword and Shield custom theme, which you can see in the above video.
Will you be taking part in this event? Leave a comment below.
[via twitter.com]


LICENSE TO KILL A film review by Mark R. Leeper Copyright 1989 Mark R. Leeper
Capsule review: More action, less campy self-parody is the by-word of the latest Bond film. There is almost too little humor in this hard-edged adventure film involving Bond's vendetta against a Panamanian drug lord. Rating: +2.
Operative 007 had been getting older and softer as the series progressed. The series had lost its hard edge. In the early days, Bond was a sort of all-purpose thug for the good guys fighting people who were basically grandiose hoods toppling missiles or holding cities for ransom. Later he lost the hard edge and became a sort of fop. His foes were people wanting to start nuclear wars and/or kill everyone in the world. And the stories became more campy and more silly, with more idiotic special equipment and more and more obvious product placements. Around the time they made MOONRAKER, the series hit bottom. After MOONRAKER, somebody must have seen that the series needed rethinking. Since then the plots have been better constructed, but there has been an uneasy blend of the tongue-in- cheek with some tighter storylines. The choice of Timothy Dalton, with a face like a Swiss Army knife and a sharp edge to match fueled speculation that the series was going back to hard adventure. LICENSE TO KILL is the least fanciful Bond film ever made. James Bond is no longer the lucky but greying fop; he is young and vital and angry. But for a couple of stagey stunts toward the end of the film, this is a surprisingly serious action film.
There is a lot of story in this 133-minute film. Even the pre-credit action sequence advances the main story. It is rare that it ever does and this time it really is an integral part of the plot. Bond is helping old friend Felix Leiter(played by David Hedison, who becomes the first actor to play the role twice) catch Sanchez, a Central American drug lord. Things go extremely wrong and Bond finds he has a serious vendetta against Sanchez (played by Robert Davi, whose pockmarked face adds a touch of realism). Bond must track the drug lord to Panama (thinly disguised under the name Isthmus) where Sanchez ruthlessly holds his own empire through schemes involving drug-running, evangelists, and Contras.
The credit sequence is once again stunning in spite of the instantly forgettable credit song by Gladys Knight. Michael Kamen's score is not up to the classic John Barry efforts, but it gets the job done. Some aerial stunts are impressive though driving stunts tend to be a weak point in the film. The characters lack some of the interest value of those in FROM RUSSIA WITH LOVE, the only other Bond film with any credibility. LICENSE TO KILL is a sign that the Bond series is improving. I give it a +2 on the -4 to +4 scale.
Mark R. Leeper att!mtgzx!leeper<EMAIL_ADDRESS>The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


Options
top, left, right, bottom, center
head, body, right, middle, side
up, down, left, right, middle
inside, outside, forward, backward, center
Ans:
top, left, right, bottom, center


Here is a static content, this page is just pure html.
Note that comment time & date are shown fully while example1 show them relatively


Some of my work experiences will be listed below
Assist in implementing action plans that meet service expectations and balance task completion within guidelines.
Demonstrate behaviors that align with the company values of Accountability, Collaboration, Humility, and Passion.
Partner with the management team to understand daily/weekly/monthly store priorities and participate in and support merchandise placement, the #prepped process, and store recovery.
Participate in monitoring associate compliance to all company policies and procedures as well as adherence to Loss Prevention Standards.
Assist in assigned projects and tasks to support service levels which include opening and closing the store.
Help maintain smooth administrative operations for UW Women’s Center, including assisting with ProCard reconciliation and documentation, data entry, filing, and upkeep of shared spaces. Manage front desk including, greeting visitors, providing Center and campus resources to WC visitors, and routing phone calls. Assist Administrator in the management of office projects and communication to other student staff. Assist Women’s Center Executive Director in a variety of capacities, including, correspondence, filing, online research, scheduling, and help with special events and publications; organization and management of daily, weekly and quarterly tasks and projects.
Provide excellent customer service to ensure great in store experience. Operate cash registers, collect cash and receipts with a high degree of accuracy. Responsible for maintaining the appearance of the store and selling, stocking, and merchandising products. Train and mentor new employees to bring up to speed and work with established employees to improve performance.


If checked, the plug-in default view is set to the original view where tests are sorted by package. If left unchecked, the new view where tests are sorted by suite is used.
A button will always be available to switch between the two views, this option only sets the default behavior.


Combines RunDLL32.exe and Shell32.dll exported functions to execute another executable
Autoruns prior to 13.80 would display Shell32.dll as the persisted binary
Shell32.dll Overview
Provides much of explorer.exe functionality (open as, running execs, etc)
Exports a ton of useful functions that can load DLLs and execute applications
ShellExec_RunDLL, Control_RunDLL, DllInstall, etc
Signed Microsoft binary
AutoRuns 13.80
Stopped parsing parameters
Autoruns will show Rundll32.exe as the persisted executable
Many legitimate applications use Rundll32.exe to persist a DLL
Persisted Rundll is now more obvious, but requires understanding what is legit and what is malicious


Boilerplate
Etymology
"Boiler plate" originally referred to the maker's label used to identify the builder of steam boilers.[1]
In the field of printing, the term dates back to the early 1900s. From the 1890s onwards, printing plates of text for widespread reproduction such as advertisements or syndicated columns were cast or stamped in steel (instead of the much softer and less durable lead alloys used otherwise) ready for the printing press and distributed to newspapers around the United States. By analogy, they came to be known as 'boilerplates'. One large supplier to newspapers of this kind of boilerplate was the Western Newspaper Union, which supplied "ready-to-print stories [which] contained national or international news" to papers with smaller geographic footprints, which could include advertisements pre-printed next to the conventional content.[2]
Some companies also sent out press releases as boilerplate so that they had to be printed as written. The modern equivalent is the press release boilerplate, or "boiler," a paragraph or two that describes the company and its products.
Boilerplate Language
In contractual law, the term "boilerplate language" describes the parts of a contract that are considered standard.
Boilerplate language may also exist in pre-created form letters on the Internet for such things as issues to be broached by a politician based on an issue ad, requests that a cable or satellite operator add a cable network to a system, pre-written complaints about a product that is opposed by groups that create such letters, or online petitions. The person requesting the action usually only needs to type or sign his or her name at the end of the pre-written greeting and body.
Boilerplate Code
In computer programming, boilerplate is the sections of code that have to be included in many places with little or no alteration. Such boilerplate is particularly salient when the programmer must include a lot of code for minimal functionality. The need for boilerplate can be reduced through high-level mechanisms.
A related phenomenon, bookkeeping code, is code that is not part of the business logic but is interleaved with it in order to keep data structures updated or able to handle secondary aspects of the program.
- Library (computer science)
- Template processors are used to generate boilerplate text automatically
- Transpromotional
References
- "boiler plate", Oxford English Dictionary, 2nd Edition (online).(subscription required)
- "Building that was home to boilerplate to become luxury condos". Retrieved 2016-07-21.


Overview
LEVEL is an assessment and exercise system designed to supplement rehabilitation professionals with real-time data on measurements and movement, collected by our sensors. LEVEL automates the information needed for charting, allowing clinicians more time to focus on patient diagnosis and treatment.
LEVEL began as a research project at the University of Waterloo and Cardon Rehabilitation with the goal of creating a system for the rehabilitation industry, integrating together sensor data collection, pose estimation, and motion segmentation system with a strong focus in clinical development. LEVEL’s various components have been verified with rehabilitation data collected from several clinics in Ontario, alongside with feedback from patients and clinicians.
Today, the goal of the LEVEL team is to build and commercialize the system. We want to create and support a robust and user-friendly system that both patient and clinicians can utilize as a tool which will strengthen clinical capabilities.
Contact
Contact:
Agnes Lam
LEVEL Rehabilitation Tracking
1200 Burloak Drive
Burlington, Ontario
Canada


Pools¶
Contents:
Overview¶
In designate we support the concept of multiple “pools” of DNS Servers.
This allows operators to scale out their DNS Service by adding more pools, avoiding the scalling problems that some DNS servers have for number of zones, and the total number of records hosted by a single server.
This also allows providers to have tiers of service (i.e. the difference between GOLD vs SILVER tiers may be the number of DNS Servers, and how they are distributed around the world.)
In a private cloud situation, it allows operators to separate internal and external facing zones.
To help users create zones on the correct pool we have a “scheduler” that is responsible for examining the zone being created and the pools that are available for use, and matching the zone to a pool.
The filters are pluggable (i.e. operator replaceable) and all follow a simple interface.
The zones are matched using “zone attributes” and “pool attributes”. These are key: value pairs that are attached to the zone when it is being created, and the pool. The pool attributes can be updated by the operator in the future, but it will not trigger zones to be moved from one pool to another.
Note
Currently the only zone attribute that is accepted is the pool_id attribute. As more filters are merged there will be support for dynamic filters.
Managing Pools¶
In mitaka we moved the method of updating pools to a CLI in designate-manage
There is a YAML file that defines the pool, and is used to load this information into the database.
---
- name: default
# The name is immutable. There will be no option to change the name after
# creation and the only way will to change it will be to delete it
# (and all zones associated with it) and recreate it.
description: Default PowerDNS Pool
# Attributes are Key:Value pairs that describe the pool. for example the level
# of service (i.e. service_tier:GOLD), capabilities (i.e. anycast: true) or
# other metadata. Users can use this information to point their zones to the
# correct pool
attributes: {}
# List out the NS records for zones hosted within this pool
ns_records:
- hostname: ns1-1.example.org.
priority: 1
- hostname: ns1-2.example.org.
priority: 2
# List out the nameservers for this pool. These are the actual PowerDNS
# servers. We use these to verify changes have propagated to all nameservers.
nameservers:
- host: <IP_ADDRESS>
port: 53
- host: <IP_ADDRESS>
port: 53
# List out the targets for this pool. For PowerDNS, this is the database
# (or databases, if you deploy a separate DB for each PowerDNS server)
targets:
- type: powerdns
description: PowerDNS Database Cluster
# List out the designate-mdns servers from which PowerDNS servers should
# request zone transfers (AXFRs) from.
masters:
- host: <IP_ADDRESS>
port: 5354
# PowerDNS Configuration options
options:
host: <IP_ADDRESS>
port: 53
connection: 'mysql+pymysql://designate:password@<IP_ADDRESS>/designate_pdns?charset=utf8'
# Optional list of additional IP/Port's for which designate-mdns will send
# DNS NOTIFY packets to
also_notifies:
- host: <IP_ADDRESS>
port: 53
Designate Manage Pools Command Reference¶
Update Pools Information¶
designate-manage pool update [options]
Options:¶
--file Input file (Default: /etc/designate/pools.yaml
)--dry_run Simulate an update. (Default: False) --delete Delete Pools that are not in the input file (Defaults: False)
Warning
--delete True
can be extremely dangerous.--delete True
we recommend operators run with--delete True --dry_run True
to view the outcome.


Privileged Pfam-A domains mediate small molecule binding
We query the ChEMBL database for measured interactions of small molecules with single domain proteins containing a given domain. The requirements for a measurement to be counted as evidence are then the following:
The intial implementation built on a slightly different set of requirements, listed below. The most profound difference is that it set the threshold at 50 μM. Upon revisiting activities in the range between 10 and 50 μM, we found that they mostly represented unusual assay formats or ligands that do not fit in well with classical definitions of small molecules.
Evidence for small molecule binding to {{ names|length }} Pfam-A domains is listed below.
The catalogue of Pfam-A domains which are known to mediate small molecule binding can be downloaded in whole as valid_domains.
download expand table legend| Col name | explained |
|---|---|
| entry_id | unique identifier for each row |
| domain_name | name of the Pfam-A domain |
| comment | Curation comment |
| timestamp | time of last curation |
| submitter | user who submitted last curation decision |
The catalogue of valid Pfam-A domains is subject to revision. For example, if new data in the literature suggests that a given domain mediates small molecule binding, it can be added to the PPDMs list of domains under review. In the next cycle of curations, it can be included in the main catalogue and will be projected onto proteins that are associated with eligible binding assays. Similarly, a domain that is currently listed in the catalogue can be shortlisted for removal if evidence for small molecule binding turns out to be insubstantial.
All domains that are currently under review are listed below {{ held_doms|length }}.
| domain_name | comment | submitter | time |
|---|---|---|---|
| {{dom.0}} | {{dom.1}} | {{dom.3}} | {{dom.2}} |


PBO suite.
More...
#include <ioh/suite.hpp>
|
| | PBO (const std::vector< int > &problem_ids, const std::vector< int > &instances, const std::vector< int > &dimensions) |
| | Construct a new PBO object. More...
|
| |
|
void | reset () |
| | reset all problems in the suite
|
| |
|
void | attach_logger (Logger &logger) |
| | Attach a logger.
|
| |
|
void | detach_logger () |
| | Detach a logger.
|
| |
|
Iterator | begin (const bool track_problems=true) |
| | start iteration
|
| |
|
Iterator | end () |
| | end iteration
|
| |
|
std::vector< int > | problem_ids () const |
| | Accessor for problem_ids_.
|
| |
|
std::vector< int > | dimensions () const |
| | Accessor for dimensions_.
|
| |
|
std::vector< int > | instances () const |
| | Accessor for instances_.
|
| |
|
std::string | name () const |
| | Accessor for name_.
|
| |
|
size_t | size () const |
| | Accessor for size.
|
| |
◆ PBO()
| ioh::suite::PBO::PBO |
( |
const std::vector< int > & |
problem_ids, |
|
|
const std::vector< int > & |
instances, |
|
|
const std::vector< int > & |
dimensions |
|
) |
| |
|
inline |
Construct a new PBO object.
- Parameters
-
| problem_ids | List of problem ids |
| instances | List of problem instances |
| dimensions | List of problem dimensions |
◆ registration_invoker
template<class Type , class Factory >
Initial value:=
InvokeApplyOnConstruction<Type, Factory>()
Forces creation of registration_invoker
The documentation for this struct was generated from the following file:


My Team Members
Mack
Manager
ID:1
Email:
<EMAIL_ADDRESS>Office Number: 42
Alex
Engineer
ID:2
Email:
<EMAIL_ADDRESS>Github:
Profile
Mike
Engineer
ID:3
Email:
<EMAIL_ADDRESS>Github:
Profile
Marin
Intern
ID:4
Email:
<EMAIL_ADDRESS>UofU


{% extends "global/Page.html" %} {% load staticfiles otree_tags %} {% block title %}
In stage 3 for each round, you will see how many {{ Constants.exp_currency }} you get in that round. The {{ Constants.exp_currency }} are calculated by the gains of coordinating with your active connections minus the costs of your proposed connections. A coordination is an instance where you and another player with whom you have an active connection both chose the same action: or . The computer will do the calculations for you in each round, but below you can see how the {{ Constants.exp_currency }} are calculated in 3 simple steps:
Gains in each round depend on (i) your group, (ii) the action you pick, and (iii) the number of your active connections choosing the same (including yourself). You do not earn anything with a player if you do not have an active connection together and choose the same action.
If your group is ● "{{ circles_label }}" and you:
If your group is ▲ "{{ triangles_label }}" and you:
Your costs in each round depend only on the number of connections you propose. You pay a cost of {{ Constants.link_cost }} {{ Constants.exp_currency }} for each proposal you make, independently of whether the other player also proposes a connection to you or not.
Your {{ Constants.exp_currency }} are calculated as the gains from coordinating with your active connections minus the cost of each connection you propose. The examples illustrate this:
1. Earnings: Player 6 formed two active connections (with players 2 and 3) and have two coordinations,
(with player 2 and with himself). The two coordinations are multiplied by {{ Constants.liked_gain }}
(because his group is ● "{{ circles_label }}" and he chose ).
Player 6 did not coordinate with player 3, therefore he does not earn {{ Constants.exp_currency }} with that active connection.
Player 6 coordinated with players 4 and 5, but did not form an active connection with either of them, so he cannot earn {{ Constants.exp_currency }}
with them. Player 6's earnings are: 12 {{ Constants.exp_currency }}.
2. Costs: Player 6 proposed four connections (to players 1, 2, 3 and 4), the cost of each proposal is {{ Constants.link_cost }}
{{ Constants.exp_currency }}, so he pays 8 {{ Constants.exp_currency }}.
3. Total Points: Player 6 gets 12 in gains minus 8 in costs: 12 - 8 = 4 {{ Constants.exp_currency }} in this round.
1. Earnings: Player 6 formed three active connections (with players 1, 2 and 3) and have two coordinations,
(with player 1 and with himself). The two coordinations are multiplied by {{ Constants.disliked_gain }}
(because his group is ● "{{ circles_label }}" and he chose ).
Player 6 did not coordinate with players 2 and 5, therefore he does not earn {{ Constants.exp_currency }} with those active connection.
Player 6 coordinated with players 3 and 7, but did not form an active connection with either of them, so he cannot earn {{ Constants.exp_currency }}
with them. Player 6's earnings are: 8 {{ Constants.exp_currency }}.
2. Costos: Player 6 proposed five connections (to players 1, 2, 3, 4 and 5), the cost of each proposal is {{ Constants.link_cost }}
{{ Constants.exp_currency }}, so he pays 10 {{ Constants.exp_currency }}.
3. Puntos Totales: Player 6 gets 8 in gains minus 10 in costs: 8 - 10 = -2 {{ Constants.exp_currency }} in this round.
1. Imagine your group is ● "{{ circles_label }}", you chose action and you have one active connection
with a player who chose action . What are the total {{ Constants.exp_currency }} you get from this
connection (not including what you get from coordinatng with yourself)?
{% formfield player.pay_coord label="" %}
2. Imagine your group is ● "{{ circles_label }}", you chose action and you have one active connection
with a player who chose action . What are the total {{ Constants.exp_currency }} you get from
this connection (not including what you get from coordinatng with yourself)?
{% formfield player.pay_nocoord label="" %}


Having read a lot about blue lotus, we decided we had to at least try it before it got banned. We purchased a quantity of dried petals online.
Pharmacokinetics
I am 65kg, female, 27y, with a fast metabolism
My co-conspirator is 75kg, male, 28y, and similar.
7g of blue lotus petals each
Extraction
Since we didn't want to eat the quite large amount of plant material, and suspecting the active ingredient to be a water-soluble alkaloid, we placed the petals into microfibre infusion pouches- like fill-it-yourself teabags- and dropped them into 400ml of tap water that was just off the boil. We dunked and squashed the pouches with a stirrer and kept the temperature around 95 deg C with further low heat in order to keep the infusion going for twelve to fifteen minutes.
We strained the infusion through muslin into a glass container. We then used the muslin to squeeze as much fluid from the pouches as possible.
The result was about 320ml of dark brown, slightly gritty solution. We split it in two and placed it in glasses. We drank it, my friend downed it in one hit and I sipped at it. It was intensely bitter and made me feel nauseous- though I do not believe this to be a pharma effect, rather that it just tastes nasty.
This was T+0:00
We then smoked a joint of cannabis and drank 120ml of 40% vodka each over about an hour.
At T+0:15, I felt the muscles of my face relax and experienced a bump.
At T+1:00 I started to experience serotonergic rushes. Colors became slightly more intense and the neon lights in the middle distance looked really sharp.
At T+1:30, we smoked another joint. We both felt very relaxed and the slight visual effects were a little more pronounced.
At T+2:00, I was well under the influence and I tickled my friend. He felt it kick off at that point. We speculate that the blue lotus makes the brain more eager to produce serotonin, but does not itself stimulate production directly.
At T+2:30, we were both regularly feeling rushing, and my friend determined that the effect was closely modulated by alcohol- it only took a couple of minutes after swallowing a little vodka for another rush to come in. We both felt very friendly and extremely social. My mind did not feel dulled by the various drugs, and I was very able to converse in a social way, however I noticed that my higher reasoning was somewhat impaired. We were hacking at my new Mac and we couldn't really work things out as well as we normally could. Speech was also somewhat affected, not slurring, but I suffered some nominative dyspraxia (I couldn't always think of the names for things, though I still knew what they were.) I also stuttered more than I usually do. My friend says he sometimes found himself saying the wrong words, though I don't remember this. By this time we were listening to music and finding our moods were very closely influenced by the songs. It was very pleasant.
T+3:00, we were coming down a little, and it was very late at night, so we split a can of Red Bull and added a little more vodka (~100ml vodka each). This contained about 75mg caffeine for each of us. This turned out to be somewhat of a mistake, I shortly felt quite overwhelmed. Not nauseous, but very overstimulated. Having my eyes open became disorienting and unpleasant, and I spent about the next 40 minutes curled in a fetal position with a duvet over me. Fortunately, my friend is not easily freaked out, and as long as I kept telling him I felt okay, he was fine. I felt quite happy and comfortable, as long as I kept my eyes closed. I felt safe, and the high felt very clean and warm and friendly. A few minutes later, my friend started to feel the same effect, we speculate that the caffeine was too much at this point.
T+4:00, this had passed, we were still coasting along. We watched some videos and were having a great time.
The effects gradually trickled away over about seven hours, and from this we estimate that the active ingredient in blue lotus has an elimination half life of about three to five hours. We still notice some slight social effects and a mild high some eighteen hours later. At no time did I feel that I was 'not myself', which markedly distinguishes this from a tryptophan effect, they always make me feel quite 'un-self'. My friend agrees, this drug does not produce a feeling of 'otherness' like many drugs we have tried.
At 8am, we were feeling a bit tired and hungry, so we went to get something to eat. We ate sandwiches and drank fruit juice, which brought the effects down to a very mellow level and then I went home to bed. I felt just fine riding the tram home on my own, I didn't feel that I was looking at all crazy, or fear that people were looking at me. I just felt very normal.
Each time we added a little alcohol to the mix, we noticed a 'rush' come up, these started quite gently, peaking at about T+3:00. The difficulty of separating the effect of the blue lotus active ingredient concentration from the 'pushing' effect of the alcohol makes it difficult to draw a conclusion from this.
This drug is very strongly synergistic with alcohol, nicotine and cannabis (at least) and there is a risk of an overstimulation episode with injudicious use. We both noticed that every time it felt like the drug had 'stopped working', we could kick it off again very easily and quickly with alcohol, I stopped drinking alcohol for several hours after my overstimulation episode and the drug's effects quickly diminished. When I sipped a little more, somewhat later, it came back just the same as before the overstimulation, it was very pleasant and controllable, without the dizzying height of MDMA. Really, the combination of alcohol and blue lotus felt like a really mild version of MDMA, without the methamphetamine buzzing and without the hyperactivity. I was happy to sit wherever I was and listen and talk to people. I felt very connected to my friend, and I opened up my computer to chat to people who weren't physically present.
Experience Reports are the writings and opinions of the individual authors who submit them.
Some of the activities described are dangerous and/or illegal and none are recommended by Erowid.


Cover yourself up! Protecting your APIs with mutual auth
Jan 22, 2016 Marc Savy gateway, security, mutual-auth, ssl, mtls, and 1.2.xNote: This is a redux of our blogpost for apiman 1.2.x. If you're still using apiman 1.1.x, you can refer to the older revision.
 The typical solution for this is to lock down your network so that the only publicly accessible part is the apiman gateway, whilst APIs are hidden in the private part of the network, which apiman can access, but not someone in the outside world. However, in some situations fine-grained network controls may not be available, such as the cloud; or, you may wish to have an additional layer of security to be reassured that no funny business is going on (such as imposters).
The class of solutions to this problem generally falls under the banner of mutual authentication. One such mutual auth offering apiman supports is Mutually Authenticated TLS[1].
What is mutual transport layer security (Mutual TLS)?
Most developers are familiar with SSL/TLS; it facilitates authentication via certificates followed by the establishment of an encrypted channel between the parties. It is overwhelmingly used in a one-way configuration: the client (often a browser) connects to a server, inspects the certificates it presents, and makes a determination as to whether the server is trustworthy. The connection is only made if the client is satisfied that the server is who it claims to be. In general, the server makes no determination as to who the client is.
However, in a typical apiman setup the gateway is acting as the client and the APIs act as the servers. Clearly, if we wish to prevent anyone other than approved clients from connecting directly to our APIs then unidirectional authentication is insufficient: we must ascertain the identities of both client and server before establishing a connection. In essence, each party must present certificates that the other party trusts. This a great way to prevent anyone from side-stepping our gateway, and even better, it also stops any interlopers from sneaking into the system.
Luckily, apiman makes this extremely easy to set this up, so let’s dive in and explore what’s possible.
Architecture
Let’s assume 'node' refers generically to a participant in our system, either a gateway or an API.
There are two main elements we need to work with: keystores, which contain a node’s private key material, and truststores, which contain public certificates instructing the node whom it should trust.
Ideally, each node should have its own keystore, whose key material is signed by a trusted certificate authority; a trusted party whose signature indicates that the holder of the certificate is trustworthy. In many organisations there is an internal certificate authority which will sign or issue certificates. If we add a CA’s certificate to our node’s keystores, then any certificate issued by it will be trusted by virtue of the issuer’s authority. This approach scales excellently, because we can issue an unlimited number of new certificates without needing to add them to our truststores.
It bears mentioning that any client apps[2] legitimately using our gateway will never be exposed to any mutual auth issues; they will establish a standard one-way authenticating TLS connection that is terminated at the gateway, with the gateway then establishing the two-way TLS connection to the API.
Notice that the APIs trust the gateway (and vice versa), but the APIs do not trust the client app. The client app tries its luck and attempts to bypass the gateway, but it doesn’t hold a trusted certificate, so it fails.
The keys to success
| Remember, this is just a quick blog demonstration; you need to take extreme care with how you look after your key infrastructure to avoid a catastrophic security incident. If you’re unsure, consult someone who knows what they’re doing! |
Truststore
Let’s create a simple shared truststore that we’ll use on all of our nodes. We’re going to imagine that we have an internal root CA called apimanCA
, and that whomever controls it has taken appropriate security precautions to ensure no baddies get their certificates signed.
keytool -import -keystore shared_trust_store.jks -file apimanCA.cer -alias apimanCA
That’s the easy bit done, now onto key wrangling.
Keystore
Each of our nodes needs its own keystore, which we can create using keytool
, followed by generating a certificate signing request (CSR), which we can then send to our CA to be signed:
keytool -keystore gateway_ks.jks -genkey -alias gateway -keyalg rsa
keytool -keystore gateway_ks.jks -certreq -alias gateway -keyalg rsa -file gateway.csr
keytool -keystore API_a_ks.jks -genkey -alias API_a -keyalg rsa
keytool -keystore API_a_ks.jks -certreq -alias API_a -keyalg rsa -file API_a.csr
Do the same for each of your APIs, and send off the csr
files to be signed by CA (internal or otherwise). They should come back as certificate replies in one of several formats, import them back into their corresponding keystores:
keytool -import -keystore gateway_ks.jks -file gateway.cer -alias gateway
keytool -import -keystore API_a_ks.jks -file API_a.cer -alias API_a
Hooking it up
Your APIs may not use Java, so you’ll need to find the appropriate solution for enabling mutual TLS in your language’s ecosystem. It doesn’t really matter, as long as you have the appropriate certificates hooked in and have set client authentication to required.
Gateway to Heaven
It’s easy to set up the gateway, but you should be especially careful about what you twiddle with, as the security implications could be important. Let’s edit apiman.properties
on our gateway(s) with a few simple settings to test things out:
# ---------------------------------------------------------------------
# SSL/TLS settings for the gateway connector(s).
# ---------------------------------------------------------------------
# Trust store contains certificate(s) trusted by gateway.
apiman-gateway.connector-factory.tls.trustStore=/path/to/shared_trust_store.jks
apiman-gateway.connector-factory.tls.trustStorePassword=password
# Key store contains gateway's keys (including private components: keep it safe).
apiman-gateway.connector-factory.tls.keyStore=/path/to/gateway_ks.jks
apiman-gateway.connector-factory.tls.keyStorePassword=password
apiman-gateway.connector-factory.tls.keyPassword=password
# Whether certificate host checks should be bypassed. *Use with great care.*
apiman-gateway.connector-factory.tls.allowAnyHost=true
The last option is to make our testing easier by removing hostname checks on the certificates, but you should disable that in production. Have a look at our setup guide for a full list of options.
Service is Everything
| You must explicitly enable client authentication for any APIs you want protected by mutual TLS. |
Here’s a small Java example using Jetty to create a tiny API with mutual authentication enabled. We hook up our keystore and truststore with respective hard-to-guess passwords, and set setNeedClientAuth(true)
:
public static void main(String... args) throws Exception {
Server server = new Server();
server.setStopAtShutdown(true);
HttpConfiguration http_config = new HttpConfiguration();
http_config.setSecureScheme("https");
http_config.setSecurePort(8009);
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath("/tmp/keys/API_a_ks.jks");
sslContextFactory.setKeyStorePassword("password");
sslContextFactory.setKeyManagerPassword("password");
sslContextFactory.setTrustStorePath("/tmp/keys/shared_trust_store.jks");
sslContextFactory.setTrustStorePassword("password");
// Important: Require client auth
sslContextFactory.setNeedClientAuth(true);
HttpConfiguration https_config = new HttpConfiguration(http_config);
https_config.addCustomizer(new SecureRequestCustomizer());
ServerConnector sslConnector = new ServerConnector(server, new SslConnectionFactory(
sslContextFactory, "http/1.1"), new HttpConnectionFactory(https_config));
sslConnector.setPort(8009);
server.addConnector(sslConnector);
server.setHandler(new AbstractHandler() {
@Override
public void handle(String target, Request baseRequest,
HttpServletRequest request, HttpServletResponse response) throws IOException,
ServletException {
response.setContentType("text/html;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
baseRequest.setHandled(true);
response.getWriter().println("apiman saves the day, again!");
}
});
server.start();
}
Fire it up
Restart everything, and you should be ready to test it!
When creating an API that is protected by mutual TLS you should set the API Security dropdown in the Implementation tab to MTLS/Two-Way-SSL
:
If things don’t seem to be working quite how you expected, you’ll probably notice that the error messages emitted are fairly vague. If you need more information to figure out what’s going on then you can pass the flag -Djavax.net.debug=all
, which will print helpful debug info from Java’s SSL subsystems onto the console.
For example:
./bin/standalone.sh -Djavax.net.debug=all -c standalone-apiman.xml
In Conclusion
Mutually authenticated TLS is a good way to ensure both client and server are who they claim to be before connecting to one another. If you need to prevent unauthorized direct access to your APIs, this is an option worth considering.


We are GROUP 1 in the industrial practice with Huaxin corporation.Our group consists of Shaobo Wang,Kaixin Li,Kaihua Liu,Mingye Zou,four excellent software engineering students in Harbin University of Technology(Weihai).
Welcome to contact us!


Intro
In Part II we parsed the JSON data found in the DbSNP JSON download. In Part III, we will bulk-insert this data into our PostgreSQL database.
Choosing a PostgreSQL Python Driver
The list of options here is long, but I ended up choosing asyncpg for a number of reasons:
- Great support for PostgreSQL’s
COPY FROM ... STDIN
command.- Albeit this is supported in other drivers, but doesn’t have the python-object level of abstraction that I’d like.
- I tried adding a higher-level-of-abstraction to
psycopg2
’scopy_from()
method, but got nowhere fast with this Pull Request
- Great support for PostgreSQL’s
PREPARE
statement - The entire library is asynchronous, and writing lots of data to a remote datastore is a good usecase for
async
Python.- …we are writing to localhost in this walkthrough, so we don’t actually leverage async concurrency.
Writing to Database
In Part II we introduced the _load(self, parsed_data_iter)
method, agnostic of any implementation details. Let’s implement the method!
Naively, we could insert one row at a time, as each is parsed, as follows:
async def _load(self,
parsed_data_iter: Iterator[RefSnpCopyFromData]):
conn = await asyncpg.connect(database=self.database_name,
user="SeanH")
for copy_from_data in parsed_data_iter:
for table_name in copy_from_data._fields:
rows = getattr(copy_from_data, table_name)
for row in rows:
await conn.execute(
f"INSERT INTO {table_name} "
"{row._fields} "
"VALUES ($1, $2)", *row)
But we can do better than this!
PostgreSQL has the best (strong opinion loosely held) BULK INSERT method available. I make this claim having written ETLAlchemy: a library facilitating full-database (schema and data) migrations between any database supported by SQLAlchemy Core.
To properly bulk-insert, we need a buffer to continuously aggregate our data, and bulk-insert/dump buffer to the database intermittently when we hit our threshold.
Let’s try this:
async def _load(self, parsed_data_iter):
conn = await asyncpg.connect(
database=self.database_name, user="SeanH")
await conn.execute(
"SET session_replication_role to 'replica'")
# This should stop FK checks...
table_names = [table_name
for table_name in RefSnpCopyFromData._fields]
row_buff_dict = {table_name: []
for table_name in table_names}
buff_size = 0
for copy_from_data in parsed_data_iter:
for table_name in table_names:
for copy_from_row in getattr(copy_from_data,
table_name):
row_buff_dict[table_name].append(copy_from_row)
buff_size += 1
if buff_size % 5000 == 0: # Dump
print(f"Dumping (SNPs Processed: {buff_size})")
await self._dump_buffer(row_buff_dict, conn)
row_buff_dict = {table_name: []
for table_name in table_names}
print("Done.")
await conn.close()
async def _dump_buffer(self, row_buff_dict, conn):
for table_name in row_buff_dict.keys():
records = row_buff_dict[table_name]
if not records:
continue
await conn.copy_records_to_table(
table_name,
records=records,
columns=records[0]._fields)
As each RefSnpCopyFromData
object becomes available, we add its contents to our buffer. We apply the KISS principle, implementing our buffer as a dict
, mapping table_name
-> List[namedtuple]
.
Note: For simplicity’s sake, rather than tracking the memory footprint of our buffer, we are just tracking the # of
RefSNPs
processed.
When we hit our buff_size
, in this case 5000
, we leverage asyncpg
’s copy_records_to_table()
method to write to the database, and free up memory by re-initializing our buffer.
The Top-level Method: Revisited
Remember our load_ref_snps()
method? Recall that our _load()
method is asynchronous, this means we will have to run it with a Python asyncio
loop. We update our method as follows:
def load_ref_snps(self, dbsnp_filename, chromosome):
self.chromosome = chromosome
loop = asyncio.get_event_loop()
with gzip.open(dbsnp_filename) as gzip_fp:
loop.run_until_complete(
self._load((self._generate_parsed_data(line)
for line in gzip_fp)))
Note: It’s worth noting that we get NOTHING from running the
_load()
method in anasyncio
loop. We are only using asyncio because theasyncpg
library requires us to do so, that’s the only reason!
In the future, this also opens up the door to asynchronously download/stream each refsnp-chr*.json.gz
file, while we concurrently parse and insert the data into the database. This would be a great optimization, but is outside our scope!
The Top-level Method: Multiprocessed
Our current implementation presents a great opportunity to leverage Python’s multiprocessing
library, without any design changes. We just simply “hand-off” the streaming and parsing of our JSON to a pool of child processes, while our parent process accumulates our data buffer, eventually dumping to our database.
On my 8-core 2016 Macbook Pro, making the change from non-parallelized code to parallelized code reduces the run time from 1 hour and 3 minutes down to 20 minutes: a 300% performance increase. Not too shabby…
def load_ref_snps(self, dbsnp_filename, chromosome):
self.chromosome = chromosome
num_processes = cpu_count()
print(f"Found '{num_processes}' CPUs")
loop = asyncio.get_event_loop()
with Pool(num_processes) as pool:
with gzip.open(dbsnp_filename) as gzip_fp:
copy_from_data_iter = pool.imap_unordered(
self._generate_parsed_data,
gzip_fp,
1024) # chunksize
loop.run_until_complete(
self._load(copy_from_data_iter))
That’s it! Our Pool
object manages each child process by handing off lines from gzip_fp
to each process, returning an Iterator of RefSnpCopyFromData
objects which is handed off to load()
, satisfying the methods contract!
Note: It is not by coincidence that we were able to easily parallelize our application, nor was it by some perfect design. In my experience, it is a combination of:
- A desire to design and produce small, concise pieces of code, encapsulated in classes and methods with well-defined interfaces.
- Many, many iterations. (I went through 3 full refactors while putting this together)
Knowing that you want to parallelize something can obviously be factored into design, but is generally easier to do when you satisfy (1) above.
Putting it All Together
We can now easily write a script to download, parse and bulk insert all 23 Chromosome’s DbSNP data into our local database:
import os
from snip_warehouse import SnipLoader
from snip_warehouse.schema import init_db
input("Are you sure you want to re-init DB?"
"This takes 2-3 hrs per chromosome")
init_db(DB_NAME)
snip_loader = SnipLoader(DB_NAME)
chr_suffixes = [str(i) for i in range(1, 23)]
chr_suffixes += ["X", "Y", "MT"]
for chr_suffix in chr_suffixes:
snip_loader.download_dbsnp_file(
f"refsnp-chr{chr_suffix}.json.gz",
chr_suffix)
snip_loader.load_ref_snps(
f"refsnp-chr{chr_suffix}.json.gz",
chr_suffix)
os.system(f"rm refsnp-chr{chr_suffix}.json.gz")
More good news, on my 2016, 8-core Macbook Pro (w/ SSD), the Wall Time of warehousing the data of all 23 Chromosomes is 9 hours and 21 minutes. This satisfies the “overnight goal” - you can kick the above script off before bed, wake up, eat breakfast, and it should be done!
What’s Next?
You can find the full source code repo on github here
By open-sourcing this project, it is my hope that folks can take snippets from the walkthrough to build their own hand-curated, DbSNP-related database. Whether you are a Bioinformatician, a hobbying dev, or a PhD without much time or money, don’t recreate the wheel. Take bits and pieces and build something better.
I’ve already built one practical application of this database: The Snip API. This API allows a user to turn his/her 23&Me
Raw SNP Export into insights. It helped me discover that the instigator of my father’s Gallstones and Gallbladder removal was likely genetic.
You can find the Snip API client on github here.
I encourage everyone to use the API, and explore the JSON output: you will likely find something of interest. Further, I would encourage folks to:
- Build more APIs like it
- Build a GUI for Snip
- Find bugs/issues with Snip
- Integrate this data with other datasets
- Share all of this code/information with as many people as you can!
It’s an exciting time for the intersection of Biology and Software Engineering. My hope is that we can all ride the wave.


The data that is passed to this application will appear below. We also send it back to the calling application
attachEventListener(window, "load", function() { var output = document.getElementById("output"); setText(output, intent.data[0]); intent.postResult(["http://kin.ly/A" ]); }, false);