MAG(1) MAG(1) NAME mag - computes fontsizes and magsteps SYNOPSIS mag [-Rdpi] magstep . . . mag [-r] [-Rdpi] fontsize . . . DESCRIPTION delim $$ This tool calculates fontsizes given magsteps. TeXfonts are provided as true sized fonts or as magnifications. The fontsize of a true sized font equals the resolution of the printer (ex. 300). The fontsize of a font magnified $n$ magsteps equals: 1.2 sup{n} times 300 delim off rounded to its nearest integer value. Fontnames for TeX fonts normally consists of the name (cmr), pointsize (10), type (pk) and font‐ size (360), for example: cmr10.360pk. EXAMPLES The result of mag -R240 -2 0 0.5 1 will be: 167 240 263 288 The inverse function is computed with the -r option. The result of mag -r -R240 167 240 263 288 will be the fontsteps: -2 0 0.5 1 The UNIX shells allow command substitution. One can write: mag -r -R240 `mag -R240 -2 0 0.5 1` DATE 18 December, 1989 AUTHOR Piet Tutelaers University of Technology Eindhoven<EMAIL_ADDRESS>UMFT MAG(1)


Computer Security: 2016-2017
|
Lecturer |
|
|
Degrees |
Schedule B2 (CS&P) — Computer Science and Philosophy Schedule B2 — Computer Science |
|
Term |
Michaelmas Term 2016 (16 lectures) |
Overview
Computer security pervades every aspect of the modern online experience, now reaching into mobile phones and games consoles as well as conventional computers. This course covers some of the fundamental principles of computer security.After identifying some different aspects of security, a number of practical challenges will be presented. For each one, the aim is to specify the requirements of a solution, explain an appropriate (mathematics-based) tool, and then discuss pitfalls, attacks, and countermeasures. Topics covered include will one-way functions, symmetric and asymmetric block ciphers, keyed hashes, digital signatures, and simple key exchange protocols.
Learning outcomes
An understanding of the differences between various forms of computer security, where they arise, and appropriate tools to achieve them; an appreciation of some common security pitfalls; knowledge of appropriate ways to quantify security.
This is a course for computer scientists, not system administrators. Don't expect to learn how to build "secure" websites, nor how to install firewalls.
Prerequisites
- Basic modular arithmetic (as amply covered by the Discrete Mathematics course).
- Elementary discrete probability (as amply covered by the first-year Probability course).
- Java for the practicals. No advanced structures or techniques will be required.
Practicals
There will be two practicals, with preparatory reading in weeks 2 and labs in weeks 3-8.
MSc Assessment
There will be a take-home exam, similar to problem sheets but with a smaller number of longer questions, to be completed
during the Christmas vacation.
Synopsis
Introduction [1 lecture]. Motivating example, definitions of security aspects.
Access control [1 lecture]. Models of security and the example of Unix permissions.
Symmetric key ciphers [3 lectures]. Block ciphers, Kerckhoffs' Principle, attack models, examples of attacks (including meet-in-the-middle). Perfect security, Shannon's conditions, Vernam cipher and the one-time pad. Feistel networks, DES, state-of-art encryption. Block modes, stream ciphers.
Cryptographic hash functions [2-3 lectures]. One-way and cryptographic hash functions, relationships with other security properties; attacks on iterative algorithms. Hashes for password storage and key generation: offline attacks, strengthening by salting and stretching, examples in practice. Hashes for message integrity, collision resistance. The Merkle-Damgard construction, padding, MD4 and its successors.
Asymmetric key ciphers [2-3 lectures]. The RSA cryptosystem: proof of correctness, discussion of efficiency. The RSA security assumption, relationship with integer factorization. Discussion of appropriate key size. Homomorphic property, number theoretic attacks, PKCS v1.5 padding. Brief survey of alternative public key ciphers.
Message authentication & digital signatures [2-3 lectures]. The Dolev-Yao model. Message authentication codes, HMAC. Digital signatures, attack models. RSA signatures, textbook weaknesses, and PKCS v1.5 padding. Combining signatures and encryption. Brief survey of alternative signature schemes.
Protocols [3 lectures]. Entity-entity authentication protocols given shared secret or public keys, weaknesses and attacks. Key distribution and certification, chains of trust, PKI. Mediated authentication protocols, weaknesses and attacks. The SSL/TLS application layer protocol.
Syllabus
Aspects of security, security models. Tools for achieving particular security goals, attacks, and countermeasures: one-way functions, symmetric and asymmetric block ciphers including key generation and block modes, keyed hashes, digital signatures, simple key exchange protocols. Applications in practice.
Reading list
Primary Text
- Charlie Kaufman, Radia Perlman, & Mike Speciner. Network Security: Private Communication in a Public World, second edition. Prentice-Hall, 2002. Covers nearly everything in the course in a very readable style. Good detail, but sometimes lacks formality.
- Andrew Ker. Computer Security Lecture Notes. 2013. Available as handouts in lectures.
Further Reading
- Dieter Gollmann. Computer Security, third edition (any edition is fine). Wiley, 2010. Has more material on computer security concepts, and models of security, than any of the other books, and less on ciphers and hashes. A good complement.
- Niels Ferguson, Bruce Schneier, & Tadayoshi Kohno. Cryptography Engineering - Design Principles and Practical Applications. Wiley, 2010. Alternates between chatty prose and detailed implementations of security primitives, but good on the common pitfalls. Cheap.
- Alfred Menezes, Paul van Oorschot, & Scott Vanstone. Handbook of Applied Cryptography. CRC Press, 1996. Comprehensive, contains the state of the art as of 1996 and thus sometimes out of date. Freely downloadable.


Your environment directory contains log files. Berkeley DB log files are used to record all the transactional activity performed against the Berkeley DB database files. This information is used after an application or system failure to automatically restore the database to an up-to-date consistent point.
Your log files are maintained by Berkeley DB's logging subsystem.
There are some aspects of the Berkeley DB logging subsystem that
you can configure using DB_CONFIG
parameters, and (sometimes) by using PRAGMAs.
For most users of the BDB SQL interface, there should not normally be any reason to manage your log files or otherwise worry about them. However, it is important to realize that they can not simply be deleted. Note that when using the Berkeley DB SQL interface, your log files will be automatically deleted by Berkeley DB when they are no longer needed.
The things you can manage for your logging subsystem are:
Size of the log files. See Setting the Log File Size.
Size of the logging subsystem's region. See Configuring the Logging Region Size.
Size of the log buffer in memory. Setting the In-Memory Log Buffer Size.
Whenever a pre-defined amount of data is written to a
log file (10 MB by default), the BDB SQL interface stops using the
current log file and starts writing to a new file.
You can change the maximum amount of data contained in each
log file by using either PRAGMA journal_size_limit
or
the set_lg_max
DB_CONFIG file parameter.
If you use PRAGMA journal_size_limit
,
then using this PRAGMA with no value simply returns the
current journal size limit. Using:
PRAGMA journal_size_limit=N
sets the log size to N bytes. If the PRAGMA is successful, N is returned. If it fails, the previous log file size is returned. Failures can occur if you specify a log file size that is less than 4K bytes, or if you specify a log file size larger than the permitted file size on the system.
If you use the DB_CONFIG file to manage this value,
set_lg_max
may be changed without
re-creating the environment. You will, however, have to
restart your application in order for the DB_CONFIG
file to be re-read.
The DB_CONFIG file is described in The DB_CONFIG File.
The set_lg_max
parameter is
described in the
Berkeley DB C API
.
For a description of how, when and why you should change the size of your log files, see the Selecting a page size section in the Berkeley DB Programmer's Reference Guide.
The logging subsystem's default region size is 512 KB. The logging region is used to store database and table names, and so you may need to increase its size if you will be using a large number of tables.
You can set the size of your logging region by using the
set_lg_regionmax
DB_CONFIG parameter. Note that
to manage this value you must set it before you create your
environment, or you must re-create your environment. See The DB_CONFIG File
for more information.
The set_lg_regionmax
parameter is described in the
Berkeley DB C API
.
When using named (persistent) databases, log information is stored in-memory until the storage space fills up, or a transaction commit forces the log information to be flushed to disk.
It is possible to increase the amount of memory available to your file log buffer. Doing so improves throughput for long-running transactions, or for transactions that produce a large amount of data. Note that for named (persistent) databases, the default log buffer space is 32 KB.
You can increase your log buffer space by using the
set_lg_bsize
DB_CONFIG parameter.
For the BDB SQL interface, when the logging subsystem is configured for on-disk logging, the
default size of the in-memory log buffer is approximately 64KB.
Note that this
method can only be called before the environment
is first opened, so you will have to set this by creating
your -journal
directory, and then
creating your database. See
The DB_CONFIG File
for more information.
The set_lg_bsize
parameter is described
in the
Berkeley DB C API
.
When working with in-memory databases, the environment is configured to perform logging in-memory. The log buffer is set to 64 * 1024, and the maximum log size is set to 32 * 1024.


| {% if hint.claimed_datetime %} Claimed {% duration_between hint.claimed_datetime now %} ago by {{ hint.claimer }} {% else %} CLAIM: Created {% duration_between hint.submitted_datetime now %} ago {% endif %} | {{ hint.team }} | {{ hint.puzzle }} | (guesses) |
|---|---|---|---|
| (view without claiming) | (all from same team) | (all from same puzzle) | (both) |
{{ hint.hint_question }} |
Requested by most teams
| {{ entry.count }} | {{ entry.puzzle.name }} | {{ entry.puzzle.metas.all|join:", " }} |


rails.service
Classes
DistanceCalculation
JourneyPlanning
ShortestRoute
ShortestRoute.ShortestRouteResult


Although the languages have many similarities and there is no right or wrong on to learn. I think the C#/.NET track would be a good fit for you. Check out this link for more information on this track. Show me more!
Although the languages have many similarities and there is no right or wrong on to learn. I think the JAVA/Android track would be a good fit for you. Check out this link for more information on this track. Show me more!
Although the languages have many similarities and there is no right or wrong on to learn. I think the PHP/Drupal track would be a good fit for you. Check out this link for more information on this track. Show me more!
Although the languages have many similarities and there is no right or wrong on to learn. I think the Ruby/Rails track would be a good fit for you. Check out this link for more information on this track. Show me more!
Although the languages have many similarities and there is no right or wrong on to learn. I think the CSS/Design track would be a good fit for you. Check out this link for more information on this track. Show me more!
It seems that you selections are a little broad at this point. Try keeping your answers a bit more related. Check out this link to learn more about the tracks offered and what each languages is used for. I'd like to learn more!


