15 May 2021

Get More Details when Emacs Crashes

As I live on the edge (i.e. on Emacs master branch), it happens from time to time that Emacs crashes after an update – but not often enough that I can remember how to provide enough details for maintainers to investigate.

So here are some notes on how to proceed.

First compile Emacs with enough debugging information: this requires the '-O0 -g3' flags to be passed to configure:

 CFLAGS="-g3 -O0" CXXFLAGS="-g3 -O0" ./configure --with-cairo  --with-modules . . .
make && sudo make install


(You don’t have to make install, but the following assumes you have.

To execute with gdb:

gdb emacs


gdb starts, you can then run Emacs, passing arguments as well by calling run at the prompt, and appending the args:

(gdb) run -Q --load init-ido.el


This starts emacs with a init file (here init-ido.el) that you need to create, and which typically would contain the recipe producing the issue. A full backtrace can be obtained by running the following command:

(gdb) bt full


To also get a Lisp backtrace, you need to use src/.gdbinit, by running gdb in the src directory. The Lisp backtrace can be obtained by executing:

(gdb) xbacktrace


To set a breakpoint, you can run the following – prior to running Emacs, if needs be:

(gdb) b Factive_minibuffer_window


You can then print the value of various variables, using the p command:

(gdb) p minibuf_level
$1 = 0  You may need to select the correct frame first to be able to view the relevant variables: (gdb) select-frame 2  To report the bug you can gather all these details, and add them to a bug report that you can kick off with M-x report-emacs-bug in Emacs). Hopefully this will help everyone save some time next time another nasty crash occurs! Comment 13 March 2020 Why isn't A1 paper 595 mm × 841 mm? In those troubled times of pandemic, it is good to be focusing on existential questions. And here is one that has been causing me to lose the little bit of hair I have left: why isn’t the A1 paper size 595 mm by 841 mm, or A5 149 mm by 210 mm? The ISO standard defines the A series as follows: Size Format 0 841 × 1189 1 594 × 841 2 420 × 594 3 297 × 420 4 210 × 297 5 148 × 210 6 105 × 148 7 74 × 105 8 52 × 74 9 37 × 52 10 26 × 37 You’ll notice that the height of a given size is the width of the previous size; a paper size is defined by “halving the preceding paper size across the larger dimension.” The base size is A0, whose area is 1m² and ratio 1:√2. The formula given by Wikipedia gives for size i is: $$\alpha_A \times (2^{-\frac{i+1}{2}}) \qquad \mathrm{by} \qquad \alpha_A \times (2^{-\frac{i}{2}})$$ In Clojure this becomes: (defn iso-aseries-size [size] {:size (str "A" size) :width (* alpha-a (Math/pow 2 (- (/ (inc size) 2))) 1000.0) :height (* alpha-a (Math/pow 2 (- (/ size 2))) 1000.0)})  with the following: (defn fourth-root [n] (Math/sqrt (Math/sqrt n)))  (def alpha-a (fourth-root 2))  Trying our formula, we get for the following paper sizes from A0 to A10: pdfdata.paper> (map #(iso-aseries-size %) (range 11)) ;; => ({:size "A0", :width 840.8964152537146, :height 1189.2071150027211} {:size "A1", :width 594.6035575013606, :height 840.8964152537146} {:size "A2", :width 420.4482076268573, :height 594.6035575013606} {:size "A3", :width 297.3017787506803, :height 420.4482076268573} {:size "A4", :width 210.22410381342866, :height 297.3017787506803} {:size "A5", :width 148.65088937534014, :height 210.22410381342866} {:size "A6", :width 105.11205190671433, :height 148.65088937534014} {:size "A7", :width 74.32544468767007, :height 105.11205190671433} {:size "A8", :width 52.556025953357164, :height 74.32544468767007} {:size "A9", :width 37.162722343835036, :height 52.556025953357164} {:size "A10", :width 26.278012976678582, :height 37.162722343835036})  If we round correctly, we get A5 595 mm × 841 mm, and other sizes also look wrong: pdfdata.paper> (map #(iso-aseries-size %) (range 11)) ;; => ({:size "A0", :width 841, :height 1189} {:size "A1", :width 595, :height 841} {:size "A2", :width 420, :height 595} {:size "A3", :width 297, :height 420} {:size "A4", :width 210, :height 297} {:size "A5", :width 149, :height 210} {:size "A6", :width 105, :height 149} {:size "A7", :width 74, :height 105} {:size "A8", :width 53, :height 74} {:size "A9", :width 37, :height 53} {:size "A10", :width 26, :height 37})  OK. So digging a bit more, another site gives this other formula For size n, • if n is even, the dimensions are: • if n is odd, the dimensions are: It’s not difficult to see this formula is actually identical to the previous one ($2^\{frac{1}{4} = \sqrt4{2}$), but for the fun of writing in Clojure, here it is: (defn iso-aseries-size [size] (if (even? size) {:size (str "A" size) :width (/ 1000.0 (* (Math/pow 2.0 (/ size 2)) (fourth-root 2))) :height (/ (* 1000.0 (fourth-root 2)) (Math/pow 2 (/ size 2)))} {:size (str "A" size) :width (/ (* 1000.0 (fourth-root 2)) (Math/pow 2 (/ (inc size) 2))) :height (/ 1000.0 (* (Math/pow 2.0 (/ (dec size) 2)) (fourth-root 2)))}))  So how do we correctly calculate the dimensions? We just go back to the basic principles: set the width of the previous size as the height of the new size, calculate the area of a given size by halving the area of the previous size, round down, and divive by height to get the new width: (defn iso-aseries-size [size] (if (= size 0) {:size (str "A" size) :height (round (* 1000.0 alpha-a)) :width (round (* 1000.0 (/ 1.0 alpha-a)))} (let [prev (iso-aseries-size (dec size)) area (* (:width prev) (:height prev)) new-area (floor (/ area 2.0))] {:size (str "A" size) :height (:width prev) :width (floor (/ new-area (:width prev)))})))  which returns the correct dimensions: pdfdata.paper> (map #(iso-aseries-size %) (range 11)) ;; => ({:size "A0", :height 1189, :width 841} {:size "A1", :height 841, :width 594} {:size "A2", :height 594, :width 420} {:size "A3", :height 420, :width 297} {:size "A4", :height 297, :width 210} {:size "A5", :height 210, :width 148} {:size "A6", :height 148, :width 105} {:size "A7", :height 105, :width 74} {:size "A8", :height 74, :width 52} {:size "A9", :height 52, :width 37} {:size "A10", :height 37, :width 26})  Comment 10 November 2019 Tiens ? Il y a un site web ici ?! (Bon, apparemment, il fallait mettre à jour la base de données, parce que comme quoi MySQL 4, c’est plus à la mode, alors je m’y suis mis. Je savais que j’allais me déguster du double-encodage UTF-8, je n’ai pas été déçu…) Comment 8 March 2015 , Cucumber-jvm Examples Updated I have recently updated the cucumber-jvm-examples to use the latest version of cucumber-jvm (1.2.2), and other libraries such as selenium and jetty. Enjoy! Comment 16 December 2013 Maven Tips: What I Wish I Had Been Told from the Start Maven is still very much alive, but still suffers from a serious lack of understanding. It can appear very daunting at first, and going through the documentation does not do much to make that feeling go away. Here are some tips that I would have loved being told when I first started using Maven. A Quick Introduction I won’t go into too much details (you probably already know about Maven’s dependency management) here, but will quickly describe what I think is important to know before using Maven. Maven helps you build a project. The way it does that is through the build lifecycle and the plugins. The lifecycle is made of phases that you can call explicitly on the command line, for example: mvn package  package is a phase part of the default build lifecycle, like compile or deploy. All the phases of the default lifecycle can be found in the reference. At each phase, Maven calls a goal in a plugin that does something for you. For example, the maven-compiler-plugin has a compile goal that compiles your java code during the compile phase of the lifecycle. You can also explicitly call a plugin on the command line, like: mvn clean:clean  which calls the clean goal on the maven-clean-plugin. By default this goal is bound to the clean phase, so you can call it by executing mvn clean. You can call any plugin by using its group id, its artifact id, its version and the goal you want to execute, e.g.: mvn org.codehaus.mojo:versions-maven-plugin:2.1:set -DnewVersion=1.2.3  (A plugin named blah-maven-plugin can be called by the shortened version of its name, blah. See also the Guide to Developing Java Plugins) To “bind” a plugin goal to a phase, you just need to define your plugin in your pom.xml, and define its execution to a phase of the lifecycle:  <plugin> <groupId>org.mirah.maven</groupId> <artifactId>maven-mirah-plugin</artifactId> <version>1.1-SNAPSHOT</version> <executions> <execution> <phase>compile</phase> <goals><goal>compile</goal></goals> </execution> </executions> </plugin>  Here we are attaching the mirah compile goal to the compile phase of the lifecycle. When Maven executes the compile phase, it will the compile the Mirah code for us. That’s pretty much the most important stuff you need to understand to get going with Maven: build lifecycle and plugin goals. Once you understand this, the hardest part is to find the plugin that does what you want, and going through its documentation to see how to configure it. Here are the Tips! In no particular order. How to find a plugin goals? Use the help goal for that plugin, for example: mvn dependency:help  You can also use the @help@ plugin:  mvn help:describe -Dplugin=de.saumya.mojo:rake-maven-plugin:1.0.0-rc3  How to get completion on the command line? Check out this project in GitHub. After a while it becomes impossible to do without. How to find a project dependencies? To list all the dependencies of the project: mvn dependency:list  To display a tree of the transitive dependencies of the project: mvn dependency:tree  How to download dependencies’ sources?  mvn dependency:sources  How to copy dependencies locally? Use: mvn dependency:copy-dependencies -DoutputDirectory=/tmp  This copies all the dependencies into the /tmp folder. To do this automatically during the package phase, add the plugin to your pom, as follows:  <plugin> <artifactId>maven-dependency-plugin</artifactId> <version>2.8</version> <executions> <execution> <id>copy-dependencies</id> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${project.build.directory}</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
</configuration>
</execution>
</executions>
</plugin>


