This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to<EMAIL_ADDRESS>. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.
make-ipair-comparator
,
which was referenced in the document despite not being
defined.)
Scheme currently does not provide immutable pairs corresponding to its existing mutable pairs, although most uses of pairs do not exploit their mutability. The Racket system takes the radical approach of making Scheme's pairs immutable, and providing a minimal library of mutable pairs with procedures named mpair?, mcons, mcar, mcdr, set-mcar!, set-mcdr!
. This SRFI takes the opposite approach of leaving Scheme's pairs unchanged and providing a full set of routines for creating and dealing with immutable pairs. The sample implementation is portable (to systems with SRFI 9) and efficient.
The first question about this library is why it should exist at all. Why not simply eliminate mutability from Scheme's ordinary pairs and use a version of SRFI-1 that treats the linear-update procedures (with !
) as identical to their functional counterparts, as Racket does? The main answer is that this approach breaks R5RS and R7RS-small. All the data structures in these versions of Scheme are inherently mutable, and portable code is allowed to depend on that property.
R6RS segregates set-car!
and set-cdr!
into a separate library, thus allowing implementations to provide immutable Scheme pairs if this library is not (transitively) imported into a program, and mutable ones if it is. However, it is not possible to write portable R6RS programs that differentiate between mutable and immutable pairs, for example by using immutable pairs most of the time and mutable pairs where necessary.
Because of the Liskov Substitution Principle, it is not possible
to treat immutable pairs as either a subtype or a supertype of
mutable ones; they must be distinct, and if operations are to apply
to both, they can do so only by ad hoc polymorphism of the
kind that Scheme traditionally avoids for several reasons, including
clarity, efficiency, and flexibility.
This proposal, therefore, treats mutable and immutable pairs
separately, while allowing easy conversion from one to the other.
Rather than attempting to design this library from scratch, I have chosen the conservative option of modifying SRFI 1. Consequently, most of the rationale given in that document applies to this one as well. I have made the following changes:
!
i
at a judicious place in each identifier, usually at the beginning. However, because "icons" means something else in both ordinary English and computer jargon, the basic constructor and its immediate relatives are named ipair
, xipair
and ipair*
instead.apply
for applying a procedure to an immutable list of arguments.Note: In the prose, immutable pairs and lists are known as ipairs and ilists throughout.
Here is a short list of the procedures provided by this SRFI.
ipair ilist xipair ipair* make-ilist ilist-tabulate ilist-copy iiota
ipair? proper-ilist?/ilist? dotted-ilist? not-ipair? null-ilist? ilist=
icar icdr ... icddadr icddddr ilist-ref ifirst isecond ithird ifourth ififth isixth iseventh ieighth ininth itenth icar+icdr itake idrop/ilist-tail itake-right idrop-right isplit-at ilast last-ipair
ilength iappend iconcatenate ireverse iappend-reverse izip iunzip1 iunzip2 iunzip3 iunzip4 iunzip5 icount
imap ifor-each ifold iunfold ipair-fold ireduce ifold-right iunfold-right ipair-fold-right ireduce-right iappend-map ipair-for-each ifilter-map imap-in-order
ifilter ipartition iremove
imember imemq imemv ifind ifind-tail iany ievery ilist-index itake-while idrop-while ispan ibreak
idelete idelete-duplicates
iassoc iassq iassv ialist-cons ialist-delete
replace-icar replace-icdr
pair->ipair ipair->pair list->ilist ilist->list tree->itree itree->tree gtree->itree gtree->tree
iapply
ipair-comparator ilist-comparator make-ilist-comparator make-improper-ilist-comparator make-icar-comparator make-icdr-comparator
A set of general criteria guided the design of the SRFI-1 library that underlies this library. They are reproduced here.
List-filtering procedures such as ifilter
or idelete
do not disorder
lists. Elements appear in the answer list in the same order as they appear in
the argument list. This constrains implementation, but seems like a desirable
feature, since in many uses of lists, order matters. (In particular,
disordering an association list is definitely a bad idea.)
Contrariwise, although the sample implementations of the list-filtering procedures share longest common tails between argument and answer lists, it is not part of the spec.

