This section will present basic graph traversals by way of examples on the simple property graph diagrammed below.
gremlin> g = TinkerGraphFactory.createTinkerGraph()
==>tinkergraph[vertices:6 edges:6]
gremlin> v = g.v(1)
==>v[1]
The symbol v
denotes that the element is a vertex and 1
denotes the elements unique identifier. To determine all of the outgoing edges from the vertex, the following statement suffices.
gremlin> v.outE
==>e[7][1-knows->2]
==>e[9][1-created->3]
==>e[8][1-knows->4]
As a convenience, Gremlin prints the outgoing and incoming vertex identifiers along with the edge label. To acquire the vertices at the head of these edges (known as the incoming vertices), apply another step in the path.
gremlin> v.outE.inV
==>v[2]
==>v[3]
==>v[4]
It is important to note that in Gremlin, vertices are incident to edges and edges are incident to vertices. The reason for this will become apparent later when making use of element properties in path expressions. The reserved terms for denoting adjacency selection are the steps outE
, inE
, bothE
, outV
, inV
, and bothV
(see Gremlin Steps). The components of a property graph are diagrammed in the example sub-graph below.
The process of traversing a graph, in this manner, can continue indefinitely (granted, if there are loops in the graph).
gremlin> v.outE.inV.outE.inV
==>v[5]
==>v[3]
There are the steps out
, in
, and both
that skip over edges as such to jump from vertex to vertex.
gremlin> v.out.out
==>v[5]
==>v[3]
Moreover, it is possible to make use of Groovy’s language to repeat patterns. For example, the previous example can be denoted as follows.
gremlin> list = [v]
gremlin> for(i in 1..2)
list = list._().out.collect{it}
gremlin> list
==>v[5]
==>v[3]
This can also be done using the loop
step.
gremlin> v.out.loop(1){it.loops < 3}
==>v[5]
==>v[3]
If the Gremlin graph data structure was only a directed graph, then outgoing/incoming edges and outgoing/incoming vertices would be the limits of what could be expressed. However, given that vertices and edges can have properties, it is possible to use these properties within a path expression. For example, suppose you want to know the name of vertex 1.
gremlin> v = g.v(1)
==>v[1]
gremlin> v.name
==>marko
The name
construct denotes the property key name
and returns the value of that key. The first component of the path is vertex 1. Thus, the name
of vertex 1 is “marko.” Another, more complex example that uses vertex and edge properties is to determine the name
of the vertices that vertex 1 knows
and that are older than 30 years of age, is expressed as such.
gremlin> v.outE('knows').inV.filter{it.age > 30}.name
==>josh
In this expression, the filter{ }
step serves to filter results of previous step in the path (a closure filter). Thus, v.outE
is filtered to only those edges that have a label
of “knows.” With respect to the diagrammed graph, this leaves only two edges. Next, the incoming vertices at the head of these two edges are determined and then filtered to only those whose age
property is greater than 30. Given the diagram, this only leaves vertex 4. In the final segment of the path expression, the name
of vertex 4 is selected and what is returned is “josh.”
To conclude, let’s do a more complicated graph traversal that uses backtracking and an in-line regular expression.
gremlin> v.out('knows').filter{it.age > 21}.name.filter{it.matches('jo.{2}|JO.{2}')}.back(3).age
==>32
With the root vertex being vertex 1, this path expression returns the age of those vertices that vertex 1 knows, are older than 21, and whose names are 4 characters and start with a ‘jo’ or ‘JO’. While contrived, it demonstrates using closures to call functions on properties as well as backtracking to a vertex previously visited.
This expression does the same thing without backtracking. Both are provided in order to demonstrate the many ways in which to express the same thing.
gremlin> v.out('knows').filter{it.age > 21 & it.name.matches('jo.{2}|JO.{2}')}.age
==>32


--- title: About ---
I'm thelazychef and this is my food blog. I am lazy, but I like food. So the recipes here are going to be easy to cook with easy to get ingredients
Share your pics and I might use it on the blog(Or something like that)
Thanks to the template makers here


Activity and Process
Our team is really good at research. I mean, when I say, really good, I really mean it. We can go through tons and tons of articles in matter of a couple of days. But what happens next? Where can we go from there? How do all these individual pieces of knowledge contribute to the bigger picture of project? With hundred of notes in our Mendeley Account, we were starting to think we will never be able to effectively realize the value of research we have done. However, with our dedication to using the best practices in the design and research process, we decided to try an Affinity Mapping Exercise—a method that Karen Holtzblatt (InContext Design) puts so much emphasis on as a primary method of consolidating research findings.
We started by individually going through the papers we had read, summarizing the highlights on Post-Its and explaining them to the other team members as they put the Post-It on the board. We filled out multiple whiteboards and got kicked out of two different libraries because they were closing. In the end, we had identified major themes on our Post-Its and had started to categorize them into those themes (clusters). We then did a pass through the information on the board, eliminating redundant facts and pieces of information that were way outside of our scope or irrelevant to our current direction.
Having organized our Post-Its into clusters, we then started to find connections and overlays between the different clusters. Specifically, we worked to establish relationships between the clusters of 3D gesture technologies and the clusters of publishing industry information.
With two giant whiteboards full of information, we had managed to boil down and categorize our research findings into clusters that we could work to dig deeper or dismiss as irrelevant to our current focus.
Activity Findings
We formed groups around problems, types, and properties of gesture technology; print and digital media; mobile platforms; content delivery; storytelling platforms; the focus of media coverage; user-contributed content; revenue and advertising; business models; audience; inter-business sharing of content; and social sharing. After looking at these groups, we felt that there were opportunities in the following areas:
- The intersection of social-sharing, storytelling platforms, reader-generated content, and gesture technology
- Relationships between print media, digital media, and the changing focus of coverage
- Consumers, news media, and content creation (from stakeholder map) For better access and retrieval of this valuable research artifact, we decided to digitize this big diagram using OmniGraffle. Below is the digital version of our affinity diagram.
Implications for Design
Having concluded our primary phase of secondary research, we are planning on using this diagram as a useful way of determining and guiding our primary research activities. Furthermore, having a consolidated source of current trends, information, and technology has helped us greatly in achieving a common mental model and understanding of the problem space we are working with.


1600 pennsylvania avenue washington dc
The White House 1600 Pennsylvania Avenue NW Washington, DC 20500. ... 1600 Pennsylvania Ave NW Washington DC 20502 (38.898748, -77.037684) ...
http://www.spyfu.com/Term.aspx?t=9264
geocoder.us: a free US geocoder
1600 Pennsylvania Ave NW. Washington DC 20502 (38.898748, -77.037684) (it can take a bit for the map to load-wait for the red circle to turn green. ...
http://geocoder.us/demo.cgi?address=1600+Pennsylvania+Ave%2C+Washin...
Colonial Parking
1701 Pennsylvania Ave NW. Washington, DC 20006. 0.13. Hours, Map, ... 1600 Pennsylvania Ave NW, Washington, DC 20502. These maps/directions are informational only. ...
http://www.ecolonial.com/location.pl?addr=Ellipse
geocoder.us: a free US geocoder
38.898748,-77.037684,1600 Pennsylvania Ave NW,Washington,DC,20502 ... 1600,prefix=,street=Pennsylvania,type=Ave,suffix=NW,city=Washington,state=DC,zip ...
http://geocoder.us/help/
Geocoder Documentation
... geocoder.geocode "1600 pennsylvania ave nw washington dc" result.lat ... ave nw washington dc 38.8987,-77.037223,1600 PENNSYLVANIA AVE NW,WASHINGTON,DC,20502 ...
http://geocoder.rubyforge.org/
Federal Chief Financial Officers Council
1600 Pennsylvania Avenue, NW. Washington, DC 20502<EMAIL_ADDRESS>... Pennsylvania Avenue, NW. Ariel Rios Bldg, Room 4412, MS 2710A. Washington, DC ...
http://www.cfoc.gov/index.cfm?function=membersall
Federal Chief Acquisition Officers Council
1600 Pennsylvania Avenue, NW. Washington, DC 20502<EMAIL_ADDRESS>... 1300 Pennsylvania Avenue, NW. Washington, DC 20523. Office Phone:<PHONE_NUMBER> ...
http://caoc.gov/index.cfm?function=membersall
WASH Sign-On letters to U.S. Y2K/Nuclear Officials
1600 Pennsylvania Ave. NW. Washington, DC 20525. From: The ... 1600 Pennsylvania Ave NW. Washington, DC 20525. Chairman Greta Joy Dicus ... Washington, DC 20502 ...
http://www.co-intelligence.org/y2k_WASHsign-on.html


accept share
access privileges
activity stream
Moving Less Important Mail Out of the Inbox
Working with Email Filters
activity stream folder
add
calendar
add external accounts
Accessing Your External Accounts
Using Other Account Identities When You Send an Email
add external calendar
add personas
address book
Adding Members to a Contact Group List
Exporting an Address Book
Automatically Add Contacts to Emailed Contacts List
Importing an Address Book
Using Address Books
exporting
importing
address bubbles work
advanced search
advanced search criteria
advanced web client
alerts
all day appointments
always show search string
attachments
Opening Attachments to an Email Message
Adding Attachments
attachments using drag
automatically add received appointments
Automatically add received appointments to calendar.
Responding to a Meeting Invitation
basic filters
briefcase
Delete a Document from Briefcase
Move Files in Briefcase
Adding Files to Your Briefcase Folders
CalDAV
calendar
Other Calendar Preferences to Configure
Print a Calendar
print
calendar preferences
calendars into groups
certificates, adding to address book
change the message view
changing your password
check box
checking in files
briefcase
checks for new mail
color coding your calendars
compose right to left
compose s/mime message
composing messages
configure your default meeting duration
configures
PIN
contact
moving
contact group
contact group list
content pane
conversation
create
folder
creating
Working in Briefcase
Creating a Filter
briefcase folders
filter
date, group by
default mail search
default time zone
delete
folder
deleting
message
deleting contacts
desktop alerts
digitally signed messages, compose
disable
zimlet
distribution list
distribution list, manage
distribution list, modify
distribution list, unsubscribe
draft
editing
contact information
email filters
email messages
replying
email notification
email replies
email, send later
emailed contacts
emailed contacts list
automatically add contacts
empty junk
empty trash
enable
optional zimlet
encrypted email
encrypted messages, compose
equipment
scheduling
export your ical calendar
exporting
address book
external accounts,access
external POP account
filter
Editing a Filter
Creating a Filter for Calendar Invitations
Creating a Filter
creating
editing
filter active
filter calendar invitations
filter conditions
Filter Conditions
Filter Conditions and Actions Supported
filter mail
filter order
viewing
filter rule actions
find shares
flag
Flag a Message or Conversation
Remove a Flag from a Message or Conversation
forward contact
forwarded email
forwarding messages
Automatically Forwarding Messages You Receive
Forwarding Email Messages
free_busy
future delivery message
global address list
group messages
html
Search Syntax
Displaying Messages in HTML Format or Plain Text
Using HTML to Compose Messages
ical to do list
icalendar, adding
ics
imap
import your ical calendar
importing
Importing an Address Book
Importing a Task Lists
address book
task lists
inbox
automatically move less important mail out
items shared with you
junk
keyboard shortcuts
language, change
list view
mail
reading
mail trash folder
managing
Managing Your Mobile Devices
Managing Your Shared Items
your mobile devices
your shared items
mandatory spellcheck
Spell Check All Messages Before They are Sent
Customizing Your Options for Composing Messages
Spell Check a Message
manually check for mail
meeting invitation
responding
message arrival notification
mini-calenda
mobile device
mobile security features
move message
new contact
new mail notification
notifications
Setting Desktop Alerts For New Email Messages
Setting Email and SMS Reminder Notification
>>


Abu Ogogo: Not celebrating Bristol Rovers winner out of respect for Shrewsbury was extremely difficult
by Lewis CoxBristol Rovers match-winner Abu Ogogo insists not celebrating his late winner at former club Shrewsbury Town was one of the toughest moments of his life.
The former Shrewsbury captain popped up with a 86th minute winner at Montgomery Waters Meadow to cap a memorable afternoon for the visitors, who survived a spirited Town fightback in the 4-3 thriller.
Ogogo's reception was largely greeted positively by Town fans after three years of service between 2015 and 2018.
"I knew I didn't have too much time. It was set perfectly, I didn't have to take a touch and used the defender's body to bend it around him," Ogogo said.
"I can't explain that feeling. I wanted to celebrate and go wild but obviously I was here for three years so I didn't out of respect, but it was so hard not to.
"It was one of the hardest things I've ever had to do. When I score I love to celebrate and go wild.
"To get a last minute winner – in any other game I'd have stripped off and gone in with the fans but I couldn't, it was really hard to keep my emotions in check."
Ogogo admitted that the spirit shown by the side belonging to another former Shrewsbury captain, Graham Coughlan, reminded him of the Town's play-off final campaign under Paul Hurst two seasons ago.
The all-action midfielder was injured towards the end of that season and unable to start either of Town's Wembley finals.
"It's similar here to the season I had under Paul Hurst (at Shrewsbury) to get to the play-off final and the Cup final," the midfielder, who left Town for Coventry before joining the Memorial Stadium side, added.
"Similar things are happening this season as to what happened that season so hopefully we can do the same."


Conference Digest - COLT 2020
COLT 2020 was held online in July, and featured nine papers on differential privacy, as well as a keynote talk by Salil Vadhan. While differential privacy has always had a home in the COLT community, it seems like this year was truly exceptional in terms of the number of results. We link all the content below, including pointers to the papers, videos on Youtube, and the page on the conference website. Please let us know if we missed any papers on differential privacy, either in the comments below or by email.
Keynote
Papers
-
Domain Compression and its Application to Randomness-Optimal Distributed Goodness-of-Fit (video, page)
Jayadev Acharya, Clément L. Canonne, Yanjun Han, Ziteng Sun, Himanshu Tyagi -
Closure Properties for Private Classification and Online Prediction (video, page)
Noga Alon, Amos Beimel, Shay Moran, Uri Stemmer -
Pan-Private Uniformity Testing (video, page)
Kareem Amin, Matthew Joseph, Jieming Mao -
Efficient, Noise-Tolerant, and Private Learning via Boosting (video, page)
Mark Bun, Marco L. Carmosino, Jessica Sorrell -
PAC Learning with Stable and Private Predictions (video, page)
Yuval Dagan, Vitaly Feldman -
Locally Private Hypothesis Selection (video, page)
Sivakanth Gopi, Gautam Kamath, Janardhan D. Kulkarni, Aleksandar Nikolov, Zhiwei Steven Wu, Huanyu Zhang -
Private Mean Estimation of Heavy-Tailed Distributions (video, page)
Gautam Kamath, Vikrant Singhal, Jonathan Ullman -
Privately Learning Thresholds: Closing the Exponential Gap (video, page)
Haim Kaplan, Katrina Ligett, Yishay Mansour, Moni Naor, Uri Stemmer -
Reasoning About Generalization via Conditional Mutual Information (video, page)
Thomas Steinke, Lydia Zakynthinou
[cite this]


(). {border-style px;} #ffffff;} floods :–. flood reported diseases fever flooding infections outbreaks viral dengue Iran. disease borne Dis; Khuzestan affected outbreak px; {font-family Iran font-size health hepatitis increase infection virus Available Golestan Med Trop diseases. double; people respiratory risk water Floods Infect Iran, Public RVF border-color border-width cases communicable disasters. flooding, identified infectious mosquito provinces review solid; study transmission vector {font-style {font-weight .collab: Microbiol; Rift Valley bold courier; deaths diarrheal different disasters em; flooding. high pt;} rainfall related species spring


This is an early preview of our new package, Tplyr
. This package is still in development, and we’re actively working on new features. We decided to release this version early to get community feedback. If you find a bug in our code - please report it! If you’d like to see some particular feature - let us know! The more feedback we collect, the better the end product will be when we publish the first version on CRAN.
dplyr
from tidyverse is a grammar of data manipulation. So what does that allow you to do? It gives you, as a data analyst, the capability to easily and intuitively approach the problem of manipulating your data into an analysis ready form. dplyr
conceptually breaks things down into verbs that allow you to focus on what you want to do more than how you have to do it.
Tplyr
is designed around a similar concept, but its focus is on building summary tables within the clinical world. In the pharmaceutical industry, a great deal of the data presented in the outputs we create are very similar. For the most part, most of the tables created can be broken down into a few categories:
For many of the tables that go into a clinical submission, at least when considering safety outputs, the tables are made up of a combination of these approaches. Consider a demographics table - and let’s use an example from the PHUSE project Standard Analyses & Code Sharing - Analyses & Displays Associated with Demographics, Disposition, and Medications in Phase 2-4 Clinical Trials and Integrated Summary Documents.
When you look at this table, you can begin breaking this output down into smaller, redundant, components. These components can be viewed as ‘layers’, and the table as a whole is constructed by stacking the layers. The boxes in the image above represent how you can begin to conceptualize this.
So we have one table, with 6 summaries (7 including the next page, not shown) - but only 2 different approaches to summaries being performed. In the same way that dplyr
is a grammar of data manipulation, Tplyr
aims to be a grammar of data summary. The goal of Tplyr
is to allow you to program a summary table like you see it on the page, by breaking a larger problem into smaller ‘layers’, and combining them together like you see on the page.
Enough talking - let’s see some code. In these examples, we will be using data from the PHUSE Test Data Factory based on the original pilot project submission package. Note: You can see our replication of the CDISC pilot using the PHUSE Test Data Factory data here.
tplyr_table(adsl, TRT01P, where = SAFFL == "Y") %>% add_layer( group_desc(AGE, by = "Age (years)") ) %>% add_layer( group_count(AGEGR1, by = "Age Categories n (%)") ) %>% build() #> # A tibble: 9 x 8 #> row_label1 row_label2 var1_Placebo `var1_Xanomelin… `var1_Xanomelin… #> <chr> <chr> <chr> <chr> <chr> #> 1 Age (year… n " 86" " 84" " 84" #> 2 Age (year… Mean (SD) "75.2 ( 8.5… "74.4 ( 7.89)" "75.7 ( 8.29)" #> 3 Age (year… Median "76.0" "76.0" "77.5" #> 4 Age (year… Q1, Q3 "69.2, 81.8" "70.8, 80.0" "71.0, 82.0" #> 5 Age (year… Min, Max "52, 89" "56, 88" "51, 88" #> 6 Age (year… Missing " 0" " 0" " 0" #> 7 Age Categ… <65 "14 ( 16.3%… "11 ( 13.1%)" " 8 ( 9.5%)" #> 8 Age Categ… >80 "30 ( 34.9%… "18 ( 21.4%)" "29 ( 34.5%)" #> 9 Age Categ… 65-80 "42 ( 48.8%… "55 ( 65.5%)" "47 ( 56.0%)" #> # … with 3 more variables: ord_layer_index <int>, ord_layer_1 <int>, #> # ord_layer_2 <dbl>
Here are some of the high level benefits of using Tplyr
:
A Tplyr
table is constructed of two main objects, a table_table
object and tplyr_layer
objects making up the different summaries that are to be performed.
tplyr_table
ObjectThe tplyr_table
object is the main container upon which a tplyr
table is constructed. tplyr
tables are made up of one or more layers. Each layer contains an instruction for a summary to be performed. The tplyr_table
object contains those layers, and the general data, metadata, and logic necessary.
When a tplyr_table
is created, it will contain the following bindings:
treat_var
)where
parameter provided, used to subset the target
datatreat_var
pop_data
(if different)tplyr_table
tplyr_table
allows you a basic interface to instantiate the object. Modifier functions are available to change individual parameters catered to your analysis.
t <- tplyr_table(adsl, TRT01P, where = SAFFL == "Y") t #> *** tplyr_table *** #> Target (data.frame): #> Name: adsl #> Rows: 254 #> Columns: 49 #> pop_data (data.frame) #> Name: target #> Rows: 254 #> Columns: 49 #> treat_var variable (quosure) #> TRT01P #> header_n: header groups #> treat_grps groupings (list) #> Table Columns (cols): #> where: == SAFFL Y #> Number of layer(s): 0 #> layer_output: 0
tplyr_layer
ObjectUsers of Tplyr
interface with tplyr_layer
objects using the group_<type>
family of functions. This family specifies the type of summary that is to be performed within a layer. count
layers are used to create summary counts of some discrete variable. desc
layers create descriptive statistics, and shift
layers summaries the counts of different changes in states.
tplyr
already that you can perform, including n, mean, median, standard deviation, variance, min, max, interquartile range, Q1, Q3, and missing value counts. From these available summaries, the default presentation of a descriptive statistics layer will output ‘n’, ‘Mean (SD)’, ‘Median’, ‘Q1, Q3’, ‘Min, Max’, and ‘Missing’. You can change these summaries using set_format_strings
, and you can also add your own summaries using set_custom_summaries
. This allows you to easily implement any additional summary statistics you want presented.cnt <- group_count(t, AGEGR1) cnt #> *** count_layer *** #> Self: count_layer < 0x55c36d686aa8 > #> Parent: tplyr_table < 0x55c368eec440 > #> target_var: #> AGEGR1 #> by: #> where: TRUE #> Layer(s): 0 dsc <- group_desc(t, AGE) dsc #> *** desc_layer *** #> Self: desc_layer < 0x55c36d7e13d8 > #> Parent: tplyr_table < 0x55c368eec440 > #> target_var: #> AGE #> by: #> where: TRUE #> Layer(s): 0
Everyone has their own style of coding - so we’ve tried to be flexible to an extent. Overall, tplyr
is built around tidy syntax, so all of our object construction supports piping with magrittr (i.e. %>%
).
There are two ways to add layers to a tplyr_table
: add_layer
and add_layers
. The difference is that add_layer
allows you to construct the layer within the call to add_layer
, whereas with add_layers
you can attach multiple layers that have already been constructed upfront:
t <- tplyr_table(adsl, TRT01P) %>% add_layer( group_count(AGEGR1, by = "Age categories n (%)") )
Within add_layer
, the syntax to constructing the count layer for Age Categories was written on the fly. add_layer
is special in that it also allows you to use piping to use modifier functions on the layer being constructed
t <- tplyr_table(adsl, TRT01P) %>% add_layer( group_count(AGEGR1, by = "Age categories n (%)") %>% set_format_strings(f_str("xx (xx.x%)", n, pct)) %>% add_total_row() )
add_layers
, on the other hand, lets you isolate the code to construct a particular layer if you wanted to separate things out more. Some might find this cleaner to work with if you have a large number of layers being constructed.
t <- tplyr_table(adsl, TRT01P) l1 <- group_count(t, AGEGR1, by = "Age categories n (%)") l2 <- group_desc(t, AGE, by = "Age (years)") t <- add_layers(t, l1, l2)
Notice that when you construct the layers separately, you need to specify the table to which they belong. add_layer
does this automatically. tplyr_table
and tplyr_layer
objects are built on environments, and the parent/child relationships are very important. This is why, even though the layer knows who its table parent is, the layers still need to be attached to the table (as the table doesn’t know who its children are). Advanced R does a very good job at explaining what environments in R are, their benefits, and how to use them.
Notice that when you construct a tplyr_table
or a tplyr_layer
that what displays is a summary of information about the table or layer? That’s because when you create these objects - it constructs the metadata, but does not process the actual data. This allows you to construct and make sure the pieces of your table fit together before you do the data processing - and it gives you a container to hold all of this metadata, and use it later if necessary.
To generate the data from a tplyr_table
object, you use the function build
:
t <- tplyr_table(adsl, TRT01P) %>% add_layer( group_count(AGEGR1, by = "Age categories n (%)") ) t %>% build() #> # A tibble: 3 x 8 #> row_label1 row_label2 var1_Placebo `var1_Xanomelin… `var1_Xanomelin… #> <chr> <chr> <chr> <chr> <chr> #> 1 Age categ… <65 14 ( 16.3%) 11 ( 13.1%) " 8 ( 9.5%)" #> 2 Age categ… >80 30 ( 34.9%) 18 ( 21.4%) "29 ( 34.5%)" #> 3 Age categ… 65-80 42 ( 48.8%) 55 ( 65.5%) "47 ( 56.0%)" #> # … with 3 more variables: ord_layer_index <int>, ord_layer_1 <int>, #> # ord_layer_2 <dbl>
But there’s more you can get from Tplyr
. It’s great to have the formatted numbers, but what about the numeric data behind the scenes? What if you want to calculate your own statistics based off of the counts? You can get that information as well using get_numeric_data
. This returns the numeric data from each layer as a list of data frames:
get_numeric_data(t) #> [[1]] #> # A tibble: 9 x 5 #> TRT01P `"Age categories n (%)"` summary_var n total #> <chr> <chr> <chr> <dbl> <int> #> 1 Placebo Age categories n (%) <65 14 86 #> 2 Placebo Age categories n (%) >80 30 86 #> 3 Placebo Age categories n (%) 65-80 42 86 #> 4 Xanomeline High Dose Age categories n (%) <65 11 84 #> 5 Xanomeline High Dose Age categories n (%) >80 18 84 #> 6 Xanomeline High Dose Age categories n (%) 65-80 55 84 #> 7 Xanomeline Low Dose Age categories n (%) <65 8 84 #> 8 Xanomeline Low Dose Age categories n (%) >80 29 84 #> 9 Xanomeline Low Dose Age categories n (%) 65-80 47 84
By storing pertinent information, you can get more out of a Tplyr
objects than processed data for display. And by specifying when you want to get data out of Tplyr
, we can save you from repeatedly processing data while your constructing your outputs - which is particularly useful when that computation starts taking time.
The bulk of Tplyr
coding comes from constructing your layers and specifying the work you want to be done. Before we get into this, it’s important to discuss how Tplyr
handles string formatting.
Tplyr
String formatting in Tplyr
is controlled by an object called an f_str
, which is also the name of function you use to create these formats. To set these format strings into a tplyr_layer
, you use the function set_format_strings
, and this usage varies slightly between layer types (more on that later).
So - why is this object necessary. Consider this example:
t <- tplyr_table(adsl, TRT01P) %>% add_layer( group_desc(AGE, by = "Age (years)") %>% set_format_strings( 'n' = f_str('xx', n), 'Mean (SD)' = f_str('xx.xx (xx.xxx)', mean, sd) ) ) t %>% build() #> # A tibble: 2 x 8 #> row_label1 row_label2 var1_Placebo `var1_Xanomelin… `var1_Xanomelin… #> <chr> <chr> <chr> <chr> <chr> #> 1 Age (year… n 86 84 84 #> 2 Age (year… Mean (SD) 75.21 ( 8.5… 74.38 ( 7.886) 75.67 ( 8.286) #> # … with 3 more variables: ord_layer_index <int>, ord_layer_1 <int>, #> # ord_layer_2 <int>
In a perfect world, the f_str
calls wouldn’t be necessary - but in reality they allow us to infer a great deal of information from realistically very few user inputs. In the calls that you see above:
row_label2
column are taken from the left side of each =
in set_format_strings
f_str
callTplyr
, but you can also create your own summaries (more on that later). The default summaries that are built in include:
n
= Number of observationsmean
= Meansd
= Standard Deviationvar
= Varianceiqr
= Inter Quartile Rangeq1
= 1st quartileq3
= 3rd quartilemin
= Minimum valuemax
= Maximum valuemissing
= Count of NA valuesf_str
call, then those two summaries are formatted into the same string. This allows you to do a Mean (SD)
type format where both numbers appear.This simple user input controls a significant amount of work in the back end of the data processing, and the f_str
object allows that metadata to be collected.
f_str
objects are also used with count layers as well to control the data presentation. Instead of specifying the summaries performed, you use n
and pct
for your parameters, if you want both n’s and percents presented.
tplyr_table(adsl, TRT01P) %>% add_layer( group_count(AGEGR1, by = "Age categories") %>% set_format_strings(f_str('xx (xx.x)',n,pct)) ) %>% build() #> # A tibble: 3 x 8 #> row_label1 row_label2 var1_Placebo `var1_Xanomelin… `var1_Xanomelin… #> <chr> <chr> <chr> <chr> <chr> #> 1 Age categ… <65 14 (16.3) 11 (13.1) " 8 ( 9.5)" #> 2 Age categ… >80 30 (34.9) 18 (21.4) "29 (34.5)" #> 3 Age categ… 65-80 42 (48.8) 55 (65.5) "47 (56.0)" #> # … with 3 more variables: ord_layer_index <int>, ord_layer_1 <int>, #> # ord_layer_2 <dbl> tplyr_table(adsl, TRT01P) %>% add_layer( group_count(AGEGR1, by = "Age categories") %>% set_format_strings(f_str('xx',n)) ) %>% build() #> # A tibble: 3 x 8 #> row_label1 row_label2 var1_Placebo `var1_Xanomelin… `var1_Xanomelin… #> <chr> <chr> <chr> <chr> <chr> #> 1 Age categ… <65 14 11 " 8" #> 2 Age categ… >80 30 18 "29" #> 3 Age categ… 65-80 42 55 "47" #> # … with 3 more variables: ord_layer_index <int>, ord_layer_1 <int>, #> # ord_layer_2 <dbl>
Really - format strings allow you to present your data however you like.
tplyr_table(adsl, TRT01P) %>% add_layer( group_count(AGEGR1, by = "Age categories") %>% set_format_strings(f_str('xx (•◡•) xx.x%',n,pct)) ) %>% build() #> # A tibble: 3 x 8 #> row_label1 row_label2 var1_Placebo `var1_Xanomelin… `var1_Xanomelin… #> <chr> <chr> <chr> <chr> <chr> #> 1 Age categ… <65 14 (•◡•) 16… 11 (•◡•) 13.1% " 8 (•◡•) 9.5%" #> 2 Age categ… >80 30 (•◡•) 34… 18 (•◡•) 21.4% "29 (•◡•) 34.5%" #> 3 Age categ… 65-80 42 (•◡•) 48… 55 (•◡•) 65.5% "47 (•◡•) 56.0%" #> # … with 3 more variables: ord_layer_index <int>, ord_layer_1 <int>, #> # ord_layer_2 <dbl>
But should you? Probably not.
As covered under string formatting, set_format_strings
controls a great deal of what happens within a descriptive statistics layer. Note that there are some built in defaults to what’s output:
tplyr_table(adsl, TRT01P) %>% add_layer( group_desc(AGE, by = "Age (years)") ) %>% build() #> # A tibble: 6 x 8 #> row_label1 row_label2 var1_Placebo `var1_Xanomelin… `var1_Xanomelin… #> <chr> <chr> <chr> <chr> <chr> #> 1 Age (year… n " 86" " 84" " 84" #> 2 Age (year… Mean (SD) "75.2 ( 8.5… "74.4 ( 7.89)" "75.7 ( 8.29)" #> 3 Age (year… Median "76.0" "76.0" "77.5" #> 4 Age (year… Q1, Q3 "69.2, 81.8" "70.8, 80.0" "71.0, 82.0" #> 5 Age (year… Min, Max "52, 89" "56, 88" "51, 88" #> 6 Age (year… Missing " 0" " 0" " 0" #> # … with 3 more variables: ord_layer_index <int>, ord_layer_1 <int>, #> # ord_layer_2 <int>
To override these defaults, just specify the summaries that you want to be performed using set_format_strings
as described above. But what if Tplyr
doesn’t have a built in function to do the summary statistic that you want to see? Well - you can make your own! This is where set_custom_summaries
comes into play. Let’s say you want to derive a geometric mean.
tplyr_table(adsl, TRT01P) %>% add_layer( group_desc(AGE, by = "Sepal Length") %>% set_custom_summaries( geometric_mean = exp(sum(log(.var[.var > 0]), na.rm=TRUE) / length(.var)) ) %>% set_format_strings( 'Geometric Mean (SD)' = f_str('xx.xx (xx.xxx)', geometric_mean, sd) ) ) %>% build() #> # A tibble: 1 x 8 #> row_label1 row_label2 var1_Placebo `var1_Xanomelin… `var1_Xanomelin… #> <chr> <chr> <chr> <chr> <chr> #> 1 Sepal Len… Geometric… 74.70 ( 8.5… 73.94 ( 7.886) 75.18 ( 8.286) #> # … with 3 more variables: ord_layer_index <int>, ord_layer_1 <int>, #> # ord_layer_2 <int>
In set_custom_summaries
, first you name the summary being performed. This is important - that name is what you use in the f_str call to incorporate it into a format. Next, you program or call the function desired. What happens in the background is that this is used in a call to dplyr::summarize
- so use similar syntax. Use the variable name .var
in your custom summary function. This is necessary because it allows a generic variable name to be used when multiple target variables are specified - and therefore the function can be applied to both target variables.
Sometimes there’s a need to present multiple variables summarized side by side. Tplyr
makes this easy as well.
tplyr_table(adsl, TRT01P) %>% add_layer( group_desc(vars(AGE, AVGDD), by = "Age and Avg. Daily Dose") ) %>% build() #> # A tibble: 6 x 11 #> row_label1 row_label2 var1_Placebo `var1_Xanomelin… `var1_Xanomelin… #> <chr> <chr> <chr> <chr> <chr> #> 1 Age and A… n " 86" " 84" " 84" #> 2 Age and A… Mean (SD) "75.2 ( 8.5… "74.4 ( 7.89)" "75.7 ( 8.29)" #> 3 Age and A… Median "76.0" "76.0" "77.5" #> 4 Age and A… Q1, Q3 "69.2, 81.8" "70.8, 80.0" "71.0, 82.0" #> 5 Age and A… Min, Max "52, 89" "56, 88" "51, 88" #> 6 Age and A… Missing " 0" " 0" " 0" #> # … with 6 more variables: var2_Placebo <chr>, `var2_Xanomeline High #> # Dose` <chr>, `var2_Xanomeline Low Dose` <chr>, ord_layer_index <int>, #> # ord_layer_1 <int>, ord_layer_2 <int>
Tplyr
summarizes both variables and merges them together. This makes creating tables where you need to compare BASE, AVAL, and CHG next to each other nice and simple. Note the use of vars
- in any situation where you’d like to use multiple variable names in a parameter, use dplyr::vars
to specify the variables. You can use text strings in the calls to dplyr::vars
as well.
Count layers generally allow you to create n and n (%) count type summaries. There are a few extra features here as well. Let’s say that you want a total row within your counts. This is easy with add_total_row()
:
tplyr_table(adsl, TRT01P) %>% add_layer( group_count(AGEGR1, by = "Age categories") %>% add_total_row() ) %>% build() #> # A tibble: 4 x 8 #> row_label1 row_label2 var1_Placebo `var1_Xanomelin… `var1_Xanomelin… #> <chr> <chr> <chr> <chr> <chr> #> 1 Age categ… <65 14 ( 16.3%) 11 ( 13.1%) " 8 ( 9.5%)" #> 2 Age categ… >80 30 ( 34.9%) 18 ( 21.4%) "29 ( 34.5%)" #> 3 Age categ… 65-80 42 ( 48.8%) 55 ( 65.5%) "47 ( 56.0%)" #> 4 Age categ… NA 86 (100.0%) 84 (100.0%) "84 (100.0%)" #> # … with 3 more variables: ord_layer_index <int>, ord_layer_1 <int>, #> # ord_layer_2 <dbl>
Sometimes it’s also necessary to count summaries based on distinct values. Tplyr
allows you to do this as well with set_distinct_by
:
tplyr_table(adae, TRTA) %>% add_layer( group_count('Subjects with at least one adverse event') %>% set_distinct_by(USUBJID) %>% set_format_strings(f_str('xx', n)) ) %>% build() #> # A tibble: 1 x 6 #> row_label1 var1_Placebo `var1_Xanomelin… `var1_Xanomelin… ord_layer_index #> <chr> <chr> <chr> <chr> <int> #> 1 Subjects … " 47" 111 118 1 #> # … with 1 more variable: ord_layer_1 <lgl>
There’s another trick going on here - to create a summary with row label text like you see above, text strings can be used as the target variables. Here, we use this in combination with set_distinct_by
to count distinct subjects.
Adverse event tables often call for counting AEs of something like a body system and counting actual events within that body system. Tplyr
has means of making this simple for the user as well.
tplyr_table(adae, TRTA) %>% add_layer( group_count(vars(AEBODSYS, AEDECOD)) ) %>% build() #> # A tibble: 22 x 8 #> row_label1 row_label2 var1_Placebo `var1_Xanomelin… `var1_Xanomelin… #> <chr> <chr> <chr> <chr> <chr> #> 1 SKIN AND … "SKIN AND… " 47 (100.0… "111 (100.0%)" "118 (100.0%)" #> 2 SKIN AND … " ACTIN… " 0 ( 0.0… " 1 ( 0.9%)" " 0 ( 0.0%)" #> 3 SKIN AND … " ALOPE… " 1 ( 2.1… " 0 ( 0.0%)" " 0 ( 0.0%)" #> 4 SKIN AND … " BLIST… " 0 ( 0.0… " 2 ( 1.8%)" " 8 ( 6.8%)" #> 5 SKIN AND … " COLD … " 3 ( 6.4… " 0 ( 0.0%)" " 0 ( 0.0%)" #> 6 SKIN AND … " DERMA… " 1 ( 2.1… " 0 ( 0.0%)" " 0 ( 0.0%)" #> 7 SKIN AND … " DERMA… " 0 ( 0.0… " 0 ( 0.0%)" " 2 ( 1.7%)" #> 8 SKIN AND … " DRUG … " 1 ( 2.1… " 0 ( 0.0%)" " 0 ( 0.0%)" #> 9 SKIN AND … " ERYTH… " 13 ( 27.7… " 22 ( 19.8%)" " 24 ( 20.3%)" #> 10 SKIN AND … " HYPER… " 2 ( 4.3… " 10 ( 9.0%)" " 5 ( 4.2%)" #> # … with 12 more rows, and 3 more variables: ord_layer_index <int>, #> # ord_layer_1 <int>, ord_layer_2 <dbl>
Note that the nesting of variables happens automatically.
For simplicity of demonstration, some other features have not yet been demonstrated - so let’s get into that now!
First up, it’s common to have to present a total group, or a treated group vs. the placebo. Tplyr
allows you to create these groups as necessary using add_treat_group
and the abbreviated function add_total_group
.
tplyr_table(adsl, TRT01P) %>% add_total_group() %>% add_treat_grps(Treated = c("Xanomeline High Dose", "Xanomeline Low Dose")) %>% add_layer( group_count(AGEGR1, by = "Age categories") ) %>% build() #> # A tibble: 3 x 10 #> row_label1 row_label2 var1_Placebo var1_Total var1_Treated `var1_Xanomelin… #> <chr> <chr> <chr> <chr> <chr> <chr> #> 1 Age categ… <65 " 14 ( 16.3… " 33 ( 13… " 19 ( 11.3… " 11 ( 13.1%)" #> 2 Age categ… >80 " 30 ( 34.9… " 77 ( 30… " 47 ( 28.0… " 18 ( 21.4%)" #> 3 Age categ… 65-80 " 42 ( 48.8… "144 ( 56… "102 ( 60.7… " 55 ( 65.5%)" #> # … with 4 more variables: `var1_Xanomeline Low Dose` <chr>, #> # ord_layer_index <int>, ord_layer_1 <int>, ord_layer_2 <dbl>
What about having different by group variables? So far I’ve only demonstrated by
to present row label text. It additionally allows you to use grouping variables as well:
tplyr_table(adsl, TRT01P) %>% add_layer( group_count(AGEGR1, by = vars("Age categories", SEX)) ) %>% build() #> # A tibble: 6 x 10 #> row_label1 row_label2 row_label3 var1_Placebo `var1_Xanomelin… #> <chr> <chr> <chr> <chr> <chr> #> 1 Age categ… F <65 " 9 ( 10.5%… " 5 ( 6.0%)" #> 2 Age categ… F >80 "22 ( 25.6%… " 7 ( 8.3%)" #> 3 Age categ… F 65-80 "22 ( 25.6%… "28 ( 33.3%)" #> 4 Age categ… M <65 " 5 ( 5.8%… " 6 ( 7.1%)" #> 5 Age categ… M >80 " 8 ( 9.3%… "11 ( 13.1%)" #> 6 Age categ… M 65-80 "20 ( 23.3%… "27 ( 32.1%)" #> # … with 5 more variables: `var1_Xanomeline Low Dose` <chr>, #> # ord_layer_index <int>, ord_layer_1 <int>, ord_layer_2 <int>, #> # ord_layer_3 <dbl>
Grouping by columns? We’ve got that to - but this is actually specified at the tplyr_table
level. Why? It gets complicated if layers don’t have consistent columns, and stacking them together would get complex. Similarly, assuming you’d want the cols
argument the same between layers, it’s more tedious to specify it on every layer constructor.
tplyr_table(adsl, TRT01P, cols=SEX) %>% add_layer( group_count(AGEGR1, by = "Age categories") ) %>% build() #> # A tibble: 3 x 11 #> row_label1 row_label2 var1_Placebo_F var1_Placebo_M `var1_Xanomelin… #> <chr> <chr> <chr> <chr> <chr> #> 1 Age categ… <65 " 9 ( 17.0%)" " 5 ( 15.2%)" " 5 ( 12.5%)" #> 2 Age categ… >80 "22 ( 41.5%)" " 8 ( 24.2%)" " 7 ( 17.5%)" #> 3 Age categ… 65-80 "22 ( 41.5%)" "20 ( 60.6%)" "28 ( 70.0%)" #> # … with 6 more variables: `var1_Xanomeline High Dose_M` <chr>, #> # `var1_Xanomeline Low Dose_F` <chr>, `var1_Xanomeline Low Dose_M` <chr>, #> # ord_layer_index <int>, ord_layer_1 <int>, ord_layer_2 <dbl>
Note that in both by
and cols
- multiple variable names (or text along with variable names) should be specified using dplyr::vars
. We’ve tried to make the error messages explicit when you fail to do this, and help remind you of the proper parameter entry.
Now that we’ve gotten through a lot of the functionality of Tplyr
, what about when you’re ready to present your table? Well - we’re deferring the cosmetics to packages that already do this exceptionally well. We’re big fans of huxtable, as you may have seen from our package pharmaRTF. RStudio is continually working on and improving gt - so we’re not reinventing the wheel here. But we can do our part to make it easier.
In a huxtable
- the column headers of a table are just rows in a table. To make this preperation easier, we made the function add_column_headers
into Tplyr
. This allows you to simply use a string to created column headers - and it supports nesting. Let’s see it in action.
tplyr_table(adsl, TRT01P) %>% add_layer( group_desc(AGE, by = "Age (Years)") ) %>% build() %>% mutate_all(as.character) %>% add_column_headers( ' | Statistic | Placebo | Xanomeline (High) | Xanomeline (Low) | ord_layer_index | ord_layer_1 | ord_layer_2' ) #> # A tibble: 7 x 8 #> row_label1 row_label2 var1_Placebo `var1_Xanomelin… `var1_Xanomelin… #> <chr> <chr> <chr> <chr> <chr> #> 1 "" Statistic "Placebo" "Xanomeline (Hi… "Xanomeline (Lo… #> 2 "Age (Yea… n " 86" " 84" " 84" #> 3 "Age (Yea… Mean (SD) "75.2 ( 8.5… "74.4 ( 7.89)" "75.7 ( 8.29)" #> 4 "Age (Yea… Median "76.0" "76.0" "77.5" #> 5 "Age (Yea… Q1, Q3 "69.2, 81.8" "70.8, 80.0" "71.0, 82.0" #> 6 "Age (Yea… Min, Max "52, 89" "56, 88" "51, 88" #> 7 "Age (Yea… Missing " 0" " 0" " 0" #> # … with 3 more variables: ord_layer_index <chr>, ord_layer_1 <chr>, #> # ord_layer_2 <chr>
Columns are separated with the bar character (|). Nesting is done by adding text in curly brackets (i.e. {}).
tplyr_table(adsl, TRT01P) %>% add_layer( group_desc(vars(AGE, AVGDD), by = "Age and Avg. Daily Dose") ) %>% build() %>% mutate_all(as.character) %>% add_column_headers( ' | Statistic | Age {Placebo | Xanomeline (High) | Xanomeline (Low)} | Average Daily Dose {Placebo | Xanomeline (High) | Xanomeline (Low)} | Layer Index | Layer Order 1 | Layer Order 2' ) #> # A tibble: 8 x 11 #> row_label1 row_label2 var1_Placebo `var1_Xanomelin… `var1_Xanomelin… #> <chr> <chr> <chr> <chr> <chr> #> 1 "" "" "Age" "" "" #> 2 "" "Statisti… "Placebo" "Xanomeline (Hi… "Xanomeline (Lo… #> 3 "Age and … "n" " 86" " 84" " 84" #> 4 "Age and … "Mean (SD… "75.2 ( 8.5… "74.4 ( 7.89)" "75.7 ( 8.29)" #> 5 "Age and … "Median" "76.0" "76.0" "77.5" #> 6 "Age and … "Q1, Q3" "69.2, 81.8" "70.8, 80.0" "71.0, 82.0" #> 7 "Age and … "Min, Max" "52, 89" "56, 88" "51, 88" #> 8 "Age and … "Missing" " 0" " 0" " 0" #> # … with 6 more variables: var2_Placebo <chr>, `var2_Xanomeline High #> # Dose` <chr>, `var2_Xanomeline Low Dose` <chr>, ord_layer_index <chr>, #> # ord_layer_1 <chr>, ord_layer_2 <chr>
Ok - so, this was a lot to cover. But how does this all fit in the grand scheme of things? Let’s look at a more complete example - what if we wanted to build that demographics table
t <- tplyr_table(adsl, TRT01P, where = (SAFFL == "Y")) %>% add_total_group() %>% add_layer( group_count(SEX, by="Sex") %>% set_format_strings(f_str("xx (xxx%)",n,pct)) ) %>% add_layer( group_desc(AGE, by="Age Categories") ) %>% add_layer( group_count(RACE, by="Race") %>% set_format_strings(f_str("xx (xxx%)",n,pct)) ) %>% add_layer( group_count(ETHNIC, by="Ethnicity") %>% set_format_strings(f_str("xx (xxx%)",n,pct)) ) %>% add_layer( group_desc(WEIGHTBL, by="Weight") ) # build the table t %>% build() %>% select(starts_with('row_label'), var1_Placebo, starts_with('var1_X'), var1_Total) %>% add_column_headers(" | | Placebo | Xanomeline (Low) | Xanomeline (High) | Total") %>% apply_row_masks() %>% huxtable::as_hux(add_colnames=FALSE)
| Placebo | Xanomeline (Low) | Xanomeline (High) | Total | ||
| Sex | F | 53 ( 62%) | 40 ( 48%) | 50 ( 60%) | 143 ( 56%) |
| M | 33 ( 38%) | 44 ( 52%) | 34 ( 40%) | 111 ( 44%) | |
| Age Categories | n | 86 | 84 | 84 | 254 |
| Mean (SD) | 75.2 ( 8.59) | 74.4 ( 7.89) | 75.7 ( 8.29) | 75.1 ( 8.25) | |
| Median | 76.0 | 76.0 | 77.5 | 77.0 | |
| Q1, Q3 | 69.2, 81.8 | 70.8, 80.0 | 71.0, 82.0 | 70.0, 81.0 | |
| Min, Max | 52, 89 | 56, 88 | 51, 88 | 51, 89 | |
| Missing | 0 | 0 | 0 | 0 | |
| Race | AMERICAN INDIAN OR ALASKA NATIVE | 0 ( 0%) | 1 ( 1%) | 0 ( 0%) | 1 ( 0%) |
| BLACK OR AFRICAN AMERICAN | 8 ( 9%) | 9 ( 11%) | 6 ( 7%) | 23 ( 9%) | |
| WHITE | 78 ( 91%) | 74 ( 88%) | 78 ( 93%) | 230 ( 91%) | |
| Ethnicity | HISPANIC OR LATINO | 3 ( 3%) | 3 ( 4%) | 6 ( 7%) | 12 ( 5%) |
| NOT HISPANIC OR LATINO | 83 ( 97%) | 81 ( 96%) | 78 ( 93%) | 242 ( 95%) | |
| Weight | n | 86 | 84 | 84 | 254 |
| Mean (SD) | 62.76 ( 12.772) | 70.00 ( 14.653) | 67.28 ( 14.124) | 66.65 ( 14.131) | |
| Median | 60.55 | 69.20 | 64.90 | 66.70 | |
| Q1, Q3 | 53.62, 74.18 | 56.98, 80.30 | 56.05, 77.45 | 55.30, 77.10 | |
| Min, Max | 34.0, 86.2 | 41.7, 108.0 | 45.4, 106.1 | 34.0, 108.0 | |
| Missing | 0 | 0 | 1 | 1 |
And just like that - you have a huxtable table ready to go.
Wouldn’t it be nice if you had some resources for where to take it from here? Oh wait - you do! This is the perfect point to take things to the next step in the workflow: preparing and delivering your final output. We have plenty for you to read in our pharmaRTF vignettes about how to get started with huxtable, and create your RTF output files.
We’ve gotten a lot built into Tplyr
, but there’s a ways to go. Here are some of the things that we’re planning to implement but don’t have ready yet:
And more.
Help us out! Test out our package, submit issues, submit feature requests. We’d love to hear from you!