See the maven-dependency-plugin page for more details.

How to remove the dependencies from the local repo?

mvn dependency:purge-local-repository


By default, purge-local-repository will then re-resolve your dependencies. If you don’t want that behaviour, add -DreResolve=false on the command line.

This is particularly handy when, for some reason, Maven is choking on a dependency that was temporarily unavailable, stubbornly refusing to download it again.

How to find a dependency?

To find the coordinates of a dependency, you can use http://mvnrepository.com. You can also use a ruby gem I have written, called mvnizer. Once installed (gem install mvnizer), you can easily search for existing artefacts:

$mvnizer search slf4j-simple org.slf4j:slf4j-simple:1.7.5:jar com.googlecode.sli4j:sli4j-slf4j-simple:2.0:jar  How to add a dependency? You can copy/paste the coordinates from mvnrepository. You can also use mvnizer: mvnizer add org.slf4j:slf4j-simple:1.7.5:jar  Beware, mvnizer applies its own formatting to your pom file. How to update dependencies to their latest versions? mvn versions:use-latest-releases  See versions-maven-plugin page for more details. How to see if there are recent versions of the plugins you use? mvn versions:display-plugin-updates  See versions-maven-plugin page for more details. How to change the version of my project? Use: mvn versions:set -DnewVersion=1.2.3  Generally speaking, for anything that deals with the version of your project (and its submodules) or its dependencies, use versions-maven-plugin. How to add locations for code or tests? Use build-helper-maven-plugin. Example:  <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <version>1.8</version> <executions> <execution> <id>add-source</id> <phase>generate-sources</phase> <goals> <goal>add-test-source</goal> </goals> <configuration> <sources> <source>src/it/java</source> </sources> </configuration> </execution> </executions> </plugin>  How to store properties in external files? Use properties-maven-plugin. Example:  <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>properties-maven-plugin</artifactId> <version>1.0-alpha-2</version> <executions> <execution> <phase>initialize</phase> <goals> <goal>read-project-properties</goal> </goals> <configuration> <files> <file>example.properties</file> </files> </configuration> </execution> </executions> </plugin>  Properties can then be stored in example.properties as key/value pairs: key1=value1 key2=value2  How to set the Main-Class in the MANIFEST file? Use the maven-jar-plugin.  <plugin> <artifactId>maven-jar-plugin</artifactId> <version>2.3.2</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <mainClass>org.example.YourMainClass</mainClass> </manifest> </archive> </configuration> </plugin>  How to create a standalone executable jar (i.e. an über-jar)? Use the maven-shade-plugin. Example:  <plugin> <artifactId>maven-shade-plugin</artifactId> <version>2.0</version> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>org.example.YourMainClass</mainClass> </transformer> </transformers> <artifactSet> <excludes> <exclude>rubygems:*</exclude> </excludes> </artifactSet> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> </execution> </executions> </plugin>  How to change the name of my artefact (name of war or jar)? Use finalName: <build> <finalName>new-name</finalName> . . . </build>  How to start a jetty server for your integration tests? Bind the run goal of the jetty-maven-plugin to the pre-integration-test phase, and bind stop to the post-integration-test phase:  <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>8.1.14.v20131031</version> <configuration> <stopKey>ungeduldig</stopKey> <stopPort>9995</stopPort> </configuration> <executions> <execution> <id>start-jetty</id> <phase>pre-integration-test</phase> <goals> <goal>run</goal> </goals> <configuration> <daemon>true</daemon> </configuration> </execution> <execution> <id>stop-jetty</id> <phase>post-integration-test</phase> <goals> <goal>stop</goal> </goals> </execution> </executions> </plugin>  Comment [2] 12 October 2013 Call Rake from Maven When it comes to interacting between Maven and Ruby, the TorqueBox JRuby Maven plugins are the best solutions. Mostly maintained by Christian (who has also done a lot of work converting JRuby to Maven), they work quite well, albeit lacking in documentation. As part of these plugins, the rake-maven-plugin allows you to call Rake tasks in a project, which can be useful if the build tool of your comapny is based on Java, but your project is Ruby-based (and you don’t want to use JRuby). To illustrate its use, we’ll use a very straightforward Rakefile: task :do_that_thing do puts " *** RAKE RUNNING ***" end  It has a unique task, do_that_thing, that we’ll call from Maven. In the pom, you need to add the rake-maven-plugin:  <plugin> <groupId>de.saumya.mojo</groupId> <artifactId>rake-maven-plugin</artifactId> <version>1.0.0-rc3</version>  We are now going to define its execution, and tie it to the verify lifecycle step (you can choose what step you want):  <executions> <execution> <id>run-spec</id> <phase>verify</phase> <goals> <goal>rake</goal> </goals> <configuration> <args>do_that_thing</args> </configuration> </execution> </executions> </plugin>  The goal we are calling on the Rake plugin is rake, and the name of the Rake task is passed in args. As we are using Rake, we need to define a gem dependency to rake. To do so, you first need to add the rubygems Maven repo provided by TorqueBox:  <repositories> <repository> <id>rubygems-releases</id> <url>http://rubygems-proxy.torquebox.org/releases</url> </repository> </repositories>  You can then add the dependency to the rake gem:  <dependencies> <dependency> <groupId>rubygems</groupId> <artifactId>rake</artifactId> <version>10.1.0</version> <type>gem</type> </dependency> </dependencies>  Running mvn verify will then execute the Rake task. The full example can be found on my GitHub repo, rake-maven-example. To get more details about the Rake maven plugin (or any plugin at all in general), the help plugin comes, as usual, quite handy: mvn help:describe -Dplugin=de.saumya.mojo:rake-maven-plugin:1.0.0-rc3 -Ddetail  Comment 20 April 2013 Find in What Jar a Class Is Oh my. Somebody’s been exceedingly verbose… Here’s another attempt: Comment [1] 20 April 2013 Java Annotations with JRuby: A Spring MVC Example To illustrate the use of Java annotations with JRuby code, I have put together a little Spring MVC example. This is quite straightforward, especially if you are familiar with Spring MVC already. The Controller in JRuby The “heart” of the app is the Spring MVC controller which must be annotated with the Controller annotation, and its request path defined with the RequestMapping annotation: We also put the class in the com.weblogism.myapp package, we’ll see why in a second. Spring Configuration The Spring MVC configuration is pretty much “standard”: It defines the component-scan tag that will look for all the classes annotated with Controller in the com.weblogism.myapp; you now see why we used java_package for our controller. Compiling The compiling and packaging is done by Maven. Again, nothing really extraordinary in the pom.xml. The only unconventional feature is the use of the jruby-maven-plugin to compile our JRuby class into a Java class: It generates its output into target/generate-sources/jruby, and compiles out class into target/classes, like any other Java class. The output of the build is a war file that can be deployed in a Java EE container. Running To see our amazing app in action, run Jetty:  mvn jetty:run  Once Jetty is up, you can access the app at http://localhost:8080/welcome.html Comment [1] 12 April 2013 Cucumber-jvm 1.1.3 issue with JSON formatter I have been struggling with a weird cucumber issue today, as it took me some time to figure out what was going on, I thought I’d share this in case somebody is going down the same path. It started when I decided to upgrade my cucumber-jvm example to the latest version (1.1.3). Quickly after upgrading, I hit that error: java.lang.ArrayIndexOutOfBoundsException: -1 at java.util.ArrayList.get(ArrayList.java:324) at gherkin.formatter.JSONFormatter.getFeatureElement(JSONFormatter.java:199) at gherkin.formatter.JSONFormatter.addHook(JSONFormatter.java:156) at gherkin.formatter.JSONFormatter.before(JSONFormatter.java:147) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)  This is known issue, that has already been fixed in gherkin. So I rebuilt gherkin locally, thinking it would solve all my problems, and I was still the exact same error, at the same line number. After changing version, deleting the jar from the Maven repository, I was still getting the same error, so it was clear that the class was being pulled from somewhere else. It turns out the jar was being pulled from cucumber-picocontainer, which uses shade to create an über-jar with its dependencies, including gherkin. How did I figure that out? Using this piece of code:  URL location = JSONFormatter.class.getProtectionDomain().getCodeSource().getLocation(); System.err.println(location.getPath());  The solution to the problem is therefore to rebuild gherkin, then cucumber-picocontainer, and you’re sorted. Alternatively you can also just rebuild gherkin, and then make sure it is defined before cucumber-picocontainer:  <dependency> <groupId>info.cukes</groupId> <artifactId>gherkin</artifactId> <version>2.11.8</version> <scope>test</scope> </dependency> <dependency> <groupId>info.cukes</groupId> <artifactId>cucumber-picocontainer</artifactId> <version>1.1.3</version> <scope>test</scope> </dependency>    Comment [2] 8 October 2012 joblist.ie now live! A new job website for Ireland IT companies has been launched; the frontend is HTML5 and Backbone.js. It is still work in progress, and lots of cool features are coming up. Comment 7 September 2012 How to use System Properties and Maven profiles to change Cucumber-jvm’s behaviour In a previous post, I had shown how to use Maven profiles to execute integration tests with cucumber-jvm. I have now updated the example to use WebDriver rather than selenium RC, and to show how to use the cucumber.options system properties to change the cucumber-jvm runtime behaviour. To use cucumber.options and its default value, you create a variable: that you can then use as a system variable for failsafe: It is then straightforward to override these options using a profile to run different tags or produce different reports depending on the development cycle you are in: It is also possible to override these options using the command line by executing: mvn install -Dcucumber.options="--tags @foo --format pretty --monochrome"  Passing your own properties If you need to define your own properties and want to pass them either from the command line with -D=, or from the <properties> tag, and want to be able to retrieve these system properties from your step definitions, you must add an entry in the systemPropertyVariables tag when configuring failsafe. For example, say you want to have a ui.language property, add that property to the properties tag: <properties> <ui.language>FR</ui.language> . . . <cucumber.options>--format html:target/cucumber --tags @wip,@foo</cucumber.options> </properties>  This will give you the “default” value for your property; then add it to systemPropertyVariables:  <plugin> <artifactId>maven-failsafe-plugin</artifactId> <version>2.12</version> <executions> <execution> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> </execution> </executions> <configuration> <systemPropertyVariables> <cucumber.options>${cucumber.options}</cucumber.options>
<ui.language>\${ui.language}</ui.language>
</systemPropertyVariables>
</configuration>
</plugin>