However, constructors, such as
and the mapping
procedures (ilist-tabulate
iappend-map
, ipair-for-each
, ifilter-map
,
imap-in-order
), do not specify the dynamic order in which their procedural
argument is applied to its various values.
Predicates return useful true values wherever possible. Thus iany
must return
the true value produced by its predicate, and ievery
returns the final true
value produced by applying its predicate argument to the last element of its
argument list.
No special status is accorded Scheme's built-in equality predicate.
Any functionality provided in terms of eq?
, eqv?
, equal?
is also
available using a client-provided equality predicate.
These procedures are not generic as between ordinary pairs/lists and immutable pairs/lists; they are specific to immutable lists. Like Olin, I prefer to keep the library simple and focused. However, there are a few conversions between mutable and immutable lists provided.
Scheme does not properly have a list type, just as C does not have a string type. Rather, Scheme has a binary-tuple type, from which one can build binary trees. There is an interpretation of Scheme values that allows one to treat these trees as lists. The same interpretation is applied to immutable pairs.
Because the empty list, written as ()
, is already immutable, it is shared between mutable and immutable lists as the termination marker. It is the only Scheme object that is both a mutable list and an immutable list.
Users should note that dotted lists, whether mutable or immutable, are not commonly
used, and are considered by many Scheme programmers to be an ugly artifact of
Scheme's lack of a true list type.
Dotted ilists are not fully supported by this SRFI. Most procedures are
defined only on proper ilists — that is, ()
-terminated ilists. The
procedures that will also handle dotted ilists are specifically
marked. While this design decision restricts the domain of possible arguments
one can pass to these procedures, it has the benefit of allowing the
procedures to catch the error cases where programmers inadvertently pass
scalar values to an ilist procedure by accident,
e.g., by switching the arguments to a procedure call.
The various Scheme standards permit, but do not require,
Scheme implementations to treat quoted pairs and lists as unchangeable.
Thus whereas the expression
(let ((foo (list 1 2 3))) (set-car! foo 10) foo)
evaluates to (10 2 3)
, the value of
(let ((foo '(1 2 3))) (set-car! foo 10) foo)
is not portable, and is in fact an error.
This SRFI recommends that
implementations that provide both this SRFI and
unchangeable quotations should cause quotations
to return the same immutable pairs that this SRFI describes.
This means that the standard Scheme pair and list operations,
as well as libraries like SRFI 1 which are built on them,
should accept both mutable and immutable pairs: thus
(car (ilist 1 2))
should evaluate to 1
.
If this SRFI is implemented on a Scheme system which does in fact disallow the modification of quoted pairs, then this SRFI recommends that the procedures given here accept such quoted pairs as arguments where ipairs are expected.
In addition, this SRFI recommends that (where feasible) procedures
that expect either pairs or ipairs as arguments accept both pairs and ipairs.
If this implementation option is chosen, then
if such a call is defined to return newly allocated pairs
(such as cons
), then it returns ordinary pairs,
but if it is defined to return newly allocated ipairs
(such as icons
), then it returns ipairs.
However, if it returns existing objects, they will be pairs or ipairs
or other objects as the case may be.
This SRFI further recommends that read
should return mutable
pairs and lists when reading list structure. No recommendation is made about the
behavior of write
, display
, and similar output
procedures on immutable lists.
To make life easier for Scheme programmers, given that many implementations
do not provide immutable quotation, the syntax keyword iq
is
provided as part of this SRFI. It is partly analogous to quote
,
taking an arbitrary number of literals and constructing an ilist from them,
with any pairs in the literals converted to ipairs. It is useful
for providing constant ipair-based objects.
Note that pairs within literal vectors or other implementation-dependent literals
will not be converted. Unfortunately, there is no ilist analogue of '
,
so we save keystrokes by using iq
rather than iquote
and omitting the top-level parentheses.
The templates given below obey the following conventions for procedure formals:
| ilist | A proper (() -terminated) ilist
|
|---|---|
| dilist | A proper or dotted ilist |
| ipair | An immutable pair |
| x, y, d, a | Any value |
| object, value | Any value |
| n, i | A natural number (an integer >= 0) |
| proc | A procedure |
| pred | A procedure whose return value is treated as a boolean |
| = | A boolean procedure taking two arguments |
To interpret the examples, pretend that they are executed on a Scheme that prints immutable pairs and lists with the syntax of mutable ones.
It is an error to pass a dotted ilist to a procedure not defined to accept such an argument.
Added after finalization: Implementers should extend the Scheme
predicate equal?
to descend into immutable pairs in the same
way that it descends into mutable pairs.
ipair
a d -> ipair
eqv?
)
from every existing object.
(ipair 'a '()) => (a) (ipair (iq a) (iq b c d)) => ((a) b c d) (ipair "a" (iq b c)) => ("a" b c) (ipair 'a 3) => (a . 3) (ipair (iq a b) 'c) => ((a b ) . c)
ilist
object ... -> ilist
(ilist 'a (+ 3 4) 'c) => (a 7 c) (ilist) => ()
xipair
d a -> ipair
(lambda (d a) (ipair a d))Of utility only as a value to be conveniently passed to higher-order procedures.
(xipair (iq b c) 'a) => (a b c)The name stands for "eXchanged Immutable PAIR."
ipair*
elt1 elt2 ... -> object
ilist
,
but the last argument provides the tail of the constructed ilist,
returning
(ipair elt1 (ipair elt2 (ipair ... eltn)))
(ipair* 1 2 3 4) => (1 2 3 . 4) (ipair* 1) => 1
make-ilist
n [fill] -> ilist
(make-ilist 4 'c) => (c c c c)
ilist-tabulate
n init-proc -> ilist
(init-proc i)
. No guarantee is made about the dynamic
order in which init-proc is applied to these indices.
(ilist-tabulate 4 values) => (0 1 2 3)
ilist-copy
dilist -> dilist
iiota
count [start step] -> ilist
(start start+step ... start+(count-1)*step)The start and step parameters default to 0 and 1, respectively. This procedure takes its name from the APL primitive.
(iiota 5) => (0 1 2 3 4) (iiota 5 0 -0.1) => (0 -0.1 -0.2 -0.3 -0.4)
proper-ilist?
x -> boolean
ilist?
x -> boolean
()
-terminated ilist.
More carefully: The empty list is a proper ilist. An ipair whose icdr is a proper ilist is also a proper ilist. Everything else is a dotted ilist. This includes non-ipair, non-() values (e.g. symbols, numbers, mutable pairs), which are considered to be dotted ilists of length 0.
dotted-ilist?
x -> boolean
(dotted-ilist? x) = (not (proper-ilist? x))
ipair?
object -> boolean
(ipair? (ipair 'a 'b)) => #t (ipair? (iq a b c)) => #t (ipair? (cons 1 2)) => #f (ipair? '()) => #f (ipair? '#(a b)) => #f (ipair? 7) => #f (ipair? 'a) => #f
null-ilist?
ilist -> boolean
not-ipair?
x -> boolean
(lambda (x) (not (ipair? x)))Provided as a procedure as it can be useful as the termination condition for ilist-processing procedures that wish to handle all ilists, both proper and dotted.
ilist=
elt= ilist1 ... -> boolean
(elt= a b)
for a an element of ilist A,
and b an element of ilist B.
In the n-ary case,
every ilisti is compared to
ilisti+1
(as opposed, for example, to comparing
ilist1 to ilisti,
for i>1).
If there are no ilist arguments at all,
ilist=
simply returns true.
It is an error to apply ilist=
to anything except proper ilists.
It
cannot reasonably be extended to dotted ilists, as it provides no way to
specify an equality procedure for comparing the ilist terminators.
Note that the dynamic order in which the elt= procedure is
applied to pairs of elements is not specified.
For example, if ilist=
is applied
to three ilists, A, B, and C,
it may first completely compare A to B,
then compare B to C,
or it may compare the first elements of A and B,
then the first elements of B and C,
then the second elements of A and B, and so forth.
The equality procedure must be consistent with eq?
.
That is, it must be the case that
(eq? x y)
=> (elt= x y)
.
eq?
are always ilist=
, as well; implementations may exploit this
fact to "short-cut" the element-by-element comparisons.
(ilist= eq?) => #t ; Trivial cases (ilist= eq? (iq a)) => #t
icar
ipair -> value
icdr
ipair -> value
(icar (iq a b c)) => a (icdr (iq a b c)) => (b c) (icar (iq (a) b c d)) => (a) (icdr (iq (a) b c d)) => (b c d) (icar (ipair 1 2)) => 1 (icdr (ipair 1 2)) => 2 (icar '()) => *error* (icdr '()) => *error*
icaar
ipair -> value
icadr
ipair -> value
:
icdddar
ipair -> value
icddddr
ipair -> value
icar
and icdr
,
where for example icaddr
could be defined by
(define icaddr (lambda (x) (icar (icdr (icdr x))))).Arbitrary compositions, up to four deep, are provided. There are twenty-eight of these procedures in all.
ilist-ref
ilist i -> value
(idrop ilist i)
.)
It is an error if i >= n,
where n is the length of ilist.
(ilist-ref (iq a b c d) 2) => c
ifirst
ipair -> object
isecond
ipair -> object
ithird
ipair -> object
ifourth
ipair -> object
ififth
ipair -> object
isixth
ipair -> object
iseventh
ipair -> object
ieighth
ipair -> object
ininth
ipair -> object
itenth
ipair -> object
car
, cadr
, caddr
, ...
(ithird '(a b c d e)) => c
icar+icdr
ipair -> [x y]
(lambda (p) (values (icar p) (icdr p)))This can, of course, be implemented more efficiently by a compiler.
itake
x i -> ilist
idrop
x i -> object
ilist-tail
x i -> object
itake
returns the first i elements of ilist x.idrop
returns all but the first i elements of ilist x.ilist-tail
is either the same procedure as idrop
or else a procedure with the same behavior.
(itake (iq a b c d e) 2) => (a b) (idrop (iq a b c d e) 2) => (c d e)x may be any value — a proper or dotted ilist:
(itake (ipair 1 (ipair 2 (ipair 3 'd))) => (1 2) (idrop (ipair 1 (ipair 2 (ipair 3 'd))) 2) => (3 . d) (itake (ipair 1 (ipair 2 (ipair 3 'd))) 3) => (1 2 3) (idrop (ipair 1 (ipair 2 (ipair 3 'd))) 3) => dFor a legal i,
itake
and idrop
partition the ilist in a manner which
can be inverted with iappend
:
(iappend (itake x i) (idrop x i)) = x
idrop
is exactly equivalent to performing i icdr operations on x;
the returned value shares a common tail with x.
itake-right
dilist i -> object
idrop-right
dilist i -> ilist
itake-right
returns the last i elements of dilist.idrop-right
returns all but the last i elements of dilist.
(itake-right (iq a b c d e) 2) => (d e) (idrop-right (iq a b c d e) 2) => (a b c)The returned ilist may share a common tail with the argument ilist.
dilist may be any ilist, either proper or dotted:
(itake-right (iq ipair 1 (ipair 2 (ipair 3 'd))) 2) => (2 3 . d) (idrop-right (ipair 1 (ipair 2 (ipair 3 'd))) 2) => (1) (itake-right (ipair 1 (ipair 2 (ipair 3 'd))) 0) => d (idrop-right (ipair 1 (ipair 2 (ipair 3 'd))) 0) => (1 2 3)For a legal i,
itake-right
and idrop-right
partition the ilist in a manner
which can be inverted with iappend
:
(iappend (itake dilist i) (idrop dilist i)) = dilist
itake-right
's return value is guaranteed to share a common tail with dilist.
isplit-at
x i -> [ilist object]
isplit-at
splits the ilist x
at index i, returning an ilist of the
first i elements, and the remaining tail. It is equivalent
to
(values (itake x i) (idrop x i))
ilast
ipair -> object
last-ipair
ipair -> ipair
last-ipair
returns the last ipair in the non-empty
ilist pair.
(ilast (iq a b c)) => c (last-ipair (iq a b c)) => (c)
ilength
ilist -> integer
ilength
which is not a proper
ilist (()
-terminated).
The length of a proper ilist is a non-negative integer n such that icdr
applied n times to the ilist produces the empty list.
iappend
ilist1 ... -> ilist
(iappend (iq x) (iq y)) => (x y) (iappend (iq a) (iq b c d)) => (a b c d) (iappend (iq a (b)) (iq (c))) => (a (b) (c))The resulting ilist is always newly allocated, except that it shares structure with the final ilisti argument. This last argument may be any value at all; an improper ilist results if it is not a proper ilist. All other arguments must be proper ilists.
(iappend (iq a b) (ipair 'c 'd)) => (a b c . d) (iappend '() 'a) => a (iappend (iq x y)) => (x y) (iappend) => ()
iconcatenate
ilist-of-ilists -> value
iconcatenate
returns
(iapply iappend ilist-of-ilists)or, equivalently,
(ireduce-right iappend '() ilist-of-ilists)
Note that some Scheme implementations do not support passing more than a
certain number (e.g., 64) of arguments to an n-ary procedure.
In these implementations, the (iapply iappend ...)
idiom
would fail when applied to long lists,
but iconcatenate
would continue to function properly.
As with iappend
,
the last element of the input list may be any value at all.
ireverse
ilist -> ilist
(ireverse (iq a b c)) => (c b a) (ireverse (iq a (b c) d (e (f)))) => ((e (f)) d (b c) a)
iappend-reverse
rev-head tail -> ilist
iappend-reverse
returns
(iappend (ireverse rev-head) tail)
.
It is provided because it is a common operation — a common
list-processing style calls for this exact operation to transfer values
accumulated in reverse order onto the front of another ilist, and because
the implementation is significantly more efficient than the simple
composition it replaces. (But note that this pattern of iterative
computation followed by a reverse can frequently be rewritten as a
recursion, dispensing with the reverse
and iappend-reverse
steps, and
shifting temporary, intermediate storage from the heap to the stack,
which is typically a win for reasons of cache locality and eager storage
reclamation.)
izip
ilist1 ilist2 ... -> ilist
(lambda ilists (iapply imap ilist ilists))If
izip
is passed n ilists, it returns an ilist as long as the shortest
of these ilists, each element of which is an n-element ilist comprised
of the corresponding elements from the parameter ilists.
(izip (iq one two three) (iq 1 2 3) (iq odd even odd even odd even odd even)) => ((one 1 odd) (two 2 even) (three 3 odd)) (izip (iq 1 2 3)) => ((1) (2) (3))
iunzip1
ilist -> ilist
iunzip2
ilist -> [ilist ilist]
iunzip3
ilist -> [ilist ilist ilist]
iunzip4
ilist -> [ilist ilist ilist ilist]
iunzip5
ilist -> [ilist ilist ilist ilist ilist]
iunzip1
takes an ilist of ilists,
where every ilist must contain at least one element,
and returns an ilist containing the initial element of each such ilist.
That is, it returns (imap icar ilists)
.
iunzip2
takes an ilist of ilists, where every ilist must contain at least
two elements, and returns two values: an ilist of the first elements,
and an ilist of the second elements. iunzip3
does the same for the first
three elements of the ilists, and so forth.
(iunzip2 (iq (1 one) (2 two) (3 three))) => (1 2 3) (one two three)
icount
pred ilist1 ilist2 ... -> integer
count
is "iterative" in that it is guaranteed
to apply pred to the ilist elements in a
left-to-right order.
The counting stops when the shortest ilist expires.
(count even? (iq 3 1 4 1 5 9 2 5 6)) => 3 (count < (iq 1 2 4 8) (iq 2 4 6 8 10 12 14 16)) => 3
ifold
kons knil ilist1 ilist2 ... -> value
First, consider the single ilist-parameter case. If ilist1 = (e1 e2 ... en), then this procedure returns
(kons en ... (kons e2 (kons e1 knil)) ... )
(ifold kons knil lis) = (ifold kons (kons (icar lis) knil) (icdr lis)) (ifold kons knil '()) = knilExamples:
(ifold + 0 lis) ; Add up the elements of LIS. (ifold ipair '() lis) ; Reverse LIS. (ifold ipair tail rev-head) ; See APPEND-REVERSE. ;; How many symbols in LIS? (ifold (lambda (x count) (if (symbol? x) (+ count 1) count)) 0 lis) ;; Length of the longest string in LIS: (ifold (lambda (s max-len) (max max-len (string-length s))) 0 lis)If n ilist arguments are provided, then the kons function must take n+1 parameters: one element from each ilist, and the "seed" or fold state, which is initially knil. The fold operation terminates when the shortest ilist runs out of values:
(ifold ipair* '() (iq a b c) (iq 1 2 3 4 5)) => (c 3 b 2 a 1)
ifold-right
kons knil ilist1 ilist2 ... -> value
First, consider the single ilist-parameter case. If ilist1 = (e1 e2 ... en)
,
then this procedure returns
(kons e1 (kons e2 ... (kons en knil)))
(ifold-right kons knil lis) = (kons (icar lis) (ifold-right kons knil (icdr lis))) (ifold-right kons knil '()) = knilExamples:
(ifold-right ipair '() lis) ; Copy LIS. ;; Filter the even numbers out of LIS. (ifold-right (lambda (x l) (if (even? x) (ipair x l) l)) '() lis))If n ilist arguments are provided, then the kons procedure must take n+1 parameters: one element from each ilist, and the "seed" or fold state, which is initially knil. The fold operation terminates when the shortest ilist runs out of values:
(ifold-right ipair* '() (iq a b c) (iq 1 2 3 4 5)) => (a 1 b 2 c 3)
ipair-fold
kons knil ilist1 ilist2 ... -> value
fold
, but kons is applied to successive sub-ilists of the
ilists, rather than successive elements — that is, kons is applied to the
ipairs making up the lists, giving this (tail) recursion:
(ipair-fold kons knil lis) = (let ((tail (icdr lis)))
(ipair-fold kons (kons lis knil) tail))
(ipair-fold kons knil '()
) = knil
Example:
(ipair-fold ipair '() (iq a b c)) => ((c) (b c) (a b c))
ipair-fold-right
kons knil ilist1 ilist2 ... -> value
ifold-right
that ipair-fold
holds with ifold
.
Obeys the recursion
(ipair-fold-right kons knil lis) =
(kons lis (ipair-fold-right kons knil (icdr lis)))
(ipair-fold-right kons knil '()
) = knil
Example:
(ipair-fold-right ipair '() (iq a b c)) => ((a b c) (b c) (c))
ireduce
f ridentity ilist -> value
ireduce
is a variant of ifold
.
ridentity should be a "right identity" of the procedure f — that is, for any value x acceptable to f,
(f x ridentity) = x
ireduce
has the following definition:
(ifold f (icar ilist) (icdr ilist))
.
(ifold f ridentity ilist)
.
Note that ridentity is used only in the empty-list case.
You typically use ireduce
when applying f is expensive and you'd
like to avoid the extra application incurred when ifold
applies
f to the head of ilist and the identity value,
redundantly producing the same value passed in to f.
For example, if f involves searching a file directory or
performing a database query, this can be significant.
In general, however, ifold
is useful in many contexts where ireduce
is not
(consider the examples given in the ifold
definition — only one of the
five folds uses a function with a right identity.
The other four may not be performed with ireduce
).
;; take the max of an ilist of non-negative integers. (ireduce max 0 nums) ; i.e., (iapply max 0 nums)
ireduce-right
f ridentity ilist -> value
ireduce-right
is the fold-right variant of ireduce
.

While iunfold
may seem a bit abstract
to novice functional programmers, it can be used in a number of ways:
;; Ilist of squares: 1^2 ... 10^2 (iunfold (lambda (x) (> x 10)) (lambda (x) (* x x)) (lambda (x) (+ x 1)) 1) (iunfold null-ilist? icar icdr lis) ; Copy a proper ilist. ;; Read current input port into an ilist of values. (iunfold eof-object? values (lambda (x) (read)) (read)) ;; Copy a possibly non-proper ilist: (iunfold not-ipair? icar icdr lis values) ;; Append HEAD onto TAIL: (iunfold null-ilist? icar icdr head (lambda (x) tail))Interested functional programmers may enjoy noting that
ifold-right
and iunfold
are in some sense inverses.
That is, given operations knull?, kar,
kdr, kons, and knil satisfying
(kons (kar x) (kdr x))
= x
and
(knull? knil)
= #t
(ifold-right kons knil (iunfold knull? kar kdr x))
= x
(iunfold knull? kar kdr (ifold-right kons knil x))
= x.
iunfold-right
p f g seed [tail] -> ilist
iunfold-right
constructs an ilist with the following loop:
(let lp ((seed seed) (lis tail)) (if (p seed) lis (lp (g seed) (ipair (f seed) lis))))
'()
.
In other words, we use g to generate a sequence of seed values
iunfold-right
is the fundamental iterative ilist constructor,
just as ifold
is the
fundamental iterative ilist consumer.
While iunfold-right
may seem a bit abstract
to novice functional programmers, it can be used in a number of ways:
;; Ilist of squares: 1^2 ... 10^2 (iunfold-right zero? (lambda (x) (* x x)) (lambda (x) (- x 1)) 10) ;; Reverse a proper ilist. (iunfold-right null-ilist? icar icdr lis) ;; Read current input port into an ilist of values. (iunfold-right eof-object? values (lambda (x) (read)) (read)) ;; (iappend-reverse rev-head tail) (iunfold-right null-ilist? icar icdr rev-head tail)Interested functional programmers may enjoy noting that
ifold
and iunfold-right
are in some sense inverses.
That is, given operations knull?, kar,
kdr, kons, and knil satisfying
(kons (kar x) (kdr x))
= x
and
(knull? knil)
= #t
(ifold kons knil (iunfold-right knull? kar kdr x))
= x
(iunfold-right knull? kar kdr (ifold kons knil x))
= x.
imap
proc ilist1 ilist2 ... -> ilist
imap
applies proc element-wise to the elements
of the ilists and returns an ilist of the results,
in order.
The dynamic order in which proc
is applied to the elements of the ilists is unspecified.
(imap icadr (iq (a b) (d e) (g h))) => (b e h) (imap (lambda (n) (expt n n)) (iq 1 2 3 4 5)) => (1 4 27 256 3125) (imap + (iq 1 2 3) (iq 4 5 6)) => (5 7 9) (let ((count 0)) (imap (lambda (ignored) (set! count (+ count 1)) count) (iq a b))) => (1 2) or (2 1)
ifor-each
proc ilist1 ilist2 ... -> unspecified
ifor-each
are like the arguments to
imap
, but
ifor-each
calls proc for its side effects rather
than for its values.
Unlike imap
, ifor-each
is guaranteed to call
proc on the elements of the ilists in order from the first
element(s) to the last,
and the value returned by ifor-each
is unspecified.
(let ((v (make-vector 5))) (ifor-each (lambda (i) (vector-set! v i (* i i))) (iq 0 1 2 3 4)) v) => #(0 1 4 9 16)
iappend-map
f ilist1 ilist2 ... -> value
(iapply iappend (imap f ilist1 ilist2 ...))
(iapply iappend (imap f ilist1 ilist2 ...))
imap
function.
However, the results of the applications are appended together (using iappend
) to
make the final result.
The dynamic order in which the various applications of f are made is not specified.
Example:
(iappend-map (lambda (x) (ilist x (- x))) (iq 1 3 8)) => (1 -1 3 -3 8 -8)
imap-in-order
f ilist1 ilist2 ... -> ilist
imap
procedure that guarantees to apply f across
the elements of the ilisti arguments in a left-to-right order. This
is useful for mapping procedures that both have side effects and
return useful values.
ipair-for-each
f ilist1 ilist2 ... -> unspecific
ifor-each
, but f is applied to successive sub-ilists of the argument
ilists. That is, f is applied to the cells of the ilists, rather
than the ilists' elements. These applications occur in left-to-right
order.
(ipair-for-each (lambda (ipair) (display ipair) (newline)) (iq a b c)) ==> (a b c) (b c) (c)
ifilter-map
f ilist1 ilist2 ... -> ilist
imap
, but only true values are saved.
(ifilter-map (lambda (x) (and (number? x) (* x x))) (iq a 1 b 3 c 7)) => (1 9 49)The dynamic order in which the various applications of f are made is not specified.
ifilter
pred ilist -> ilist
(ifilter even? (iq 0 7 8 8 43 -4)) => (0 8 8 -4)
ipartition
pred ilist -> [ilist ilist]
(ipartition symbol? (iq one 2 3 four five 6)) => (one four five) (2 3 6)
iremove
pred ilist -> ilist
(lambda (pred ilist) (ifilter (lambda (x) (not (pred x))) ilist))The ilist is not disordered — elements that appear in the result ilist occur in the same order as they occur in the argument ilist. The returned ilist may share a common tail with the argument ilist. The dynamic order in which the various applications of pred are made is not specified.
(iremove even? (iq 0 7 8 8 43 -4)) => (7 43)
The following procedures all search ilists for a leftmost element satisfying some criteria. This means they do not always examine the entire ilist; thus, there is no efficient way for them to reliably detect and signal an error when passed a dotted ilist. Here are the general rules describing how these procedures work when applied to different kinds of ilists:
In brief, compliant code may not pass a dotted ilist argument to these procedures.
Here are some examples, using the ifind
and iany
procedures as canonical
representatives:
;; Proper ilist — success (ifind even? (iq 1 2 3)) => 2 (iany even? (iq 1 2 3)) => #t ;; proper ilist — failure (ifind even? (iq 1 7 3)) => #f (iany even? (iq 1 7 3)) => #f ;; Failure is error on a dotted ilist. (ifind even? (ipair 1 (ipair 3 'x))) => error (iany even? (ipair 1 (ipair 3 'x))) => error ;; The dotted ilist contains an element satisfying the search. ;; This case is not specified — it could be success, an error, ;; or some third possibility. (ifind even? (ipair 1 (ipair 2 'x))) => error/undefined (iany even? (ipair 1 (ipair 2 'x))) => error/undefined ; success, error or other.
ifind
pred ilist -> value
(ifind even? (iq 3 1 4 1 5 9)) => 4Note that
ifind
has an ambiguity in its lookup semantics — if ifind
returns #f
, you cannot tell (in general) if it found a #f
element
that satisfied pred, or if it did not find any element at all. In
many situations, this ambiguity cannot arise — either the ilist being
searched is known not to contain any #f
elements, or the ilist is
guaranteed to have an element satisfying pred. However, in cases
where this ambiguity can arise, you should use ifind-tail
instead of
ifind
— ifind-tail
has no such ambiguity:
(cond ((ifind-tail pred lis) => (lambda (ipair) ...)) ; Handle (icar ipair) (else ...)) ; Search failed.
ifind-tail
pred ilist -> ipair or false
ifind-tail
can be viewed as a general-predicate variant of the imember
function.
Examples:
(ifind-tail even? (iq 3 1 37 -8 -5 0 0)) => (-8 -5 0 0) (ifind-tail even? (iq 3 1 37 -5)) => #f ;; IMEMBER X LIS: (ifind-tail (lambda (elt) (equal? x elt)) lis)
Ifind-tail
is essentially idrop-while
,
where the sense of the predicate is inverted:
Ifind-tail
searches until it finds an element satisfying
the predicate; idrop-while
searches until it finds an
element that doesn't satisfy the predicate.
itake-while
pred ilist -> ilist
(itake-while even? (iq 2 18 3 10 22 9)) => (2 18)
idrop-while
pred ilist -> ilist
(idrop-while even? (iq 2 18 3 10 22 9)) => (3 10 22 9)
ispan
pred ilist -> [ilist ilist]
ibreak
pred ilist -> [ilist ilist]
ispan
splits the ilist into the longest initial prefix whose
elements all satisfy pred, and the remaining tail.
ibreak
inverts the sense of the predicate:
the tail commences with the first element of the input ilist
that satisfies the predicate.
In other words:
ispan
finds the initial span of elements
satisfying pred,
and ibreak
breaks the ilist at the first element satisfying
pred.
ispan
is equivalent to
(values (itake-while pred ilist) (idrop-while pred ilist))
(ispan even? (iq 2 18 3 10 22 9)) => (2 18) (3 10 22 9) (ibreak even? (iq 3 1 4 1 5 9)) => (3 1) (4 1 5 9)
iany
pred ilist1 ilist2 ... -> value
If there are n ilist arguments ilist1 ... ilistn, then pred must be a procedure taking n arguments and returning a boolean result.
iany
applies pred to the first elements of the ilisti parameters.
If this application returns a true value, iany
immediately returns
that value. Otherwise, it iterates, applying pred to the second
elements of the ilisti parameters, then the third, and so forth.
The iteration stops when a true value is produced or one of the ilists runs
out of values; in
the latter case, iany
returns #f
.
The application of pred to the last element of the
ilists is a tail call.
Note the difference between ifind
and iany
— ifind
returns the element
that satisfied the predicate; iany
returns the true value that the
predicate produced.
Like ievery
, iany
's name does not end with a question mark — this is to
indicate that it does not return a simple boolean (#t
or #f
), but a
general value.
(iany integer? (iq a 3 b 2.7)) => #t (iany integer? (iq a 3.1 b 2.7)) => #f (iany < (iq 3 1 4 1 5) (iq 2 7 1 8 2)) => #t
ievery
pred ilist1 ilist2 ... -> value
If there are n ilist arguments ilist1 ... ilistn, then pred must be a procedure taking n arguments and returning a boolean result.
ievery
applies pred to the first elements of the ilisti parameters.
If this application returns false, ievery
immediately returns false.
Otherwise, it iterates, applying pred to the second elements of the
ilisti parameters, then the third, and so forth. The iteration stops
when a false value is produced or one of the ilists runs out of values.
In the latter case, ievery
returns
the true value produced by its final application of pred.
The application of pred to the last element of the ilists
is a tail call.
If one of the ilisti has no elements, ievery
simply returns #t
.
Like iany
, ievery
's name does not end with a question mark — this is to
indicate that it does not return a simple boolean (#t
or #f
), but a
general value.
ilist-index
pred ilist1 ilist2 ... -> integer or false
If there are n ilist arguments ilist1 ... ilistn, then pred must be a function taking n arguments and returning a boolean result.
ilist-index
applies pred to the first elements of the ilisti parameters.
If this application returns true, ilist-index
immediately returns zero.
Otherwise, it iterates, applying pred to the second elements of the
ilisti parameters, then the third, and so forth. When it finds a tuple of
ilist elements that cause pred to return true, it stops and returns the
zero-based index of that position in the ilists.
The iteration stops when one of the ilists runs out of values; in this
case, ilist-index
returns #f
.
(ilist-index even? (iq 3 1 4 1 5 9)) => 2 (ilist-index < (iq 3 1 4 1 5 9 2 5 6) (iq 2 7 1 8 2)) => 1 (ilist-index = (iq 3 1 4 1 5 9 2 5 6) (iq 2 7 1 8 2)) => #f
imember
x ilist [=] -> ilist
imemq
x ilist -> ilist
imemv
x ilist -> ilist
(idrop ilist i)
for i less than the length of ilist.
If x does
not occur in ilist, then #f
is returned.
imemq
uses eq?
to compare x
with the elements of ilist,
while imemv
uses eqv?
, and
imember
uses equal?
.
(imemq 'a (iq a b c)) => (a b c) (imemq 'b (iq a b c)) => (b c) (imemq 'a (iq b c d)) => #f (imemq (list 'a) (ilist 'b '(a) 'c)) => #f (imember (list 'a) (ilist 'b '(a) 'c))) => ((a) c) (imemq 101 (iq 100 101 102)) => *unspecified* (imemv 101 (iq 100 101 102)) => (101 102)
The comparison procedure is used to compare the elements ei of ilist to the key x in this way:
(= x ei) ; ilist is (E1 ... En)
(imember 5 ilist <)
Note that fully general ilist searching may be performed with
the ifind-tail
and ifind
procedures, e.g.
(ifind-tail even? ilist) ; Find the first elt with an even key.
idelete
x ilist [=] -> ilist
idelete
uses the comparison procedure =, which defaults to equal?
, to find
all elements of ilist that are equal to x, and deletes them from ilist. The
dynamic order in which the various applications of = are made is not
specified.
The ilist is not disordered — elements that appear in the result ilist occur in the same order as they occur in the argument ilist. The result may share a common tail with the argument ilist.
Note that fully general element deletion can be performed with the iremove
procedures, e.g.:
;; idelete all the even elements from LIS: (iremove even? lis)The comparison procedure is used in this way:
(= x ei)
.
That is, x is always the first argument,
and an ilist element is always the
second argument. The comparison procedure will be used to compare each
element of ilist exactly once; the order in which it is applied to the
various ei is not specified. Thus, one can reliably remove all the
numbers greater than five from an ilist with
(idelete 5 ilist <)
idelete-duplicates
ilist [=] -> ilist
idelete-duplicates
removes duplicate elements from the
ilist argument.
If there are multiple equal elements in the argument ilist, the result ilist
only contains the first or leftmost of these elements in the result.
The order of these surviving elements is the same as in the original
ilist — idelete-duplicates
does not disorder the ilist (hence it is useful
for "cleaning up" immutable association lists).
The = parameter is used to compare the elements of the ilist; it defaults
to equal?
. If x comes before y in ilist, then the comparison is performed
(= x y)
.
The comparison procedure will be used to compare each pair of elements in
ilist no more than once;
the order in which it is applied to the various pairs is not specified.
Implementations of idelete-duplicates
are allowed to share common tails
between argument and result ilists — for example, if the ilist argument
contains only unique elements, it may simply return exactly
this ilist.
Be aware that, in general, idelete-duplicates
runs in time O(n2) for n-element ilists.
Uniquifying long ilists can be accomplished in O(n lg n) time by sorting
the ilist to bring equal elements together, then using a linear-time
algorithm to remove equal elements. Alternatively, one can use algorithms
based on element-marking, with linear-time results.
(idelete-duplicates (iq a b a c a b c z)) => (a b c z) ;; Clean up an ialist: (idelete-duplicates (iq (a . 3) (b . 7) (a . 9) (c . 1)) (lambda (x y) (eq? (icar x) (icar y)))) => ((a . 3) (b . 7) (c . 1))
An "immutable association list" (or "ialist") is an ilist of ipairs. The icar of each ipair contains a key value, and the icdr contains the associated data value. They can be used to construct simple look-up tables in Scheme. Note that ialists are probably inappropriate for performance-critical use on large data; in these cases, immutable maps or some other alternative should be employed.
iassoc
key ialist [=] -> ipair or #f
iassq
key ialist -> ipair or #f
iassv
key ialist -> ipair or #f
#f
is returned.
iassq
uses eq?
to compare key
with the icar fields of the ipairs in ialist,
while iassv
uses eqv?
and iassoc
uses equal?
.
(define e (iq (a 1) (b 2) (c 3))) (iassq 'a e) => (a 1) (iassq 'b e) => (b 2) (iassq 'd e) => #f (iassq (ilist 'a) (iq ((a)) ((b)) ((c)))) => #f (iassoc '(a) (ilist '((a)) '((b)) '((c)))) => ((a)) (iassq 5 (iq (2 3) (5 7) (11 13))) => *unspecified* (iassv 5 (iq (2 3) (5 7) (11 13))) => (5 7)
The comparison procedure is used to compare the elements ei of ilist to the key parameter in this way:
(= key (icar ei)) ; ilist is (E1 ... En)
(iassoc 5 ialist <)
Note that fully general ialist searching may be performed with
the ifind-tail
and ifind
procedures, e.g.
;; Look up the first association in ialist with an even key: (ifind (lambda (a) (even? (icar a))) ialist)
ialist-cons
key datum ialist -> ialist
(lambda (key datum ialist) (ipair (ipair key datum) ialist))Construct a new ialist entry mapping key -> datum onto ialist.
ialist-delete
key ialist [=] -> ialist
ialist-delete
deletes all associations from ialist with the given key,
using key-comparison procedure =, which defaults to equal?
.
The dynamic order in which the various applications of = are made is not
specified.
Return values may share common tails with the ialist argument. The ialist is not disordered — elements that appear in the result ialist occur in the same order as they occur in the argument ialist.
The comparison procedure is used to compare the element keys ki of ialist's
entries to the key parameter in this way:
(= key ki)
.
Thus, one can reliably remove all entries of ialist whose key is greater
than five with
(ialist-delete 5 ialist <)
These two procedures are analogues of the primitive
side-effect operations on pairs, set-car!
and set-cdr!
.
replace-icar
ipair object -> ipair
replace-icdr
ipair object -> ipair
These procedures convert between mutable and immutable pair structures.
pair->ipair
pair -> ipair
ipair->pair
ipair -> pair
list->ilist
flist -> dilist
ilist->list
dilist -> flist
These procedures return an ilist and a list respectively that have the same elements as the argument. The tails of dotted (i)lists are preserved in the result, which makes the procedures not inverses when the tail of a dotted ilist is a list or vice versa. The empty list is converted to itself.
It is an error to apply list->ilist
to a circular list.
tree->itree
object -> object
itree->tree
object -> object
These procedures walk a tree of pairs or ipairs respectively and make a deep copy of it, returning an isomorphic tree containing ipairs or pairs respectively. The result may share structure with the argument. If the argument is not of the expected type, it is returned.
These procedures are not inverses in the general case. For example,
a pair of ipairs would be converted by tree->itree
to
an ipair of ipairs, which if converted by itree->tree
would produce a pair of pairs.
gtree->itree
object -> object
gtree->tree
object -> object
This procedure allows a procedure to be applied to an ilist.
iapply
procedure object ... ilist -> object
iapply
procedure is an analogue of apply
whose last
argument is an ilist rather than a list. It is equivalent to
(apply
procedure object ... (ilist->list
ilist))
,
but may be implemented more efficiently.
ipair-comparator
ipair-comparator
object is a SRFI-114 comparator suitable for comparing ipairs.
Note that it is not a procedure.
It compares pairs using default-comparator
on their cars. If the cars are not equal, that value is returned. If they are equal, default-comparator
is used on their cdrs and that value is returned.
ilist-comparator
ilist-comparator
object is a SRFI-114 comparator suitable for comparing ilists.
Note that it is not a procedure.
It compares ilists lexicographically, as follows:
default-comparator
, then the result is the result of that comparison. Otherwise, the icdrs are compared using ilist-comparator
.make-ilist-comparator
comparator -> comparator
make-ilist-comparator
procedure returns a comparator suitable for comparing ilists
using element-comparator to compare the elements.
make-improper-ilist-comparator
comparator -> comparator
make-improper-ilist-comparator
procedure returns a comparator that compares arbitrary objects as follows: the empty list precedes all ipairs, which precede all other objects. Ipairs are compared as if with (make-ipair-comparator
comparator
comparator)
. All other objects are compared using comparator.
make-ipair-comparator
icar-comparator icdr-comparator -> comparator
make-icar-comparator
comparator -> comparator
make-icar-comparator
procedure returns a comparator that compares ipairs on their icars alone using comparator.
make-icdr-comparator
comparator -> comparator
make-icdr-comparator
procedure returns a comparator that compares ipairs on their icdrs alone using comparator.
The sample implementation of this SRFI is derived from the sample implementation of SRFI 1. It depends on SRFI 9 (or R7RS) records. The five files in the implementation are as follows:
ilists-impl.scm
is a modified version of the SRFI 1 implementation.ilists-base.scm
provides the definition of ipair records as well as additional procedures that are required by this SRFI.ilists.sld
is an R7RS library.ilists.scm
is a Chicken library.ilists-test.scm
is a set of tests using the Chicken test
egg, which is also available in Chibi as the R7RS library (chibi test)
.Without the work of Olin Shivers on SRFI 1, this SRFI would not exist. Everyone acknowledged there is transitively acknowledged here. This is not to imply that either Olin or anyone else necessarily endorses the final results, of course.
Copyright (C) John Cowan 2014. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


{% extends 'Home/index.html' %} {% block content %}
Teacher Name:
{{ feedback.teacher_name }}
Dated on:
{{ feedback.date_submitted|date:'d F, Y H:i e' }}
The teacher is punctual in coming to class:
{{ feedback.punctuality }}
The teacher completes portions at the appropriate time:
{{ feedback.portion }}
The teacher takes in effort to clear your doubts:
{{ feedback.doubt }}
The teacher makes the class interactive:
{{ feedback.interactive }}
Other Comments:
{{ feedback.comments }}


class EditProfileViewModel : ViewModel
Edit profile view model
EditProfileViewModel()
Edit profile view model |
val changed: MutableLiveData<Boolean> |
|
val currentBio: MutableLiveData<String> |
|
val currentName: MutableLiveData<String> |
|
val currentUsername: MutableLiveData<String> |
|
var originalBio: String |
|
var originalName: String |
|
val savingProgress: MutableLiveData<Resource<Boolean>> |
fun checkChanged(): Unit |
|
fun getBio(): String
Get the bio of the user |
|
fun getName(): String
Get the name of the user |
|
fun save(): Unit
Save the new user Profile |
|
fun setBio(bio: String): Unit
Set the new bio |
|
fun setName(name: String): Unit
Set the new name |
|
fun setOriginalBio(bio: String): Unit
Sets the original bio value before editing |
|
fun setOriginalName(name: String): Unit
Sets the original name value before editing |
|
fun setUsername(username: String): Unit
Set the new username |


Celebrities & Public Already Wearing G-Dragon's Nike Shoes & It Becomes a New Trend Before Official Release
by k81Sportswear brand Nike will soon release a new edition of the iconic Air Force 1 sneaker in collaboration with G-Dragon. Named AF1 (Air Force 1) Para-Nose, the sneakers mark the first project for the leader of BIGBANG since being discharged from the military last month.
The collaboration bringing the pop/hip-hop icon’s energy, style, and artful eye to the Air Force 1. With an enlarged daisy on the tongue, paint streaks on the midsole, a full black upper that wears away over time, and thick laces arranged in reverse fashion, the Air Force 1 “Para-noise” is being touted as one of the year’s best collaborative releases. And it's already a trend, as the thick laces arranged in reverse already being used by public and idols, showing the great influence the icon have. And celebraties like EXO's Suho, Park Shin Hye, Grey and many more already have it and already wearing it like G-Dragon do!
Not only fans and public are interested in the shoes, but as well foreigners and fans of shoes already showed huge interest in getting it.
On October 26, 'Nike' x 'PEACEMINUSONE's limited edition 'AF1 Para-Noise' sneakers are only sold exclusively in Korea, with the first edition 'red version' already sold out in less than 10 minutes and cause the site to shut down because of the amount of people trying to get in buying the limited version. The following day people waited in a long line that covered 3 blocks from the morning till night just to get a chance to buy tickets for the private event that will be held by G-Dragon, and only lucky 800 fans will get a chance.


--- layout: post title: Telephones and Finland date: 2005-01-15 00:00:00 category: mobile ---
The Finnish infatuation with the telephone: "Firstly, the Finnish infatuation with the telephone is no new phenomenon, no mere byproduct of Nokia's dramatic rise to prominence. Finns have been crazy about phones from practically the first moment they could get their hands on them."


Contents:
Implements the processparser CherryPy instance.
Requires Python 2.7.x (no current support for Python 3.x)
Required Python modules:
Required files:
Optional files:
External dependencies:
CherryPy server information:
Generates the HTML opening tags on each page
| Parameters: | title – The contents of the html <title> tag (default “ProcessParser”) |
|---|
Generates the Google Chart Tools pie chart Javascript code on process information pages where at least one supplier supports that process
| Parameters: | workingdict – An OrderedDict with at least one entry, where the key is a pie chart heading and the value is the numeric value |
|---|
Generates the HTML closing tags on each page (including total number of entries across all suppliers and stale data notification if necessary)
| Parameters: | showBack – If showBack is False, the “[back]” link will not appear at the bottom of the page |
|---|
Reinitializes the memcached entries when they have expired (using the api.resourcecenter.org/nvman/processes JSON or, if not able to contact the server, the processFile JSON)
If using the processFile JSON, also adds a memcached entry reflecting the fact that the displayed process information uses stale data
CherryPy class for the app index page
Generates the index page with a list of links to all processes found in the processFile JSON
Corresponds to URI /app
CherryPy class for individual process information pages
If URI is formed incorrectly, displays “Unknown” and exits
Corresponds to URI /app/viewer
If a process is specified using the below URI format, generates the process information page
Queries memcached for process information. If memcached entries have expired (detected by requesting information on manufacturingProcesses), calls restoreMem() to regenerate them, then continues generating the page
If requested process does not exist, or no processKey was passed in the URI, displays “Invalid key.” and exits
Page generated includes information on:
Corresponds to URI /app/viewer/view/processKey
| Parameters: | object – CherryPy generated object containing processKey |
|---|


{% extends 'base.html' %} {% block title %}GDScript Server{% endblock %} {% block body %}
Rules: Time Limit is {{ timeout }}s; File calls and some OS calls aren't allowed.
Script:
{{ 'Output:' if gans else ''}}
{{ gans }}


Having trouble seeing this email? View in your browser
Join us for a FREE webinar on Wednesday, May 3 at 12 PM with St. Tammany Parish Supervisor of Secondary Instruction, Melissa Strata-Burger, and Livingston Parish Supervisor of Secondary Education, Jody Purvis.
These district administrators will be discussing how they used their SCA funds to prepare their students for the ACT and WorkKeys assessments.
You will be able to listen live, ask questions, and gain some insight into helpful ways you can use your SCA funds to benefit your students!
Phone:<PHONE_NUMBER>
Email: sca@masteryprep.com


The following classes extend the base BaseReader functionality to handle reading and writing different table formats. Some, such as the Basic Reader class are fairly general and include a number of configurable attributes. Others such as Cds or Daophot are specialized to read certain well-defined but idiosyncratic formats.


So I'm actually in a bit of a strange situation right now. And I think everyone who takes the stage here, or at any conference, is in the same sort of bind.
The inimitable JBD has given us the professional tip that we should never blindly apply dogmatic advice, and that we should use our judgment each and every time. Presumably also with that selfsame tip. But I have applied my judgment to this statement, and I judge it to be true.
Some guy on the internet has additionally observed that the longer it is you're in the tech industry the more your opinions end up being well it depends and I'm not sure and that these don't quite make for good talks. That also feels true to me—at least, if you're doing things right. It's my experience that if you find that you're getting more strongly opinionated as you advance in your career, chances are you're caught in a rut and becoming an expert beginner. Not great!
Taken together, these two truths about advice-giving seem to push us into a paralysis. The more experienced I become, the less sure I am about anything, and the less likely I am to deliver actionable advice to you, the audience. And the better you are at receiving advice, the less likely you are to believe what I say. So what am I even doing up here? Should we all go home?
—
To break out of this paralysis I think we can employ a couple of strategies. First, we can ensure that when we give advice, we place it into the specific context where it makes sense. If we can define an explicit scope of applicability, we can carve out a little space for ourselves to have a well-defined opinion.
That's what I've tried to do with the title of the talk. I'm speaking today about programming in an industrial context. By that I mean
This describes my work environments for most recent memory. I suspect it does for a lot of you, too. And the best advice for Go in this context is sometimes different than for Go in personal projects, or large open-source libraries, and so on.
And to speak to JBD's point, I should be careful to always justify the advice I give, so that you can follow the chain of reasoning yourself, and draw your own conclusions. I've tried my best to do that in this talk.
So with those guidelines in mind, let's review the set of topics I'd like to try to cover. I've tried to select for areas that have routinely tripped up new and intermediate Gophers in organizations I've been a part of, and particularly those things that may have nonobvious or subtle implications.
One thing I see frequently among my colleagues, especially those very new to Go, is an expectation of a rigid project structure, often decided a priori at the start of the project. I think this is generally more problematic than helpful. To understand why, remember the fourth, and maybe most important, property of industrial programming:
Industrial programming ... serves highly mutable business requirements
Industrial programming serves highly mutable business requirements:
The only constant is change, and the only rule of business requirements is that they never converge, they only diverge, grow, and mutate. So we should make sure our code accommodates this fact of life, and not box ourselves in unnecessarily. Our repos, our abstractions, our code itself should be easy to maintain by being easy to change, easy to adapt, and, ultimately, easy to delete.
There are a few things that are generally good ideas. If your project has multiple binaries, it's a good idea to have a cmd/ subdirectory to hold them. If your project is large and has significant non-Go code, like UI assets or sophisticated build tooling, it might be a good idea to keep your Go code isolated in a pkg/ subdirectory. If you're going to have multiple packages, it's probably a good idea to orient them around the business domain, rather than around accidents of implementation. That is: package user, yes; package models, no. There are a couple of good articles for package design: Ben Johnson's Standard Package Layout and Brian Ketelsen's GopherCon Russia talk this year had some good advice.
Of course, business domain and implementation are not always strictly separated. For example, large web applications tend to intermingle transport and core business concerns. Frameworks like GoBuffalo encourage package names like actions, assets, models, and templates. When you know you're dealing with HTTP exclusively, there are advantages to going all-in on the coupling.
Tim Hockin also suggests we align packages on dependency boundaries. That is, have separate packages for e.g. RedisStore, MySQLStore, etc. to avoid external consumers having to include and compile support for things they don't need. In my opinion, this is an inappropriate optimization for packages with a closed set of importers, but makes a lot of sense for packages widely imported by third parties, like Kubernetes, where the size of the compilation unit can become a real bottleneck.
So there's a spectrum of applicability. I think the best general advice is to only opt-in to a bit of structure once you feel the need, concretely. Most of my projects still start out as a few files in package main, bundled together at the root of the repo. And they stay that way until they become at least a couple thousand lines of code. Many, even most, of my projects never make it that far. One nice thing about Go is that it can feel very lightweight; I like to preserve that as long as possible.
I feel like I say this in almost every talk I give or article I write, but I wouldn't want to break the streak now, so let me repeat myself: Flags are the best way to configure your program, because they're a self-documenting way to describe the configuration surface area of your program at runtime.
They self-document the configuration surface area at runtime
This is particularly important in industrial contexts, where whoever is operating a service may not be its original author. If running your program with the -h flag provides a complete list of the knobs and switches that controls its behavior, then it's very easy for an on-call engineer to adjust something during an incident, or for a new engineer to get it running in their dev environment. Much easier than having to hunt down a set of relevant environment variables in (probably outdated) documentation, or figure out the syntax and valid key names of a config file format.
This doesn't mean never use env vars or config files. There are good reasons to use either or both in addition to flags. Env vars can be useful for connection strings and non-secret auth tokens, especially during dev. And config files are great for declaring verbose configs, as well as being the only secure way to get secrets into a program. (Both env vars and flags can be inspected by other users of the system at runtime.) Just ensure that explicit commandline flags, if given, take highest priority.
Avoid using them as the only way to configure your program
—
I've speculated in the past about a theoretical configuration package which mandated the use of flags for config, but also allowed env vars and config files in various formats, on an opt-in basis. I have strong opinions about what that package should look like, but haven't yet spent the time to implement it. Maybe I can put this out there as a package request?
var fs myflag.FlagSet var ( foo = fs.String("foo", "x", "foo val") bar = fs.String("bar", "y", "bar val", myflag.JSON("bar")) baz = fs.String("baz", "z", "baz val", myflag.JSON("baz"), myflag.Env("BAZ")) cfg = fs.String("cfg", "", "JSON config file") ) fs.Parse(os.Args, myflag.JSONVia("cfg"), myflag.EnvPrefix("MYAPP_"))
Industrial programming means writing code once and maintaining it into perpetuity. Maintenance is the continuous practice of reading and refactoring. Therefore, industrial programming overwhelmingly favors reads, and on the spectrum of easy to read vs. easy to write, we should bias strongly towards the former.
Avoid dependency injection frameworks or containers
Dependency injection is a powerful tool to optimize for read comprehension. And here I definitely don't mean the dependency container approach used by facebook-go/inject or uber/dig, but rather the much simpler practice of enumerating dependencies as parameters to types or constructors.
Here's an example of container-based dependency injection that recently made the rounds:
func BuildContainer() *dig.Container { container := dig.New() container.Provide(NewConfig) container.Provide(ConnectDatabase) container.Provide(NewPersonRepository) container.Provide(NewPersonService) container.Provide(NewServer) return container } func main() { container := BuildContainer() if err := container.Invoke(func(server *Server) { server.Run() }); err != nil { panic(err) } }
The func main is compact, and BuildContainer has the appearance of being pithy and to-the-point. But the Provide method requires reflection to interpret its arguments, and Invoke gives us no clues as to what a Server actually needs to do its job. A new employee would have to jump between multiple contexts to build a mental model of each of the dependencies, how they interact, and how they're consumed by the server. This represents a bad tradeoff of read- vs. write-comprehension.
Compare against a slightly adapted version of the code that this example is meant to improve:
func main() { cfg := GetConfig() db, err := ConnectDatabase(cfg.URN) if err != nil { panic(err) } repo := NewPersonRepository(db) service := NewPersonService(cfg.AccessToken, repo) server := NewServer(cfg.ListenAddr, service) server.Run() }
The func main is longer, but in exchange for that length we get unambiguous explictness. Each component is constructed in dependency-order, with errors handled inline. Each constructor enumerates its dependencies as parameters, allowing new code readers to quickly and easily build a mental model of the relationship graph between components. Nothing is obscured behind layers of indirection.
If a refactor requires a component to acquire a new dependency, it simply needs to be added to the constructor. The next compile will trigger errors that precisely identify the parameter lists need to be updated, and the diff in the resulting PR will clearly show the flow of the dependency through the graph.
I claim this strictly superior to the previous method, where relationships are much harder to extract from the code as written, and much of the failure detection is deferred until runtime. And I claim it's increasingly superior as the size of the program (and the size of the func main) grows, and the benefits of plain and explicit initialization compound.
—
When we talk about read comprehension, I like to reflect on what I think is the single most important property of Go, which is that it is essentially non-magical. With very few exceptions, a straight-line reading of Go code leaves no ambiguity about definitions, dependency relationships, or runtime behavior. This is great.
But there are a few ways that magic can creep in. One unfortunately very common way is through the use of global state. Package-global objects can encode state and/or behavior that is hidden from external callers. Code that calls on those globals can have surprising side effects, which subverts the reader’s ability to understand and mentally model the program.
Accordingly, and in deference to read-optimization and maintenence costs, I think the ideal Go program has little to no package global state, preferring instead to enumerate dependencies explicitly, through constructors. And since the only job of func init is to initialize package global state, I think it's best understood as a serious red flag in almost any program. I've programmed this way for many years, and I've only grown to appreciate and advocate for the practice more strongly in that time.
The single biggest cause of frustration
Incorrect or overly-complex designs for starting, stopping, and inspecting goroutines is the single biggest cause of frustration faced by new and intermediate Go programmers, in my experience.
I think the problem is that goroutines are, ultimately, a very low-level building block, with few affordances for the sort of higher-order tasks that most people want to accomplish with concurrency. We say things like "never start a goroutine without knowing how it will stop," but this advice is somewhat empty without a concrete methodology. And I think many tutorials and lots of example code, even in otherwise good references like The Go Programming Language book, do us a disservice by demonstrating concurrency concepts with fire-and-forget goroutines, global state, and patterns that would fail even basic code review.
Most goroutines I see launched by my colleagues are not incidental steps of a well-defined concurrent algorithm. They tend to be structural, managing long-running things with indistinct termination semantics, often started at the beginning of a program. I think these use cases need to be served with stronger conventions.
I think this is because goroutines are often too low-level.
Imagine for a moment that the orthotics of the go keyword were slightly different. What if we couldn't launch a goroutine without also necessarily providing a function to interrupt or stop it? In effect, enforcing the convention that goroutines shouldn't be started unless we know how they'll be stopped.
This is what I've stumbled over with package run, extracted from a larger project I was working on last year. Here's the most important method, Add:
func (g *Group) Add(execute func() error, interrupt func(error))
Add queues a goroutine to be run, but also tracks a function that will interrupt the goroutine when it needs to be killed. That enables well-defined termination semantics for the group of goroutines as a whole. For example, I use it most often when I have multiple server components that should run forever, and then Add a goroutine to trap ctrl-C and tear everything down.
ctx, cancel := context.WithCancel(context.Background()) g.Add(func() error { c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) select { case sig := <-c: return fmt.Errorf("received signal %s", sig) case <-ctx.Done(): return ctx.Err() } }, func(error) { cancel() })
If you're familiar with package errgroup, this is similar at a high level, but the devil's in the details: errgroup implicitly assumes all execute funcs will respond to the parent context provided to the group, and has no affordance to make that explicit.
There was a recent clickbaity blog post that claimed the "go statement considered harmful," and advocated for a construct it called a nursery, of lifecycle-bound threads. Both package run and package errgroup are slightly different implementation-interpretations of this nursery concept.
So this is one form of higher-order structure. But there are plenty of others! For example, did you know Go had futures? It's just a little bit more verbose than it might be in other languages.
future := make(chan int, 1) go func() { future <- process() }() result := <-future
Another way of pronouncing "future" is "async/await".
c := make(chan int, 1) go func() { c <- process() }() // async v := <-c // await
We also have scatter-gather, which I use all the time, when I know precisely how many units of work I need to process.
// Scatter c := make(chan result, 10) for i := 0; i < cap(c); i++ { go func() { val, err := process() c <- result{val, err} }() } // Gather var total int for i := 0; i < cap(c); i++ { res := <-c if res.err != nil { total += res.val } }
A good Go programmer will have a strong command of several of these higher-order concurrency patterns. A great Go programmer will be proactive in teaching those patterns to their colleagues.
I largely agree with what Charity told us earlier in the program. In particular, I agree that a core invariant of our distributed industrial systems is that there's simply no cost-effective way to do comprehensive integration or smoke testing. Integration or test environments are largely a waste; more environments will not make things easier. For most of our systems, good observability is simply more important than good testing, because good observability enables smart organizations to focus on fast deployment and rollback, optimizing for mean time to recovery (MTTR) instead of mean time between failure (MTBF).
The question for us is: what does a properly observable system in Go look like? I guess there's no single answer, no package I can tell you to import to solve the problem once and for all. The observability space is fractured, with many vendors competing for their particular worldview. There's a lot to be excited about, but the dust hasn't settled on winners yet. While we wait for that to happen, what can we do in the meantime?
If we lived in a more perfect world, it wouldn't matter. If we had a perfect observability data collection system, where all interpretation could be done at query-time with zero cost, we could emit raw observations to it, with infinite detail, and be done with it. But what makes the field interesting, or challenging, is of course that no such data system exists. So we’ve had to make engineering decisions, compromises, imbuing certain types of observations with semantic meaning, to enable specific observability workflows.
Metrics, logging, and tracing are emergent patterns of consumption of observability data, which inform the way we produce, ship, and store the corresponding signals. They’re the product of an optimization function, between how operators want to be able to introspect over their systems, and the capability of technology to meet those demands at scale. There may be other, yet-undiscovered patterns of consumption, likely driven by advances in technology, which will usher in a new era and taxonomy of observability. But this is where we’re at today, and for the forseeable future. So let's see how to best leverage each of them in Go.
Metrics are counters, gauges, and histograms, whose observations are statistically combined and reported to a system that allows fast, real-time exporation of aggregate system behavior. Metrics power dashboards and alerts.
Most metric systems provide Go client libraries by this point, and the standard exposition formats, like StatsD, are pretty well understood and implemented. If your organization already has institutional knowledge around a given system, standardize on it; if you're just getting started or looking to converge on one system, Prometheus is best-in-class.
What isn't good enough anymore are host- or check-based systems like Nagios, Icinga, or Ganglia. These keep you trapped in monitoring paradigms that stopped making sense a long time ago, and actively impede making your system observable.
Logs are streams of discrete events reported at full fidelity to a collection system, for later analysis, reporting, and debugging. Good logs are structured and permit flexible post-hoc manipulation.
There are lots of great logging options in Go these days. Good logging libraries are oriented around a logger interface, rather than a concrete logger object. They treat loggers as dependencies, avoiding package global state. And they enforce structured logging at callsites.
Logs are abstract streams, not concrete files, so avoid loggers that write or rotate files on disk; that's the responsibility of another process, or your orchestration platform. And logging can quickly dominate runtime costs of a system, so be careful and judicious in how you produce and emit logs. Capture everything relevant in the request path, but do so thoughtfully, using patterns like decorators or middlewares.
Tracing deals with all request-scoped performance data, especially as that data crosses process and system boundaries in a distributed system. Tracing systems organize metadata into tree structures, enabling deep-dive triage sessions into specific anomalies or events.
Tracing implementations these days are centered around OpenTracing, a client-side API standard implemented by concrete systems like Zipkin, Jaeger, Datadog, and others. There's also interesting work being done in OpenCensus, which promises a more integrated environment.
Tracing needs to be comprehensive if it's going to be useful, and of all of the pillars of observability it has the strictest set of domain objects and verbs. For those reasons the costs of properly implementing tracing are very high, and may only make sense to start working on when your distributed system is quite large, perhaps beyond several dozen microservices.
—
Each pillar of observability has different strengths and weaknesses. I think we can compare them along different axes: CapEx, the initial cost to start instrumenting and collecting the signals; OpEx, the ongoing cost to run the supporting infrastructure; Reaction, how good the system is at detecting and alerting on incidents; and Investigation, how much the system can help to triage and debug incidents. My subjective opinions follow:
| Metrics | Logging | Tracing | |
|---|---|---|---|
| CapEx | Medium | Low | High |
| OpEx | Low | High | Medium |
| Reaction | High | Medium | Low |
| Investigation | Low | Medium | High |
In terms of CapEx, logging systems are the easiest to get started, and adding log instrumentation to your code is easier and more intuitive than the alternatives. Metrics are a bit more involved to add, but most metrics collection systems are still relatively self-contained and pretty easy to deploy. Tracing, in contrast, is time-intensive to install across your fleet, and the tracing collection systems are typically large and require some specialized database knowledge.
In terms of OpEx, it's my experience that keeping a logging system online takes disproportionate effort, often being just as hard or harder than the corresponding production systems—made more difficult by the tendency for most organizations to indiscriminately over-log. Tracing systems benefit from the upfront costs and generally get on OK with aggressive ingest sampling and regular database maintenance. Metrics systems, in constrast, benefit from the natural data compression that occurs from statistical aggregation, and have generally very low maintenance costs.
In terms of reactive capability, metrics systems are explicitly designed to serve dashboard and alert use cases, and excel here. Logging systems frequently have tooling to perform aggregates or roll-ups that can drive dashboards and alerts, with a bit of work. And tracing systems generally don't have an ability to detect or signal on anomalies.
When it comes to investigation, however, the tables are turned. Metric systems lose data fidelity by design, and usually provide no good way to dig into the root cause of a problem after it's detected. Logging systems do much better, especially if you do structured logging and a logging system with a rich query language. And tracing is essentially designed for deep dives on specific requests or request-classes, sometimes being the only way to identify complex maladaptive behaviors.
—
The lesson here is that no single observability paradigm will solve all of your observability needs; they're all part of a complete observability breakfast. From their unique characteristics I think we can derive some general advice:
Although observability probably trumps integration testing for large distributed systems, unit and limited integration testing is still fundamental and necessary for any software project. In industrial contexts especially, I think its greatest value is providing a sort of sanity-check layer to new maintainers that their changes have the intended scope and effect.
It follows that tests should optimize for ease-of-use. If an entry-level developer can't figure out how to run your project's tests immediately after cloning the repo, there is a serious problem. In Go, I think this means that running plain go test in your project with no additional set-up work should always succeed without incident. That is, most tests should not require any sort of test environment, running database, etc. to function properly and return success. Those tests that do are integration tests, and they should be opt-in via test flag or environment variable:
func TestComplex(t *testing.T) { urn := os.Getenv("TEST_DB_URN") if urn == "" { t.Skip("set TEST_DB_URN to run this test") } db, _ := connect(urn) // ... }
The testing pyramid is good general advice, and suggests that you should focus most of your efforts on unit testing. In my experience, the ideal ratios are even more extreme than the pyramid suggests: if you have good production observability, as much as 80–90% of your testing effort should be focused toward unit tests. In Go, we know that good unit tests are table-driven, and leverage the fact that your components accept interfaces and return structs to provide fake or mock implementations of dependencies, and test only the thing being tested.
I like to reference this talk as frequently as possible: Mitchell Hashimoto's Advanced Testing with Go from last year's GopherCon is probably the single best source of information about good Go program design in industrial contexts I've seen to date. If your team writes Go, it's essential background material.
There's not much more to say on the subject. The relative stability of testing best practices over time is a welcome reprieve. As before and as always: gunning for 100% test coverage is almost certainly counterproductive, but 50% seems like a good low watermark; and avoid introducing testing DSLs or "helper packages" unless and until your team gets explicit, concrete value from them.
When we talk about testing, we talk about mocking dependencies via interfaces, but we often don't really describe how that works in practice. I think it's important to observe that the Go type system is not nominal, but rather it is structural. Looking at interfaces as a way to classify implementations is the wrong approach; instead, look at interfaces as a way to identify code that expects common sets of behaviors. Said another way, interfaces are consumer contracts, not producer (implementor) contracts—so, as a rule, we should be defining them at callsites in consuming code, rather than in the packages that provide implementations.
Interfaces belong with consumers, not implementers
How much interface do you need? Well, there's a spectrum. As much as makes sense at your callsites, especially with the aim to help testing. At one extreme, we could model every dependency to every function with a tightly-scoped interface definition. In limited circumstances this may make sense! For example, if your components are coarse-grained, well-established, and unlikely to change in the future.
But especially in industrial contexts, it's more likely that you'll have a mix of abstractions, which are fluctuating over time. In this case, you'll probably want to try to define interfaces at "fault lines" in your design. Two natural boundary points are between func main and the rest of your code, and along package APIs. Defining dependency interfaces there is a great place to start, as well as a great place to start thinking about defining unit tests.
Go 1.7 brought us package context, and since then, it's been steadily infecting our code. This isn't a bad thing! Contexts are a well-understood and ubiquitous way to manage goroutine lifecycles, which is a big and hard problem. In my experience this is their most important function. If you have a component that blocks for any reasons—typically network I/O, sometimes disk I/O, maybe due to user callbacks, and so on—then it should probably take a context as its first parameter.
The pattern is so ubiquitous, I've started to design this into my server types and interfaces from the beginning. Here's an example from a recent project that connected to Google Cloud Storage:
A good idea
// reportStore is a thin domain abstraction over GCS. type reportStore interface { listTimes(ctx context.Context, from time.Time, n int) ([]time.Time, error) writeFile(ctx context.Context, ts time.Time, name string, r io.Reader) error serveFile(ctx context.Context, ts time.Time, name string, w io.Writer) error }
Writing components to be context-aware for lifecycle semantics is straightforward: just make sure your code responds to ctx.Done. Using the value propegation features of contexts has proven to be a bit trickier. The problem with context.Value is that the key and value are untyped and not guaranteed to exist, which opens your program up to runtime costs and failure modes that may otherwise be avoidable. My experience has been that developers over-use context values for things that really ought to be regular dependencies or function parameters.
Only for request-scoped data
So, one essential of thumb: only use context.Value for data that can't be passed through your program in any other way. In practice, this means only using context.Value for request-scoped information, like request IDs, user authentication tokens, and so on. If the information is available when the program starts, like a database handle or logger, then it shouldn't be passed through the context.
Again, the rationale for this advice boils down to maintainability. It's much better if a component enumerates its requirements in the form of a constructor or function parameter, checkable at compile time, than if it extracts information from an untyped, opaque bag of values, checkable only at runtime. Not only is the latter more fragile, it makes understanding and adapting code more difficult.
I've been doing this best practice series for six years now, and while a few tips have come and gone, especially in response to emerging idioms and patterns, what's remarkable is really how little the foundational knowledge required to be an effective Go programmer has changed in that time. By and large, we aren't chasing design trends. We have a language and ecosystem that's been remarkably stable, and I'm sure I don't just speak for myself when I say I really appreciate that.
I really appreciate that!
I think it's great to orient ourselves among each other at conferences like this one. But I think the best thing we can do here is build empathy for each other. If we do our job right, as the number of Go programmers continues to grow, the community will become increasingly diverse, with different workflows, contexts, and goals. I'm happy to have presented some experience reports from my own journey with Go, and I'm excited to hear and understand all of yours. Thanks a bunch!
I'm excited to hear all of your experiences, too!
Thanks for listening!
Do I have time for questions??
@peterbourgon
— –
Read my tweets or
go back to my website.


The button to erase the previous character
The button to clear the input field
The button to close the keypad
The button to add a carriage return
Blank space equivalent to half a key
The button to toggle between upper/lower case characters
Blank space equivalent to one key
An extended space character
The button to add a tab character
The standard numeric button layout. This is the default value for the layout
setting.
The alphabetic character layout for the standard Qwerty keyboard. This is the default value for the
alphabeticLayout
setting.
The full keyboard layout for the standard Qwerty keyboard. This is the default value for the fullLayout
setting.
The set of regional settings for the keypad fields. Entries are indexed by the country or region code with the empty string providing the default (English) settings. Each entry is an object with the localized messages. Language packages load new entries into this array and automatically apply them as global defaults.
<script type="text/javascript" src="jquery.keypad-fr.js"></script>
If necessary, you can then revert to the default language settings with
$.keypad.setDefaults($.keypad.regionalOptions[""]);
and apply the language settings to individual fields with
$("#frenchKeypad").keypad($.keypad.regionalOptions["fr"]);
Define a new action key for use on the keypad. Up to 32 keys may be defined, including the built-in ones.
$.keypad.addKeyDef("UPPER", "upper", function(inst) {
this.val(this.val().toUpperCase()).focus();
});
$("#keypad").keypad({
upperText: "U/C",
upperStatus: "Convert to upper case",
layout: [
"abc" + $.keypad.CLOSE,
"def" + $.keypad.CLEAR,
"ghi" + $.keypad.BACK,
"jkl" + $.keypad.UPPER
]
});
Name of the variable to use to include this key in a layout.
Name used for a CSS styling class for the key (keypad-<name>
) and for finding its display text
(using <name>Text
and <name>Status
).
Code to be run when the key is pressed. it receives the keypad instance as a parameter, while this refers to the attached input field,
true
to suppress the highlight class when using ThemeRoller
styling.
Insert text into an input field at its current cursor position. This replaces text if a selection has been made.
An input element into which to insert the given value. May be either an element or a CSS selector.
The text to insert.
Default test for English alphabetic characters - accepting "A" to "Z" and "a" to "z". See also the
isAlphabetic
setting.
A character to check.
true
if the given character is contained in the set of alphabetic characters, or false
otherwise.
Default test for English numeric characters - accepting '0' to '9'. See also the isNumeric
setting.
A character to check.
true
if the given character is contained in the set of numerical characters, or false
otherwise.
Update the default instance settings to use with all keypad instances.
The new default settings to apply.
Convert a character into its upper case form - using the standard JavaScript toUpperCase
function. See also
the toUpper
setting.
A character to convert to upper case.
The given character, converted to upper case, or the given character itself, if it cannot be converted.
Generated using TypeDoc
Keypad related constants and utility method available on the
$.keypad
object.


Paolo Munna
I’m a Milan-based UI/UX designer interested in designing products that bring together creativity and pragmatism.
I started my journey as a front-end developer, later on I got into creative design and user behaviour. I'm influenced by art, anthropology and motion design
I've graduated in information technology at ITSOS Marie Curie, and web design at Galdus.
I have worked for IES Italia, Urban Fitness and Bemind.
Also I love every single dog in the world.


Sale
Jordan air
$1,000
Add to cart
It’s been an amazing year
because we all
survived!
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Facilis, magnam!
Explore Now


After your automated tests are executed the plug-in has to look for Test Results. This way it will know whether an automated test was executed correctly or not and then update the test status in TestLink.
TestNG result seeking strategies
TestNG class name: The plug-in matches the TestNG class name (e.g.: org.tap4j.TestParser) and the key custom field value.
TestNG method name: The plug-in matches the TestNG method name (e.g.: org.tap4j.TestParser#testTokenizer) and the key custom field value.
TestNG suite name: The plug-in matches the TestNG suite name (e.g.: functional tests) and the key custom field value.
JUnit result seeking strategies
JUnit case class name: The plug-in matches the JUnit case class name (e.g.: org.tap4j.TestParser) and the key custom field value.
JUnit case name: The plug-in matches the JUnit case class name (e.g.: testTokenizer) and the key custom field value.
JUnit method name: The plug-in matches the JUnit case class name (e.g.: org.tap4j.TestParser#testTokenizer) and the key custom field value.
JUnit suite name: The plug-in matches the JUnit suite name (e.g.:functional tests) and the key custom field value.
TAP result seeking strategies
TAP file name: The plug-in matches the TAP file name (e.g.: testFtpProtocol.tap) and the key custom field value.
New proposal
Oliver Merkel and Yury Kryazhev proposed changes to JUnit and TestNG result seeking process. I will try to organize them here for open discussion. Everybody is invited to comment, add suggestions or ideas, even if you are not using the plug-in :)-
1. Combine suite name and test case while looking for test results
If a test case is used in different test suites. It may cause the plug-in to report a test result twice in some situations. We could use the following format: "testSuiteName"."testCaseNameOrClass".
2. Add the possibility to use test methods
This proposal would add an extra option in the plug-in to match custom field values against test method names. I hadn't implemented it in version 1.0 for thinking that the method name could repeat inside other classes and that a test case in TestLink usually would be related to a test case or test suite. However, by adding this option to the plug-in we extend the possibilities of how to use it in different build pipelines. Perhaps this option could be implemented as in #1.
3. Add an option to define whether the plug-in should look for test case or test class name
In JUnit, some tools use test case name, and others the test class name attribute. At present, the plug-in tries to find a class name, and if not present then it uses the test case name. We could let the user decide which option the plug-in must utilize. This way we prevent the plug-in from running in situations where it uses test class name while it should be using the test case name. Below is an example which could cause wrong assertions in the plug-in.
<?xml version="1.0" encoding="UTF-8"?> <testsuites tests="…" failures="…" disabled="0" errors="…" time="…" name="AllTests"> <testsuite name="MyClass" tests="…" failures="…" disabled="0" errors="0" time="0"> <testcase name="MethodOne" status="run" time="0" classname="MyClass" /> <testcase name="MethodTwo" status="run" time="0" classname="MyClass" /> … </testsuite> </testsuites>


This page serves as a basic template for an HTML page in 2015. View Page Source to see the tags in the HEAD element, which have changed in recent years with the development HTML5.
This document has one heading (an H1) and three paragraphs.
To practice using HTML, you can open this document in a text editor and change some of the text in the paragraphs. A good free text editor for Mac is TextWrangler. A good free text editor for Windows is Notepad++. Then save the file and open it in your favorite Web browser, such as Firefox or Chrome.


{% extends "settings/settings.html" %} {% block setting %} {% include 'forms/create_form.html' with action_url_name='settings-userextra' %} {% endblock %}


Arranging finance to meet the working capital for running FPO business has prime agenda for UPPRO. In this regards, UPPRO helped FPOs members in the following ways :
SFAC equity matching grants: 36 FPOs have been helped to avail SFAC equity matching grants. A total amount of Rs 144 lakh has been generated with the help of SFAC equity matching grants.
Establishing Financial linkages: Total 8 FPOs have been helped in getting cash credit linkages and credit facilities. Major institution linkages have been established with Bank of Baroda, Oriental Bank of Commerce, Ananya Finance.


2021 Mercedes-AMG GLS 63 Arrives With Over 600 HP
Supercar levels of power packed into a big SUV.
by Jay TraugottMercedes-AMG has officially unveiled its flagship high-performance SUV at the 2019 Los Angeles Auto Show. Meet the 2021 Mercedes-AMG GLS 63, a 600+ horsepower full-size SUV packed with loads of technology and luxury. Let's start with its crown jewel: under its hood lies a 4.0-liter twin-turbo V8 with 603 hp and 627 lb-ft of torque. The SUV comes equipped with an integrated EQ Boost starter-generator that unites a starter motor and an alternator into a single electric motor located between the engine and transmission. It also provides an additional 21 hp and 184 lb-ft of torque and also performs hybrid functions such as boost, recuperation, gliding, and the start/stop engine function.
The result is fuel savings not previously found in a 48-volt electrical system. Mercedes-AMG claims the SUV will sprint from 0 to 60 mph in 4.1 seconds and top speed is electronically limited to 174 mph. A nine-speed automatic transmission sends power to the 4Matic all-wheel-drive system.
To help manage all of this power, the AMG GLS 63 is equipped with standard AMG Ride Control, which is comprised of an air suspension with a unique spring and damper setup and the Adaptive Damping System. A total of six driving modes are on offer: Comfort, Sport, Sport +, Individual, Trail, and Sand. All modes are linked to the AMG Dynamics agility control system, meaning the handling characteristics are closely matched with different requirements and driving conditions.
A high-performance braking system consists of ventilated and perforated brake discs with 6-piston fixed calipers painted in grey and white (with AMG lettering, of course) up front, with internally ventilated brake discs with a 1-piston floating caliper at the back.
To distinguish the AMG GLS 63 from the standard GLS, it's been equipped with an AMG-specific radiator grille – the largest grille found on any AMG model – with vertical slats in high-gloss chrome. The hood is also unique while Dynamic LED headlamps with adaptive high beam assist are standard. An AMG front bumper with an integrated jetwing design, front splitter, jetwing trim strip in silver, and side air inlets are also present. Notice the must-have flared wheel arches, side skirts, and window surrounds in high-gloss chrome trim.
Out back, the AMG rear bumper, diffuser, and two rectangular twin tailpipes are to be found. A set of 21-inch AMG multispoke wheels are standard, but buyers can select up to 23-inch wheel variants.
Step inside and you'll be indulged with more AMG-specific flare, such as brushed stainless steel sports pedals, illuminated door sill panels, and 64-color configurable ambient lighting. The cockpit is adorned with a three-spoke AMG steering wheel, high-resolution 12.3-inch driver's gauge display and a 12.3-inch touchscreen, both incorporated under a single glass cover. Drivers can select from four display styles: Modern Classic, Sport, Discreet, and the AMG-specific Supersport. AMG badging can be found throughout the three-row cabin. There's even heated seats for third-row occupants.
A number of standard safety systems include Evasive Steering Assist, Active Blind Spot Assist, Active Lane Keeping Assist, Pre-Safe Impulse Side, which actually moves the driver or front passenger up to 2.75-inches away from the impact zone by rapidly inflating the seat's side bolster.
Mercedes-AMG has not announced an on-sale date, fuel economy figures, or pricing.