Barbara {Jeannie} Hunnicutt
I'm currently a student at Ada Developers Academy, an intensive full-stack programming school for women. Having recently finished my PhD in Neuroscience, I often get asked why I spent all that time and energy just to immediately go back to school to become a software developer. Although it might seem like a drastic change from the outside, for me, the process has been so fluid that I've hardly felt like I made a decision to switch careers.
My research focused on how the brain organizes and computes information, and the obvious parallels between neural computing and machine computing have made it feel like second nature to think about the structure and dynamic interactions of software systems. As a scientist, I particularly enjoyed the constant need to implement and adapt unfamiliar technologies for experiments, and, throughout graduate school, my problem solving solutions gradually erred towards programming more and more. By the end, I realized that a scientifically literate software developer could be incredibly useful a world where scientific information is getting ever more complex.
As a newcomer to this world, I'm first and foremost devoted to learning as much as I can about all aspects of software development, but I'm particularly interested in interactive data visualization. In the long run, I hope to make tools that will enable scientists to create, explore, and share scientific information more readily.


Date
struct Date : ReferenceConvertible, Comparable, Equatable
-
Undocumented
Declaration
Swift
public static let formatter: DateFormatter
-
Undocumented
Declaration
Swift
public static let defaultFormat: String
-
Undocumented
Declaration
Swift
public static var iso8601WithoutZFormatter: DateFormatter
-
Undocumented
Declaration
Swift
public static let iso8601Formatter: DateFormatter
-
Undocumented
Declaration
Swift
public static let markdownDayFormatter: DateFormatter
-
Undocumented
Declaration
Swift
public func string( using formatter: DateFormatter = Date.formatter, with format: String = Date.defaultFormat ) -> String
-
Undocumented
Declaration
Swift
public var iso8601StringWithFullNanosecond: String { get }
-
Undocumented
Declaration
Swift
public var markdownDay: String { get }


Restaurant Survey
Please help us learn
what we're doing right
and
what we need more work
on by filling out this card
Required fields are followed by *
Please help us learn
what we're doing right
and
what we need more work
on by filling out this card
Required fields are followed by *


3D Image Transition
Mouse through the picture to produce a special transition effect. You can change the effect by changing the displacement image.
@@include('./src/components/ES6/_global/include-header.html')
@@include('./src/components/ES6/_global/include-loader.html') @@include('./src/components/ES6/_global/include-toggle-trigger.html')Mouse through the picture to produce a special transition effect. You can change the effect by changing the displacement image.


--- title: 'Creating a choropleth map with Voronoï polygons' author: admin date: '2020-05-05' slug: creating-a-choropleth-map-with-voronoï-polygons-a-peek-into-the-importance-of-projection categories: - maps tags: [] subtitle: '' summary: 'A peek into the importance of choosing a projected coordinate system' authors: [] lastmod: '2020-05-05T15:51:22+02:00' featured: yes image: caption: '' focal_point: '' preview_only: no projects: [] output: blogdown::html_page: dev: "svg" ---
I learned R by giving myself small challenges to overcome. When I started playing around with spatial data, one particular challenge helped me to understand projections better. What I wanted to do, is to make a map that showed everywhere in France what is the neareast football club (in Ligue 1) and to color the map based on the total area in which each club is the neareast in France.
I will first show you how to do this “properly”. Which mean using st_transform on the data to convert the coordinates system to a Lambert Projection (Lambert93 which is the official projection for France).
Then I will show you the first result I got, when I did not projected the data and instead used st_voronoi directly on the longitude/lattitude data.
Finally, a little bonus : a raster map of distance to nearest club everywhere in France.
#Usual suspects
library(tidyverse)
library(glue)
library(here)
#To work with geodata
library(sf)
#For geodata of the cities
library(httr)
library(jsonlite)
#For plotting
library(ggrepel)
#Extra fonts for maps
extrafont::loadfonts(device = "win")
I have a theme_map() function which comes from another project. Let’s use that.
#theme map function from other project
theme_map <- function(...) {
theme_minimal() +
theme(
text = element_text(family = "Tahoma", color = "#22211d"),
#remove all axes
axis.line = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
axis.title = element_blank(),
#remove grid
panel.grid = element_blank(),
#background colors
plot.background = element_rect(color = NA,
fill = "#f5f5f2"),
panel.background = element_rect(color = NA,
fill = "#f5f5f2"),
legend.background = element_rect(color = NA,
fill = "#f5f5f2"),
#borders and margins
plot.margin = unit(c(0.5, 0.5, 0.2, 0.5), "cm"),
panel.border = element_blank(),
panel.spacing = unit(c(-0.1, 0.2, 0.2, 0.2), "cm"),
#titles
legend.title = element_text(size = 11),
legend.text = element_text(size = 9, hjust = 0),
plot.title = element_text(size = 15, hjust = 0.5),
plot.subtitle = element_text(size = 10, hjust = 0.5,
margin = margin(b = -0.1,
t = -0.1,
l = 2,
unit = "cm"),
debug = FALSE),
#captions
plot.caption = element_text(size = 7,
hjust = 1,
margin = margin(t = 0.2,
b = 0,
unit = "cm"),
color = "#939184"),
...
)
}
We will be using the national address database, which is a convenient way to get localisation in France. I also use a France simplified geojson : that you can get here : boundary.now.
#clubs
clubs <- tibble(city =
c(
"Lille",
"Lens",
"Paris",
"Reims",
"Metz",
"Strasbourg",
"Dijon",
"Rennes",
"Angers",
"Lorient",
"Brest",
"Nantes",
"Bordeaux",
"Saint-Étienne",
"Lyon",
"Nice",
"Marseille",
"Montpellier",
"Nîmes"
))
get_location <- function(city) {
city %>%
paste0("https://api-adresse.data.gouv.fr/search/?q=",.) %>%
GET() %>%
pluck("content") %>%
rawToChar() %>%
fromJSON() %>%
pluck("features") %>%
flatten() %>%
slice(1) %>%
pluck("geometry.coordinates", 1) %>%
set_names(c("LON", "LAT")) %>%
list()
}
clubs_geo <- clubs %>%
rowwise() %>%
mutate(coords = get_location({city})) %>%
unnest_wider(coords) %>%
# I manually add Monaco which is not in France
bind_rows(tibble(city = "Monaco", LON = 7.414793, LAT = 43.728353)) %>%
st_as_sf(coords = c("LON", "LAT")) %>%
st_set_crs(4326) %>%
st_transform(2154)
clubs_geo <- clubs_geo %>%
bind_cols(as_tibble(
st_coordinates(clubs_geo)
))
#France
france <- st_read(
here("static/inputs/ligue 1 voronoi/metropole-version-simplifiee.geojson")
) %>%
st_transform(2154) %>%
st_cast("POLYGON") %>%
mutate(area = st_area(geometry)) %>%
filter(as.numeric(area) == max(as.numeric(area)))
## Reading layer `metropole-version-simplifiee' from data source `D:\Users\Alexis\Documents\Data\r-blog\static\inputs\ligue 1 voronoi\metropole-version-simplifiee.geojson' using driver `GeoJSON'
## Simple feature collection with 1 feature and 0 fields
## geometry type: MULTIPOLYGON
## dimension: XY
## bbox: xmin: -5.103601 ymin: 41.36705 xmax: 9.559721 ymax: 51.0884
## geographic CRS: WGS 84
#make voronoi ploygons
voronoi <- clubs_geo %>%
#to make voronoi polygons you need every point in the same feature
st_union() %>%
st_voronoi() %>%
st_cast() %>%
st_sf() %>%
st_join(clubs_geo, join = st_contains) %>%
st_intersection(france) %>%
mutate(area = st_area(geometry))
#plot description
description <- glue(
"For each club area in which it is the
closest club in France"
)
m1 <- ggplot(voronoi) +
geom_sf(aes(fill = as.numeric(area) / 1000000)) +
geom_sf(data = clubs_geo) +
geom_label_repel(data = clubs_geo,
aes(label = city,
x = X,
y = Y)) +
scale_fill_distiller(direction = 1,name = "Surface",
labels = scales::label_comma(big.mark = " ",
suffix = " km²"),
breaks = c(10000, 30000, 50000, 70000),
guide = guide_colorbar(barwidth = 0.5,
frame.colour = "black")) +
annotate("text", x=-Inf, y=Inf,
label = description,
hjust = 0, vjust = 1) +
theme_map() +
theme(legend.position = c(0.1,0.2),
plot.title = element_text(hjust = 0),
plot.subtitle = element_text(hjust = 0),
plot.background = element_rect(color = "black")) +
labs(title = "Territorial domination of Ligue 1 clubs",
caption = "@_Alexis_69_")
# ggsave(plot = m1, here("static/plots/ligue1_voronoi/map.png"),
# dpi = "retina",
# width = 7, height = 7.4)
m1
The code is exactly the same, except we don’t use st_transform, therefore did not include it. But you can see the warning thrown : “st_voronoi does not correctly triangulate longitude/latitude data”.
And if you look carefully at the map you can tell it is not exactly right.
## Reading layer `metropole-version-simplifiee' from data source `D:\Users\Alexis\Documents\Data\r-blog\static\inputs\ligue 1 voronoi\metropole-version-simplifiee.geojson' using driver `GeoJSON'
## Simple feature collection with 1 feature and 0 fields
## geometry type: MULTIPOLYGON
## dimension: XY
## bbox: xmin: -5.103601 ymin: 41.36705 xmax: 9.559721 ymax: 51.0884
## geographic CRS: WGS 84
## Warning in st_voronoi.sfc(.): st_voronoi does not correctly triangulate
## longitude/latitude data
## Warning: attribute variables are assumed to be spatially constant throughout all
## geometries
library(raster)
r <- raster(france, ncol = 500, nrow = 500)
distances <- distanceFromPoints(r, clubs_geo) %>%
mask(france) %>%
as.data.frame(xy = TRUE) %>%
na.omit() %>%
as_tibble() %>%
mutate(distance = layer / 1000) %>%
dplyr::select(-layer) %>%
mutate(bins = case_when(
distance < 50 ~ "<50 km",
distance <= 100 ~ "50 à 100 km",
distance <= 150 ~ "100 à 150 km",
distance <= 200 ~ "150 à 200 km",
distance >200 ~ ">200 km"),
bins = fct_reorder(bins, distance))
description_2 <- "Distance in kms to the nearest Ligue 1 football club"
ggplot() +
geom_raster(data = distances, aes(fill = bins,
x = x,
y = y),
interpolate = TRUE) +
scale_fill_brewer(name = NULL) +
geom_sf(data = clubs_geo) +
geom_sf(data = france,
fill = "transparent") +
geom_label_repel(data = clubs_geo,
aes(x = X,
y = Y,
label = city)) +
annotate("text", x = -Inf, y = Inf,
label = description_2,
hjust = 0, vjust = 1) +
theme_map() +
theme(legend.position = c(0.1,0.2),
plot.title = element_text(hjust = 0),
legend.key = element_rect(color = "black"),
plot.background = element_rect(color = "black")) +
labs(title = "La diagonale du vide du football français",
caption = "@_Alexis_69_")


A cache of currently bound buffer, contains only two members with keys ARRAY_BUFFER and ELEMENT_ARRAY_BUFFER
true
if support gl.UNSIGNED_INT
in gl.drawElements
or gl.drawElementsInstanced
true
if has ANGLE_instanced_arrays
extension
true
if we has *_vertex_array_object
extension
Cache for all buffers by id, used in case renderer gets destroyed or for profiling
Cache for all geometries by id, used in case renderer gets destroyed or for profiling
The renderer this manager works for.
Sets up the renderer context and necessary buffers.
Generic destroy methods to be overridden by the subclass
dispose all WebGL resources of all managed geometries and buffers
Disposes buffer
buffer with data
Disposes geometry
Geometry with buffers. Only VAO will be disposed
Draw the geometry
the type primitive to render
Reset and unbind any active VAO and geometry
Unbind/reset everything
Update buffers
Generated using TypeDoc
System plugin to the renderer to manage geometry.
PIXI.systems


We recognize that your privacy is very important and take it seriously. This Privacy Policy describes 's policies and procedures on the collection, use and disclosure of your information when you use the services, websites, and applications offered by (the "Services"). By using the Services, you consent to our use of your information in accordance with this Privacy Policy. We will not use or share your personal information with anyone except as described in this Privacy Policy. This Privacy Policy does not apply to personal information we collect by other means (including offline) or from other sources. Information We Collect and How We Use It :
uses personal information we collect to provide the Services, personalize content, remember information to help you efficiently access your account, analyze how the Services are used, diagnose service or technical problems, maintain security, monitor aggregate metrics such as total number of visitors, traffic, and demographic patterns, and track user Content and users as necessary to comply with the Digital Millennium Copyright Act and other applicable laws. Information we collect from businesses include email id, business name. Information we collect from end-user include facebook account details, profile picture, first and last name, demographic information as provided by Facebook, chat history of the user in Facebook Messenger.
We do not share this information with any third party services.
uses industry-standard physical, managerial, and technical safeguards to preserve the integrity and security of your personal information. We cannot, however, ensure or warrant the security of any information you transmit to or guarantee that your information on the Services may not be accessed, disclosed, altered, or destroyed by a breach of any of our physical, managerial, or technical safeguards.
In the event that personal information is compromised as a result of such a breach of security, will promptly notify those persons whose personal information has been compromised, in accordance with the notification procedures set forth in this Privacy Policy, or as otherwise required by applicable law.


Official Announcements is for Komodo news only. This is where our team will publish notices, updates and news.
100 messages
Before 05-Dec-19 12:00 AM
benohanlon14-Jan-19 11:53 AM
Komodo, just another crypto or better than Bitcoin?
00:25 Market Share
00:47 Komodo Overview
02:45 Keys of Komodo
05:31 Privacy and Security Intro
07:01 Atomic Swamps and BarterDEX
07:25 Cross Chain Smart Contracts
08:03 Delayed Proof of Work
10:09 Myths and Facts of dPoW
11:25 What the Notary Node Do
12:01 Jumbler, the decentralized tumbler
13:18 China loves Komodo
https://www.youtube.com/watch?time_continue=100&v=_jw7u_QCogc
Komodo Platform is hiring a remote Komodo Support Agent. We are looking for a Technical Blockchain Support AgentWith fluent English and experience in solving blockchain related issues.The Ideal candidate would have:Fluent English required;Excellent interpersonal skills; Exc...
Holding torch under chin
"And the bigger the projects got, the more expensive fees were because they were on the same chain"
children scream
"And it became slow and congested"
children scream more
"And nobody had heard of delayed proof of work"
*one child gets a nose...
Anyone interested in beta testing the Ledger $KMD Rewards app please DM me.
You'll need a spare Ledger running the latest KMD app and some funds to test with.
benohanlon16-Jan-19 09:42 AM
Confirmed Bittrex wallets are now accepting withdrawals/deposits.
2
benohanlon16-Jan-19 09:52 AM
"Fact: Unlike $ETH all the ecosystem projects, big or small, are NOT running their project on top of Komodo's blockchain. They own their own independent blockchains, so are free from any kind of scaling issues that $ETH is facing." - @grewalsatinder
Retweet - https://twitter.com/satindergrewal/status/1085474305880649753
Fact: Unlike $ETH all the ecosystem projects, big or small, are NOT running their project on top of @KomodoPlatform blockchain. They own their own independent blockchains, so are free from any kind of scaling issues that $ETH is facing.
SHossain16-Jan-19 08:09 PM
@everyone Dear members. We would like to encourage our community to help new members in #support and #deleted-channel channel and optionally on other channels. We will be awarding 5 KMD bounty for the best support cases via our Tipbot. This would encourage users to get a more diverse experience with our tech and products. As a whole, this will build knowledgable and resourceful Komodo community.
Learn, help, spread the knowledge and may the force be with you.
Advice to users:
- Please don't provide or post your private key
- Always keep yourself safe and your data safe
- If you are unsure about anything, please ask
- Using TeamViewer is not recommended and may bring security risk
In an effort to showcase its unique multi-chain architecture, Komodo is disabling z-transactions from the KMD blockchain and moving it to a second chain.
Ethereum Classic ($ETC) was 51% attacked yesterday. This is the largest cryptocurrency that has ever been 51% attacked, and it has really interesting implications for the future of PoW currencies. Thread.
Upcoming Gincoin blockchain changes:
- mining algorithm change to x16rt
- dPoW (delayed proof of work) 51% attack protection from Komodo
Code and Testnet for the algo change released on 21 Jan (Monday)
SUBSCRIBE HERE - http://bit.ly/SubscribeCryptoRich With 51% attacks on the increase, the CTO of this project explains how any proof of work coin can protect ...
Two short twitter threads from our CTO @ca333 worth reading @everyone !
1. Crosschain atomic swap has been executed/processed solely with SPV technology which means users wont have to sync (download) a full blockchain db or to run a blockchain daemon in order to use our DEX technology https://twitter.com/0xca333/status/1088245559134171136
2. Imagine if you could import/load new consensus rules DURING runtime? https://twitter.com/0xca333/status/1087904226460745730(edited)
We re currently testing version 2.0 of barterDEX - https://t.co/qiVuMjykt6 - this is the transaction which spends the maker payment ("maker" = seller). And the screenshot above is the output of the buying node ("taker"). This tech is coming to mobile devices this year! #KM...
James 'jl777' Lee and our CC devs are working on some really neat features right now. The last days we have been hacking around with dynamic CC libraries. Imagine if you could import/load new consensus rules (blockchain logic) DURING runtime? Guess what - with #KMD its rea...
ICO rating, listing, and calendar with details on top ICOs from various industries. Learn more about ICO funding, whitepaper, dates, teams, and roadmaps.
benohanlon24-Jan-19 03:32 PM
@everyone Komodo is looking for an excellent technical writer and we'd like to ask our community to think about if they know someone who is first class... if that is you, or you know someone, then we'd like to know. Please share this link https://komodoplatform.com/technical-writer-job-post/.
We are looking for a dedicated and passionate Technical Writer with a strong crypto background to join the Komodo team. What you’ll do: * Produce high-quality technical documentation that is appropriate for its intended audience * Create comprehensive user guides and step-b...
15
Mylo25-Jan-19 02:41 AM
Website is down for planned maintenance. Thank you.

