update with the new theme

This commit is contained in:
Alexis Métaireau 2012-11-20 19:04:32 +01:00
parent e66e36f18f
commit fac07741e1
29 changed files with 572 additions and 372 deletions

View file

@ -1,4 +1,4 @@
build:
pelican -s pelican.conf.py .
pelican -s pelican.conf.py content
upload: build
rsync -e "ssh -p 22" -P -rvz --delete output/* alexis@172.19.2.119:/home/www/notmyidea.org/blog

View file

@ -0,0 +1,190 @@
Carto Forms - First steps
#########################
:status: draft
For an introduction on carto forms, please see this blog post:
http://blog.notmyidea.org/carto-forms.html (and its variant in french if you
prefer: http://blog.notmyidea.org/carto-forms-fr.html)
So, let's not talk too much about what we want to do, and rather explain how we
will do it instead ;)
Writing this article turned out to dump my thinking while bootstraping the
project, so I'm really explaining how I'm getting from here to there ;)
First step: defining a way to describe forms
============================================
What we want is a generic way to describe forms. I'm not sure if such a thing
exist. And, because I'm on a train atm, let's suppose there isn't anything like
this already (which is probably a wrong assumption, but, let's stick with that
for now).
What do we want? A way to associate titles, descriptions to a field. We also
want to be able to describe what's *in* the field (the type of content), and if
it is a repeatable field or not. In the case of a selection, we might also want
to have a list of possibilities somewhere. Let's take a simple example:
Title: Ads spots
Description: Describe all the ads spots in Paris
Fields:
- location (geoloc/address/lat-long)
- size *the size of the ad* (choice list: small/medium/big/huge)
- light *is there light on it?* (boolean)
Okay, so what we have here is in the form: name *description* (type of field).
In some way, we need to separate the widget that will be displayed to the user
from the type of data. What we need here is the type of data, the widget thing
should be decided at a different layer. So, let's refine the "location" field
to "location (SIG point)".
Okay, we now know what we want to save. Yet, we need to define the format.
At this point, I'm wondering if I should use XML, YAML or JSON to describe this
data. To be able to choose, listing the potential consumers / providers of data
can help. The first consumer of this data will be a REST API, and the first
producer will be, probably javascript (or whatever techno is used on the
client). Of course, we can provide lots of format on the REST API and depend
on the "Content-Types" header to know how to talk to it, but well, do we really
want or need to do that? Let's assume no for now and stick with JSON, because
it's now easily validable and I can't think of a language without a lib for it
(apart COBOL, of course).
Hey-hi, JSON. How does our data look with you? Let's dump a python structure
and dump it with `json.dumps`::
data = {
'title': 'Ads spots',
'description': 'All the ads spots in paris',
'fields': (
{'name': 'location', 'type': 'SIG point'},
{'name': 'size', 'type': 'choice', 'description': 'the size of the ad',
'choices': ('small', 'medium', 'big', 'huge')},
{'name': 'light', 'desciption': 'is there light on it?', 'type': 'bool'},
)}
import json
json.dumps(data)
… and the result is (ran with `python data.py | python -m json.tool`) …::
{
"title": "Ads spots"
"description": "All the ads spots in paris",
"fields": [
{
"name": "location",
"type": "SIG point"
},
{
"choices": [
"small",
"medium",
"big",
"huge"
],
"description": "the size of the ad",
"name": "size",
"type": "choice"
},
{
"desciption": "is there light on it?",
"name": "light",
"type": "bool"
}
],
}
Validating the form definition
==============================
JSON is nice to us, JSON schema now exists and there are tools to work with it.
Quickly, it's the same kind of things than what's provided by XML Schema: you
create a schema, pass it some data and it's able to tell you if the data
complies with the schema. If not, it gives you a nice list of wrong fields.
The second option, in python, is a tool named colander, which approximately
does the same thing, but with its own syntax.
FIXME need to dig on json schema here and do an approx schema for this.
Creating the forms
==================
The next step is to actually create a form from this. Python, and django in
particular, have nice APIs to do that in python. However, I don't know how
they internally work, but you can pass to it some data provided by an HTTP POST
request and it will tell you if it validate or no.
The problem with django is that you're tied to it, and it's not possible (well,
as far as I know) to get only the validation bits out of it. On the other hand,
the form framework already comes with nice geolocation facilities. It could be
nice to have a tool able to parse the format we defined and to generate django
models out of it.
We need to be careful here: what I'm talking about is to generate code… Well,
there are two approches to do that: either we generate a python file and parse
it, or either we can read the json data and programatically create a form out
of it, at runtime. We might want to cache this at some point to avoid doing it
each time, but let's consider it's another problem we will tackle later.
So, django internals!
Let's loop on the fields provided by our format and generate the form. We will
care about how to store this / retrieve it later :)
Oh, but wait. I'm talking about forms but I should be talking about models!
Validation is one thing, but what we want to do is to describe the data we will
be handling. Forms will just be the user facing thing and what will to the
validation!
Django, no django? Let's think about this one more time. There is another
competitor on this field, because we are talking about storing information that
are changing all the time and to base validation on them: CouchDB! And there
also is GeoCouch, which brings interesting SIG features to Couch. And it's
talking JSON!
Creating a new form should be as easy as this::
$ curl -X POST localhost:5984/cartoforms/ -d "`python test.py`" -H "Content-Type: application/json"
{"ok":true,"id":"2d58ef2b02eae639b3f94e357a000d26","rev":"1-0462d0827e7cdad20b5703a923249220"}
Hmm, wait, this is cool but we got this hideous hash. Let's change this to a
PUT instead::
$ curl -X PUT localhost:5984/cartoforms/paris-ads -d "`python test.py`" -H "Content-Type: application/json"
{"ok":true,"id":"paris-ads","rev":"1-0462d0827e7cdad20b5703a923249220"}
Of course, we can already retrieve this with a GET::
curl -X GET localhost:5984/cartoforms/paris-ads -d "`python test.py`"
{"_id":"paris-ads","_rev":"1-0462d0827e7cdad20b5703a923249220","fields":[{"type":"SIG
point","name":"location"},{"choices":["small","medium","big","huge"],"type":"choice","name":"size","description":"the
size of the ad"},{"type":"bool","desciption":"is there light on
it?","name":"light"}],"description":"All the ads spots in
paris","title":"Ads spots"}
Validation? Yes, you're completely right: we need validation for this. Because
in this current state, anyone can just insert whatever data they want into this
system, which could become a problem at some point.
Let's say we don't care who is able to publish to the DB, until we know that
what's being posted complies with a certain format. And, guess what's cool?
CouchDB provides validators. Yeah, I agree, it's somewhat exhausting to realize
that we have all this for free, but, heh, that's open source, dude!
Adding validation!
==================
So, we described our format already, what we need to do is to create a couchdb
validator which is able to filter this.
Hmm, I don't remember how they are named (will find out in the couch
documentation), but if I remember correctly, you can hook up some javascript
functions to each POST / PUT, to check that the data inserted is correct, and
output appropriate error messages when it's not what you expected.
Yeah, this means writing javascript, which is cool because I wanted to re-learn
how to do javascript!
… train arrives to station, see you next :)

View file

@ -0,0 +1,14 @@
Python, functools and aliases
#############################
:status: draft
I have been playing lately with python and functools to make method aliases. I
wanted to have something like this.
.. code-block:: python
class Baby(object):
def eat(self, thing):
self.intestine.digest(thing)

View file

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 104 KiB

View file

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 117 KiB

BIN
content/images/daybed.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

View file

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 118 KiB

View file

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View file

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

View file

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View file

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 127 KiB

View file

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View file

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 119 KiB

View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,58 @@
API description using cornice and colander
##########################################
:status: draft
One of the goals we want to accomplish with Cornice is to describe the web
services in a nice and easy way, for the developer. This for different reasons.
Having web services described in some ways allows you do do interesting things,
such as automatically generating a documentation, or a client, for instance.
REST services are supposed to be discoverable, but in a lot of situations,
that's not the case, and it can be a pain to implement a client for them, even
if most of what is being done there is shared between a lot of web services.
In cornice, we alreadygenerate some documentation, but this one is incomplete in
different ways. For instance, it is currently not possible to get information
about the inputs you are waiting for, in the different locations (body,
headers and query string).
For instance, if you want to describe that a *POST* on `/foobar` needs the
*foo* and *bar* parameters, and that you eventually could add a *baz*
parameter, you can't, or you have to describe it manually in the documentation
of the web service.
Cornice, while not tied to `Colander`_, tries to make a good use of it when
possible. So it is possible to do validation of the incoming data (in different
locations) and, at the same time, documentation of the web service.
To do so, you have to use a particular `schema` keyword in the decorator. Here
is an example of definition
.. code-block:: python
from cornice import Service
from colander import MappingSchema, SchemaNode, String
foobar = Service(name="foobar", path="/foobar")
class Foobar(MappingSchema):
foo = SchemaNode(String(), location="body")
bar = SchemaNode(String(), location="headers")
baz = SchemaNode(String(), default=None)
@foobar.get(scheme=Foobar)
def foobar_get(request):
# do something here
.. _Colander: http://docs.pylonsproject.org/projects/colander/en/latest/
The output documentation currently looks like this:
.. image:: images/cornice-exampledoc-validation.png
The plans for the future are to be able to put direct curl calls in the
documentation to demonstrate how the service behaves for instance, and why not
creating a tiny python client able to consume the cornice APIs.

View file

@ -0,0 +1,87 @@
Mozilla - The sagrada token server
##################################
:date: 19-03-2012
:tags: sagrada, python, browserid
:status: draft
Since I started, back in december, we started a new project on the services
team, which aims to bring a central authentication point on our server side.
This had been motivated by the fact that we are switching our services
authentication mechanism from basic HTTP auth to browserid (this was basically
for sync in the first place, and now for AITC, a.k.a Market Place APIs).
- A Token Server ?
- Services architecture (server / nodes)
- MAC auth
- Crypto / Signing
- HKDF
- Signing the tokens
- Parsing browserid assertions
- Resources
A token server ?
================
So, we don't want to be tied to any authentication mean on our platform. The
best way to accomplish this is to chose one and to provide a way to map all the
potential authentication means to the chosen one.
In addition to trade a browserid assertion for another authentication token,
the mission of the token server is to retrieve the node allocation of a
particular user, and eventually assign it to a node.
To resume, we take any authentication scheme (browserid for now) and
trade it for another one we can use for all of our services. This has several
advantages:
* We don't need to check the browserid assertion at each request. This avoids
doing crypto at each request.
* As said, we are able to deal with different authentication schemes. If we
want to use openid, we just need to add support for it on one location
* The node allocation is done anyways (the user need to know wich node it is
assigned to) so it doesn't add an extra call for this.
Our architecture
================
I'm talking about nodes, users and services. Let's clarifiy a bit all this.
Because at the services team, we mostly care about being able to scale our
infrastructures without (too much) pain, we try to avoid SPOFs (Single Point Of
Failure) of any sort. For this purpose we expose at the authentication layer
information about the node that need to be retrieved by the clients.
What? clients? Okay, here is what the authentication looks like::
User-Agent Token Server Node
| | |
| <bid assertion> | |
|----------------------->| |
| | |
|<token + userid + node> | |
|<-----------------------| |
| | |
| <service-data + token> |
|----------------------------------------------->|
In HTTP terms, looks like this, the user agent (client) gives a browserid
assertion and receives back information about the service it should deal with
::
> HTTP POST http://token.services.mozilla.org/1.0/<app>/<app-version>
> Data: # some authentication information (browserid assertion in our case)
< Header: 200 OK
< Data: "{'id': token, 'key': secret, 'uid': uid, 'api_endpoint': api_endpoint}"
(This is an hand crafted request/response flow)
We don't bother about the signing and crypto details in here as it is explained
in a later section, but basically, we asked for a node, with a specific
browserid assertions and now we have an *api_endpoint* to send our requests
against, along with the token.
Crypto details
==============
All the flow is explained in our documentation, for the token server

View file

@ -0,0 +1,83 @@
walint - tilt
#############
:status: draft
Things start to fold together. I still need some time to be up to
speed (new job / new city / new people), but the projects I'm working on are
pretty exciting and I like what I'm doing. We've been working with Tarek on a
tool about web services testing.
At Mozilla, we produce and consume web services. As an organisation defending
web standards, providing services that match these specifications is the least
we can do.
Web App Lint (WALint) is a simple tool to help you to test your web services
against the HTTP specification. The goal is to detect potential problems a
service could be subject to, and to provide a simple-to-configure tool to test
your WS against HTTP as speced. The long term goal is to be exhaustive on the
controllers we provide, but if you have special needs, you should be able to
define tests in a simple way.
As everything we do at Mozilla, the tool is an opensource project. Our goal is
to have something useful for web service consumers and providers. If you think
you can be of any help, don't hesitate to drop me an email or fork on github.
Testing the HTTP specification
==============================
A lot of web services are written on top of HTTP. The protocol is fully
described in a specification and introduce some really interesting stuff we
should care about when implementing our services. This tool wants to check this
up and provide a ways to ensure that you are defining your web services the
right way. It's not a replacement for manual service testing, thus: you still
have to test that your web service is doing what you think it does. WALint is
checking the stuff we almost forgot all of the time.
For instance, the HTTP specification specifies that if the client sends a
request with a Content-Type not handled by the server, it should answer with a
"406 Not Acceptable" and should return the list of accepted headers (so the
client is able to send again the request with the right accept header). We also
check that sending weird data (broken json objects or authentication headers)
does not break the tested service.
Obviously, we don't have all the scenarios in mind, and they aren't all
implemented. That's where being an open source project makes sense. You, as
service providers and consumers, know what are the kind of mistake you are used
to do / to deal with. It should make "tilt": fork the project and write some
lines checking the particular behavior that's disturbing you, everyone will
enjoy it. If you prefer, just open a ticket and we'll care about the
implementation.
The documentation defines a list of all the implemented controllers:
http://packages.python.org/walint/controllers.html
What does it looks like?
========================
Here is an example of a configuration file: you describe the paths and
signatures of your web services, the controllers you want to use and the test
scenarios you want to run, that's it, just run "walint config.cfg" and you're
good.
Here's a capture of the output of the command line invocation: you get all the
paths tested with the different listed methods, and if needed what's not
working. In the future, why not putting some documentation online with
information about how to fix common mistakes?
We also provide a wizard so it's possible to describe your web service in a
simple and easy way. Just invoke it with "walint --create config.cfg".
What's next ?
=============
We plan to do some fun stuff with WALint. Here are some thoughts:
* service discovery: just provide an API root URI and we'll try to discover
what's in there and how to generate configuration files
* unittest integration, so it's possible to have an unified way to describe web
services with existing tools. (heh, we can do Web Services CI the easy way!)
* integration with cornice description language and other web services description
languages (still to be defined)
* your ideas, so please fill issues and provide us feedback, it's useful!

View file

@ -0,0 +1,84 @@
Mozilla's weekly update #1
##########################
:date: 20-09-2012
:status: draft
My day-to-day work is changing a lot these days, as I'm working on different
tools and working across different teams. I thought it could be useful to have
a place to put updates weekly about what's going-on. This can be extra useful
for folks that are not on the same timezone I am (I'm looking at you,
California), so let's try this.
I'm not used to post regularly, but I will try to update the blog with an entry
each week, if there is something interesting to say.
Circus
======
As you may know, last week we had a sprint about Circus at PyconFR, we now have
a bunch of folks interested by the project now, and some activity on our irc
channel (#mozilla-circus on freenode).
I've written `a more comprehensive wrap-up about this sprint
<http://blog.notmyidea.org/circus-sprint-at-pyconfr.html>`_, so have a look at
it if you're interested!
Vaurien
=======
Vaurien is a TCP proxy which can be useful for our load-testing. its goal is to
sometimes let the traffic go trough, sometimes play a bit with it (add delays,
timeouts, close the socket etc) to check how the stack is behaving when under
pressure.
The code isn't used to test our services yet but we have something interesting
to show: http://github.com/mozilla-services/vaurien/
I will not explain the specifics here, I've tried to make `the README
<https://github.com/mozilla-services/vaurien#vaurien>`_ explicit enough.
Marteau
=======
`Marteau <https://github.com/mozilla-services/marteau/>`_ is the tool we're
using to throw load-test to our services, to check that they're able to handle
it. It's basically a frontend to Funkload. Tarek worked on adding real-time
feedback from the nodes (when in distributed mode, Funkload clients are
deployed on some nodes and send traffic to the service from there), and I am
working on making this available on the web interface. This means playing a bit
with web-sockets and javascript, yay.
Marketplace packaging
=====================
Currently, the application behind market place, `Zamboni
<https://github.com/mozilla/zamboni>`_ uses a non-standard mechanism to deal
with its dependencies. A `vendor` folder contains the packages themselves, in
the form of git submodules. This comes with some drawbacks such as the fact
that it's not easy to upgrade dependencies etc, and very long updates of the
repository, into other things.
We were also dependant on github to deploy Marketplace, which isn't reliable at
all, especially when you know that github was down last week, for instance. We
now have a local PyPI mirror at Mozilla, and we use it to avoid reaching the
internet for something else than our code.
This also means that we need to pull all the dependencies out of this `vendor`
folder, and rely on PyPI packages when they are up to date. Then we will be
able to directly use `pip` to deal with dependency management and packaging.
Splitting up the Marketplace
============================
Zamboni is currently one big django project. This led to something quite hard
to understand and hard to deal with., especially for newcomers. Also, it means
that all the aspects of the site are inter-connected and that you need to be
comfortable with the whole infrastructure of the project to add new features
/ fix bugs.
Splitting this big project into smaller chunks can allow to have something
easier to work on. We're trying to do that these days. More on this later :)
That's all for now, I'll try to keep you posted on all this, see you next week
:-)

View file

@ -1,7 +1,6 @@
Cheese & code - Wrap-up
#######################
:status: draft
:date: 2012-10-22
This week-end I hosted a *cheese & code* session in the country-side of Angers,

View file

@ -0,0 +1,46 @@
Focusing on what's important
############################
:date: 16-03-2012
:tags: focus, time-management
:status: draft
I do have a problem with information.
Information overload.
This thing that makes me check my emails, irc, twitter, my feed reader etc.
This thing that makes me feel uncomfortable at the end of the day, because I
feel that I missed something. That I missed some good time, away from news and
agitation.
What do I need? I tried to change my tools, it helped a bit, Still, I'm not
focused like I would like to be. I've tried the pomodoro technique but… I'm not
yet convinced, mostly because this means me being interrupted every 20 minutes.
Maybe that's just me who needs some more persuasion over myself, but the best
way I found to work is to unplug the cable. Literally. At work, I'm using a
RJ45 cable to connect to the internet. When I want to work on something,
I just unplug this cable.
And that's amazing how you find yourself in the process to "check"
something on the web. Mails, irc… well, you got the idea.
Of course, that web isn't filled only with lolcats and twitter messages
(even if I would **love** to see a pie chart with the repartition of lolcats
VS the rest of the web's content), so sometimes you need some precious bit of
information that's there. Fair enough. plug the cable, do what you **need** to
do, and unplug. Alexis, unplug!
I'm feeling adventurous, so I'll try something new starting tomorrow, and I'll
report back in here my findings. Here's the challenge:
* **Check emails only twice a day**. Do not do it in the morning, before
working, to keep my mind clear. I would say at 2pm (after lunch) and at 8pm.
(This doesn't mean I will not send mails tho)
* Stay away from the internet during the morning. I'll not connect if I don't
need to.
I still need to find a way to be reachable during these off-line periods,
because that could be very painful for the folks on my team otherwise. (the
good thing is that my morning is their nights).

View file

@ -1,87 +0,0 @@
@import url(http://fonts.googleapis.com/css?family=Rosario);
@import url("pygment.css");
@import url("typogrify.css");
body {
width: 800px;
margin: auto;
font-size: 1.3em;
background-color: #fffff0;
font-family: "Georgia", serif;
}
a{
color: #000;
}
nav ul {
list-style-type: none;
}
nav ul li {
float: right;
margin-left: 10px;
}
.content {
clear: both;
}
.content h1, h2, h3, h4, h5, h6{
font-family: 'Rosario', arial, serif;
margin-left: -20px;
}
.content h1{
font-size: 2.5em;
}
.content p{
font-size: 1.1em;
text-align: justify;
text-justify: newspaper;
}
.content .date{
font-style: italic;
font-size: 0.7em;
}
.content h2{
font-size: 1.5em;
}
.content a{
padding: 2px;
color: #0F0F0F;
}
.content a:hover{
background-color: #0F0F0F;
color: #eaeaea;
}
.content .highlight pre{
padding: 15px;
background-color: black;
color: white;
overflow: scroll;
}
.content blockquote {
margin: 0px;
margin-right: 40px;
margin-left: 20px;
padding-left: 20px;
text-align: left;
border-left: 3px black solid;
letter-spacing: 2px;
font-style: italic;
text-align: justify;
}
.description {
margin-top: -15px;
font-style: italic;
}

View file

@ -1,205 +0,0 @@
.hll {
background-color:#FFFFCC;
}
.c {
color:#408090;
font-style:italic;
}
.err {
border:1px solid #FF0000;
}
.k {
color:#007020;
font-weight:bold;
}
.o {
color:#666666;
}
.cm {
color:#408090;
font-style:italic;
}
.cp {
color:#007020;
}
.c1 {
color:#408090;
font-style:italic;
}
.cs {
background-color:#FFF0F0;
color:#408090;
}
.gd {
color:#A00000;
}
.ge {
font-style:italic;
}
.gr {
color:#FF0000;
}
.gh {
color:#000080;
font-weight:bold;
}
.gi {
color:#00A000;
}
.go {
color:#303030;
}
.gp {
color:#C65D09;
font-weight:bold;
}
.gs {
font-weight:bold;
}
.gu {
color:#800080;
font-weight:bold;
}
.gt {
color:#0040D0;
}
.kc {
color:#007020;
font-weight:bold;
}
.kd {
color:#007020;
font-weight:bold;
}
.kn {
color:#007020;
font-weight:bold;
}
.kp {
color:#007020;
}
.kr {
color:#007020;
font-weight:bold;
}
.kt {
color:#902000;
}
.m {
color:#208050;
}
.s {
color:#4070A0;
}
.na {
color:#4070A0;
}
.nb {
color:#007020;
}
.nc {
color:#0E84B5;
font-weight:bold;
}
.no {
color:#60ADD5;
}
.nd {
color:#555555;
font-weight:bold;
}
.ni {
color:#D55537;
font-weight:bold;
}
.ne {
color:#007020;
}
.nf {
color:#06287E;
}
.nl {
color:#002070;
font-weight:bold;
}
.nn {
color:#0E84B5;
font-weight:bold;
}
.nt {
color:#062873;
font-weight:bold;
}
.nv {
color:#BB60D5;
}
.ow {
color:#007020;
font-weight:bold;
}
.w {
color:#BBBBBB;
}
.mf {
color:#208050;
}
.mh {
color:#208050;
}
.mi {
color:#208050;
}
.mo {
color:#208050;
}
.sb {
color:#4070A0;
}
.sc {
color:#4070A0;
}
.sd {
color:#4070A0;
font-style:italic;
}
.s2 {
color:#4070A0;
}
.se {
color:#4070A0;
font-weight:bold;
}
.sh {
color:#4070A0;
}
.si {
color:#70A0D0;
font-style:italic;
}
.sx {
color:#C65D09;
}
.sr {
color:#235388;
}
.s1 {
color:#4070A0;
}
.ss {
color:#517918;
}
.bp {
color:#007020;
}
.vc {
color:#BB60D5;
}
.vg {
color:#BB60D5;
}
.vi {
color:#BB60D5;
}
.il {
color:#208050;
}

View file

@ -1,3 +0,0 @@
.caps {font-size:.92em;}
.amp {color:#666; font-size:1.05em;font-family:"Warnock Pro", "Goudy Old Style","Palatino","Book Antiqua",serif; font-style:italic;}
.dquo {margin-left:-.38em;}

View file

@ -1,30 +0,0 @@
{% extends "base.html" %}
{% block title %}{{ article.title }}{% endblock title %}
{% block content %}
<h1>{{ article.title }}</h1>
<p class="date">{% if article.lang == "fr" %}Publié le{% else %}Published
on{% endif%} {{ article.locale_date }}.
{% if article.translations %}
{% if article.lang == "fr" %}Vous pouvez aussi lire cet article en {% else %}You can also read this article in {% endif %}
{% for tr in article.translations %}
<a href="{{ SITEURL }}/{{ tr.url}}">{{ tr.lang }}</a>
{% endfor %}
{% endif %}
</p>
{{ article.content }}
{% if DISQUS_SITENAME %}
<div class="comments">
<h2>Comments</h2>
<div id="disqus_thread"></div>
<script type="text/javascript">
var disqus_identifier = "{{ article.url }}";
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://{{ DISQUS_SITENAME }}.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
</div>
{% endif %}
{% endblock %}

View file

@ -1,12 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="{{ SITEURL }}/theme/css/{{ CSS_FILE }}" type="text/css" media="screen" charset="utf-8">
<link href="{{ SITEURL }}/{{ FEED }}" type="application/atom+xml" rel="alternate" title="{{ SITENAME }} ATOM Feed" />
<title>Alexis Métaireau</title>
</head>
<body>
<div class="content clear">{% block content %}{% endblock %}</div>
</body>
</html>

View file

@ -1,23 +0,0 @@
{% extends "base.html" %}
{% block content %}
<p>Hi and welcome in this web logs. I try here to talk about freedom, free
software, activism and education. And about anything I think would be
valuable to share.</p>
<p>Bienvenue sur ces carnets. J'essaye de parler ici de liberté,
de logiciel libre d'activisme et d'éducation. Et finalement d'un peu tout
ce qui me passe par la tête et que j'ai envie de partager.</p>
{% for article in articles %}
<h2><a href="{{ SITEURL }}/{{ article.url }}">{{ article.title }} ({{article.lang}})</a>
{% if article.translations %}
<small>(also in {% for article in article.translations %}<a href="{{ SITEURL }}/{{ article.url }}">{{ article.lang }}</a>{% endfor %})</small>
{% endif %}
<span class="date">{{ article.date.strftime('%B %Y')}}</span>
</h2>
{% if article.description %}
<p class="description">{{ article.description }}</p>
{% endif %}
{% endfor %}
{% endblock %}

View file

@ -13,8 +13,8 @@ h1 {
.hentry {
border-left: 10px solid;
border-color: rgba(200, 200, 200, .2);
color: rgba(200, 200, 200, .1);
border-color: rgba(200, 200, 200, .4);
color: rgba(200, 200, 200, .3);
padding: 40px;
}
@ -32,15 +32,15 @@ article .category {
}
.dev, .python {
border-color: rgba(150, 200, 150, .2);
color: rgba(150, 200, 150, .1);
border-color: rgba(150, 200, 150, .4);
color: rgba(150, 200, 150, .3);
}
.asso {
border-color: rgba(200, 0, 0, .2);
color: rgba(200, 0, 0, .1);
border-color: rgba(200, 0, 0, .4);
color: rgba(200, 0, 0, .3);
}
.thoughts {
border-color: rgba(100, 0, 100, .2);
color: rgba(100, 0, 100, .1);
border-color: rgba(100, 0, 100, .4);
color: rgba(100, 0, 100, .3);
}

View file

@ -17,7 +17,7 @@
/***** Global *****/
/* Body */
body {
background: #F5F4EF;
background: url('../images/background.jpg') fixed;
color: #000305;
font-size: 87.5%; /* Base font size: 14px */
font-family: 'Trebuchet MS', Trebuchet, 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
@ -165,7 +165,6 @@ img.left, figure.left {float: right; margin: 0 0 2em 2em;}
}
#banner h1 a:hover, #banner h1 a:active {
background: none;
color: #C74350;
text-shadow: none;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB