29 Jun 2015

feedPlanet Lisp

Didier Verna: Declt 1.1 is released

Hello,

as promised last week, I've just released a new version of Declt, my reference manual generator for ASDF systems. This new version (1.1) is now able to document Clon again (the documentation of which has been updated on the website).

New in this release:

But the most important addition is the ability to document several ASDF systems in the same reference manual. More precisely, Declt now documents not only the main system but also all its subsystems. A subsystem is defined as a system on which the main one depends on in any way, and which is also part of the same distribution (under the same directory tree). Declt also understands multiple system definitions from the same .asd file.

Enjoy!

29 Jun 2015 12:00am GMT

27 Jun 2015

feedPlanet Lisp

Paul Khuong: Linear-log Bucketing: Fast, Versatile, Simple

There's a couple code snippets in this post (lb.lisp, bucket.lisp, bucket-down.lisp, bin.c). They're all CC0.

What do memory allocation, histograms, and event scheduling have in common? They all benefit from rounding values to predetermined buckets, and the same bucketing strategy combines acceptable precision with reasonable space usage for a wide range of values. I don't know if it has a real name; I had to come up with the (confusing) term "linear-log bucketing" for this post! I also used it twice last week, in otherwise unrelated contexts, so I figure it deserves more publicity.

I'm sure the idea is old, but I first came across this strategy in jemalloc's binning scheme for allocation sizes. The general idea is to simplify allocation and reduce external fragmentation by rounding allocations up to one of a few bin sizes. The simplest scheme would round up to the next power of two, but experience shows that's extremely wasteful: in the worst case, an allocation for \(k\) bytes can be rounded up to \(2k - 2\) bytes, for almost 100% space overhead! Jemalloc further divides each power-of-two range into 4 bins, reducing the worst-case space overhead to 25%.

This sub-power-of-two binning covers medium and large allocations. We still have to deal with small ones: the ABI forces alignment on every allocation, regardless of their size, and we don't want to have too many small bins (e.g., 1 byte, 2 bytes, 3 bytes, ..., 8 bytes). Jemalloc adds another constraint: bins are always multiples of the allocation quantum (usually 16 bytes).

The sequence for bin sizes thus looks like: 16, 32, 48, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, ... (0 is special because malloc must either return NULL [bad for error checking] or treat it as a full blown allocation).

I like to think of this sequence as a special initial range with 4 linearly spaced subbins (0 to 63), followed by power-of-two ranges that are again split in 4 subbins (i.e., almost logarithmic binning). There are thus two parameters: the size of the initial linear range, and the number of subbins per range. We're working with integers, so we also know that the linear range is at least as large as the number of subbins (it's hard to subdivide 8 integers in 16 bins).

Assuming both parameters are powers of two, we can find the bucket for any value with only a couple x86 instructions, and no conditional jump or lookup in memory. That's a lot simpler than jemalloc's implementation; if you're into Java, HdrHistogram's binning code is nearly identical to mine.

Common Lisp: my favourite programmer's calculator

As always when working with bits, I first doodled in SLIME/SBCL: CL's bit manipulation functions are more expressive than C's, and a REPL helps exploration.

Let linear be the \(\log\sb{2}\) of the linear range, and subbin the \(\log\sb{2}\) of the number of subbin per range, with linear >= subbin.

The key idea is that we can easily find the power of two range (with a BSR), and that we can determine the subbin in that range by shifting the value right to only keep its subbin most significant (nonzero) bits.

I clearly need something like \(\lfloor\log\sb{2} x\rfloor\):

"lb.lisp"

1
2
(defun lb (x)
  (1- (integer-length x)))

I'll also want to treat values smaller than 2**linear as though they were about 2**linear in size. We'll do that with

n-bits := (lb (logior x (ash 1 linear))) === (max linear (lb x))

We now want to shift away all but the top subbin bits of x

shift := (- n-bits subbin)
sub-index := (ash x (- shift))

For a memory allocator, the problem is that the last rightward shift rounds down! Let's add a small mask to round things up:

mask := (ldb (byte shift 0) -1) ; that's `shift` 1 bits
rounded := (+ x mask)
sub-index := (ash rounded (- shift))

We have the top subbin bits (after rounding) in sub-index. We only need to find the range index

range := (- n-bits linear) ; n-bits >= linear

Finally, we combine these two together by shifting index by subbin bits

index := (+ (ash range subbin) sub-index)

Extra! Extra! We can also find the maximum value for the bin with

size := (logandc2 rounded mask)

Assembling all this yields

"bucket.lisp"

1
2
3
4
5
6
7
8
9
10
(defun bucket (x linear subbin)
  (let* ((n-bits (lb (logior x (ash 1 linear))))
         (shift (- n-bits subbin))
         (mask (ldb (byte shift 0) -1))
         (rounded (+ x mask))
         (sub-index (ash rounded (- shift)))
         (range (- n-bits linear))
         (index (+ (ash range subbin) sub-index))
         (size (logandc2 rounded mask)))
    (values index size)))

Let's look at what happens when we want \(2\sp{2} = 4\) subbin per range, and a linear progression over \([0, 2\sp{4} = 16)\).

CL-USER> (bucket 0 4 2)
0 ; 0 gets bucket 0 and rounds up to 0
0
CL-USER> (bucket 1 4 2)
1 ; 1 gets bucket 1 and rounds up to 4
4
CL-USER> (bucket 4 4 2)
1 ; so does 4
4
CL-USER> (bucket 5 4 2)
2 ; 5 gets the next bucket
8
CL-USER> (bucket 9 4 2)
3
12
CL-USER> (bucket 15 4 2)
4
16
CL-USER> (bucket 17 4 2)
5
20
CL-USER> (bucket 34 4 2)
9
40

The sequence is exactly what we want: 0, 4, 8, 12, 16, 20, 24, 28, 32, 40, 48, ...!

The function is marginally simpler if we can round down instead of up.

"bucket-down.lisp"

1
2
3
4
5
6
7
8
(defun bucket-down (x linear subbin)
  (let* ((n-bits (lb (logior x (ash 1 linear))))
         (shift (- n-bits subbin))
         (sub-index (ash x (- shift)))
         (range (- n-bits linear))
         (index (+ (ash range subbin) sub-index))
         (size (ash sub-index shift)))
     (values index size)))

CL-USER> (bucket-down 0 4 2)
0 ; 0 still gets the 0th bucket 
0 ; and rounds down to 0
CL-USER> (bucket-down 1 4 2)
0 ; but now so does 1
0
CL-USER> (bucket-down 3 4 2)
0 ; and 3
0
CL-USER> (bucket-down 4 4 2)
1 ; 4 gets its bucket
4
CL-USER> (bucket-down 7 4 2)
1 ; and 7 shares it
4
CL-USER> (bucket-down 15 4 2)
3 ; 15 gets the 3rd bucket for [12, 15]
12
CL-USER> (bucket-down 16 4 2)
4
16
CL-USER> (bucket-down 17 4 2)
4
16
CL-USER> (bucket-down 34 4 2)
8
32

That's the same sequence of bucket sizes, but rounded down in size instead of up.

The same, in GCC

"bin.c"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
static inline unsigned int
lb(size_t x)
{
        /* I need an extension just for integer-length (: */
        return (sizeof(long long) * CHAR_BIT - 1) - __builtin_clzll(x);
}

/*
 * The following isn't exactly copy/pasted, so there might be
 * transcription bugs.
 */
static inline size_t
bin_of(size_t size, size_t *rounded_size,
    unsigned int linear, unsigned int subbin)
{
        size_t mask, range, rounded, sub_index;
        unsigned int n_bits, shift;

        n_bits = lb(size | (1ULL << linear));
        shift = n_bits - subbin;
        mask = (1ULL << shift) - 1;
        rounded = size + mask; /* XXX: overflow. */
        sub_index = rounded >> shift;
        range = n_bits - linear;

        *rounded_size = rounded & ~mask;
        return (range << subbin) + sub_index;
}

static inline size_t
bin_down_of(size_t size, size_t *rounded_size,
    unsigned int linear, unsigned int subbin)
{
        size_t range, sub_index;
        unsigned int n_bits, shift;

        n_bits = lb(size | (1ULL << linear));
        shift = n_bits - subbin;
        sub_index = size >> shift;
        range = n_bits - linear;

        *rounded_size = sub_index << shift;
        return (range << subbin) + sub_index;
}