It may take some time for the DNS changes to propagate, so plz be patient.
Komodo has officially joined @binance transparency initiative. By sharing project-related information such as news and progress reports on @Binance_Info, Komodo is contributing to keeping the community informed. Check out our page here: https://t.co/40svRDx2dz #blockchain ...
Agama Wallet Update. What's New in v0.3.3a?
- Change Log:
https://t.co/GyvfMltyF5
- Download: https://t.co/Oa6H5VPyeG
#Blockchain #Crypto #Cryptocurrency #Wallet #Fintech #Komodo #agama
5
2
2
2
benohanlon30-Jan-19 05:44 PM
@jl777c just released the initial version of the sudoku CC! @ca333 has posted a challenge to celebrate with a crypto puzzle! Solve the sudoku below to find the 'key for the seed' loaded with 77.7 KMD! https://twitter.com/0xca333/status/1090664381866823681@everyone
jl777 just released the initial version of the sudoku CC! We celebreate this with another #Cryptopuzzle! Solve the sudoku below to find the 'key for the seed' loaded with 77.7 KMD! Join our discord https://t.co/NSxSfLBLBt for more infos on sudoku CC and this riddle! #crack...
The project, originally a fork of Zcash, is repositioning itself as a security service—and an Ethereum rival.
10
7
7
6
3
6
benohanlon02-Feb-19 10:21 AM
Binance are running a twitter vote, with the three most popular being invited to an AMA. There are multiple tweets with votes but if @everyone wants to vote for Komodo you can do so here: https://twitter.com/binance/status/1091637368153501696?s=21.
6 of the teams you wanted to host an AMA in the #Binance Telegram https://t.co/xYcqyDnJDx
@zilliqa $ZIL
@KomodoPlatform $KMD
@metalpaysme $MTL
@wavesplatform $WAVES
@zcoinofficial $XZC
@NeblioTeam $NEBL
There will be two polls with the rules included on the second
Poll ...
6 of the teams you wanted to host an AMA in the #Binance Telegram https://t.co/xYcqyDnJDx
@zilliqa $ZIL
@KomodoPlatform $KMD
@metalpaysme $MTL
@wavesplatform $WAVES
@zcoinofficial $XZC
@NeblioTeam $NEBL
There will be two polls with the rules included on the second
Poll ...
2018 was a huge year of evolution and growth for Komodo. Despite an ongoing bear market, the Komodo Dev Team delivered several groundbreaking technologies throughout the year. Check out our year-end report: https://t.co/NfHlhUX7Nj #blockchaintechnology #CryptoNews #fintech
I just published '@KomodoPlatform A Next-Generation Multi-Chain-Platform' $KMD
+ we have a surprise for you! The interview is also an #Cryptopuzzle. Read the Interview to find the 'key for the seed' loaded with 77.7 KMD!
First hint in the comments.
https://t.co/TO9QP1N...
On February 7, we’re launching a US dollar (USD) market for Komodo (KMD). Eligible Bittrex accounts are auto enabled for USD trading. Those wanting to deposit/withdraw US Dollars via wire should submit an application here: https://t.co/KA248OA2Bz
Great News: @KomodoPlatform support for Ledger Live's back for the Nano S! The @XSNofficial app is also available for the Nano S & Ledger Blue! It concerns a native Ledger Live integration
Updating to Ledger Live 1.3.4 is required
Get your Ledger device: https://t.co/4r4...
Exclusive: With so many cryptocurrency projects creating decentralized exchanges (DEXs) of their own, it’s reasonable to be skeptical about yet another. Today, cryptocurrency project Decred released official plans for its own Decentralized Exchange (DEX).
In cooperation with the Zcash team, Komodo quickly and securely patched a critical vulnerability that had been identified in Sprout zk-SNARK technology.
If you’ve been feeling nostalgic for the 80s and the video games of the era - especially if some dungeon crawling is what you seek - get ready for a comeback of the popular Rogue, which is being implemented on the open source blockchain platform Komodo (KMD.) And although m...
Visit us at https://patreon.com/thecoinchat for exclusive content! Komodo has atomic swaps, privacy, and an incredibly cool scalable technology #cryptocurren...
All the reasons to be excited about @KomodoPlatform Roguelander — the first blockchain based Rogue game. https://t.co/s8hAoFv0zt #blockchain #blockchaintechnology #blockchaingaming #rogue #gaming
https://t.co/EhwbOkUXiO - cool preview of South East Asia's 2nd Annual Mega Blockchain Conference 2019 - its an amazing #Blockchain #Event and #Komodo was represented there. Our CEO @bennydoda01 is in the video at 0:24 #KMD #BTC #ETH #Bitcoin
2
benohanlon19-Feb-19 10:38 AM
Thank you to our Greek cryptocurrency community! Here are some highlights from the meetup 16/02/2019 sponsored by Komodo. @Daniel CP explained Komodo's independent chains and delayed proof of work. https://youtu.be/Zpll2XZt4o8?t=5002
777 KMD #bounty for the most ROGUE via legit gameplay, farming or multiplayer. Non-devs only! Your ROGUE address will be proof of claim. Monday, Feb 25th 12:00 UTC is the deadline. Read about Komodo Roguelike here: https://t.co/s8hAoFv0zt #crypto #CryptoNews #blockchain #J...
A partnership between web giant Amazon and blockchain ecosystem Komodo, called Chainlizard, will enable the creation of blockchains in less than 60 seconds
Komodo will be at the https://t.co/WMfsd7AwSF #MWC2019 the whole coming week - reach out if you want to discover our promising and innovative #Mobile #Blockchain #Technology. It is a pleasure to personally demonstrate you some exclusive technical innovations! #Mobile #MWC...
Dear users,
Komodo（KMD）will be launched on Huobi Global on February 28, 2019 (GMT+8). Deposits will be available from 14:30, February 28, 2019 (GMT+8). KMD/BTC and KMD/ETH trading will be available...
The new episode of #KnowTheCoin is out!
Today's guest is a writer, educator, and the co-author of the original @KomodoPlatform White Paper, the awesome @siddhartha_cryp! Sidd was kind enough to share some insights of $KMD - really cool stuff! Dig in: https://t.co/RSsX...
Part 3 of our Under the Microscope series examining #Komodoplatform #KMD #Komodo is out!
https://t.co/cdAufeWiyz
benohanlon08-Mar-19 07:03 PM
Senior Lecturer & Graduate Advisor at University of Texas at Arlington and Strategic Advisor at Komodo Platform, Dr. Sajib Datta has begun teaching a blockchain and cryptocurrency course with the support of our team. https://twitter.com/KomodoPlatform/status/1104094210217656321.
The Promise, Challenges, And Evolution Of The Blockchain Industry https://t.co/1r73Q3Gydd #fintech #evolution #blockchain #blockchaintechnology #blockchaintech #crypto #cryptocurrency
Discord Scam Warning
We have gotten reports that there is a scammer impersonating well-known team and community members on our Discord. Please double check with whom you are talking.
HempCoin $THC is migrating to Komodo $KMD platform
KMD is continually providing cutting edge Blockchain Technology and Protection from 51%
Komodo Team will be providing a completely new THC atomic chain for easy transition. Snapshot block # to be announced soon!
Thank y...
This article is an intro into the new tech that solves the #blockchain #oracle problem using Komodo Platform's #opensource application framework for custom consensus. It shows how full nodes all participate in the decentralized oracle validation and then scales it using existing lite wallet protocols without any changes. Komodo's multi-chain architecture and #interoperability between coin protocols will enable application #developers to build out ecosystems that talk to one another, like current web services - but p2p, validated and secure.
Komodo is an open, multi-chain platform that gives every project an independent blockchain. Learn the 18 ways to customize your blockchain with Komodo.
"North Korean crypto hacks continue to create a need for a proper #Decentralised Exchange network" - @gerald2273 @BlockchainMT @0xca333. https://t.co/doSjv1ysSs #fintech #crypto #blockchain #atomicswaps
3
2
2
2
Audo11-Apr-19 04:45 PM
Another giant in the making: RedFOX Labs, a blockchain venture builder on a mission to accelerate Komodo adoption.
In our Ecosystem Spotlight series, we highlight key players within the Komodo ecosystem. Learn more:
https://komodoplatform.com/komodo-ecosystem-spotlight-redfox/
Komodo is pleased to highlight RedFOX Labs, a global blockchain venture builder, in this editon of the Ecosystem Spotlight. Learn more about RedFOX here.
Today is #Tech #Tuesday.
#Komodo #developer documentation is getting streamlined. Check out our new look and study $KMD.
Another news: trustless #oracle technology is coming to Komodo.
The rest won't fit into this tweet. Read more: https://t.co/l4NY0ZYsIP
Next week on #CryptoFriday will @M_eyse and @twpunkster play #UltraFighter #K64 from @blockbar070 at @The_Hague_Tech made with our Komodore Gaming SDK against @bvanmaarseveen in #Rotterdam LIVE to present #ProofOfGameplay on @KomodoPlatform #blockchain ! https://t.co/7qbHi...
Together with @bartroorda we will go through the source of #UltraFighter #K64, the #Komodore64 virtual console and its #blockchain integration on @KomodoPlatform at @blockbar070 during the co-working event. Let's put this #komodo #ecosystem project through the fire test!
Komodo Platform's core developer and founder #jl777 has started his own blog on @Medium
The blog is aimed for senior developers who want to learn about #blockchain.
#Komodo $KMD #cryptocurrency #bitcoin #development #dev #crypto
https://t.co/8wiSrPjRwe
Every hour, over $300,000 USD in electricity is pumped into #Bitcoin mining. With #Komodo #dPoW any #blockchain can leverage that protection.
... and yes, it is #decentralized. If you don't believe, read our founders reasoning from his blog post.
https://t.co/sW0g7Zst5T
dPoW was blockchain's first security mechanism to recycle the hash rate of the BTC network and yet, it's often misunderstood. This is dPoW demystified.
According to a recent #developer report from @ElectricCapital, #Komodo Platform is very active on core protocol development.
Indeed, we have kept a continuous pace of innovation since our ICO. More commits are incoming in 2019. $KMD #blockchain
https://t.co/YPRU3PQ8uQ
#Komodo provides flexible, low-level blockchain technology that can be adapted to suit just about any use case. For example, #gaming
@0xca333 @CryptoInsiderHQ @komodoregames $KMD #blockchain #crypto #cryptocurrency #proofofgameplay
https://t.co/UPRN2mAjyb
Komodo is a permissionless platform. However, with the application layer (programmable blockchain) that Komodo’s Custom Consensus modules enable, a developer team can create a permissioned blockchain solution.
https://t.co/UpK9fEMW1j
Today is the last day of voting. At the moment 27 % of the $KMD stake has voted.
Learn about the Notary Node elections on https://t.co/Fu8RoMRkA5
SHossain13-May-19 04:04 PM
@everyone We have released new version of Agama 0.3.6. The updated version has a lot of changes and an improved UI to make it more user friendly. This version changes how you create new wallet in Lite or Native mode and the way you use Lite mode vs Native mode.
Direct login using seed or WIF key is no longer supported. You will need to use restore wallet feature first with existing seed or WIF.
Concurrent usage of native and lite mode coins is deprecated. From now on you can either run Lite mode coins or Native mode coins during one session.
Your coins selection is automatically stored when you add or remove coins.
Native mode coins can be started without creating an Agama wallet. Just add them using the login screen.
Following security best practices you must write down your seed in a safe place while creating a new account. Do NOT take screenshot or picture of your seed on a machine that is connected to internet.
We have updated guides on how to use the new lite mode https://support.komodoplatform.com/en/support/solutions/articles/29000024492-create-new-wallet-and-encrypt-seed-spv-
How to restore wallet with new Lite mode using seed/WIF https://support.komodoplatform.com/en/support/solutions/articles/29000026360-use-private-key-wif-or-seed-phrase-to-login-into-agama-lite-mode
Please find all Agama Desktop related guides here https://support.komodoplatform.com/en/support/solutions/29000034534
If you have further questions please search the solutions page to find answers first before asking for help. In case you still need help, please visit #deleted-channel channel where community and team members are constantly helping users in need. Alternatively, you can create a support ticket. A link to support help desk is available within Agama, just click on 3 lines (menu icon) on the top-right corner or Agama and select Support.
New Agama v0.3.6 download: https://komodoplatform.com/komodo-wallets/
Changelog:
- Latest KMD binaries based on beta branch
- Create wallet refactor
- Restore wallet
- Add coin modal Lite mode KMD assets toggle
- Add coin modal ERC20 tokens are accessible now under a new mode option
- PIN login refactor
- Added User Agreement
- Store active coins list in PIN file
- HUSH switched to HUSH3 asset chain using SPV/Lite mode
- OUR native mode wallet -ac_perc param fix
- K64 logo change
- ILN name fix and logo change
- SPV transaction history caching fix
- Removed GBX
- Import key modal multi rescan fix
- Address book z-address fix
The voting UI hasn't changed, and you can continue voting with this version. Just make sure that you have created a new wallet with fresh 24 words seed or restored wallet with existing seed or WIF.(edited)
The Tokens Custom Consensus (CC) module enables core-asset support for the on-chain creation of colored coins, also called tokens. The functionality is facilitated by utxo technology. Tokens can be generated on any chain where the ac_cc is enabled.
https://t.co/5WUiiWQzTv
Blackbeard17-May-19 04:29 PM
@everyone We are pleased to announce that in the upcoming weeks, we will launch the Komodo Evolution Campaign to introduce new tech and go-to-market plans for the rebrand and product launches coming this summer.
Stay tuned!
this is not financial or legal advice https://komodoplatform.com
Komodo is building an ecosystem that empowers developers and businesses with end-to-end blockchain solutions with no limits.
1
1
ca33325-May-19 03:09 PM
https://twitter.com/0xca333/status/1132253046900252672 - "Our mobile DEX wallet is entering the public beta phase the coming week! Prepare yourself for a new DEX era which stands for reliability, efficiency and remarkable quality. Looking forward to show you the results of many years of hard work."
#Komodo #DEX #Update: Our mobile #DEX wallet is entering the public beta phase the coming week! Prepare yourself for a new DEX era which stands for reliability, efficiency and remarkable quality. Looking forward to show you the results of many years of hard work. #KMD #BTC...
Likes
109
62
60
47
20
20
20
16
4
4
41
Audo03-Jun-19 09:08 PM
@everyone Komodo Is Introducing Antara, An End-To-End Smart Chain Development Framework
The Next Step In Building An Open, Programmable And Interoperable Multi-Chain Ecosystem
Komodo technology has been rapidly evolving during the past years and we are no longer the same project. We have launched an 'evolution campaign' to start introducing the new Komodo terminology and product offerings.
Learn more: https://evolve.komodoplatform.com/(edited)
The blockchain industry must evolve and Komodo is leading the charge.
51
86
57
31
50
33
29
30
24
26
27
22
72
28
25
31
29
24
38
26
ca33304-Jun-19 02:38 PM
@everyone - we are at the Money2020, THE flagship fintech event in Europe and the rest of the world. We 've had the pleasure to showcase our new mobile DEX wallet "AtomicDEX mobile" & the first truly grandma-friendly blockchain creation suite with the codename "Chainlizard"- this is our BaaS Webapp that allows you to create a new blockchain with wallets, explorers, sync- & seednode infrastructure, SPV servers, dPoW integration and much more within MINUTES! We also discussed potential partnerships ref. 3rd party-utilization of "AtomicAPI", our 3rd gen marketmaker software = DEX core. And last but not least we 've checked out the blockchain-fintech space for you. Our marketing-team will provide more details soon - stay tuned!
https://twitter.com/0xca333/status/1135915458316492801
Thank you @money2020 for this AWESOME event and the amazing #Komodo presentation. I am impressed by number of blockchain based projects and startups. Forget about the cryptomarket - THIS is the real 'bull'. #KMD #DEX #M2020 #BTC #ETH
44
42
40
14
9
19
24
5
8
10
6
2
9
22
14
56
ca33305-Jun-19 01:12 AM
@everyoneSecurity Alert: if you created or used your seed phrase with Agama please deinstall it, stop using it and immediately rotate your seeds and move all your coins out from there (to a different seed - which was NOT created with Agama) - if you know what you are doing please use either cold-storage (paper-wallets, offline storage, ...), the KomodoOcean wallet or komodo-cli. We will provide you an alternative desktop wallet very soon. If you need assistance please reach out to our support team: #support.
Our team will provide you all details of the incident in the coming days.
This does only affect seeds that were used or created with Agama for Desktop, Mobile or Browser.