This will cause failsafe to pass on this property to the forked JVM running the tests. You can then override the “default” property either in a profile, or on the command line:

mvn install -Dui.language=EN


Note that this will work properly when cucumber-jvm 1.0.15 is released; until then you need to re-define the glue and path to features if you override cucumber.options, as setting that system properties clears all options set by the Cucumber.Options annotation.

30 April 2012

Integration Tests with Cucumber-jvm, Selenium and Maven

This post will show how to use cucumber-jvm and Maven to run integration tests with Selenium on a regular webapp; as you’ll see, this is more of a Maven exercise than a cucumber-jvm one, as Cucumber tests are simply executed as JUnit tests. It can be a bit tricky as it requires a bit of Maven build lifecycle knowledge1, but once you get the idea, it all makes perfect sense.

For those only interested in the example, you will find it there.

The first thing we want to do is to segregate the integration tests from the unit tests. The reason for this is that it makes it easier to locate them, but also it allows you to run them separately: this is especially important if you want run the integration tests as part of your CI build. I personally prefer to have my integration tests under src/it/java, and suffixed with IT, so to do this, we first create a new profile and add the maven-failsafe-plugin:

The profile will be helpful to separate the integration tests execution if you want to run only in certain situations; it can also be used to define property values specifically for integration tests.

