--- layout: archive title: Zulip Chat Archive permalink: /stream/113488-general/topic/sorting.20algorithms.20in.20lean.html ---
Hi guys,
A colleague at work (I'm working part-time in a tech company, Skyscanner) asked about dependent types & formal methods. After a bit of a chat he wanted to see an example implementation of some real-world algorithm with correctness guarantees, something like a selection sort would be great, but I would take anything "real enough but not too hard", e.g. binary search.
I've had a look at "programming in lean", but that's all I got:
This chapter will have to assume some familiarity with Lean as a proof assistant. Give some natural examples, for example, proving properties of functions of lists, sorting routines, properties of the extended gcd. Discuss two styles: separating functions and properties, and combining them, using subtypes.
There are the sort functions in mathlib: https://github.com/leanprover/mathlib/blob/master/data/list/sort.lean
Is this what you are looking for?
Thanks, this looks useful. It's perhaps a little bit too general (for the purpose of exposition I'd probably want to restrict myself to lists of nats and natural order of nats), and some of the methods are a little bit advanced (tactics, etc.), so I might want to change things a little bit.
There's one thing I seem to be missing, this doesn't show that the sorted list contains the same elements? Or does it?:
theorem sorted_insertion_sort : ∀ l, sorted r (insertion_sort l) | [] := sorted_nil | (a :: l) := sorted_ordered_insert totr transr a _ (sorted_insertion_sort l)
Also, could we not have this directly in the type signature of insertion_sort? Something like
"insertion sort is a function which takes a list and returns another list, which is both sorted and has the same elements as the original list"
l : list -> q : list \and sorted q \and same_elements_list l q
Put it this way, as a programmer I'd probably never care about these proofs, but maybe it would be nice to see them in the type signature?
Or maybe put it differently: let's say that I'd like to encode all the intended behaviour in the type signature and let a code monkey code the whole thing up, but for me to still have a guarantee that the monkey could never screw anything up (correctness-wise).
I don't follow, why would you want that in the type signature of insertion sort when you could prove those properties in separate lemmas. If you put it in the type signature it makes using insertion_sort
cumbersome
as in if it was in the type signature whenever i call insertion_sort
i have to remember it returns a tuple, and i only care about the first element (i.e. the sorted list it returns, if it had the type signature you propose)
There is a second lemma that I think you missed: perm_insertion_sort
says that the resulting list is a permutation of the original, meaning it has the same elements in the same multiplicity.
The whole volume 3 of Software Foundations is now devoted to such things: https://softwarefoundations.cis.upenn.edu/vfa-current/toc.html
As Andrew says, it is possible to encode the proofs in the type. Here are some reasons this is less good:
Fair enough guys, I find Mario's and Andrew's points entirely convincing, and of course I missed the lemma! I'll most likely still try to write a less generic implementation of one of those sorting algorithms. Good practice and hopefully something I'll be able to explain to my colleague.
Another possibility for simpler verified programs is the functions in list.basic
. There are lots of interesting examples of simple list functions and proofs that they have the expected properties. For example, list.filter
has a two-line definition, and its proof of correctness is list.mem_filter
(among others; that doesn't uniquely define the function).
Last updated: Apr 24 2020 at 19:02 UTC


Numbers 14:41
And Moses said, Wherefore now do ye transgress the commandment of the LORD? but it shall not prosper.


< SAME as in the assignment 4 handout >
Setting Up: Get data from BB into the appropriate folder: The links are provided only as a reference for documentation of the data. All data are provided on BB in the Assignments folder as a zipped file. Look at the data using proc contents/proc print (use the label option) to understand what variables you have. Do NOT open these tables using point & click. If you need more information, look at information on the webpages.
- Texas Discharge data (www.dshs.state.tx.us/thcic/hospitals/Inpatientpudf.shtm).
- Texas Physician Supply data (http://www.dshs.state.tx.us/chs/hprc/PHYS-lnk.shtm)
- Texas Death data (http://soupfin.tdh.state.tx.us/deathdoc.htm)
- Texas Health Regions Look-up Table (http://www.dshs.state.tx.us/chs/brfss/pages/counties.shtm)
< NEW TEXT >
The only thing you have to do differently from the full assignment is to run sas code I provide with this supplement (assign4sup.sas) ONCE before you start working.  Following are suggested sequence of action
- AFTER getting the above files into your data folder
- >Download assign4sup.sas, change the libname to point to the correct folder, then run
- That is it. You DO NOT have to rerun this again, unless you corrupt these files (overwrite them).
- Now do the assignment same as in full assignment, except look at your full data through out.
- Here are suggested steps for doing this. If you are confused, ignore.
- Create a different subfolder (e.g. orig/) from data/ in your assign4/ workspace
- Place the original large datasets in the new folder
- Point your libname to the new folder
- Now rerun your code. If you did everything correctly, the code should run with no problem.
So the work for the last 1 point: although the code runs, you will see that you have more rows than you should have (254*3). This is due to some data errors in the original data that you have to identify and fix. A strategy for this will be discussed on 3/3. See if you can fix this, and answer the questions using the full data, for full credit rather than the tiny data.


From this page, you can download and view a printer-friendly PDF version of each indicator presented on this website. Each PDF contains all the figures and text associated with a given indicator.
Additional files you can download from other pages:
- PDF versions of EPA's 2016 report and supporting elements
- PDF versions of previous editions of this report
- Detailed technical documentation for EPA's indicators
- High-resolution figures and the numerical data underlying the figures (on each indicator page)
- Antarctic Sea Ice (PDF)(5 pp, 471 K, August 2016)
- Arctic Sea Ice (PDF)(7 pp, 766 K, November 2016)
- Atmospheric Concentrations of Greenhouse Gases (PDF)(13 pp, 820 K, August 2016)
- Bird Wintering Ranges (PDF)(5 pp, 431 K, August 2016)
- Climate Forcing (PDF)(5 pp, 283 K, August 2016)
- Cherry Blossom Bloom Dates in Washington, D.C. (PDF)(3 pp, 302 K, August 2016)
- Coastal Flooding (PDF)(5 pp, 400 K)
- Drought (PDF)(6 pp, 494 K, August 2016)
- Glaciers (PDF)(7 pp, 790 K, August 2016)
- Global Greenhouse Gas Emissions (PDF)(6 pp, 387 K, August 2016)
- Great Lakes Water Levels and Temperatures (PDF)(5 pp, 865 K, August 2016)
- Heating and Cooling Degree Days (PDF)(5 pp, 476 K, August 2016)
- Heat-Related Deaths (PDF)(8 pp, 570 K, August 2016)
- Heat-Related Illnesses (PDF)(6 pp, 445 K, August 2016)
- Heavy Precipitation (PDF)(5 pp, 429 K, August 2016)
- High and Low Temperatures (PDF)(10 pp, 1 MB, August 2016)
- Ice Breakup in Two Alaskan Rivers (PDF)(3 pp, 353 K, August 2016)
- Lake Ice (PDF)(9 pp, 723 K, August 2016)
- Land Loss Along the Atlantic Coast (PDF)(4 pp, 255 K, August 2016)
- Leaf and Bloom Dates (PDF)(6 pp, 995 K, August 2016)
- Length of Growing Season (PDF)(8 pp, 907 K, August 2016)
- Lyme Disease (PDF)(7 pp, 666 K, August 2016)
- Marine Species Distribution (PDF)(6 pp, 582 K, August 2016)
- Ocean Acidity (PDF)(7 pp, 692 K, August 2016)
- Ocean Heat (PDF)(4 pp, 323 K, August 2016)
- Ragweed Pollen Season (PDF)(5 pp, 338 K, August 2016)
- River Flooding (PDF)(5 pp, 521 K, August 2016)
- Sea Level (PDF)(5 pp, 432 K, August 2016)
- Sea Surface Temperature (PDF)(5 pp, 459 K, August 2016)
- Snow Cover (PDF)(6 pp, 479 K, August 2016)
- Snowfall (PDF)(5 pp, 603 K, August 2016)
- Snowpack (PDF)(3 pp, 482 K, August 2016)
- Stream Temperature (PDF)(4 pp, 369 K, August 2016)
- Streamflow (PDF)(7 pp, 754 K, August 2016)
- Temperature and Drought in the Southwest (PDF)(5 pp, 627 K, August 2016)
- Trends in Stream Temperature in the Snake River (PDF)(2 pp, 252 K, August 2016)
- Tropical Cyclone Activity (PDF)(6 pp, 528 K, August 2016)
- U.S. and Global Precipitation (PDF)(5 pp, 547 K, August 2016)
- U.S. and Global Temperature (PDF)(6 pp, 517 K, August 2016)
- U.S. Greenhouse Gas Emissions (PDF)(6 pp, 469 K, August 2016)
- West Nile Virus (PDF)(5 pp, 393 K, August 2016)
- Wildfires (PDF)(9 pp, 618 K, August 2016)


Maradona leaves Gimnasia
by BeSoccerAfter three wins from eight matches in charge of Gimnasia y Esgrima La Plata, Diego Maradona has stepped down
Diego Maradona has stepped down as head coach of Superliga Argentina club Gimnasia y Esgrima La Plata after a little over two months in charge.
The former Argentina and Napoli great oversaw eight matches at Gimnasia, which yielded three wins and five defeats. Relegation-threatened Gimnasia remain third bottom of the table and the news that club president Gabriel Pellegrino will not stand for re-election this weekend has persuaded Maradona to walk away.
"Maradona stopped working today, he's no longer Gimnasia's head coach," Pellegrino told Radio La Red. "Maradona worked in a collective scheme. He said he was here to add, not to rest. He'd love to continue, but he wants unity. It just didn't happen."
Mariano Cowen and Salvador Robustelli will contest the presidency, but Maradona did not wish to continue in Pellegrino's absence. "Today's meeting failed. There will be elections on Saturday. [Diego Maradona] gave his will and he gave his time. He had an enormous will. There will be elections on Saturday and [the candidates] will look for a head coach."
Featured links
- Pochettino sacked as Tottenham manager
- The latest football transfers news and rumours
- Who has the most free-kicks goals: Messi or Cristiano?
- Luis Enrique returns to Spain national team
Pellegrino was influential in persuading Maradona to resume a fitful and nomadic coaching career. Gimnasia were the first team the 59-year-old had led in his homeland since the mid-1990s, when he enjoyed brief spells in charge of Textil Mandiyu and Racing Club while serving a playing ban for a failed drugs test during the 1994 World Cup.
He spectacularly returned more than a decade later to lead Argentina at the 2010 World Cup, where they were beaten by Germany in the quarter-finals. Stints with Al-Wasl and Fujairah in the UAE came before a 2018-19 tenure at Mexican second-tier club Dorados de Sinaloa, which became the subject of a Netflix documentary series.
Mariano Messera, the club's former midfielder, will take charge of Gimnasia's home match against Arsenal de Sarandi this weekend.


The simulation you are editing is out of sync or some other error has occurred.
Please reload the simulation to continue making edits.


Words where the vowel says its name:" Open, begins, rifle" , the letter says its name. The men on combat patrol are tense. A bus is stuck in the sand. Is it a trap" The men discuss tactics. To get to the bus, they must cross open land. Moss and Black slink up to the bus. The rest of the patrol is hidden in the dense forest. Black drops onto the grass, rifle in hand. Moss begins his run to the bus. There is a sudden bang and Moss gets hit in the leg. The patrol attacks. The locals run off into the forest. Black helps Moss stand up and limp back to camp.
in-context


roomai.sevenking package¶
Submodules¶
roomai.sevenking.SevenKingAction module¶
-
class
roomai.sevenking.SevenKingAction.
SevenKingAction
(key)[source]¶ Bases:
roomai.common.common.AbstractAction
The SevenKing action. The SevenKing action contains some cards. Examples of usages:
>> import roomai.sevenking
>> action = roomai.sevenking.SevenKingAction.lookup(“A_Spade,A_Heart”)
>> ## We strongly recommend you to get an action with the lookup function.
>> action.key
“A_Heart, A_Spade”
>> action.cards[0].point
“A”
>> action.cards[0].suit
“Heart”
>> action.pattern
p_2 # There are 2 cards in this action
-
cards
¶ The cards in this action. For example, cards=[roomai.sevenking.SevenKingPokerCards.lookup(“A_Spade”)]
-
key
¶ The key of this action. For example, key = “3_Heart,3_Spade”. The check action’s key = “”
-
classmethod
lookup
(key)[source]¶ lookup a SevenKing action with the specified key
Parameters: key – The specified key Returns: The action
-
pattern
¶ The pattern of the action
-
roomai.sevenking.SevenKingEnv module¶
-
class
roomai.sevenking.SevenKingEnv.
SevenKingEnv
[source]¶ Bases:
roomai.common.common.AbstractEnv
The SevenKing game environment
-
classmethod
compete
(env, players)[source]¶ Use the game environment to hold a compete for the players
Parameters: - env – The game environment
- players – The players
Returns: scores for the players
-
forward
(action)[source]¶ The SevenKing game environment steps with the action taken by the current player
Parameters: action – Returns:
-
init
(params={})[source]¶ Initialize the SevenKing game environment with the initialization params.
The initialization is a dict with some options
- allcards: the order of all poker cards appearing
- record_history: whether to record all history states. if you need call the backward function, please set it to True. default False
- num_players: how many players are in the game
An example of the initialization param is {“num_players”:2,”record_history”:True}
Parameters: params – the initialization params Returns: infos, public_state, person_states, private_state
-
classmethod
roomai.sevenking.SevenKingInfo module¶
-
class
roomai.sevenking.SevenKingInfo.
SevenKingPersonState
[source]¶ Bases:
roomai.common.common.AbstractPersonState
The person state of SevenKing
-
hand_cards
¶ The hand cards of the person state. For example, hand_cards = [roomai.sevenking.SevenKingPokerCard.lookup(“A_Spade”)]
-
hand_cards_key
¶ The hand cards key of the person state. For example, hand_cards_key = “3_Spade,A_Spade”
-
hand_cards_keyset
¶ The set of the poker cards’ key in the hand cards. For example, hand_cards_keyset={“A_Spade”}
-
-
class
roomai.sevenking.SevenKingInfo.
SevenKingPrivateState
[source]¶ Bases:
roomai.common.common.AbstractPrivateState
The private state of SevenKing
-
keep_cards
¶ The keep cards
-
-
class
roomai.sevenking.SevenKingInfo.
SevenKingPublicState
[source]¶ Bases:
roomai.common.common.AbstractPublicState
-
is_fold
¶ is_fold is an array of which player has take the fold action. For example, is_fold = [true,true,false] denotes the player0 and player1 have taken the fold action
-
license_action
¶ Generally, the player need takes an action with the same pattern as the license action. Unless the player takes an action at the beginning of a round
-
num_fold
¶ The number of players who has taken the fold action
-
num_hand_cards
¶ The number of cards in different players. For example, num_hand_cards = [3,5,2] denotes the player0 has 3 poker cards, the player1 has 5 poker cards and the player2 has 2 poker cards
-
num_players
¶ The number of players in this game
-
num_showed_cards
¶ The number of showed poker cards
-
showed_cards
¶ The poker cards have been thrown by the players and are public to all now.For example, showed_cards = [roomai.sevenking.SevenKingPokerCards.lookup(“A_Spade”),roomai.sevenking.SevenKingPokerCards.lookup(“3_Heart”)]
-
stage
¶ There are two stages in SevenKing. In the first stage(stage = 0), the player gets the same number of the poker cards after he takes an action (throws some cards).In the second stage (stage=1), the player doesn’t get the supplement. The player who firstly throws all his hand cards is the winner.
-
roomai.sevenking.SevenKingUtils module¶
-
class
roomai.sevenking.SevenKingUtils.
SevenKingPokerCard
(point, suit=None)[source]¶ Bases:
roomai.common.common.PokerCard
A poker card used in SevenKing game
The suit ranks in the common poker card(roomai.common.PokerCard) and the SevenKing poker card(roomai.SevenKing.SevenKingPokerCard) are different:
The common poker card: ‘Spade’: ‘Spade’:0, ‘Heart’:1, ‘Diamond’:2, ‘Club’:3, ‘ForKing’:4
The SevenKing poker card:’Spade’: 3, ‘Heart’: 2, ‘Club’: 1, ‘Diamond’:0, ‘ForKing’:4


Reports generated for [[ .Count ]] unique repos so far. Only repos with >= 50 files are considered for the high score list.


Check here for the progress of your execution.
Before executing an analysis, make sure that Docker is running and that
you have installed and configured a CWL executor.
You are offline.
Cannot pull Docker image. Retrying in {{ dockerPullTimeoutCountdown }} seconds.
Execution failed with exit code {{ execution?.error.code }}
{{ execution?.error.message }}


We are still a small but with a BIG heart a brand that promotes eco-style to the masses.
We do this through our amazing and warm, necessary and useful products, which not only in everyday affairs,
but also attract attention. Be stylish and protect the planet.
Choose EcoStyle!


Texas leaves state AGs antitrust suit vs T-Mobile-Sprint
by TALI ARBELThe coalition of state attorneys general suing to stop the merger of Sprint and T-Mobile has lost another state, Texas, two weeks before trial is scheduled to begin.
Texas said Monday that it has made its own settlement with T-Mobile.
The state attorneys general go to trial Dec. 9, arguing that the T-Mobile-Sprint deal will raise prices and be bad for competition. Mississippi and Colorado left the coalition in October, but 14 states and the District of Columbia remain.
Texas says T-Mobile won’t raise wireless prices in the state for five years and that it will build a next-generation 5G network in Texas.
T-Mobile has already promised a national 5G network and to keep prices steady for three years to federal regulators. They have approved the deal.
Sign up for Daily Newsletters
Copyright © 2019 The Washington Times, LLC.
Please read our comment policy before commenting.


If you are interested in contacting me or would like to see my resume:
Email me
Skills & Tools
| Languages: | JavaScript, Ruby, Java, Python, C, C++ |
| Web Development: | HTML/5, CSS/3, JQuery, PHP |
| Web Frameworks: | React Redux, AngularJS |
| Backend: | Ruby on Rails, Node.js |
| API: | GraphQL |
| Mobile Development: | React Native, Android |
| Database: | PostgreSQL, MongoDB |
Experience
-
Wealthsimple
Software Engineer(May 2019 - Current)- Develop and maintain mobile application and backend services for Trade product
- Previously developed and maintained web and mobile application for Invest product
-
Konrad
Software Developer(Nov 2017 - May 2019)- Developed Android applications for clients
- Technologies: Java, Kotlin
-
Mercatus Technologies
PHP Software Engineer Intern(Aug 2015 - Dec 2015)- Worked on an ecommerce application built on AngularJS
- Technologies: PHP, AngularJS, Twitter Bootstrap, Drupal
-
ON Semiconductor
Signal Processing Algorithm Developer(Jan 2015 - Apr 2015)- Developed, improved and tested audio processing algorithms to support C and MATLAB
- Technologies: C, MATLAB
-
Grand Rounds
Software Engineering Intern(Apr 2014 - Aug 2014)- Worked across the full-stack on Ruby on Rails using MVC design pattern
- Technologies: Ruby on Rails, Twitter Bootstrap
Interests
Baking
Photography
Piano
Travelling


CSS Media Queries Sizing
This page has CSS media query sizing formatting, so as you resize the page.
You should notice visible differences in the page content.
1800 Min Width
1600 Min Width
1400 Min Width
1200 Min Width
1000 Min Width
800 Min Width
600 Min Width
400 Min Width


Duda-Mara Totem Spirit:
Have you brought liquor for the ritual?
Well, it's not enough, but it's certainly better than nothing!
Give me your hand.
"OK."


2.3 Visualizing data using ggplot2
Now that you’ve grown familiar with the basics of data manipulation using dplyr and reshape2, the next logical step in our workflow is to visualize the data that we’ve exhaustively prepared. Be aware that there are plenty of marvellous graphics packages available in R depending on which tasks you’d like to perform. Within the scope of our short course, ggplot2 will do just fine not least because it is closely linked to the previously performed manipulation tasks (maybe because of the same author).
In ggplot2, every plot we want to draw consists of incremental calls on how to represent the individual plot components (basically x
and y
). This means a much more consistent way of building visualizations as compared, for instance, to the much more conventional style of lattice, but it also means that things are rather different from what you might have learned about syntax and structure of (plotting) objects in R so far.
Note also that the brief examples shown below are mainly taken from another MARA course about Creating publication quality graphs using R. Feel free to browse the code tutorial or the accompanying course slides in case you’re not entirely satisfied with the rather shallow introduction given here or if you wish to learn more about lattice-style figures.
Scatter plots
Scatter plots are produced by invoking geom_points()
. If we wanted to plot variables ‘price’ and ‘carat’ from diamonds
against each other, the ggplot()
call would be as follows.
library(ggplot2)
ggplot(aes(x = carat, y = price), data = diamonds) +
geom_point()
Let’s look at the above code in a little more detail. The first line is the fundamental definition of what we want to plot. We provide the ‘aesthetics’ for the plot (aes()
) and state that we want the values on the x
-axis (y
-axis) to represent ‘carat’ (‘price’). The data
to take these variables from is our diamonds
dataset. That’s basically it, and this will not change a hell of a lot in the subsequent plotting routines.
What will change in the code chunks that follow is how we want the relationship between these variables to be represented in our plot. This is done by defining so-called geometries (geom_*()
). In this first case we stated that we want the relationship between x
and y
to be represented as points, hence we used geom_point()
.
For the sake of practicing, let’s add another layer to our plot. In order to provide the regression line, for instance, we need a function called stat_smooth()
. Note that we also specify the smoothing method
and the line colour
, size
and linetype
. se = FALSE
tells the function not to display confidence intervals for the moment. See ?stat_smooth
for a more detailed overview of costumization possibilities.
ggplot(aes(x = carat, y = price), data = diamonds) +
geom_point() +
stat_smooth(method = "lm", se = FALSE,
colour = "red", size = 1.5, linetype = "dashed")
If we wanted to provide a plot showing the relationship between ‘price’ and ‘carat’ in panels representing the quality of the diamonds, we need what in ggplot2 is called facetting (similar to panels in lattice). To achive this, we simply repeat our plotting call from earlier and add another layer to the call which does the facetting. Note that this time, confidence intervals are included via se = TRUE
and fill
-ed grey.
ggplot(aes(x = carat, y = price), data = diamonds) +
geom_point() +
stat_smooth(method = "lm", se = TRUE,
colour = "red", fill = "grey35") +
facet_wrap(~ cut)
One thing that some people dislike about the default settings in ggplot2 is the grey background of the plots. This grey background is, in my opinion, a good idea when colors are involved as it tends to increase the contrast of the colors. If, however, the plot is a simple black-and-white scatter plot, a white facet background seems more reasonable. We can easily change this using a pre-defined theme called theme_bw()
. Note that in the following, we also change the axis titles (labs()
) and the number of rows (nrow
) and columns (ncol
) into which the facets should be arranged – simple and straightforward, isnt’t it?
ggplot(aes(x = carat, y = price), data = diamonds) +
geom_point(colour = "grey65") +
stat_smooth(method = "lm", se = TRUE,
colour = "black", fill = "grey35") +
facet_wrap(~ cut, nrow = 2, ncol = 3) +
labs(x = "Carat", y = "Price ($)") +
theme_bw()
Box and whisker plots
Box and whisker plots (in the following ‘boxplots’) drawn with ggplot2 look quite nice and, in contrast to lattice, do not require the user to exhaustively modify graphical parameter settings in order to get an acceptable result. But see for yourselves (using the default settings).
## basic frame
p <- ggplot(aes(x = color, y = price), data = diamonds)
## add boxplot
p_bw <- p + geom_boxplot()
## print
print(p_bw)
Note that this time, we stored the basic frame of our plot in a variable p
and added the desired geom_boxplot()
layer afterwards. In order to keep a clear structure, this is possibly the ideal way to create graphics using ggplot2 - so stick to it!
As we’ve already seen, facetting and modifying the default theme require also just one more line of code each.
## add faceted boxplots
p_bw <- p +
geom_boxplot(fill = "grey90") +
facet_wrap(~ cut) +
theme_bw()
print(p_bw)
Histograms and density plots
Much like with boxplots, ggplot2 produces quite nice histograms and density plots when using the default settings.
## new basic frame
p <- ggplot(aes(x = price), data = diamonds)
## add histogram
p_hist <- p + geom_histogram()
print(p_hist)
When working with density plots in ggplot2, it is quite easy to fill the area under the curve which really contributes to the visual representation of the data.
## add densityplot
p_dens <- p + geom_density(fill = "black", alpha = 0.5)
print(p_dens)
In addition to theme_bw()
, there’s a lot of different theme()
settings that let you customize your plots at will. For instance, let us slightly rotate the tick labels on the x-axis and move them horizontally a little bit. element_text()
is an essential function to achieve such things as it allows you to modify, among others,
- font
family
andface
(e.g. ‘bold’), - text
colour
andsize
, - horizontal (
hjust
) and vertical (vjust
) justification as well as angle
of the tick labels.
(In case you prefer American English, element_text()
– or for that matter any ggplot2 function – also understands color
instead of colour
☺)
p_dens <- p +
geom_density(fill = "black", alpha = 0.5) +
facet_grid(color ~ cut) +
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
print(p_dens)


{% load staticfiles i18n %}
Tell Appagoo what you'd like to share and what must remain private
Check apps that match your profile, or check your installed apps
Which information are you ready to share?
Let's see how your installed apps match the criteria in your profile
Appagoo has gathered more fun information for you


Cool Maze privacy terms
These terms apply since September, 2019.
These terms may evolve. In case this happens, the new terms will apply to data transfered after the new terms have been published. The new terms won't revoke protections granted to previously transfered data.
Cool Maze (the Service) is an online system to transfer data from a source device A to a target device B.
The User must be in control of the source device A, of the browser of the target device B, and of the data D to be transfered from A to B.
The Service is provided free of charge for the User.
The Service is provided without any guarantee, except the best-effort policy to respect the privacy of the personal data of its Users.
The Service doesn't use and doesn't store the identity of its Users.
The only personal data involved is the payload D that the User explicitly requests to transit by the Service, using a "Share via ... Cool Maze" action.
The data D sent from A to B is routed through intermediary servers: the Brokers and the File server.
All data transfers are protected by HTTPS protocol:
- Web pages from Service to User web browser
- Short text messages from User mobile device A to Brokers
- Files from User mobile device A to File server
- Short text messages and notifications from Brokers to target computer web browser B
- Files from File server to target computer web browser B
The transfered data D is kept private and is never made publicly available.
The transfered data D is not disclosed to third parties.
The transfered files are provided to the target B through short-lived URLs. The URLs expire after a maximum of ten minutes. This means that after ten minutes, the User cannot use a specific URL anymore. Expiring URLs do not prevent the User from saving the transfered files to the storage of target device B.
The Service uses cloud computing infrastructure providers. The facilities are Google App Engine, Google Cloud Storage, and Pusher.
Cool Maze for Android uses end-to-end encryption (E2EE) since its version 1.1.1909 released in September 2019. This means that the service owner and the cloud infrastructure vendors can't read the data D transiting through the Service.
Cool Maze for iOS currently doesn't implement end-to-end encryption. This means that the service owner could (theorically) read the data D transiting through the Service. The infrastructure providers are bound by explicit privacy policies. However, it is technically feasible that they read the data D transiting through the Service. Whether this would constitute a violation of their own policies is debatable on a case-by-case basis.
Anonymous data may be gathered for statistics purpose. This data includes, and is not limited to:
- country and city of usage,
- size and type of transfered data D,
- actions made by the same User,
- software quality metrics, such as the timing performances of Service processings.
Data sent from the mobile to the server, necessary for proper message delivery:
- actionid
- The unique ID of the current "Share" action
- qrKey
- The unique ID of the ephemeral communication channel of the current "Share" action
- crypto
- The encryption scheme used by the current "Share" action to achieve E2EE (when E2EE is active)
- cryptoiv
- The Initialization vector (IV) used by the current encryption scheme of the current "Share" action to achieve E2EE
- multiCount
- Number of resources being shared by the current "Share" action
- message
- Text message being shared or URL to the resource being shared (when E2EE is active, this field is encrypted)
- filename
- Filename of the resource being shared (when E2EE is active, this field is encrypted)
- thumb
- Thumbnail of the resource being shared (when E2EE is active, this field is encrypted)
- resized
- Whether the shared resource was resized by the Cool Maze mobile app
- width
- The width of the shared resource (after optional resizing)
- height
- The height of the shared resource (after optional resizing)
- bup
- Number of resource bytes already sent, when QR-code is read
- gcsObjectName
- File server path to the data being shared
- hash
- Hash of the resource being shared (not used when E2EE is active)
- user-agent
- The Cool-Maze mobile app User Agent contains: App name, App version, App build number, plus 3 fields for service quality monitoring
Data sent from the mobile to the server for service quality monitoring:
- connection
- Mobile connexion type: wifi, or mobile data
- type
- MIME type of the resource being shared
- nth
- Number of "Share" actions made by the current mobile app instance (since installation)
- dark
- Whether Cool Maze is displayed in Dark Mode
- tte
- Time to encrypt the resource on the mobile before uploading, in milliseconds (when E2EE is active)
- ttup
- Time to upload the single resource from the mobile to the cloud File server, in milliseconds
- ttmultup
- Time to upload all of the multiple resources from the mobile to the cloud File server, in milliseconds
- ttscan
- Time between the start of the "Share" action and the QR-code scan, in milliseconds
- user-agent
- The Cool-Maze mobile app User Agent contains: App installation ID, mobile OS, mobile model, plus 3 necessary App fields
Data sent from the target web browser to the server for service quality monitoring:
- ttf
- Time to fetch (download) the resource from the cloud File server, in milliseconds
- ttd
- Time to decrypt the resource on the target web browser, in milliseconds
- qrttnotif
- Time between the generation of the QR-code and a scan notification for a single resource received by the web browser, in milliseconds
- qrttcast
- Time between the generation of the QR-code and a notification of (single or multiple) resource ready received by the web browser, in milliseconds
Acknowlegements
We thank
Copyright
©2017-2021 Bartalog Software
Contact
admin@coolmaze.io


Karaoke is an "audience participation" sound system, in which the soundtrack and usually the melody are played along with a moving display of the lyrics. This chapter considers the features, formats and user-level tools for playing Karaoke.
Karaoke is an "audience participation" sound system, in which the soundtrack and usually the melody are played along with a moving display of the lyrics. Within this, there can be variations or different features:
Karaoke is very popular in Asia, and has a following in European countries. Karaoke systems are believed to have originated in Asia although the history according to Wikipedia is a little muddy.
There are various file formats for Karaoke described by Jean-Pierre.Cocatrix KaraWin
Video CDs are an older form of video storage on an optical disk. The resolution is fairly low, typically 352x240 pixels, with a frame rate of 25 framse per second. Although they were used by a few movies they have been supplanted for movies by DVDs. However, they were used extensively at one stage for Karaoke disks.
The cheaper CD/DVD players from Asia often have microphone inputs, and can be used as Karaoke players with VCD disks. Typically files are simple movies in AVI or MPEG format and so you can just sing along. While the lyrics are usually displayed, highlighted in time to the melody, there are no advanced features such as scoring, or display of the melody.
If you have VCD disks, they can be mounted as IC9660 files on your computer, but on a Linux system you cannot directly extract the files. Players such as VLC, mplayer and Totem can play files from them.
You need to use something like vcdimager
to extract files from a
VCD disk.
This may be in your package system, or you can download it from the
GNU developer site
and build it from source. The video files can then be extracted as MPEG or AVI files by
vcdxrip --cdrom-device=/dev/cdrom --rip
(On my system I had to replace /dev/cdrom with /dev/sr1 as I could not extract
from the default DVD player.
I found out what device it was by running mount
,
then unmounted it by umount
.)
From Wikipedia "CD+G":
CD+G (also known as CD+Graphics) is an extension of the compact disc standard that can present low-resolution graphics alongside the audio data on the disc when played on a compatible device. CD+G discs are often used for karaoke machines, which utilize this functionality to present on-screen lyrics for the song contained on the disc.
Each song is composed of two files: an audio file and a video file containing the lyrics (and maybe some background scenes).
There are many disks that you can buy using this format. You can't play them on directly your computer. rythmbox will play the audio, but not the video. vlc and totem don't like them.
Ripping the files onto your computer for storage on your
hard disk is not so straightforward. The audio disks do
not have a file system in the normal sense. For example,
you cannot mount them using the Unix mount
command; they are not even in ISO format. Instead you need
to use a program like cdrdao
to rip the
files to a binary file and then work on that,
$ cdrdao read-cd --driver generic-mmc-raw --device /dev/cdroms/cdrom0 --read-subchan rw_raw mycd.toc
creates a data file and a table of contents file.
The format of the CDG files has not apparently been publically released, but is decribed by Jim Bumgardner (back in 1995!) at CD+G Revealed: Playing back Karaoke tracks in Software
Programs such as SoundJuicer will extract the audio tracks, but leave the video behind.
MP3+G files are CD+G files adapted for use on a normal PC. They consist of an MP3 file containing the audio and a CDG file containing the lyrics. Frequently they are zipp'ed together.
Many sites selling CD+G files also sell MP3+G files. Various web sites give instructions on how to create your own MP3+G files. There are not many free sites.
The program cgdrip.py
from
cdgtools-0.3.2
can rip CD+G files from an audio disk and convert
them to a pair of MP3+G files.
The instructions from the (Python) source code are
To start using cdgrip immediately, try the following from the command-line (replacing the --device option by the path to your CD device):
$ cdrdao read-cd --driver generic-mmc-raw --device /dev/cdroms/cdrom0 --read-subchan rw_raw mycd.toc
$ python cdgrip.py --with-cddb --delete-bin-toc mycd.toc
You may need to use a different --driver option or --read-subchan mode
to cdrdao depending on your CD device.
The MP3 and CDG files usually share the same root e.g. Track1.mp3 and Track1.cdg. When unzipped,
vlc
can play them by giving it the MP3 file only to play as invlc Track1.mp3
Other players such as mplayer do not recognise this combination and only play the audio.
Buying CD+G or MP3+G files
There are many sites selling CD+G or MP3+G songs. Just do a Google search. However, the average price per song is about US$3, and if you want to build up a large collection that can become very expensive. Some sites will give discounts for larger volume purchases, but even at US$30 for 100 songs, the expense can be high.
The cheapest site for really large collections that I have found so far is Unify mall There you can purchase (for example) 29,000 English CDG songs for US$399. There is a little hiccup in this: if you buy their "UNIFY PCKP1000A 500-2000GB HDD MP4/DVD/CDG PC Karaoke Player" for US$559 you should be able to get these English songs for free! If you want to also get, say, 30,000 Mandarin songs thrown in for free, the economics of building your own Karaoke player become more shaky... We will ignore that issue here - it's your choice!
Converting MP3+G to video files
The tool
ffmpeg
can merge the audio and video to a single video file by e.g.ffmpeg -i Track1.cdg -i Track1.mp3 -y Track1.avi
or
avconv -i Track1.cdg -i Track1.mp3 test.avi avconv -i test.avi -c:v libx264 -c:a copy outputfile.mp4
to create an AVI file containing both video and audio. This can be played by vlc, mplayer, rhythmbox, etc.
There is a program cdg2video. While it is last dated February, 2011, changes in the FFMpeg internals means that it no longer compiles. Even if you fix the obvious changes, there are a huge number of complaints from the C compiler about the use of deprecated FFMpeg functions.
MPEG 4 files
It is becoming common to have Karaoke systems using MPEG 4 video players. These embed all of the information into a video. There is no scoring system with players of these files.
Some rate them as much higher sound quality: "MIDI files sound so cheesy it's sick" . I would suggest it is more an issue with the synthesizer used than the format. Certainly high-end synthesizer manufacturers such as Yamaha would not agree!
MPEG 4 files are certainly larger than the corrsponding MIDI files, and you will need a substantial disk to hold many of them.
There are many sites selling MP4 songs. Just do a Google search. However, the average price per song is about US$3, and if you want to build up a large collection that can become very expensive. Some sites will give discounts for larger volume purchases, but even at US$30 for 100 songs, the expense can be high.
The cheapest site for really large collections that I have found so far is Unify mall There you can purchase (for example) 6,200 English MP4 songs for US$199. There is a little hiccup in this: if you buy their "UNIFY PCKP1000A 500-2000GB HDD MP4/DVD/CDG PC Karaoke Player" for US$559 you should be able to get these English songs for free! If you want to also get, say, 25,000 Mandarin songs thrown in for free, the economics of building your own Karaoke player become more shaky. We will ignore that issue here - it's your choice!
Karaoke machines
There are many Karaoke machines which come with a DVD, such as the Malata or Songken systems. In most cases the songs are stored as MIDI files, with the songtrack in one MIDI file and the lyrics in another. Some more recent systems will use WMA files for the soundtrack, and this allows one track to have a vocal supplied and the other without the vocal. Such systems will usually include a scoring mechanism, although the basis for the scoring is not made explicit. The most recent ones are hard-disk based, usually with MP4 files. They do not seem to have a scoring system.
The two systems I own show different characteristics. The Songken MD-388 plays songs from multiple languages, such as Chinese, Korean, English, etc. My wife is Chinese, but I cannot read Chinese characters. There is an Anglicised script called PinYin and the Songken shows both the Chinese characters and the PinYin, so I can sing along too. It looks like
The Malata MDVD-6619 does not show the PinYin when playing Chinese songs. But it does show the notes you are supposed to be singing and the notes you are actually singing. This screen image shows that I am way off key:
MIDI players
Karaoke files in MIDI format can be found from several sites, usually ending in .kar. Any MIDI player such as Timidity can play such files. However, they do not always show the lyrics synchronised to the melody.
Finding MIDI files
There are several sites on the Web offering files in MIDI format.
- MIDIZone
- midiworld
- CoolMIDI
- ElectroFresh
- Freemidi
- Karaoke Version e.g. "House of the Rising Sun" melody on track 4
- MIDaoke e.g. Pink Floyd "Wish you were here" melody on track 2
- Home Musician e.g. the Eages "Hotel California" has melody labelled "Melody" on Clarinet on track 4. kmid plays through lyrics. e.g. Jimi Hendrix "Purple Haze" with melody labelled "Vocals - Choir Ahhs" on track 4. e.g. The Polics "Don't stand so close to me" melody on track 4
- 1001 Midis e.g. 10cc "I'm not in love" has melody on track 4, no lyrics (MIDI only)
KAR file format
There is no formal standard for Karaoke MIDI files. There is a widely accepted industry format called the MIDI Karaoke Type 1 file format.
From MIDI Karaoke Frequently Asked Questions
What is the MIDI Karaoke Type 1 (.KAR) file format? A: A MIDI Karaoke file is a Standard MIDI File type 1 that contains a separate track with lyrics of the song entered as text events. Load one of the MIDI karaoke files into a sequencer to examine the contents of the tracks of the file. The first track contains text events that are used to make the file recognizable as the MIDI Karaoke file. @KMIDI KARAOKE FILE text event is used to for that purpose. The optional text event @V0100 denotes the format version number. Anything starting with @I is any information you want to include in the file.
The second track contains the text meta events for the lyrics of the song. The first event is @LENGL. It identifies the language of the song, in this case English. The next couple of events start with @T which identifies the title of the songs. You can have up to three events like these. The first event should contain the title of the song. Some programs (ex. Soft Karaoke) read this event to get the name of the song to be displayed in the File Open dialog box. The second event usually contains the performer or author of the song. The third event can contain any copyright information or anything else.
The rest of the second track contains the words of the song. Each event is the syllable that is supposed to be sung at the time of the event. If the text starts with \, it means to clear the screen and show the words at the top of the screen. If the text starts with /, it means to go to the next line.
Important note: There can be only 3 lines per screen in a .kar file for Soft Karaoke being able to play the file correctly. In other words, there can be only two / (forward slashes) beginning each line in a line of lyrics. The next line has to start with \ (back slash).
There are several weaknesses in this format:
- The list of possible languages is not specified, only English
- The encoding of text is not specified (e.g. Unicode UTF-8?))
- There is no means of identifying the channel carrying the melody
pykaraoke
This is a dedicated Karaoke player written in Python, using a variety of libraries such as Pygame and WxPython. It plays the song and shows where in the lyrics you are. A screen dump of "Smoke gets in your eyes" looks like
PyKaraoke plays the soundtrack and displays the lyrics. It does not act as a proper Karaoke system by also playing the singer's input. But PyKaraoke uses the PulseAudio system, so you can simultaneously play other programs. In particular, you can have PyKaraoke running in one window, while
pa-mic-2-speaker
is running in another. PulseAudio will mix the two output streams and play both sources together. Of course, there will no scoring possible in such a system without extra work.kmid
kmid
is a KDE-based Karaoke player. It plays the song and shows where in the lyrics you are. A screen dump of "Smoke gets in your eyes" looks like
kmid uses either Timidity or Fluidsynth as MIDI backend.
kmid
plays the soundtrack and displays the lyrics. It does not act as a proper Karaoke system by also playing the singer's input. Butkmid
can use the PulseAudio system, so you can simultaneously play other programs. In particular, you can havekmid
running in one window, whilepa-mic-2-speaker
is running in another. PulseAudio will mix the two output streams and play both sources together. Of course, there will no scoring possible in such a system without extra work.Microphone inputs and reverb effects
Nearly all PCs and laptops have a soundcard to play audio. While nearly all of these also have a microphone input, some do not. For example, my Dell laptop does not; the Raspberry Pi does not; and many Android TV media boxes do not.
Those computers without microphone inputs often have USB ports. They will usually accept USB soundcards, and if the USB has a microphone input then that is recognised.
If you want to support two or more microphones, then you will need the corresponding number of soundcards, or a mixer device. I have seen the Behringer MX-400 MicroMix, a "Four Channel Compact Low Noise Mixer" for US$20, or you can find circuit diagrams on electronics web sites (Google for "circuit diagram for audio mixer").
Reverb is an effect which gives a fuller "body" to the voice by adding (artificial) echoes with different delays. Behringer also make the MIX800 MiniMix which can mix two microphones with reverb effects and also has a passthrough for line input (so you can play the music and control the microphones). (I have no links to Behringer.). A similar unit is the UNIFY K9 Reverb Computer Karaoke Mixer.
DVD players from China often have dual microphone inputs with mix and reverb capabilities. Given that they can cost as little as US$13 (admittedly for 1,000 units :-), it shows that mixing and reverb should not be too costly. My guess is that they use something like the Mitsubishi M65845AFP , "DIGITAL ECHO WITH MICROPHONE MIXING CIRCUIT". The data sheet shows a number of possible configurations, for those who like to build their own.
Conclusion
There are a variety of Karaoke systems, using VCD disks or dedicated systems. MIDI format Karaoke files files can be played using ordinary MIDI software, and there are a couple of Linux Karaoke players.


BES
Store
Dress To Impress
Suit up in our all new collection!
Don't Miss Out On All The New Summer Items!
Men
Shirts
40
Tops
50
Pants & Shorts
70
Shoes
25
Accessories
95
Women
Dresses
75
Tops
140
Pants & Shorts
60
Shoes
250
Accessories
65
Stylish Bag
$125.00
Watch
$1,250.00
Heart Necklace
$370.00
Eastern Bag
$205.00
Twin Jewel Earings
$115.00
Dual Fin Earings
$125.00
Black Bag
$110.00
Dolphin Tail Earings
$125.00
Blue Jeweled Heart Necklace
$230.00
Previous
1
2
3
>>
Next


Understanding results in RadarGun 3
What's wrong about how RadarGun 2.x measures response times
The stress tests used in Radargun 2.x (the logic mostly in TestStage and its inheritors, and Stressor) share a flaw that appears in many benchmark tools. These tools try to simulate unlimited amount of users, executing requests (or sequences of requests - conversations) using fixed number of threads.
Currently, we set fixed number of threads and (when we set non-zero request period
) each of them follows this pattern:
long startTime = currentTime();
for (long request = 1; ; ++request) {
doRequest();
long nextRequestTime = startTime + request * period;
long sleepTime = nextRequestTime - currentTime();
if (sleepTime > 0) {
sleep(sleepTime);
}
}
This works as long as all the requests take shorter time than period
, but this is not true in practice. As an example imagine that period
= 10ms, regular request takes 2ms but a stalled request takes 35ms.
When we're benchmarking for 100ms (for the sake of this example), we can execute e.g. 4x 2ms (at time 0, 10, 20 and 30), then at 40 the 35ms one, then another 4 at 75, 77, 79 and 81 and last one at 90. The average response time would be (9 * 2 + 35) / 10 = 5.3ms
, but this is not correct.
The thread that is stalled for 35 ms is often holding a lock (or occupying worker thread - any kind of synchronization) on the service and therefore it can block the other requests.
If users requested our service uniformly (every 10ms), they would experience latencies 2, 2, 2, 2, 35, 27, 19, 11, 3 and 2ms. This gives us average response time 5 * 2 + 35 + 27 + 19 + 11 + 3 / 10 = 10.5ms
which is almost twice the previous result. And this is what users would actually experience.
Average response time is not the only property we measure, but others are skewed as well by our way of sampling the requests.
So, current stress tests don't report response times correctly. Do these provide precise value for throughput? Yes, we have actually been able to execute X requests in Y minutes, but that's all. It is not the maximum throughput possible; for determining maximum throughput we need to scale up the load = lower the period of requests or increase the number of threads. But finding out the maximum throughput takes several iterations. We can also see throughput when the server is overloaded, although the response times are in this situation even further from users experienced response times.
In the past we also used tests with no request period whatsoever (this configuration option is preserved), just having fixed number of threads executing requests as fast as possible. This is a degenerated case of the above; we even don't attempt to set certain load on the servers, the response time defines the load through backpressure. So you can compare two services at certain concurrency, but not at given load. Another glitch is that you can execute different types of requests, with certain probabilities. If the same thread executes different requests, one slow type limits the number of executed requests of another type.
When designing/configuring a benchmark, always ask yourselves: what do I want to measure? You can't measure just performance - that's not a quantity. Common things you'd like to see is:
- response time (average and distribution) under certain load ** meeting certain threshold may be more important than the actual values; your SLA can tell e.g. 90% requests < 1ms, 99% < 100ms
- maximum throughput: in any test, you need to increase the load until the service can't handle that ** not handling the load can either mean not meeting certain performance criteria (SLA), or just not getting the responses at all (usually you get an exceptional response such as timeout) - that means that you're not actually executing the desired load
- compare different services/versions under the same load: backpressure must not affect the test itself, otherwise you are not comparing apples to apples
- scale cluster size (or any resource that can be scaled) ** keep the load constant or scale load along with the resources, and see how response times change
- compare maximum throughput of different versions or with different number of responses: measure maximum throughput independently and compare the result values
How to measure response time
One user does not prevent another user from issuing a request, so we have to do the same. As the users keep coming, we would need unlimited number of threads - though, that's not really practical. This PR tries to solve it.
Each test requires at least two stages: setup stage, in which we set the target throughput and start executing the requests and spawn threads, and test stage when the test should be in steady state - we execute the requests with requested frequency and do not spawn any additional threads. We measure and record response times only during the test, not in setup. These pairs of stages can be chained (for tests that seek the maximum throughput or just want to acquire data at different load levels).
For each conversation (sequence of requests), the setup stage specifies request period and number of invocations in this period. This is a base for the schedule (actually implemented in the SchedulingSelector
); the threads are blocked in the selector until the schedule assigns them to execute a conversation. When the threads get its task assigned, it checks if there are another threads (configurable number, but at least 1) waiting for next conversation. If this condition is satisfied, it executes its conversation and waits for next one in the selector. If it is not satisfied, the behavior differs for setup and for test:
During setup, the thread spawns another sibling, since no threads waiting for next conversation means that all threads are occupied and a scheduled conversation might be missed. Spawning a thread can take some time, but we don't care about missed operations during setup. The stage has configurable minimum duration and steady period: the setup is finished when there are no more threads created in last X seconds (defined by this steady period). There is also a cap on the number of threads that prevents RadarGun from running out of memory. This cap is reached when the requests stall too long and in this case the setup (and whole test) fails. Reaching maximum number of threads is in fact the only way for the setup to fail - service's inability to handle the target throughput results in spawning more and more threads.
During test, we don't want to spawn any more threads. Attempt to create another thread means that we can't reach the desired throughput; the setup has not created enough threads as it has not experienced all the possible situations (it was too short). Therefore, the test fails and you need to reconfigure the benchmark.
It can happen that the scheduled quantum of conversations is not retrieved from SchedulingSelector
in target period, although there are threads waiting for next operations. This happens quite usually even if the CPU load on machine is low, in practice I have observed that about 2-3% of requests are not executed on time. We do not re-schedule those operations for later, just ignore them. In the report, you can then see that this lower number of requests - at this point it's up to the user to validate if the test is acceptable or not, in future we might issue more warnings/invalidate the test if we miss too many of them.
At this point, old logic was mostly preserved and moved to legacy
package, with stages having legacy
in their names, too. We might consider keeping the old names and having them in separate legacy XML namespace.
For more information about the subject I highly recommend watching Gil Tene's presentation about latency. It also gives hints for understanding the percentiles chart that RadarGun reports (when using histogram-based statistics). Note that in this presentation Gil mentions service time and response time; in RadarGun we can measure only response time of the service implementation, if the request goes remotely, RadarGun can't know about that.
The concept mapped to the code
As the test is spread over multiple stages, its state is preserved in RunningTest
. This works as the thread-pool implementation; it's the RunningTest.ThreadPoolingSelector
checks the number of threads waiting for next conversation and possibly lets the RunningTest
add a new thread.
Conversations are mapped to Conversation
. Stages do not define the ConversationSelector
directly anymore, instead they use SchedulingSelector.Builder
to define the frequency of conversations. When defining stress tests on new traits, inherit from TestSetupStage
. TestStage
needs to be overridden only in cases that you want to gather other information than just statistics (invocations' response times). When chaining multiple tests (changing the frequency of operations), set <test finish="false"/>
and then use <finish-test/>
in the end.