|
Gephi Toolkit Javadoc | ||||||||
| PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |
See:
Description
| Interface Summary | |
|---|---|
| TimelineChart | Sparkline type chart visible in the timeline, for instance the number of nodes over time. |
| TimelineController | Controls the timeline bounds and animation features. |
| TimelineModel | Timeline model which holds timeline bounds, interval and animation flags. |
| TimelineModelListener | Timeline model listener. |
| Class Summary | |
|---|---|
| TimelineModelEvent | Timeline model event. |
| Enum Summary | |
|---|---|
| TimelineModel.PlayMode | Defines how the interval is moved when animating. |
| TimelineModelEvent.EventType |
API which controls the Timeline, the UI component which allows network exploration over time.
The Timeline API allows to set custom bounds and visible interval. The
timeline is the UI component which controls the network exploration
over time. It is connected to the DynamicAPI
which
controls the time scale and intervals. The API also allows to
control the animation (i.e play feature).
The TimelineController
is managing models (one per workspace)
and is the access door to the system. This controller is a service, and can be
retrieved by using the following command:
TimelineController tc = Lookup.getDefault().lookup(TimelineController.class);
|
Gephi Toolkit Javadoc | ||||||||
| PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |


An implementation of the majorization-minimization (MM) algorithm introduced by Xu, Chi, Yang, and Lange (2017) <arXiv:1612.05614> for solving multi-set split feasibility problems. In the multi-set split feasibility problem, we seek to find a point x in the intersection of multiple closed sets and whose image under a mapping also must fall in the intersection of several closed sets.
| Version: | 0.1.0 |
| Depends: | compiler, corpcor, matrixStats |
| Published: | 2018-04-11 |
| Author: | Eric C. Chi [aut, cre, cph], Jason Xu [ctb], Meng Yang [ctb], Kenneth Lange [ctb] |
| Maintainer: | Eric C. Chi <ecchi1105 at gmail.com> |
| License: | MIT + file LICENSE |
| NeedsCompilation: | no |
| Citation: | splitFeas citation info |
| CRAN checks: | splitFeas results |
| Reference manual: | splitFeas.pdf |
| Package source: | splitFeas_0.1.0.tar.gz |
| Windows binaries: | r-devel: splitFeas_0.1.0.zip, r-release: splitFeas_0.1.0.zip, r-oldrel: splitFeas_0.1.0.zip |
| OS X binaries: | r-release: splitFeas_0.1.0.tgz, r-oldrel: splitFeas_0.1.0.tgz |
Please use the canonical form https://CRAN.R-project.org/package=splitFeas to link to this page.


Hello everone
I'll try to introduce myslef to give you a good image about me.
My Name is Naziha Qawasmeh,Iam 34 Years
old from Jordan.
- i studied accounting in Yarmouk University & graduated in 2020 with Master degree
- I worked as a teacher in Som Secondary School for one year
- i love reading books. MyFavorite one is One Hundred Years of Solitude
- My favorite food is Dawali
- I am studing coding right now in LTUC Collage, and try to be better end better


Preparation time
less than 30 mins
Cooking time
10 to 30 mins
Serves
Serves 4
This soup is as easy as it gets and tastes wonderful when served with crisp Parma ham or bacon.
Bring the water to the boil in a large pan and add a generous pinch of salt.
Add the mint leaves and bring the liquid back to the boil.
Add the peas and cook for 2-3 minutes, until the peas are just tender and bright green.
Strain the mint and peas, reserving the cooking liquid, and transfer the peas and mint to a food processor. Allow to cool for 3-4 minutes.
Add just enough of the cooking liquid to cover the peas and mint, then blend for 1-2 minutes, to create a smooth, bright green purée.
Season, to taste, with salt and freshly ground black pepper and add a generous drizzle of olive oil.
Add 140ml/4½fl oz of the crème fraîche to the pea and mint purée and pulse in the blender for a few seconds, until combined.
To serve, pour equal amounts of the soup into four warmed bowls. Add a neat tablespoon of crème fraîche into the centre of each and, if you wish, garnish with the crisp Parma ham.


This Week in Rust
Hello and welcome to another issue of This Week in Rust! It’s late this week because bors was having some issues which bounced every pull request, and it’s no fun writing about nothing.
What’s cooking on master?
61 PRs were merged this week.
Breaking Changes
- The first part of the
box
changes has landed.box
is a keyword, and in an expression is now synonymous with~
(ie, it allocates an owned box). std::vec::raw
has seen some cleanup.- Link meta attributes have been
replaced with a
pkgid
. rustdoc also now requires apkgid
attribute, rather than the deprecated link meta. - Some fairly obscure import syntax has been
changed.
use {foo, bar}
is now permitted, and the olduse foo, bar
is not. Cell
has been removed.RefCell
supersedes it.- Attempting to implement private traits no longer works.
- The coherence
-Z
flag has been removed. - The
self
lifetime is now illegal, like the rest of the keywords. Now, lifetime parameters are truly only identifiers.
Other changes
- A dead code warning has been
implemented. This is pretty
awesome and will do things like warn for test functions that are accidentally
never marked
#[test]
and so are never called. Some bugs in it were also fixed. - The benchmark runner now handles slow benchmarks. Previously, it wouldn’t run a benchmark that took more than 1ms. Now, it will!
- The
shootout-fasta
benchmark has been rewritten. It’s about 10x faster, and looks nicer. - Stepping through / breaking on function calls no longer goes through the function prelude.
- The vector
move_iter
has been made faster. - A single
#[inline]
has madevec::from_elem
20x faster Buffer
now has an iterator over its lines. The gotcha is that the newlines are included in the yielded strings.- Struct pattern shorthand has been
improved by allowing ref/mut,
like
let Foo { mut x, .. } = some_foo
, rather than the previouslet Foo { x: mut x, .. } = some_foo
. - LTO (link time optimization) has been implemented. Rejoice.
- All landing pads (and thus unwinding!) can now be omitted when doing LTO.
std::io::util
has been added with:LimitReader
that will only readn
bytes from another readerNullWriter
that ignores everything written to itNullReader
that is always EOFZeroReader
which returns all zeroes,MultiWriter
which will replicate a written buffer to many writersChainedReader
which reads readers in order to completionTeeReader
which will write to a Writer while reading- a
copy
function which copies the full contents of a reader into a writer.
- Windows application manifests are now embedded, so we don’t get special cased.
- A
--dep-info
flag has been added which is like-MMD
to C compilers. &mut
underneath&
can now be frozen.PortReader
andChanWriter
have been implemented.- Some more random distributions have been implemented.
- We now use LLVM’s integrated assembler on Windows.
New contributors
- Cadence Marseille
- Edward Z. Yang
- Erik Price
- Fabrice Desré
- Jan Niklas Hasse
- Richard Diamond
Meeting
The weekly
meeting
discussed enum mod
, using types to drive inference (rather than attributes
like #[no_send]
etc), a formal grammar, unwinding, and some various PRs (all
mentioned above).
This Week in Servo
Servo is a web browser engine written in Rust and is one of the primary test cases for the Rust language.
We landed 29 PRs this week.
Notable additions
- Patrick Walton landed a number of changes to layout to avoid going back to the DOM for properties to make layout’s access to the DOM more opaque. He also cleaned up a significant number of regressions and added a huge number of ref tests.
- Keegan McAllister made content tests work in headless mode in #1382.
- Daniel Glazman added namespace info to elements in #1358.
- Daniel Hedlund added support for leading font metrics on Linux #1352.
Meetings
This week’s meeting discussed an upcoming Servo workweek in SF on January 20th. We also discussed the Rust version update and some general team frustration at a large number of regressions lately, primarily caused by the need to disable some of our automated testing due to instability (particularly at shutdown). This week of work saw many of those issues fixed.
Announcements, etc
- FAQ Cheatsheet – A cookbook-style cheatsheet of how to do simple things, based on IRC FAQs.
- Building Rust Code – Current Issues
- Building Rust Code – Using Make
- A Rust port of kissdb
- Reddit
discussion
of the
box
change.


SEVO entangled ISO photons interaction two-photon absorption quantum ether diethyl Fig. anesthetics using Chem. shown state anesthetic excited {border-style nm classical interact px;} #ffffff;} properties studies optical sevoflurane electronic photon Phys. used ethers light spectra spectroscopy study energy ether, experimental general mechanism mechanisms molecule excitation halogenated molecular molecules seen signal virtual Supplementary action aliphatic compared emission interactions nonlinear photons. shows completed dipole isoflurane potentials px; results structure studied {font-family nm, ./. Entangled Figure ISO, ability calculations experiment font-size induce large methyl photons, previous spectrum wavelength Table changes correlated double; ground liquid low organic state, transition use Figs However, Lett. Opt. Raman anesthesia anesthetic-induced blue-shift border-color border-width compounds coupling data detuning difference directly does ether. ethyl fluorescence functional helped high information intensity laser light. neural orbitals order particles pathways previously pure rate similar solid; strongly transmission work {font-style {font-weight Cieślik-Boczula Commons Creative Goodson Rospenk SEVO, Sci. Soc. ZnTPP, basis bold brain channels chlorine communication compound courier; create cross did different effects em; expected gas incident including inhalational interacting investigated isopropyl linear max neurons parent pathway permanent phase pt;} reported specific spin states unique