We then create the src/it/java and src/it/resources folders: src/it/resources will contain the feature files, whereas src/it/java will contain the step definitions and the JUnit test cases to be executed. We also need to add the new source folders to
the build with the build-helper-maven-plugin:

The JUnit test case is very simple:

It actually is empty: it cannot contain any method. It uses the Cucumber JUnit runner. The Cucumber.Options can be used to specify the format of the report created during the test, the feature files to execute, or the tags to run.

Next, the feature file is here somewhat trivial:

Finally, here are the step definitions:

As you can see, we are using the Selenium client in this step definition. We therefore need to add the dependencies to selenium (along with the cucumber-jvm ones) in our profile:

We also need to start the selenium server before the tests begin:

This plugin defines here two executions: start-selenium-server, which is executed before the integration tests during the phase called pre-integration-test, and calls the start goal, and stop-selenium-server called after the integration tests, during the post-integration-test phase, and that calls the stop goal of that plugin (for a reminder of the different phases of the build lifecycle, see the reference).

Finally, we configure the Jetty maven plugin to start and deploy the war we want to test:

Similarly to the selenium plugin, we start the Jetty server pre-integration-test (by running the run goal, and stop it post-integration-test with the stop goal.

We can now execute the tests by running:

 mvn clean verify -Pintegration-tests


The -P flag indicates that Maven must activate the integration-tests profile; as the plugins and dependencies are defined in that profile, the integration tests will only be executed if you activate that profile.

Summary

All the required “services” (Jetty, Selenium) are started during the pre-integration-test phase, and then stopped during the post-integration-test phase. The cucumber integration tests stored in src/it/java are executed during the integration-test phase by running the JUnit tests that use Cucumber.class as a runner.

To run the integration tests:

• Create a new profile,
• Add src/it/java as a test source folder,
• Implement the step definitions,
• Add the failsafe plugin,
• Add the selenium server plugin,

Hope this helps!

1 Once you’ve understood the build lifecycle, you understand Maven, so most definitely a knowledge worth having!

Comment [13]

5 March 2012

Example of .jrubyrc

I have put together an example of .jrubyrc, which can prove very useful when working on JRuby devs:

Comment

28 November 2011

Closed root in LaTeX

Stefan Kottwitz on how to make closed root symbols. Cool.

8 September 2011

,

Ruby, mongodb, genome... Cool.

Probably not what Mr. Yegge had in mind, but still inspiring all the same: analysing how many SNPs are in common between different populations using ruby and mongodb.

SNP (snip) stands for single-nucleotide polymorphism it is a variation of a single base pair amongst individuals of a species. SNPs can occur in coding and non-coding sequences, or between genes in the genome and can be used to identity genotypes.

(Pity MS isn’t a genetic condition)

On another note:

Comment [1]