What's it good for?

I first implementated this code to mimic's jemalloc binning scheme: in a memory allocator, a linear-logarithmic sequence give us alignment and bounded space overhead (bounded internal fragmentation), while keeping the number of size classes down (controlling external fragmentation).

High dynamic range histograms use the same class of sequences to bound the relative error introduced by binning, even when recording latencies that vary between microseconds and hours.

I'm currently considering this binning strategy to handle a large number of timeout events, when an exact priority queue is overkill. A timer wheel would work, but tuning memory usage is annoying. Instead of going for a hashed or hierarchical timer wheel, I'm thinking of binning events by timeout, with one FIFO per bin: events may be late, but never by more than, e.g., 10% their timeout. I also don't really care about sub millisecond precision, but wish to treat zero specially; that's all taken care of by the "round up" linear-log binning code.

In general, if you ever think to yourself that dispatching on the bitwidth of a number would mostly work, except that you need more granularity for large values, and perhaps less for small ones, linear-logarithmic binning sequences may be useful. They let you tune the granularity at both ends, and we know how to round values and map them to bins with simple functions that compile to fast and compact code!

P.S. If a chip out there has fast int->FP conversion and slow bit scans(!?), there's another approach: convert the integer to FP, scale by, e.g., \(1.0 / 16\), add 1, and shift/mask to extract the bottom of the exponent and the top of the significand. That's not slow, but unlikely to be faster than a bit scan and a couple shifts/masks.

27 Jun 2015 9:06pm GMT

26 Jun 2015

feedPlanet Lisp

Vsevolod Dyomkin: Running Lisp in Production at Grammarly


We have written a blog post describing almost 3 years of our Lisp in production experience at Grammarly. Here's a small abstract for it.

At Grammarly, the foundation of our business, our core grammar engine, is written in Common Lisp. It currently processes more than a thousand sentences per second, is horizontally scalable, and has reliably served in production for almost 3 years.

We noticed that there are very few, if any, accounts of how to deploy Lisp software to modern cloud infrastructure, so we thought that it would be a good idea to share our experience. The Lisp runtime and programming environment provides several unique, albeit obscure, capabilities to support production systems (for the impatient, they are described in the final chapter).

Continue to the full text »


26 Jun 2015 6:08pm GMT

Zach Beane: Lisp in production at Grammarly

Vsevolod Dyomkin (who conducted the Lisp Hackers interviews) has an interesting blog post today about running Lisp in production at Grammarly:

At Grammarly, the foundation of our business, our core grammar engine, is written in Common Lisp. It currently processes more than a thousand sentences per second, is horizontally scalable, and has reliably served in production for almost 3 years.

We noticed that there are very few, if any, accounts of how to deploy Lisp software to modern cloud infrastructure, so we thought that it would be a good idea to share our experience.

Full article.

26 Jun 2015 5:22pm GMT

25 Jun 2015

feedPlanet Lisp

Didier Verna: Clon 1.0b24 is released -- IMPORTANT

Hello,

I'm happy to announce the release of the next beta version of Clon, the Common Lisp / Command Line Options Nuker library. This release doesn't contain much change in terms of functionality, but it contains a lot of change in terms of infrastructure, plus very important and backward-incompatible modifications. So if you're a Clon user, please read on.