--- layout: post title: "An F# implementation of the Maître d' kata" description: "This article walks you through the Maître d' kata done in F#." date: 2020-04-27 14:41 UTC tags: [F#, Unit Testing, Functional Programming] --- {% include JB/setup %}
{{ page.description }}
In a previous article, I presented the Maître d' kata and promised to publish a walkthrough. Here it is.
I used test-driven development and F# for both unit tests and implementation. As usual, my test framework was xUnit.net (2.4.0) with Unquote (5.0.0) as the assertion library.
I could have done the exercise with a property-based testing framework like FsCheck or Hedgehog, but I chose instead to take my own medicine. In the kata description, I suggested some test cases, so I wanted to try and see if they made sense.
The entire code base is available on GitHub.
I wrote the first suggested test case this way:
[<Fact>]
let ``Boutique restaurant`` () =
test <@ canAccept 12 [] { Quantity = 1 } @>
This uses Unquote's test
function to verify that a Boolean expression is true. The expression is a function call to canAccept
with the capacity 12
, no existing reservations, and a reservation with Quantity = 1
.
The simplest thing that could possibly work was this:
type Reservation = { Quantity : int } let canAccept _ _ _ = true
The Reservation
type was required to make the test compile, but the canAccept
function didn't have to consider its arguments. It could simply return true
.
The next test case made me turn the test function into a parametrised test:
[<Theory>] [<InlineData( 1, true)>] [<InlineData(13, false)>] let ``Boutique restaurant`` quantity expected = expected =! canAccept 12 [] { Quantity = quantity }
So far, the only test parameters were quantity
and the expected
result. I could no longer use test
to verify the result of calling canAccept
, since I added variation to the expected
result. I changed test
into Unquote's =!
(must equal) operator.
The simplest passing implementation I could think of was:
let canAccept _ _ { Quantity = q } = q = 1
It ignored the capacity and instead checked whether q
is 1
. That passed both tests.
Before adding another test case, I decided to refactor my test code a bit. When working with a real domain model, you often have to furnish test data in order to make code compile - even if that data isn't relevant to the test. I wanted to demonstrate how to deal with this issue. My first step was to introduce an 'arbitrary' Reservation
value in the spirit of Test data without Builders.
let aReservation = { Quantity = 1 }
This enabled me to rewrite the test:
[<Theory>] [<InlineData( 1, true)>] [<InlineData(13, false)>] let ``Boutique restaurant`` quantity expected = expected =! canAccept 12 [] { aReservation with Quantity = quantity }
This doesn't look like an immediate improvement, but it made it possible to make the Reservation
record type more realistic without damage to the test:
type Reservation = {
Date : DateTime
Name : string
Email : string
Quantity : int }
I added some fields that a real-world reservation would have. The Quantity
field will be useful later on, but the Name
and Email
fields are irrelevant in the context of the kata.
This is the type of API change that often gives people grief. To create a Reservation
value, you must supply all four fields. This often adds noise to tests.
Not here, though, because the only concession I had to make was to change aReservation
:
let aReservation = { Date = DateTime (2019, 11, 29, 12, 0, 0) Name = "" Email = "" Quantity = 1 }
The test code remained unaltered.
With that in place, I could add the third test case:
[<Theory>] [<InlineData( 1, true)>] [<InlineData(13, false)>] [<InlineData(12, true)>] let ``Boutique restaurant`` quantity expected = expected =! canAccept 12 [] { aReservation with Quantity = quantity }
The simplest passing implementation I could think of was:
let canAccept _ _ { Quantity = q } = q <> 13
This implementation still ignored the restaurant's capacity and simply checked that q
was different from 13
. That was enough to pass all three tests.
Adding the next suggested test case proved to be a problem. I wanted to write a single [<Theory>]
-driven test function fed by all the Boutique restaurant test data. To do that, I'd have to supply arrays of test input, but unfortunately, that wasn't possible in F#.
Instead I decided to refactor the test case code to use ClassData
-driven test cases.
type BoutiqueTestCases () as this = inherit TheoryData<int, bool> () do this.Add ( 1, true) this.Add (13, false) this.Add (12, true) [<Theory; ClassData(typeof<BoutiqueTestCases>)>] let ``Boutique restaurant`` quantity expected = expected =! canAccept 12 [] { aReservation with Quantity = quantity }
These are the same test cases as before, but now expressed by a class inheriting from TheoryData<int, bool>
. The implementing code remains the same.
The next suggested test case includes an existing reservation. To support that, I changed the test case base class to TheoryData<int, int list, int, bool>
, and passed empty lists for the first three test cases. For the new, fourth test case, I supplied a number of seats.
type BoutiqueTestCases () as this = inherit TheoryData<int, int list, int, bool> () do this.Add (12, [], 1, true) this.Add (12, [], 13, false) this.Add (12, [], 12, true) this.Add ( 4, [2], 3, false) [<Theory; ClassData(typeof<BoutiqueTestCases>)>] let ``Boutique restaurant`` capacity reservatedSeats quantity expected = let rs = List.map (fun s -> { aReservation with Quantity = s }) reservatedSeats let actual = canAccept capacity rs { aReservation with Quantity = quantity } expected =! actual
This also forced me to to change the body of the test function. At this stage, it could be prettier, but it got the job done. I soon after improved it.
My implementation, as usual, was the simplest thing that could possibly work.
let canAccept _ reservations { Quantity = q } =
q <> 13 && Seq.isEmpty reservations
Notice that although the fourth test case varied the capacity
, I still managed to pass all tests without looking at it.
The next test case introduced another existing reservation, but this time with enough capacity to accept a new reservation.
type BoutiqueTestCases () as this = inherit TheoryData<int, int list, int, bool> () do this.Add (12, [], 1, true) this.Add (12, [], 13, false) this.Add (12, [], 12, true) this.Add ( 4, [2], 3, false) this.Add (10, [2], 3, true)
The test function remained unchanged.
In the spirit of the Devil's advocate technique, I actively sought to avoid a correct implementation. I came up with this:
let canAccept capacity reservations { Quantity = q } = let reservedSeats = match Seq.tryHead reservations with | Some r -> r.Quantity | None -> 0 reservedSeats + q <= capacity
Since all test cases supplied at most one existing reservation, it was enough to consider the first reservation, if present.
To many people, it may seem strange to actively seek out incorrect implementations like this. An incorrect implementation that passes all tests does, however, demonstrate the need for more tests.
I then added another test case, this time with three existing reservations:
type BoutiqueTestCases () as this = inherit TheoryData<int, int list, int, bool> () do this.Add (12, [], 1, true) this.Add (12, [], 13, false) this.Add (12, [], 12, true) this.Add ( 4, [2], 3, false) this.Add (10, [2], 3, true) this.Add (10, [3;2;3], 3, false)
Again, I left the test function untouched.
On the side of the implementation, I couldn't think of more hoops to jump through, so I finally gave in and provided a 'proper' implementation:
let canAccept capacity reservations { Quantity = q } = let reservedSeats = Seq.sumBy (fun r -> r.Quantity) reservations reservedSeats + q <= capacity
Not only does it look simpler that before, but I also felt that the implementation was warranted.
Although I'd only tested“As the tests get more specific, the code gets more generic.”
canAccept
with lists, I decided to implement it with Seq
. This was a decision I later regretted.
The last Boutique restaurant test case was to supply an existing reservation on another date. The canAccept
function should only consider existing reservations on the date in question.
First, I decided to model the two separate dates as two values:
let d1 = DateTime (2023, 9, 14) let d2 = DateTime (2023, 9, 15)
I hoped that it would make my test cases more readable, because the dates would have a denser representation.
type BoutiqueTestCases () as this = inherit TheoryData<int, (int * DateTime) list, (int * DateTime), bool> () do this.Add (12, [], ( 1, d1), true) this.Add (12, [], (13, d1), false) this.Add (12, [], (12, d1), true) this.Add ( 4, [(2, d1)], ( 3, d1), false) this.Add (10, [(2, d1)], ( 3, d1), true) this.Add (10, [(3, d1);(2, d1);(3, d1)], ( 3, d1), false) this.Add ( 4, [(2, d2)], ( 3, d1), true)
I changed the representation of a reservation from just an int
to a tuple of a number and a date. I also got tired of looking at that noisy unit test, so I introduced a test-specific helper function:
let reserve (q, d) = { aReservation with Quantity = q; Date = d }
Since it takes a tuple of a number and a date, I could use it to simplify the test function:
[<Theory; ClassData(typeof<BoutiqueTestCases>)>] let ``Boutique restaurant`` (capacity, rs, r, expected) = let reservations = List.map reserve rs let actual = canAccept capacity reservations (reserve r) expected =! actual
The canAccept
function now had to filter the reservations
on Date
:
let canAccept capacity reservations { Quantity = q; Date = d } = let relevantReservations = Seq.filter (fun r -> r.Date = d) reservations let reservedSeats = Seq.sumBy (fun r -> r.Quantity) relevantReservations reservedSeats + q <= capacity
This implementation specifically compared dates, though, so while it passed all tests, it'd behave incorrectly if the dates were as much as nanosecond off. That implied that another test case was required.
The final test case for the Boutique restaurant, then, was to use two DateTime
values on the same date, but with different times.
type BoutiqueTestCases () as this = inherit TheoryData<int, (int * DateTime) list, (int * DateTime), bool> () do this.Add (12, [], ( 1, d1 ), true) this.Add (12, [], (13, d1 ), false) this.Add (12, [], (12, d1 ), true) this.Add ( 4, [(2, d1)], ( 3, d1 ), false) this.Add (10, [(2, d1)], ( 3, d1 ), true) this.Add (10, [(3, d1);(2, d1);(3, d1)], ( 3, d1 ), false) this.Add ( 4, [(2, d2)], ( 3, d1 ), true) this.Add ( 4, [(2, d1)], ( 3, d1.AddHours 1.), false)
I just added a new test case as a new line and lined up the data. The test function, again, didn't change.
To address the new test case, I generalised the first filter.
let canAccept capacity reservations { Quantity = q; Date = d } = let relevantReservations = Seq.filter (fun r -> r.Date.Date = d.Date) reservations let reservedSeats = Seq.sumBy (fun r -> r.Quantity) relevantReservations reservedSeats + q <= capacity
An expression like r.Date.Date
looks a little odd. DateTime
values have a Date
property that represents its date part. The first Date
is the Reservation
field, and the second is the date part.
I was now content with the Boutique restaurant implementation.
In the next phase of the kata, I now had to deal with a configuration of more than one table, so I introduced a type:
type Table = { Seats : int }
It's really only a glorified wrapper around an int
, but with a real domain model in place, I could make its constructor private and instead afford a smart constructor that only accepts positive integers.
I changed the canAccept
function to take a list of tables, instead of capacity
. This also required me to change the existing test function to take a singleton list of tables:
let actual = canAccept [table capacity] reservations (reserve r)
where table
is a test-specific helper function:
let table s = { Seats = s }
I also added a new test function and a single test case:
let d3 = DateTime (2024, 6, 7) type HauteCuisineTestCases () as this = inherit TheoryData<int list, (int * DateTime) list, (int * DateTime), bool> () do this.Add ([2;2;4;4], [], (4, d3), true) [<Theory; ClassData(typeof<HauteCuisineTestCases>)>] let ``Haute cuisine`` (tableSeats, rs, r, expected) = let tables = List.map table tableSeats let reservations = List.map reserve rs let actual = canAccept tables reservations (reserve r) expected =! actual
The change to canAccept
is modest:
let canAccept tables reservations { Quantity = q; Date = d } = let capacity = Seq.sumBy (fun t -> t.Seats) tables let relevantReservations = Seq.filter (fun r -> r.Date.Date = d.Date) reservations let reservedSeats = Seq.sumBy (fun r -> r.Quantity) relevantReservations reservedSeats + q <= capacity
It still works by looking at a total capacity as if there was just a single communal table. Now it just calculates capacity
from the sequence of tables
.
Then I added the next test case to the new test function:
type HauteCuisineTestCases () as this = inherit TheoryData<int list, (int * DateTime) list, (int * DateTime), bool> () do this.Add ([2;2;4;4], [], (4, d3), true) this.Add ([2;2;4;4], [], (5, d3), false)
This one attempts to make a reservation for five people. The largest table only fits four people, so this reservation should be rejected. The current implementation just considered the total capacity of all tables, to it accepted the reservation, and thereby failed the test.
This change to canAccept
passes all tests:
let canAccept tables reservations { Quantity = q; Date = d } = let capacity = tables |> Seq.map (fun t -> t.Seats) |> Seq.max let relevantReservations = Seq.filter (fun r -> r.Date.Date = d.Date) reservations let reservedSeats = Seq.sumBy (fun r -> r.Quantity) relevantReservations reservedSeats + q <= capacity
The function now only considered the largest table in the restaurant. While it's incorrect to ignore all other tables, all tests passed.
Only considering the largest table is obviously wrong, so I added another test case where there's an existing reservation.
type HauteCuisineTestCases () as this = inherit TheoryData<int list, (int * DateTime) list, (int * DateTime), bool> () do this.Add ([2;2;4;4], [], (4, d3), true) this.Add ([2;2;4;4], [], (5, d3), false) this.Add ( [2;2;4], [(2, d3)], (4, d3), true)
While canAccept
should accept the reservation, it didn't when I added the test case. In a variation of the Devil's Advocate technique, I came up with this implementation to pass all tests:
let canAccept tables reservations { Quantity = q; Date = d } = let largestTable = tables |> Seq.map (fun t -> t.Seats) |> Seq.max let capacity = tables |> Seq.sumBy (fun t -> t.Seats) let relevantReservations = Seq.filter (fun r -> r.Date.Date = d.Date) reservations let reservedSeats = Seq.sumBy (fun r -> r.Quantity) relevantReservations q <= largestTable && reservedSeats + q <= capacity
This still wasn't the correct implementation. It represented a return to looking at the total capacity of all tables, with the extra rule that you couldn't make a reservation larger than the largest table. At least one more test case was needed.
I added another test case to the haute cuisine test cases. This one came with one existing reservation for three people, effectively reserving the four-person table. While the remaining tables have an aggregate capacity of four, it's two separate tables. Therefore, a reservation for four people should be rejected.
type HauteCuisineTestCases () as this = inherit TheoryData<int list, (int * DateTime) list, (int * DateTime), bool> () do this.Add ([2;2;4;4], [], (4, d3), true) this.Add ([2;2;4;4], [], (5, d3), false) this.Add ( [2;2;4], [(2, d3)], (4, d3), true) this.Add ( [2;2;4], [(3, d3)], (4, d3), false)
It then dawned on me that I had to explicitly distinguish between a communal table configuration, and individual tables that aren't communal, regardless of size. This triggered quite a refactoring.
I defined a new type to distinguish between these two types of table layout:
type TableConfiguration = Communal of int | Tables of Table list
I also had to change the existing test functions, including the boutique restaurant test
[<Theory; ClassData(typeof<BoutiqueTestCases>)>] let ``Boutique restaurant`` (capacity, rs, r, expected) = let reservations = List.map reserve rs let actual = canAccept (Communal capacity) reservations (reserve r) expected =! actual
and the haute cuisine test
[<Theory; ClassData(typeof<HauteCuisineTestCases>)>] let ``Haute cuisine`` (tableSeats, rs, r, expected) = let tables = List.map table tableSeats let reservations = List.map reserve rs let actual = canAccept (Tables tables) reservations (reserve r) expected =! actual
In both cases I had to change the call to canAccept
to pass either a Communal
or a Tables
value.
I'd previously done the kata in Haskell and was able to solve this phase of the kata using the built-in deleteFirstsBy
function. This function doesn't exist in the F# core library, so I decided to add it. I created a new module named Seq
and first defined a function that deletes the first element that satisfies a predicate:
// ('a -> bool) -> seq<'a> -> seq<'a> let deleteFirstBy pred (xs : _ seq) = seq { let mutable found = false use e = xs.GetEnumerator () while e.MoveNext () do if found then yield e.Current else if pred e.Current then found <- true else yield e.Current }
It moves over a sequence of elements and looks for an element that satisfies pred
. If such an element is found, it's omitted from the output sequence. The function only deletes the first occurrence from the sequence, so any other elements that satisfy the predicate are still included.
This function corresponds to Haskell's deleteBy
function and can be used to implement deleteFirstsBy
:
// ('a -> 'b -> bool) -> seq<'b> -> seq<'a> -> seq<'b> let deleteFirstsBy pred = Seq.fold (fun xs x -> deleteFirstBy (pred x) xs)
As the Haskell documentation explains, the "deleteFirstsBy
function takes a predicate and two lists and returns the first list with the first occurrence of each element of the second list removed." My F# function does the same, but works on sequences instead of linked lists.
I could use it to find and remove tables that were already reserved.
I first defined a little helper function to determine whether a table can accommodate a reservation:
// Reservation -> Table -> bool let private fits r t = r.Quantity <= t.Seats
The rule is simply that the table's number of Seats
must be greater than or equal to the reservation's Quantity
. I could use this function for the predicate for Seq.deleteFirstsBy
:
let canAccept config reservations ({ Quantity = q; Date = d } as r) = let contemporaneousReservations = Seq.filter (fun r -> r.Date.Date = d.Date) reservations match config with | Communal capacity -> let reservedSeats = Seq.sumBy (fun r -> r.Quantity) contemporaneousReservations reservedSeats + q <= capacity | Tables tables -> let rs = Seq.sort contemporaneousReservations let remainingTables = Seq.deleteFirstsBy fits (Seq.sort tables) rs Seq.exists (fits r) remainingTables
The canAccept
function now branched on Communal
versus Tables
configurations. In the Communal
configuration, it simply compared the reservedSeats
and reservation quantity to the communal table's capacity
.
In the Tables
case, the function used Seq.deleteFirstsBy fits
to remove all the tables that are already reserved. The result is the remainingTables
. If there exists a remaining table that fits
the reservation, then the function accepts the reservation.
This seemed to me an appropriate implementation of the haute cuisine phase of the kata.
Now it was time to take seating duration into account. While I could have written my test cases directly against the TimeSpan API, I didn't want to write TimeSpan.FromHours 2.5
, TimeSpan.FromDays 1.
, and so on. I found that it made my test cases harder to read, so I added some literal extensions:
type Int32 with member x.hours = TimeSpan.FromHours (float x) member x.days = TimeSpan.FromDays (float x)
This enabled me to write expressions like 1 .days
and 2 .hours
, as shown in the first test case:
let d4 = DateTime (2023, 10, 22, 18, 0, 0) type SecondSeatingsTestCases () as this = inherit TheoryData<TimeSpan, int list, (int * DateTime) list, (int * DateTime), bool> () do this.Add (2 .hours, [2;2;4], [(4, d4)], (3, d4.Add (2 .hours)), true)
I used this initial parametrised test case for a new test function:
[<Theory; ClassData(typeof<SecondSeatingsTestCases>)>] let ``Second seatings`` (dur, tableSeats, rs, r, expected) = let tables = List.map table tableSeats let reservations = List.map reserve rs let actual = canAccept dur (Tables tables) reservations (reserve r) expected =! actual
My motivation for this test case was mostly to introduce an API change to canAccept
. I didn't want to rock the boat too much, so I picked a test case that wouldn't trigger a big change to the implementation. I prefer incremental changes. The only change is the introduction of the seatingDur
argument:
let canAccept (seatingDur : TimeSpan) config reservations ({ Date = d } as r) = let contemporaneousReservations = Seq.filter (fun x -> x.Date.Subtract seatingDur < d.Date) reservations match config with | Communal capacity -> let reservedSeats = Seq.sumBy (fun r -> r.Quantity) contemporaneousReservations reservedSeats + r.Quantity <= capacity | Tables tables -> let rs = Seq.sort contemporaneousReservations let remainingTables = Seq.deleteFirstsBy fits (Seq.sort tables) rs Seq.exists (fits r) remainingTables
While the function already considered seatingDur
, the way it filtered reservation
wasn't entirely correct. It passed all tests, though.
The next test case I added made me write what I consider the right implementation, but I subsequently decided to add two more test cases just for confidence. Here's all of them:
type SecondSeatingsTestCases () as this = inherit TheoryData<TimeSpan, int list, (int * DateTime) list, (int * DateTime), bool> () do this.Add ( 2 .hours, [2;2;4], [(4, d4)], (3, d4.Add (2 .hours)), true) this.Add ( 2.5 .hours, [2;4;4], [(2, d4);(1, d4.AddMinutes 15.);(2, d4.Subtract (15 .minutes))], (3, d4.AddHours 2.), false) this.Add ( 2.5 .hours, [2;4;4], [(2, d4);(2, d4.Subtract (15 .minutes))], (3, d4.AddHours 2.), true) this.Add ( 2.5 .hours, [2;4;4], [(2, d4);(1, d4.AddMinutes 15.);(2, d4.Subtract (15 .minutes))], (3, d4.AddHours 2.25), true)
The new test cases use some more literal extensions:
type Int32 with member x.minutes = TimeSpan.FromMinutes (float x) member x.hours = TimeSpan.FromHours (float x) member x.days = TimeSpan.FromDays (float x) type Double with member x.hours = TimeSpan.FromHours x
I added a private isContemporaneous
function to the code base and used it to filter the reservation to pass the tests:
let private isContemporaneous (seatingDur : TimeSpan) (candidate : Reservation) (existing : Reservation) = let aSeatingBefore = candidate.Date.Subtract seatingDur let aSeatingAfter = candidate.Date.Add seatingDur aSeatingBefore < existing.Date && existing.Date < aSeatingAfter let canAccept (seatingDur : TimeSpan) config reservations r = let contemporaneousReservations = Seq.filter (isContemporaneous seatingDur r) reservations match config with | Communal capacity -> let reservedSeats = Seq.sumBy (fun r -> r.Quantity) contemporaneousReservations reservedSeats + r.Quantity <= capacity | Tables tables -> let rs = Seq.sort contemporaneousReservations let remainingTables = Seq.deleteFirstsBy fits (Seq.sort tables) rs Seq.exists (fits r) remainingTables
I could have left the functionality of isContemporaneous
inside of canAccept
, but I found it just hard enough to get my head around that I preferred to put it in a named helper function. Checking that a value is in a range is in itself trivial, but for some reason, figuring out the limits of the range didn't come naturally to me.
This version of canAccept
only considered existing reservations if they in any way overlapped with the reservation in question. It passed all tests. It also seemed to me to be a satisfactory implementation of the second seatings scenario.
This state of the kata introduces groups of tables that can be reserved individually, or combined. To support that, I changed the definition of Table
:
type Table = Discrete of int | Group of int list
A Table
is now either a Discrete
table that can't be combined, or a Group
of tables that can either be reserved individually, or combined.
I had to change the test-specific table
function to behave like before.
let table s = Discrete s
Before this change to the Table
type, all tables were implicitly Discrete
tables.
This enabled me to add the first test case:
type AlternativeTableConfigurationTestCases () as this = inherit TheoryData<Table list, int list, int, bool> () do this.Add ( [Discrete 4; Discrete 1; Discrete 2; Group [2;2;2]], [3;1;2], 2, true) [<Theory; ClassData(typeof<AlternativeTableConfigurationTestCases>)>] let ``Alternative table configurations`` (tables, rs, r, expected) = let res i = reserve (i, d4) let reservations = List.map res rs let actual = canAccept (1 .days) (Tables tables) reservations (res r) expected =! actual
Like I did when I introduced the seatingDur
argument, I deliberately chose a test case that didn't otherwise rock the boat too much. The same was the case now, so the only other change I had to make to pass all tests was to adjust the fits
function:
// Reservation -> Table -> bool let private fits r = function | Discrete seats -> r.Quantity <= seats | Group _ -> true
It's clearly not correct to return true
for any Group
, but it passed all tests.
I wanted to edge a little closer to correctly handling the Group
case, so I added a test case:
type AlternativeTableConfigurationTestCases () as this = inherit TheoryData<Table list, int list, int, bool> () do this.Add ( [Discrete 4; Discrete 1; Discrete 2; Group [2;2;2]], [3;1;2], 2, true) this.Add ( [Discrete 4; Discrete 1; Discrete 2; Group [2;2;2]], [3;1;2], 7, false)
A restaurant with this table configuration can't accept a reservation for seven people, but because fits
returned true
for any Group
, canAccept
would return true
. Since the test expected the result to be false
, this caused the test to fail.
Edging closer to correct behaviour, I adjusted fits
again:
// Reservation -> Table -> bool let private fits r = function | Discrete seats -> r.Quantity <= seats | Group tables -> r.Quantity <= List.sum tables
This was still not correct, because it removed an entire group of tables when fits
returned true
, but it passed all tests so far.
I added another failing test:
type AlternativeTableConfigurationTestCases () as this = inherit TheoryData<Table list, int list, int, bool> () do this.Add ( [Discrete 4; Discrete 1; Discrete 2; Group [2;2;2]], [3;1;2], 2, true) this.Add ( [Discrete 4; Discrete 1; Discrete 2; Group [2;2;2]], [3;1;2], 7, false) this.Add ( [Discrete 4; Discrete 1; Discrete 2; Group [2;2;2]], [3;1;2;1], 4, true)
The last test case failed because the existing reservations should only have reserved one of the tables in the group, but because of the way fits
worked, the entire group was deleted by Seq.deleteFirstsBy fits
. This made canAccept
reject the four-person reservation.
To be honest, this step was difficult for me. I should probably have found out how to make a smaller step.
I wanted a function that would compare a Reservation
to a Table
, but unlike Fits
return None
if it decided to 'use' the table, or a Some
value if it decided that it didn't need to use the entire table. This would enable me to pick only some of the tables from a Group
, but still return a Some
value with the rest of tables.
I couldn't figure out an elegant way to do this with the existing Seq
functionality, so I started to play around with something more specific. The implementation came accidentally as I was struggling to come up with something more general. As I was experimenting, all of a sudden, all tests passed!
// Reservation -> Table -> Table option let private allot r = function | Discrete seats -> if r.Quantity <= seats then None else Some (Discrete seats) | Group tables -> Some (Group tables) // seq<Table> -> Reservation -> seq<Table> let private allocate (tables : Table seq) r = seq { let mutable found = false use e = tables.GetEnumerator () while e.MoveNext () do if found then yield e.Current else match allot r e.Current with | None -> found <- true | Some t -> yield t } let canAccept (seatingDur : TimeSpan) config reservations r = let contemporaneousReservations = Seq.filter (isContemporaneous seatingDur r) reservations match config with | Communal capacity -> let reservedSeats = Seq.sumBy (fun r -> r.Quantity) contemporaneousReservations reservedSeats + r.Quantity <= capacity | Tables tables -> let rs = Seq.sort contemporaneousReservations let remainingTables = Seq.fold allocate (Seq.sort tables) rs Seq.exists (fits r) remainingTables
I wasn't too happy with the implementation, which I found (and still find) too complicated. This was, however, the first time I've done this part of the kata (in any language), so I wasn't sure where this was going.
The allocate
function finds and allocates one of its input tables to a reservation. It does that by not yielding the first table it finds that can accommodate the reservation. Don't hurt your head too much with the code in this version, because there's plenty of cases that it incorrectly handles.  Still, it passed all tests.
The implementation was wrong because the allot
function would just keep returning a Group
without consuming it. This would imply that canAccept
would use it more than once, which was wrong, so I added a test case:
type AlternativeTableConfigurationTestCases () as this = inherit TheoryData<Table list, int list, int, bool> () do this.Add ( [Discrete 4; Discrete 1; Discrete 2; Group [2;2;2]], [3;1;2], 2, true) this.Add ( [Discrete 4; Discrete 1; Discrete 2; Group [2;2;2]], [3;1;2], 7, false) this.Add ( [Discrete 4; Discrete 1; Discrete 2; Group [2;2;2]], [3;1;2;1], 4, true) this.Add ( [Discrete 4; Discrete 1; Discrete 2; Group [2;2;2]], [3;1;2;1;4], 3, false)
Given the existing reservations, this restaurant is effectively sold out that day. All the Discrete
tables are reserved, and the last two reservations for one and four effectively consumes the Group
. The latest test case expected canAccept
to return false
, but it returned true
. Since I was following test-driven development, I expected that.
I needed a function that would consume from a Group
of tables and return the remaining tables from that group; that is, the tables not consumed. I've already discussed this function in a different context.
// int -> seq<int> -> seq<int> let consume quantity = let go (acc, xs) x = if quantity <= acc then (acc, Seq.append xs (Seq.singleton x)) else (acc + x, xs) Seq.fold go (0, Seq.empty) >> snd
I put this function in my own Seq
module. It consumes values from the left until the sum is greater than or equal to the desired quantity
. It then returns the rest of the sequence:
> consume 1 [1;2;3];; val it : seq<int> = seq [2; 3] > consume 2 [1;2;3];; val it : seq<int> = seq [3] > consume 3 [1;2;3];; val it : seq<int> = seq [3] > consume 4 [1;2;3];; val it : seq<int> = seq []
The first example consumes only the leading 1
, while both the second and the third example consumes both 1
and 2
because the sum of those values is 3
, and the requested quantity is 2
and 3
, respectively. The fourth example consumes all elements because the requested quantity is 4
, and you need both 1
, 2
, and 3
before the sum is large enough. You have to pick strictly from the left, so you can't decide to just take the elements 1
and 3
.
I could now use my Seq.consume
function to improve allot
:
// Reservation -> Table -> Table option let private allot r = function | Discrete seats -> if r.Quantity <= seats then None else Some (Discrete seats) | Group tables -> tables |> Seq.consume r.Quantity |> Seq.toList |> Group |> Some
It handles the Group
case by consuming the reservation Quantity
and then returning a Some Group
with the remaining tables.
It also turned out that sorting the reservations wasn't appropriate, mainly because it's not entirely clear how to sort a list with elements of a discriminated union. My final implementation of canAccept
was this:
// TimeSpan -> TableConfiguration -> seq<Reservation> -> Reservation -> bool let canAccept seatingDur config reservations r = let contemporaneousReservations = Seq.filter (isContemporaneous seatingDur r) reservations match config with | Communal capacity -> let reservedSeats = Seq.sumBy (fun r -> r.Quantity) contemporaneousReservations reservedSeats + r.Quantity <= capacity | Tables tables -> let remainingTables = Seq.fold allocate (Seq.ofList tables) contemporaneousReservations Seq.exists (fits r) remainingTables
Nothing much has changed - only that neither reservations nor tables are now sorted. It passes all tests.
I must admit that I ran out of steam towards the end. It's possible that there's some edge cases I didn't think of. I'd probably feel more confident of the final implementation if I'd used property-based testing instead of Example-Guided Development.
I also took some unfortunate turns along the way. Early in the kata, I could easily implement canAccept
with functionality from the Seq
module. This meant that the function could take a seq<Reservation>
as an input argument. I'm always inclined to follow Postel's law and be liberal with what I accept. I thought that being able to accept any seq<Reservation>
was a good design decision. It might have been if I'd been publishing a reusable library, but it made things more awkward.
I'm also not sure that I chose to model the table layouts in the best way. For example, I currently can't handle a scenario with both bar seating and individual tables. I think I should have made Communal
a case of Table
. This would have enabled me to model layouts with several communal tables combined with discrete tables, and even groups of tables.
In general, my solution seems too complicated, but I don't see an easy fix. Often, if I work some more with the problem, insight arrives. It usually arrives when you least need it, so I thought it better to let the problem rest for a while. I can always return to it when I feel that I have a fresh approach.
This article walks you through my first F# attempt at the Maître d' kata. The repository is available on GitHub.
I'm not entirely happy with how it turned out, but I don't consider it an utter failure either.
Comments
You could leverage library functions and avoid mutability like so:
Ghillie, thank you for writing. It looks like you're on the right track, but I think you have to write the function like this:


Westeros Social Network
Home
Profile
Friends
Welcome to the Westeros Social Network
Here you can find allies but mostly foes.
No spam! No morals! No Starks!


The sika deer (Cervus nippon) also known as the spotted deer or the Japanese deer, is a species of deer native to much of East Asia, and introduced to various other parts of the world. Previously found from northern Vietnam in the south to the Russian Far East in the north, it is now uncommon in these areas, excluding Japan, where the species is overabundant. Its name comes from shika (鹿?), the Japanese word for "deer"; in Japan the species is known as the nihonjika (ニホンジカ（日本鹿）?, lit. "Japan deer").
The sika deer is one of the few deer species that does not lose its spots upon reaching maturity. Spot patterns vary with region. The mainland subspecies have larger and more obvious spots, in contrast to the Taiwanese and Japanese subspecies, whose spots are nearly invisible. Many introduced populations are from Japan, so also lack significant spots.
Sika deer are found in the temperate and subtropical forests of eastern Asia, preferring areas with dense understory, and where snowfall does not exceed 10–20 cm (3.9–7.9 in). They tend to forage in patchy clearings of forests. Introduced populations are found in areas with similar habitats to their native ranges, including Western and Central Europe, Eastern United States, and New Zealand.