{% extends 'index.html' %} {% block title %}DataBase{% endblock %} {% block content %}
The words “Malicious URL” coin the word “Malware” and the meaning remains the same. Malicious URL refers to any malicious program that causes harm to a computer system or network. These attacks a computer or network in the form of viruses, worms, trojans, spyware, adware or rootkits. Their mission is often targeted at accomplishing unlawful tasks such as robbing protected data, deleting confidential documents or add software without the user consent. A simple and short URL can cause a lot of damage. The potential harm is so great that malicious links are considered one of the biggest threats to the digital world, especially when we talk about attacks and threats that arrive by email. To define it, a malicious URL is a link created with the purpose of promoting scams, attacks and frauds. By clicking on an infected URL, you can download a malware or a Trojan that can take your devices, or you can be persuaded to provide sensitive information on a fake website. The most common scams with malicious URLs involve spam and phishing. Phishing is a type of fraud used by criminals who try to deceive victims by impersonating well-known and trusted organizations or people. It means that you may receive a malicious URL within an email from a friend if his email account has been compromised or if the criminal is trying to deceive you by spoofing your friend’s name and address. Malicious links may also be hidden in supposedly safe download links and may spread quickly through the sharing of files and messages in sharing networks. Remember as well that, just like with emails, websites can also be compromised, which can lead users to click on malicious URLs and provide sensitive information directly to fraudsters.  In the case of email networks, for example, you can get a Secure Email Gateway. In the case of browsers, you can install protection plugins. The most effective and common protection techniques are based on filters that use URL blacklists, comparing domains and hosts. Other techniques involve machine learning, URL rewriting, Sandboxing and real-time click detection.