First of all, a huge revamp of the library's infrastructure (package hierarchy, ASDF and Make implementations) occurred. A large portion of this work is actually not mine, but Fare's (big thanks to him, 'cause the level of ASDF expertise required just means that I couldn't have done that by myself). The purpose here was twofold: first, remove all logic from the ASDF files (so that other system managers could be used; not sure that's actually useful right now) and second, split the library in two: the core, basic functionality and the non-standard platform-dependent bells and whistles (read: termio support). The result is that Clon now comes with 4 different ASDF systems! A setup system allows you to configure some stuff prior to loading the library, a core system allows you to load only the basic functionality and the regular one loads everything, autodetecting platform-dependent features as before. The fourth system is auxiliary and not to be used by hand. All of this is properly documented. For a code maniac like me, this new infrastructure is much more satisfactory, and I've learned a lot about ASDF less known features.

Next, I've moved the repository to Github. Please update your links! It seems that I've lost all my former tags in the process, but oh well...Only the Git repo has moved. The main Clon web page still contains the full history of tarballs, the preformatted documentation, and will continue to do so in the future.

Finally (I've kept this to myself until the last possible minute because I'm scared like hell to tell): I've changed the systems and packages names... The com.dvlsoft prefix has been replaced with net.didierverna. All other libraries of mine will eventually endure the same surgery. It's for the best, I apologize for it and I swear I will never ever do that again, EVER (fingers crossed behind my back).

So what's next? Before considering an official 1.0 release, there are two things that I want to do. First, cleanup some remaining Fixmes and some shaky error handling. Second, provide an even simpler way of using Clon than what the Quick Start chapter in the doc demonstrates. The idea is to just implement a main function with keyword arguments, and those argument magically become command-line options.

A side-effect of this work is that Declt now chokes on Clon, because some ASDF features that it doesn't understand are in use. So Declt has a couple of new challenges ahead, and you should expect a new release in the weeks to come.

25 Jun 2015 12:00am GMT

16 Jun 2015

feedPlanet Lisp

Patrick Stein: Syntactic Corn Syrup

I've been bouncing around between Java and C++ and C and loads of JNI cruft in between. At some point today, I accidentally used a semicolon to separate parameters in my C function declaration:

void JNI_myJNIMethod( int paramA; int paramB; int paramC )
{
...
}

It looked wrong to me. But, I had one of those brain-lock moments where I couldn't tell if it was wrong. I was pretty sure that it was wrong by the time my brain locked on pre-ANSI K&R:

void
JNI_myJNIMethod(paramA, paramB, paramC)
int paramA;
int paramB;
int paramC;
{
...
}

Regardless, it got me thinking about the programming maxims: Deleted code has no bugs and Deleted code is debugged code.

I never have this kind of brain-lock in Lisp. Some of that is because my Emacs configuration has been molded to my Lisp habits better than to my C/C++/Java habits. Most of it, though, is that Lisp understands the difference between syntactic sugar and syntactic cruft.

Lisp decided long ago that writing code should be easy even if it makes writing the compiler tougher. C and C++ and Java all decided that LALR(1) was more important than me. As if that weren't bad enough, C++ and Java have thrown the lexers and parsers under the bus now, too. No one gets a free ride.

16 Jun 2015 3:06pm GMT

15 Jun 2015

feedPlanet Lisp

drmeister: I gave a talk on Clasp and my Chemistry at Google in Cambridge Mass last week

Here is the link for the talk.

This talk describes our unique approach to constructing large, atomically precise molecules (called "Molecular Lego" or "spiroligomers") that could act as new therapeutics, new catalysts (molecules that make new chemical reactions happen faster) and ultimately to construct atomically precise molecular devices. Then I describe Clasp and CANDO, a new implementation of the powerful language Common Lisp. Clasp is a Common Lisp compiler that uses LLVM to generate fast machine code and it interoperates with C++. CANDO is a molecular design tool that uses Clasp as its programming language. Together I believe that these are the hardware (molecules) and the software (the CANDO/Clasp compiler) that will enable the development of sophisticated molecular nanotechnology.

For more info see: https://chem.cst.temple.edu/directory/faculty/schafmeister/

What a great place Google was! My host, Martin Cracauer was fantastic, he made me feel really, really welcome and made sure that the talk would be recorded and put up on the web. He arranged it so that I could spend the afternoon talking with him and Doug and James, two Lisp/compiler gurus at Google. He also gave me a tour of Google, it was great.


15 Jun 2015 7:54pm GMT

11 Jun 2015

feedPlanet Lisp

Nicolas Hafner: The Great UI Warts - Confession 56

header
It's now been about a year since I first started work on Parasol. In the process, I had to learn about UI programming in Common Lisp. It pains me a lot to say this, but it is definitely not one of the great strengths of CL. It certainly wasn't back then, and it still isn't now. Since Parasol started I learned a lot about Qt and in particular the Common Lisp bindings, CommonQt. While using Qt is your best bet at writing a native GUI, it just isn't as pleasant as writing other lisp code. Too many things can break, too many brick walls are laying in wait for you to hit your head against, too many things are simply not there infrastructure wise. However, as Parasol grew, and I grew tired of CommonQt's shortcomings, I started to write more and more systems to work around these problems and make the UI experience for the developer a better one. This is the goal of Qtools.

This library started out as an innocent encapsulation of a few things I'd developed in tandem with Parasol. The first serious issue I had with Parasol was memory leaking. Since we're accessing Qt -a C++ library- we need to go back to the old times and deal with our memory by hand. This is a very arduous task and one prone to mistakes. So, a system was developed to alleviate this pain. The result of this is Qtools' finalizers. At the core of it is a generic function that takes care of cleaning up the object it is passed. So in other words, a destructor function. Using this I could ensure that foreign objects were always properly cleaned up. However, I quickly came to realise that I did one very similar thing all the time: Add a finalizer method for my widget, and call finalize on its slot values. Thanks to the Meta Object Protocol's capabilities, I was able to hide this away completely. Now there's almost never a need to write a finalizer method again. It suffices to just add :finalized T to a widget's slot, and in the case of sub-widgets, the system already does it automatically.

The next issue I had was that writing in CommonQt's style is really uncomfortable. You need to duplicate a lot of information and keep track of the slots, signals, and overrides you define in the class definition. You also need to take care of different type and naming styles that come from C++ and leak into your CL application. This spawned Qtools' widget system. Not only does it take care of mapping naming styles and types, but it also allows a much more normal-looking way of defining your widgets. Instead of having to stuff information into your class definition, you can use multiple, separated forms. Just the way it works in your usual Lisp programs. At the heart of this system lies reinitialize-instance. Thanks to this fantastic function (and the MOP), I was able to separate everything out. What happens in the back when you compile a separate form is that it appends the option that should be in the class definition onto a class property, and calls reinitialize-instance. This call subsequently computes the effective class options and injects them into the class re/initialisation, effectively making it appear as if you had indeed added an option onto the class definition itself.

With this step done, much of the awkwardness was gone. Programs looked much more naturally structured, and things could be specified in a way that felt intuitive. However, one stain remained in the picture: Qt method calls. In order to call Qt methods, CommonQt provides a reader macro: #_. Sadly, in order for this reader macro to work, you need to specify the method name as it is in Qt, including the proper capitalisation. Since it is a foreign call, you also can't inspect it, or get any documentation information out of it. Argument list validity also isn't checked. Getting rid of this and allowing some form of normal-looking function call instead was a rather tricky problem to solve. My first thought was to dynamically analyse the available methods and generate Lisp wrapper functions for them. Those wrapper definitions are dumped to file, and then loaded. Sadly, doing so results in a couple hundred thousand method wrappers and a roughly 50Mb FASL file (on SBCL). The initial compile time also suffered because of this of course. This seemed like a less than stellar solution to me, mostly because the overwhelming majority of the wrappers included would never be called by the GUI anyway. So I sought a different solution. I did find one, albeit it is rather mad.

This solution is called Q+. The first part of it is the aforementioned wrapper compiler that I previously used to generate static wrappers. Modifying it a bit, I could use the same system to generate individual wrappers for any specific method I wanted. The second part is detecting when a supposed call to a wrapper function is made. Since it is not precompiled, the CL host cannot know of it. Thus, we need to somehow intercept when such a form is compiled, dynamically compile the wrapper, and then replace it with a call to the actual wrapper function. That sounds like a macro! And indeed, the q+ macro does that. It takes a method name and an argument list, dynamically compiles the wrapper, and finally emits a call to the new wrapper. The truth is a bit trickier here, since the wrapper needs to be available when a file is merely loaded as well, which wouldn't be the case if it was only generated during macro expansion. So instead, a load-time-value form that generates the wrapper is emitted alongside the wrapper call. That way, methods are always around as needed, with no run-time overhead. The last trick to Q+ is the hiding of the q+ macro call. Using the q+ macro solved most of the problems, but it was essentially the same thing as the #_ reader macro, with a bit nicer method name handling. What I wanted instead was to be able to write the actual wrapper function names. That would also allow slime to show docstrings, arguments, and similar information. In order to make this last trick work, I had to hack into the reader.

One of the greater blemishes of the the Common Lisp standard is the inability to hook into the reader's symbol creation process. This exclusion from the standard makes it impossible to write such things as package local nicknames as a library, or make a case like mine easy. What I had to do instead was to override the ( reader macro. Q+ then reads ahead, to see whether you're trying to reference a symbol from the q+ package. If so, it reads the rest of the form, and emits a call to the q+ macro from above instead. It not, it delegates to the standard reader macro for (. Overriding this reader macro is a dirty trick, and I'd rather not have done it. However, there simply is no other way to accomplish this feat, short of writing a complete reader implementation and demanding that people use that instead of the host implementation's, which is a bit too much to ask for, in my opinion. Still, it works fine, and I haven't run into any obvious issues so far. Now Qtools applications look and read like regular lisp code.

However, how the code looks is only one of the aspects that influence writing GUIs. There's a lot more to it, like for example the initial installation and the binary deployment. Those two things are what I've worked on in the past few weeks now. Out of the first item grew qt-libs, which should ensure that the required libraries like smoke and CommonQt are available easily. This currently works fine for Linux, however I did not get enough time before the Quicklisp release to find testers for Mac OS X. Windows is another problem entirely, one that I can only solve through downloading of precompiled libraries. I've wasted the entire day today with trying to get 64bit versions of the smoke libraries compiled on Windows. Hopefully I can push through with that and allow easy setup of a Qt environment on Windows as well. Qt-libs builds fine on Mac OS X now as well, though there's currently an issue remaining in loading the libraries. I'll get that sorted out before the next Quicklisp release though.

The second part grew into Qtools' new deployment system part. This allows really convenient and easy generation of ready-to-ship binaries of your application. The only thing you have to do is update your system definition a little:

(asdf:defsystem :my-system
  ...
  :defsystem-depends-on (:qtools)
  :build-operation "qt-program-op"
  :build-pathname "binary-name"
  :entry-point "my-package:start-function-or-main-class")

Once these four lines are added, you can simply launch your implementation from a shell, invoke (asdf:operate :program-op :my-system) and it'll do all the magic -like closing foreign libraries before dump, restoring the proper library search paths after resume, reloading the foreign libraries again using the new paths, etc.- for you. All you'll get is a bin folder in your project folder that you can zip and ship. I've tried this for Halftone and it Just Works™ on Linux so far.

But, the road ahead is still long and twisted. Once deployment and installation work flawlessly, there's still a lot of code left to be written to make working with Qt itself less painful. Hopefully some day I'll be able to say that writing native GUIs in Lisp is actually a nice experience!

The Qtools documentation is long and extensive. It contains a lot of talk on both how to start using Qtools, as well as what the internals are and how they work. If you're interested, have a read.

footer

11 Jun 2015 11:02pm GMT

10 Jun 2015

feedPlanet Lisp

Zach Beane: SLIME 2.13 and SBCL 1.2.12 error:The value NIL is not of type POLICY

If you run into this error message, there's a quick runtime fix: evaluate (sb-ext:restrict-compiler-policy 'safety)

You can also add that form to your .sbclrc.

You can also update to SLIME 2.14 or downgrade to SBCL 1.2.11. Unfortunately, SLIME 2.14 isn't in the recent June Quicklisp update, but I might do a quick second update to fix this problem.

10 Jun 2015 3:46pm GMT

Quicklisp news: June 2015 Quicklisp dist update now available

This Quicklisp update is supported by my employer, Clozure Associates. If you need commercial support for Quicklisp, or any other Common Lisp programming needs, it's available via Clozure Associates.
New projects:

Updated projects: apply-argv, arrow-macros, asdf-dependency-grovel, asdf-encodings, asdf-finalizers, asdf-linguist, asdf-package-system, avatar-api, babel, bit-smasher, black-tie, blackbird, blackthorn-engine, bordeaux-fft, buffalo, burgled-batteries, burgled-batteries.syntax, caveman, cells, cffi, chanl, city-hash, cl+ssl, cl-6502, cl-abnf, cl-ana, cl-annot, cl-autowrap, cl-bencode, cl-bibtex, cl-charms, cl-cli-parser, cl-coveralls, cl-cron, cl-csv, cl-dbi, cl-dot, cl-dropbox, cl-durian, cl-emb, cl-factoring, cl-ftp, cl-fuse-meta-fs, cl-gendoc, cl-geometry, cl-glfw3, cl-gpu, cl-growl, cl-influxdb, cl-isaac, cl-launch, cl-lexer, cl-libpuzzle, cl-libusb, cl-libuv, cl-llvm, cl-marklogic, cl-memcached, cl-messagepack, cl-mlep, cl-mustache, cl-netstring-plus, cl-nxt, cl-odesk, cl-pass, cl-pdf, cl-plplot, cl-ppcre, cl-primality, cl-project, cl-protobufs, cl-qrencode, cl-quickcheck, cl-rabbit, cl-recaptcha, cl-rethinkdb, cl-rlimit, cl-rrt, cl-sam, cl-sdl2, cl-shellwords, cl-slug, cl-smtp, cl-sophia, cl-strftime, cl-string-match, cl-tk, cl-unification, clack, classimp, cletris, clim-widgets, clinch, clipper, clos-diff, closer-mop, coleslaw, colleen, com.google.base, command-line-arguments, common-doc, common-doc-plump, common-html, contextl, crane, croatoan, css-selectors, daemon, dartsclhashtree, defclass-std, defpackage-plus, dissect, djula, dyna, eazy-gnuplot, eazy-process, eazy-project, eco, eos, escalator, esrap, esrap-peg, event-glue, exscribe, fare-csv, fare-memoization, fare-mop, fare-quasiquote, fare-utils, fast-io, fft, find-port, gendl, glaw, glop, glu-tessellate, hdf5-cffi, hermetic, html-template, http-parse, hu.dwim.asdf, hu.dwim.common, hu.dwim.common-lisp, hu.dwim.computed-class, hu.dwim.debug, hu.dwim.def, hu.dwim.defclass-star, hu.dwim.delico, hu.dwim.logger, hu.dwim.partial-eval, hu.dwim.perec, hu.dwim.quasi-quote, hu.dwim.rdbms, hu.dwim.reiterate, hu.dwim.serializer, hu.dwim.stefil, hu.dwim.syntax-sugar, hu.dwim.uri, hu.dwim.util, hu.dwim.walker, hu.dwim.web-server, ieee-floats, imago, inferior-shell, inner-conditional, inotify, intel-hex, ip-interfaces, jonathan, jwacs, kebab, lack, lambda-gtk, lambda-reader, lass, let-over-lambda, lfarm, linedit, lisp-executable, lisp-gflags, lisp-interface-library, lisp-invocation, lisp-namespace, lispbuilder, local-time, lparallel, lucerne, lw-compat, magicffi, md5, meta, mexpr, mgl, mgl-pax, micmac, misc-extensions, mixalot, modf, modf-fset, modularize, modularize-interfaces, myweb, named-readtables, nibbles, ningle, npg, opticl, osicat, pal, parse-js, periods, perlre, pg, plump, png-read, pooler, postmodern, projectured, protobuf, pzmq, qlot, qtools, query-fs, quri, random, rcl, readable, reader-interception, repl-utilities, retrospectiff, rfc3339-timestamp, rock, rpc4cl, rpm, rucksack, s-xml, scalpl, scriba, scribble, sdl2kit, serapeum, shuffletron, single-threaded-ccl, sip-hash, smackjack, smug, snappy, software-evolution, st-json, staple, stem, stumpwm, swank-client, swank-crew, sxql, temporary-file, thorn, trivia, trivia.balland2006, trivial-download, trivial-extract, type-i, type-r, unix-options, unix-opts, usocket, utilities.print-items, utils-kt, verbose, vertex, vgplot, websocket-driver, weft, with-c-syntax, woo, wookie, workout-timer, wuwei, xhtmlgen, zip, zlib, zs3.

Removed projects: arnesi+, asdf-contrib, asdf-project-helper, asdf-utils, until-it-dies.

arnesi+ has been removed because its repo has disappeared and its authors have not replied to inquiries in months.

asdf-contrib and asdf-utils have been removed by request of the author. asdf-project-helper has stopped working as a result.

until-it-dies has never actually worked, but was previously included because some of its auxiliary systems worked.

To get this update, use (ql:update-dist "quicklisp")

10 Jun 2015 3:01pm GMT