@* * Copyright 2010-2017 Artima, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *@ @import controllers.Application.scaladocsPageUrl @import controllers.Application.baseScalaVersion @userGuidePage("Migrating to 2.0") {
We have always worked very hard to maintain source compatibility from one release of ScalaTest to the next. Upgrading is usually simply a matter of bumping the ScalaTest version number in your build doing a full recompile, and over time cleaning up any deprecation warnings. With ScalaTest 2.0, however, we made some improvements for which it was not possible to deprecate, so some of your existing code may not compile. Neverthless, we expect the vast majority of existing ScalaTest user code to just recompile as is.
To ensure the smoothest migration, first please eliminate any deprecation warnings being emitted by your current version of ScalaTest on your existing code. (For best results, upgrade to 1.9.2 first and clear any deprecation warnings, though many of those reported will still be deprecated and working in 2.0.) Then just bump the ScalaTest version number to 2.0 and do a full build. If you encounter compilation errors, check the list below for help in resolving them.
These are the points of potential breakage in ScalaTest 2.0, which are described in the sections that follow:
Reporter
s (rare, but requires some rewriting)
withFixture
methods (common, but easy to fix)
run
method signatures (rare and easy to fix)
List
to immutable.IndexedSeq
(extremely rare, easy to fix)
length
, size
and HavePropertyMatcher
s (extremely rare, easy to fix)
If you have any confusion about how to migrate your ScalaTest 1.x code to ScalaTest 2.0, or encounter other problems, please post your specific issues
to scalatest-users
and we'll be happy to help.
Reporter
s
We greatly enhanced ScalaTest's event model in 2.0 to improve tools integration and reporting. Because it is not possible in Scala to deprecate
extractors, custom Reporter
s written for ScalaTest 1.x will usually
need to be migrated. You still write custom Reporters
in 2.0 the same way as in 1.x: you implement
apply
and handle events, usually by pattern matching on them. In 2.0, however, more events exist, and several of the pre-existing events now have more fields in them
(though all the old fields still exist and mean the same thing). So if an existing pattern match no longer compiles, look at the event (located in package
org.scalatest.events
) and make necessary changes to your pattern to accomodate the
new structure of the event. You may also want or need to handle events newly added in ScalaTest 2.0. For a nice list of all the 2.0 events, with links to the appropriate
Scaladoc documentation, see the main documentation for Reporter
.
withFixture
methods
In 2.0, the withFixture
methods declared in
Suite
and fixture.Suite
, and the
NoArgTest
and OneArgTest
functions passed to them, now
return an Outcome
. Because withFixture
previously
returned Unit
, you will need to insert an =
before the open curly brace of your overridden withFixture
implementations if you
didn't already do so, and in some cases, : Outcome =
.
I.e., change a withFixture
like this:
override def withFixture(test: NoArgTest) { // before setupDb() try super.withFixture(test) finally cleanupDb() }
To this (by adding the =
sign):
override def withFixture(test: NoArgTest) = { // after setupDb() try super.withFixture(test) finally cleanupDb() }
That will most often be all that's required, but if you were catching exceptions in a
withFixture
implementation, you will likely also need to change your catch clauses to a corresponding pattern match
on Outcome
types.
I.e., change a catch clause like this one:
override def withFixture(test: NoArgTest) { // before try super.withFixture(test) catch { case ex: Throwable => // log ex (the exception) and a screenshot throw ex } }
To a corresponding pattern match on Outcome
:
override def withFixture(test: NoArgTest) = { // after val outcome = super.withFixture(test) outcome match { case Failed(ex) => // log ex (the exception) and a screenshot } outcome }
run
method signatures
We modified the signature of four of Suite
's lifecycle methods: run
,
runNestedSuites
, runTests
, and runTest
. First, to make these methods more pleasant to override, we gathered
the parameters common to these methods into an Args
value object. If you have previously overridden them, you'll need to change
the method signature. Because the parameters have the exact same name inside the Args
object, however, you can simply import args._
to get them back in scope in your existing code.
For example, you'd change an overridden method like this:
override def runTests(testName: Option[String], reporter: Reporter, // before stopper: Stopper, filter: Filter, configMap: Map[String, Any], distributor: Option[Distributor], tracker : Tracker) { // Your existing code }
To this:
override def runTests(testName: Option[String], args: Args): Status = { // after import args._ // Your existing code }
By importing the members of args
, all the parameter names in scope before—reporter
, stopper
, etc.—will
again be in scope. Note that invocations of methods using the old signatures will also need to be changed to use the new signatures.
In addition to collecting parameters in Args
, we changed the result type from Unit
to
Status
. A Status
is
like a Future[Boolean]
that ultimately will indicate whether any failed test or aborted suite occurred. The Status
``completes''
when the tests and/or nested suites started by that method have all completed. Thus you may also need change your code so that an appropriate
Status
is returned. If so, familiarize yourself with the convenience Status
subclasses:
SuccceededStatus
,
FailedStatus
,
StatefulStatus
,
and CompositeStatus
.
Here's an example overriden runTests
method that cancels an entire suite of tests if its Selenium
driver is not supported. If the driver is supported, it just invokes super.runTests
and returns the
resulting Status
. Otherwise it fires an alert message and returns SucceededStatus
. (A succeeded Status
doesn't necessarily mean
that any tests ran, just that no test failed and no suite aborted.)
abstract override def runTests(testName: Option[String], args: Args): Status = { if (driverSupported) super.runTests(testName, args) else { alert("Cancelling " + this.suiteName + " : " + browserType + " not installed") SucceededStatus } }
List
to immutable.IndexedSeq
Where List
appeared as a result type in ScalaTest 1.x, immutable.IndexedSeq
is used instead in ScalaTest 2.0; for example, the result type of Suite
's nestedSuites
lifecycle method.
(Under the covers we return a Vector
.) When ScalaTest 1.0 was initially released, Vector
did
not yet exist in the Scala library and List
was considered by many to be the default Seq
type to use. In practice, it was discovered that
it is too easy to use List
(and other LinearSeq
's) in a non-performant way. In 2.0 we wanted to take the opportunity to make the
potentially breaking change of replacing List
result types with immutable.IndexedSeq
. This potentially breaking change is expected
to affect very little, if any, user code, essentially only code that called nestedSuites
then used ::
or :::
operators
on the result. To fix such a break, use +:
instead of ::
and ++
instead of :::
.
length
, size
and HavePropertyMatcher
s
Although ScalaTest's matchers have undergone a major refactor in 2.0, all previously documented syntax for matchers should continue to work exactly
the same with one potential exception, which should in practice be extremely rare. The potential breakage is that if you included length
or size
along with custom have-property matchers that you wrote, you'll get a compiler error. To fix such an error, add after
your length
or size
invocation an (of [<type>])
clause, as
described in the main Scaladoc documentation for Matchers
.
In ScalaTest 1.9.2, we refactored each style trait into a style class/style trait pair, to obtain speedier compiles. For example, in ScalaTest 1.9.1 and prior
versions, FlatSpec
was
a trait. In 1.9.2 and 2.0, FlatSpec
is a class; FlatSpecLike
is the trait. Same for FunSuite
(now a class) FunSuiteLike
(now the trait), and so on. Usages that directly extend a style trait will continue
to work fine (but should compile slightly faster). For example, this will continue to compile as before:
class MySpec extends FlatSpec with Matchers { // OK as is // ... }
However, if you were mixing in a style trait after with
, you'll need to add Like
. For example, you'd need to change this:
class MySpec extends TestKit(ActorSystem("my actors")) // before with FlatSpec with Matchers { // ... }
To this (by adding “Like
” to FlatSpec
):
class MySpec extends TestKit(ActorSystem("my actors")) // after with FlatSpecLike with Matchers { // ... }
To our knowledge, the only other source of potential breakage in ScalaTest 2.0 is the fragile base class problem. We have added fields and methods to traits such as
Matchers
and Suite
in 2.0 that may
conflict with fields and methods in your existing classes and cause a compiler error. Such issues can usually be easily fixed locally with simple renames or refactors.


Currency Exchanger
Current Currencies Supported:
Peso(Argentina)
Dollar(Australia)
Lev(Bulgaria)
Real(Brazil)
Piso(The Philippines)
Enter Desired Currency:
Enter Amount($):
Submit
Convert from any currency below!
Enter 1st Currency:
Enter 2nd Currency:
Enter Amount:
Submit