Initial commit
127
Makefile
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
PY?=python3
|
||||||
|
PELICAN?=pelican
|
||||||
|
PELICANOPTS=
|
||||||
|
|
||||||
|
BASEDIR=$(CURDIR)
|
||||||
|
INPUTDIR=$(BASEDIR)/content
|
||||||
|
OUTPUTDIR=$(BASEDIR)/../mdk/
|
||||||
|
CONFFILE=$(BASEDIR)/pelicanconf.py
|
||||||
|
PUBLISHCONF=$(BASEDIR)/publishconf.py
|
||||||
|
|
||||||
|
FTP_HOST=localhost
|
||||||
|
FTP_USER=anonymous
|
||||||
|
FTP_TARGET_DIR=/
|
||||||
|
|
||||||
|
SSH_HOST=localhost
|
||||||
|
SSH_PORT=22
|
||||||
|
SSH_USER=root
|
||||||
|
SSH_TARGET_DIR=/var/www
|
||||||
|
|
||||||
|
S3_BUCKET=my_s3_bucket
|
||||||
|
|
||||||
|
CLOUDFILES_USERNAME=my_rackspace_username
|
||||||
|
CLOUDFILES_API_KEY=my_rackspace_api_key
|
||||||
|
CLOUDFILES_CONTAINER=my_cloudfiles_container
|
||||||
|
|
||||||
|
DROPBOX_DIR=~/Dropbox/Public/
|
||||||
|
|
||||||
|
GITHUB_PAGES_BRANCH=gh-pages
|
||||||
|
|
||||||
|
DEBUG ?= 0
|
||||||
|
ifeq ($(DEBUG), 1)
|
||||||
|
PELICANOPTS += -D
|
||||||
|
endif
|
||||||
|
|
||||||
|
RELATIVE ?= 0
|
||||||
|
ifeq ($(RELATIVE), 1)
|
||||||
|
PELICANOPTS += --relative-urls
|
||||||
|
endif
|
||||||
|
|
||||||
|
html:
|
||||||
|
$(PELICAN) $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS)
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo 'Makefile for a pelican Web site '
|
||||||
|
@echo ' '
|
||||||
|
@echo 'Usage: '
|
||||||
|
@echo ' make html (re)generate the web site '
|
||||||
|
@echo ' make clean remove the generated files '
|
||||||
|
@echo ' make regenerate regenerate files upon modification '
|
||||||
|
@echo ' make publish generate using production settings '
|
||||||
|
@echo ' make serve [PORT=8000] serve site at http://localhost:8000'
|
||||||
|
@echo ' make serve-global [SERVER=0.0.0.0] serve (as root) to $(SERVER):80 '
|
||||||
|
@echo ' make devserver [PORT=8000] start/restart develop_server.sh '
|
||||||
|
@echo ' make stopserver stop local server '
|
||||||
|
@echo ' make ssh_upload upload the web site via SSH '
|
||||||
|
@echo ' make rsync_upload upload the web site via rsync+ssh '
|
||||||
|
@echo ' make dropbox_upload upload the web site via Dropbox '
|
||||||
|
@echo ' make ftp_upload upload the web site via FTP '
|
||||||
|
@echo ' make s3_upload upload the web site via S3 '
|
||||||
|
@echo ' make cf_upload upload the web site via Cloud Files'
|
||||||
|
@echo ' make github upload the web site via gh-pages '
|
||||||
|
@echo ' '
|
||||||
|
@echo 'Set the DEBUG variable to 1 to enable debugging, e.g. make DEBUG=1 html '
|
||||||
|
@echo 'Set the RELATIVE variable to 1 to enable relative urls '
|
||||||
|
@echo ' '
|
||||||
|
|
||||||
|
clean:
|
||||||
|
[ ! -d $(OUTPUTDIR) ] || rm -rf $(OUTPUTDIR)
|
||||||
|
|
||||||
|
regenerate:
|
||||||
|
$(PELICAN) -r $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS)
|
||||||
|
|
||||||
|
serve:
|
||||||
|
ifdef PORT
|
||||||
|
cd $(OUTPUTDIR) && $(PY) -m pelican.server $(PORT)
|
||||||
|
else
|
||||||
|
cd $(OUTPUTDIR) && $(PY) -m pelican.server
|
||||||
|
endif
|
||||||
|
|
||||||
|
serve-global:
|
||||||
|
ifdef SERVER
|
||||||
|
cd $(OUTPUTDIR) && $(PY) -m pelican.server 80 $(SERVER)
|
||||||
|
else
|
||||||
|
cd $(OUTPUTDIR) && $(PY) -m pelican.server 80 0.0.0.0
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
devserver:
|
||||||
|
ifdef PORT
|
||||||
|
$(BASEDIR)/develop_server.sh restart $(PORT)
|
||||||
|
else
|
||||||
|
$(BASEDIR)/develop_server.sh restart
|
||||||
|
endif
|
||||||
|
|
||||||
|
stopserver:
|
||||||
|
$(BASEDIR)/develop_server.sh stop
|
||||||
|
@echo 'Stopped Pelican and SimpleHTTPServer processes running in background.'
|
||||||
|
|
||||||
|
publish:
|
||||||
|
$(PELICAN) $(INPUTDIR) -o $(OUTPUTDIR) -s $(PUBLISHCONF) $(PELICANOPTS)
|
||||||
|
|
||||||
|
ssh_upload: publish
|
||||||
|
scp -P $(SSH_PORT) -r $(OUTPUTDIR)/* $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR)
|
||||||
|
|
||||||
|
rsync_upload: publish
|
||||||
|
rsync -e "ssh -p $(SSH_PORT)" -P -rvzc --delete $(OUTPUTDIR)/ $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR) --cvs-exclude
|
||||||
|
|
||||||
|
dropbox_upload: publish
|
||||||
|
cp -r $(OUTPUTDIR)/* $(DROPBOX_DIR)
|
||||||
|
|
||||||
|
ftp_upload: publish
|
||||||
|
lftp ftp://$(FTP_USER)@$(FTP_HOST) -e "mirror -R $(OUTPUTDIR) $(FTP_TARGET_DIR) ; quit"
|
||||||
|
|
||||||
|
s3_upload: publish
|
||||||
|
s3cmd sync $(OUTPUTDIR)/ s3://$(S3_BUCKET) --acl-public --delete-removed --guess-mime-type
|
||||||
|
|
||||||
|
cf_upload: publish
|
||||||
|
cd $(OUTPUTDIR) && swift -v -A https://auth.api.rackspacecloud.com/v1.0 -U $(CLOUDFILES_USERNAME) -K $(CLOUDFILES_API_KEY) upload -c $(CLOUDFILES_CONTAINER) .
|
||||||
|
|
||||||
|
github: publish
|
||||||
|
ghp-import -m "Generate Pelican site" -b $(GITHUB_PAGES_BRANCH) $(OUTPUTDIR)
|
||||||
|
git push origin $(GITHUB_PAGES_BRANCH)
|
||||||
|
|
||||||
|
rsync:
|
||||||
|
rsync --delete -vah /home/mdk/my/www/ mdk.fr:/var/www/
|
||||||
|
|
||||||
|
.PHONY: html help clean regenerate serve serve-global devserver publish ssh_upload rsync_upload dropbox_upload ftp_upload s3_upload cf_upload github rsync
|
1
content/blog/.hyde_deps
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{}
|
109
content/blog/a-justintime-class.md
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
---
|
||||||
|
Title: A JustInTime class
|
||||||
|
Date: 2008-08-30 00:10:55
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
I discovered in my code a redundant pattern :
|
||||||
|
|
||||||
|
:::csharp
|
||||||
|
private SomeType _something;
|
||||||
|
private SomeType something { get { if (_something == null) _something = new SomeType(....); return _something;} }
|
||||||
|
|
||||||
|
Usefull in Silverlight, when your Blender always say "Can't compile !
|
||||||
|
Strange errors ! but compiles when i comment your WebClient... in ctor
|
||||||
|
of that class..." So i use it to have members builded the first time
|
||||||
|
they are used, "Just in time". /!\\ It's not a Singleton ! i can have
|
||||||
|
others instance of this class new-ing it directly ! /!\\ Singleton is
|
||||||
|
Evil // feed the Troll So i factorized it :
|
||||||
|
|
||||||
|
:::csharp
|
||||||
|
public class Jit
|
||||||
|
{
|
||||||
|
T _instance;
|
||||||
|
object[] _ctor_params;
|
||||||
|
|
||||||
|
public Jit(object[] ctor_params)
|
||||||
|
{
|
||||||
|
_ctor_params = ctor_params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Jit()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public T create(object[] ctor_params)
|
||||||
|
{
|
||||||
|
Type[] param_types = ctor_params.Aggregate>(
|
||||||
|
new List(),
|
||||||
|
(List lt, object o) =>
|
||||||
|
{
|
||||||
|
lt.Add(o.GetType());
|
||||||
|
return lt;
|
||||||
|
}).ToArray();
|
||||||
|
var ctor = typeof(T).GetConstructor(param_types);
|
||||||
|
if (ctor == null)
|
||||||
|
throw new Exception(param_types.Aggregate(
|
||||||
|
"No constructor found for " + typeof(T).Name + " taking",
|
||||||
|
(string i, Type t) => { return i + " " + t.Name; }));
|
||||||
|
return (T)ctor.Invoke(_ctor_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T create()
|
||||||
|
{
|
||||||
|
return (_ctor_params == null)
|
||||||
|
? create(new object[] { })
|
||||||
|
: create(_ctor_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T single()
|
||||||
|
{
|
||||||
|
if (_instance == null)
|
||||||
|
_instance = create();
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
A usage demo:
|
||||||
|
|
||||||
|
:::csharp
|
||||||
|
public class Test
|
||||||
|
{
|
||||||
|
Test(string foo, int bar)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Test ctor with : " + foo + " and " + bar);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void foo()
|
||||||
|
{
|
||||||
|
Console.WriteLine("bar");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class Page : UserControl
|
||||||
|
{
|
||||||
|
public event EventHandler my_event;
|
||||||
|
private Jit test = new Jit(new object[]{"42", 42});
|
||||||
|
|
||||||
|
public Page()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
// test is not yet built
|
||||||
|
test.single().foo(); // Whill build a Test and call foo()
|
||||||
|
test.single().foo(); // Whill call foo on the same Test.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
So a:
|
||||||
|
|
||||||
|
:::csharp
|
||||||
|
private SomeType _something;
|
||||||
|
private SomeType something { get { if (_something == null) _something = new SomeType(....); return _something;} }
|
||||||
|
|
||||||
|
become:
|
||||||
|
|
||||||
|
:::csharp
|
||||||
|
private Jit something = new Jit(new object[]{...});
|
||||||
|
|
||||||
|
Note the Jit ctor, taking a array of objects, it's the objects to pass
|
||||||
|
to your ctor's class (found by reflection using their types).
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
Title: ashttp: vt100 screen scraping exported over HTTP
|
||||||
|
Date: 2011-08-27 15:08:21
|
||||||
|
|
||||||
|
---
|
||||||
|
Originally written for
|
||||||
|
[logtop](https://github.com/JulienPalard/logtop) I just wrote a vt100
|
||||||
|
screen scraper that listen to a port and serve the screen over
|
||||||
|
HTTP. Basically, you want a `top` (or logtop ;-) ) to be displayed in
|
||||||
|
your website back office ? But top outputs in your terminal and you
|
||||||
|
don't know how to capture it ? Use
|
||||||
|
[ashttp](http://dev-tricks.net/wp-content/uploads/2011/08/ashttp1.png),
|
||||||
|
like this:
|
||||||
|
|
||||||
|
:::bash
|
||||||
|
$ ashttp -p 8080 top
|
||||||
|
|
||||||
|
And then just open the port 8080 with an HTTP client and enjoy (typing
|
||||||
|
some F5...). You can find the code on [my
|
||||||
|
github](https://github.com/JulienPalard/ashttp).
|
477
content/blog/asyncio-0.md
Normal file
|
@ -0,0 +1,477 @@
|
||||||
|
Title: Python coroutines with async and await
|
||||||
|
Date: 2016-06-05
|
||||||
|
|
||||||
|
This is a short introduction of the basic vocabulary and knowledge
|
||||||
|
needed to start with `async` and `await`, we'll go from "scratch", but
|
||||||
|
not from the whole "let's use generators" era, when everything
|
||||||
|
started, but from a contemporary (Python 3.5) point of view with
|
||||||
|
`natives coroutines`, `async`, `await`.
|
||||||
|
|
||||||
|
# Coroutine
|
||||||
|
|
||||||
|
A [coroutine](https://en.wikipedia.org/wiki/Coroutine) is a function
|
||||||
|
whose execution can be suspended.
|
||||||
|
|
||||||
|
Coroutines are a great tool to avoid the callback hell, still offering
|
||||||
|
a non-blocking way to express ourselves.
|
||||||
|
|
||||||
|
When a function has to wait for something, suspending it instead
|
||||||
|
of blocking allows to do something else. In other words, it permits
|
||||||
|
concurrency (without involving threads or other processes).
|
||||||
|
|
||||||
|
Without coroutines there are two solutions: Block or use callbacks.
|
||||||
|
|
||||||
|
A typical callback example in a imaginary language may look like:
|
||||||
|
|
||||||
|
function pong_handler(client)
|
||||||
|
{
|
||||||
|
client.on('data', function (data)
|
||||||
|
{
|
||||||
|
client.on('data_written', function ()
|
||||||
|
{
|
||||||
|
client.close()
|
||||||
|
};
|
||||||
|
client.write(data)
|
||||||
|
client.flush()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
With coroutines, it would look like:
|
||||||
|
|
||||||
|
async function pong_handler()
|
||||||
|
{
|
||||||
|
client.write(await client.read())
|
||||||
|
await client.flush()
|
||||||
|
client.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
## Coroutines in Python
|
||||||
|
|
||||||
|
To be exhaustive, there are two kinds of coroutines in Python:
|
||||||
|
|
||||||
|
- generator-based coroutines
|
||||||
|
- native coroutines
|
||||||
|
|
||||||
|
Generator-based coroutines, are the old-style ones, but you may
|
||||||
|
enconter some of them, they are written using the `@types.coroutine`
|
||||||
|
(or `@asyncio.coroutine`) decorator:
|
||||||
|
|
||||||
|
:::python
|
||||||
|
@types.coroutine
|
||||||
|
def get_then_print(url):
|
||||||
|
...
|
||||||
|
|
||||||
|
Native coroutines, the ones you should remember, are defined using the
|
||||||
|
`async` keyword:
|
||||||
|
|
||||||
|
:::python
|
||||||
|
async def get_then_print(url):
|
||||||
|
...
|
||||||
|
|
||||||
|
A `coroutine function`, when called returns a `coroutine object`:
|
||||||
|
|
||||||
|
:::pycon
|
||||||
|
>>> async def tum():
|
||||||
|
... print("tum")
|
||||||
|
...
|
||||||
|
>>> tum()
|
||||||
|
<coroutine object tum at 0x7fa294538468>
|
||||||
|
|
||||||
|
From this `coroutine object` the `coroutine function` can be manipulated:
|
||||||
|
|
||||||
|
:::pycon
|
||||||
|
>>> async def tum():
|
||||||
|
... print("tum")
|
||||||
|
...
|
||||||
|
>>> a_coroutine_object = tum()
|
||||||
|
>>> a_coroutine_object.send(None)
|
||||||
|
tum
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "<stdin>", line 1, in <module>
|
||||||
|
StopIteration
|
||||||
|
|
||||||
|
As you can see, calling `tun()` did not execute the `print("tum")`,
|
||||||
|
but calling `.send(None)` on the coroutine object did (see PEP 342). Also, `send`
|
||||||
|
told us the coroutine is complete by [throwing a
|
||||||
|
`StopIteration`](https://www.python.org/dev/peps/pep-0342/).
|
||||||
|
|
||||||
|
## Coroutine invocation
|
||||||
|
|
||||||
|
As a coroutine just return a coroutine object when called, at some
|
||||||
|
point, some code have to call `send(None)` on it. But that's typically
|
||||||
|
the role of a "main loop". The main loop will also watch for
|
||||||
|
`StopIteration`.
|
||||||
|
|
||||||
|
## Getting result from a coroutine call
|
||||||
|
|
||||||
|
A coroutine give its returned value in a `StopIteration` exception,
|
||||||
|
meaning "Job is done, stop trying to un-suspend me", but typically a
|
||||||
|
scheduler / event loop will do that for you and provide the result
|
||||||
|
by one way or another.
|
||||||
|
|
||||||
|
|
||||||
|
There's also a keyword dedicated to pull a value from a coroutine:
|
||||||
|
`await`. Given an `awaitable`, `await` tries to get a value from it,
|
||||||
|
and if the `awaitable` suspends, `await` also suspends the current
|
||||||
|
coroutine, and so on, up to the `.send()` caller.
|
||||||
|
|
||||||
|
As long as no coroutine suspends themselves, there is no need call
|
||||||
|
`send(None)` a second time to restore the coroutines. So, there's no
|
||||||
|
need for a loop or a scheduler, simply calling `send(None)` once is
|
||||||
|
enough:
|
||||||
|
|
||||||
|
|
||||||
|
:::python
|
||||||
|
async def two():
|
||||||
|
return 2
|
||||||
|
|
||||||
|
|
||||||
|
async def four():
|
||||||
|
return await two() + await two()
|
||||||
|
|
||||||
|
|
||||||
|
async def eight():
|
||||||
|
return await four() + await four()
|
||||||
|
|
||||||
|
|
||||||
|
coro = eight()
|
||||||
|
coro.send(None)
|
||||||
|
|
||||||
|
Which gets `StopIteration: 8`, in a completly synchronous way, despite
|
||||||
|
the vocabulary used.
|
||||||
|
|
||||||
|
## Suspending a coroutine
|
||||||
|
|
||||||
|
This is just not possible for a coroutine to suspend itself. But the
|
||||||
|
whole chain of `await` can be suspended using a `yield` in a
|
||||||
|
"future-like object".
|
||||||
|
|
||||||
|
A `future-like` object is an object with an `__await__` method, which
|
||||||
|
can `yield` a value which will traverse the whole `await` chain up to
|
||||||
|
the caller of `.send(None)`, at this point, an event loop, a
|
||||||
|
scheduler, a tranpoline, whatever it's called need to understand why
|
||||||
|
the `future-like object` did it by reading the value received from the
|
||||||
|
`send(None)` call, act accordingly, like restoring another coroutine,
|
||||||
|
wait for an event on the network, whatever.
|
||||||
|
|
||||||
|
# Awaitables
|
||||||
|
|
||||||
|
[awaitable](https://www.python.org/dev/peps/pep-0492/#await-expression)
|
||||||
|
are objects that can be `awaited` with an `await` keyword.
|
||||||
|
|
||||||
|
Basically a `coroutine` or an object with an `__await__` method
|
||||||
|
returning an iterator are both awaitables.
|
||||||
|
|
||||||
|
# Managing coroutines
|
||||||
|
|
||||||
|
The Python library provide `asyncio` which contains an event loop
|
||||||
|
which take the scheduler role between coroutines, allowing them to
|
||||||
|
suspend, trying to understand why, and restoring them at the right
|
||||||
|
time.
|
||||||
|
|
||||||
|
## Coroutine manager, step 1
|
||||||
|
|
||||||
|
The first step for a coroutine manager is probably to call
|
||||||
|
`send(None)`, which is enough to do some work:
|
||||||
|
|
||||||
|
:::python
|
||||||
|
async def two():
|
||||||
|
return 2
|
||||||
|
|
||||||
|
|
||||||
|
async def four():
|
||||||
|
return await two() + await two()
|
||||||
|
|
||||||
|
|
||||||
|
async def eight():
|
||||||
|
return await four() + await four()
|
||||||
|
|
||||||
|
def coro_manager(coro):
|
||||||
|
try:
|
||||||
|
coro.send(None)
|
||||||
|
except StopIteration as stop:
|
||||||
|
return stop.value
|
||||||
|
|
||||||
|
print(coro_manager(eight()))
|
||||||
|
# prints 8
|
||||||
|
|
||||||
|
But this `coro_manager` will just don't terminate the work if a
|
||||||
|
suspension occurs:
|
||||||
|
|
||||||
|
:::python
|
||||||
|
class Awaitable:
|
||||||
|
def __await__(self):
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
async def wont_terminate_here():
|
||||||
|
await Awaitable()
|
||||||
|
print("Terminated")
|
||||||
|
return 42
|
||||||
|
|
||||||
|
print(coro_manager(wont_terminate_here()))
|
||||||
|
# prints 'None', but no "Terminated" to be seen
|
||||||
|
|
||||||
|
So a `coro_manager` should probably restore a suspended coroutine, by
|
||||||
|
calling back `send(None)`, like this `frenetic_coro_manager`:
|
||||||
|
|
||||||
|
:::python
|
||||||
|
def frenetic_coro_manager(coro):
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
coro.send(None)
|
||||||
|
except StopIteration as stop:
|
||||||
|
return stop.value
|
||||||
|
|
||||||
|
We're now getting "Terminated" followed by "42".
|
||||||
|
|
||||||
|
But here, this `frenetic_coro_manager` can only execute a single coroutine,
|
||||||
|
blindly restoring it if it suspends. Here is an implementation working
|
||||||
|
with a list of coroutines instead of a single one, restoring a random
|
||||||
|
one:
|
||||||
|
|
||||||
|
:::python
|
||||||
|
def frenetic_coro_manager(*coros):
|
||||||
|
coros = list(coros)
|
||||||
|
while coros:
|
||||||
|
coro = random.choice(coros)
|
||||||
|
try:
|
||||||
|
coro.send(None)
|
||||||
|
except StopIteration as stop:
|
||||||
|
coros.remove(coro)
|
||||||
|
|
||||||
|
Still print "Terminated" followed by "42", but can work with multiple
|
||||||
|
coroutines, like:
|
||||||
|
|
||||||
|
async def tum():
|
||||||
|
while True:
|
||||||
|
await Awaitable()
|
||||||
|
print("Tum")
|
||||||
|
|
||||||
|
|
||||||
|
async def pak():
|
||||||
|
while True:
|
||||||
|
await Awaitable()
|
||||||
|
print("Pak")
|
||||||
|
|
||||||
|
frenetic_coro_manager(tum(), pak())
|
||||||
|
|
||||||
|
This time, this frenetically print "Tum"s and "Pak"s. But the
|
||||||
|
interesting point is that both coroutines co-existed, by co-executing
|
||||||
|
their `while True`.
|
||||||
|
|
||||||
|
Here, `await Awaitable()` is only usefull to give the hand back to the `frenetic_coro_manager`, but it awaits nothing, which is semantically… empty.
|
||||||
|
|
||||||
|
But it's possible for the `yield` of the `awaitable object` to yield
|
||||||
|
something usefull to the coroutine manager, like an ETA before calling
|
||||||
|
`send` again:
|
||||||
|
|
||||||
|
:::python
|
||||||
|
class Sleep:
|
||||||
|
def __init__(self, seconds):
|
||||||
|
self.sleep_until = datetime.now() + timedelta(seconds=seconds)
|
||||||
|
|
||||||
|
def __await__(self):
|
||||||
|
yield self.sleep_until
|
||||||
|
|
||||||
|
|
||||||
|
async def tum():
|
||||||
|
while True:
|
||||||
|
await Sleep(1)
|
||||||
|
print("Tum")
|
||||||
|
|
||||||
|
|
||||||
|
async def pak():
|
||||||
|
while True:
|
||||||
|
await Sleep(2)
|
||||||
|
print("Pak")
|
||||||
|
|
||||||
|
|
||||||
|
def measured_coro_manager(*coros):
|
||||||
|
coros = [(datetime.now(), coro) for coro in coros]
|
||||||
|
heapq.heapify(coros)
|
||||||
|
while coros:
|
||||||
|
exec_at, coro = heapq.heappop(coros)
|
||||||
|
if exec_at > datetime.now():
|
||||||
|
sleep((exec_at - datetime.now()).total_seconds())
|
||||||
|
try:
|
||||||
|
heapq.heappush(coros, (coro.send(None), coro))
|
||||||
|
except StopIteration as stop:
|
||||||
|
coros.remove(coro)
|
||||||
|
|
||||||
|
print(measured_coro_manager(tum(), pak()))
|
||||||
|
|
||||||
|
Gives:
|
||||||
|
|
||||||
|
Tum
|
||||||
|
Pak
|
||||||
|
Tum
|
||||||
|
Tum
|
||||||
|
Pak
|
||||||
|
Tum
|
||||||
|
Tum
|
||||||
|
Pak
|
||||||
|
…
|
||||||
|
|
||||||
|
|
||||||
|
In this implementation, the "main loop" `measured_coro_manager` waited
|
||||||
|
gracefully as specified by `Sleep` before calling `send(None)`.
|
||||||
|
|
||||||
|
From this point we can go further by playing with the [dining philosophers problem](https://en.wikipedia.org/wiki/Dining_philosophers_problem):
|
||||||
|
|
||||||
|
:::python
|
||||||
|
import heapq
|
||||||
|
from time import sleep
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
|
||||||
|
class Sleep:
|
||||||
|
"""Basic Sleep implementation, tightly paired with `measured_coro_manager`
|
||||||
|
which expect each `yield` to give an absolute datetime of revival.
|
||||||
|
"""
|
||||||
|
def __init__(self, seconds):
|
||||||
|
self.sleep_until = datetime.now() + timedelta(seconds=seconds)
|
||||||
|
|
||||||
|
def __await__(self):
|
||||||
|
yield self.sleep_until
|
||||||
|
|
||||||
|
|
||||||
|
class ForkTaking:
|
||||||
|
"""Asynchronous context manager describing the action of taking a
|
||||||
|
fork. The fork may be a context manager by itself, but it's nice
|
||||||
|
to get verbose logging by knowing which is taking what.
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, fork, philosopher):
|
||||||
|
self.philosopher = philosopher
|
||||||
|
self.fork = fork
|
||||||
|
|
||||||
|
async def __aenter__(self):
|
||||||
|
self.philosopher.speak("Need fork {}".format(self.fork.number))
|
||||||
|
while self.fork.held_by:
|
||||||
|
# self.philosopher.speak("Need fork {}".format(self.fork.number))
|
||||||
|
await Sleep(.1)
|
||||||
|
self.fork.held_by = self.philosopher
|
||||||
|
self.philosopher.speak("Took fork {}".format(self.fork.number))
|
||||||
|
return self
|
||||||
|
|
||||||
|
async def __aexit__(self, exc_type, exc, traceback):
|
||||||
|
self.philosopher.speak("Release fork {}".format(self.fork.number))
|
||||||
|
self.fork.held_by = None
|
||||||
|
|
||||||
|
|
||||||
|
class Fork:
|
||||||
|
"""Represent a fork a Philosopher can grab and release via
|
||||||
|
an asynchronous context manager.
|
||||||
|
"""
|
||||||
|
def __init__(self, number):
|
||||||
|
self.number = number
|
||||||
|
self.held_by = None
|
||||||
|
|
||||||
|
def take(self, philosopher):
|
||||||
|
return ForkTaking(self, philosopher)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "<Fork {}>".format(self.number)
|
||||||
|
|
||||||
|
|
||||||
|
class Philosopher:
|
||||||
|
"""Having a reference to a left fork and a right fork so he can grab them,
|
||||||
|
the philosopher thinks and eat.
|
||||||
|
"""
|
||||||
|
def __init__(self, number, left_fork, right_fork):
|
||||||
|
self.number = number
|
||||||
|
print("Hello, I'm philosopher {} with forks {} and {}".format(
|
||||||
|
number, left_fork, right_fork))
|
||||||
|
self.left_fork = left_fork
|
||||||
|
self.right_fork = right_fork
|
||||||
|
self.hungry_since = None
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "<Philosopher {}>".format(self.number)
|
||||||
|
|
||||||
|
def speak(self, message):
|
||||||
|
print(' ' * self.number * 20, message)
|
||||||
|
|
||||||
|
async def behave(self):
|
||||||
|
"""Basic implementations of rules:
|
||||||
|
- think
|
||||||
|
- hungry, grab forks
|
||||||
|
- eat
|
||||||
|
in a loop.
|
||||||
|
"""
|
||||||
|
if self.left_fork.number > self.right_fork.number:
|
||||||
|
first_fork, second_fork = self.left_fork, self.right_fork
|
||||||
|
else:
|
||||||
|
first_fork, second_fork = self.right_fork, self.left_fork
|
||||||
|
while True:
|
||||||
|
self.speak("*thinking*")
|
||||||
|
await Sleep(.5)
|
||||||
|
self.hungry_since = datetime.now()
|
||||||
|
self.speak("I'm hungry!")
|
||||||
|
async with first_fork.take(self):
|
||||||
|
await Sleep(0)
|
||||||
|
async with second_fork.take(self):
|
||||||
|
self.hungry_since = None
|
||||||
|
self.speak("*eating*")
|
||||||
|
await Sleep(.5)
|
||||||
|
|
||||||
|
|
||||||
|
class Table():
|
||||||
|
"""The table is responsible of creating Forks and Philosophers,
|
||||||
|
and distributing forks to them, what a powerfull table.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
self.forks = [Fork(i) for i in range(5)]
|
||||||
|
self.philosophers = []
|
||||||
|
for i in range(5):
|
||||||
|
self.philosophers.append(Philosopher(
|
||||||
|
i,
|
||||||
|
self.forks[i - 1],
|
||||||
|
self.forks[i]))
|
||||||
|
|
||||||
|
|
||||||
|
async def check_life(philosophers):
|
||||||
|
while True:
|
||||||
|
await Sleep(1)
|
||||||
|
for philosopher in philosophers:
|
||||||
|
if philosopher.hungry_since is None:
|
||||||
|
continue
|
||||||
|
if philosopher.hungry_since < datetime.now() - timedelta(seconds=60):
|
||||||
|
print("Philosopher {} is dead".format(philosopher))
|
||||||
|
|
||||||
|
|
||||||
|
def measured_coro_manager(*coros):
|
||||||
|
coros = [(datetime.now(), i, coro) for i, coro in enumerate(coros)]
|
||||||
|
i = len(coros)
|
||||||
|
heapq.heapify(coros)
|
||||||
|
while coros:
|
||||||
|
exec_at, _, coro = heapq.heappop(coros)
|
||||||
|
now = datetime.now()
|
||||||
|
if exec_at > now:
|
||||||
|
sleep((exec_at - now).total_seconds())
|
||||||
|
try:
|
||||||
|
heapq.heappush(coros, (coro.send(None), i, coro))
|
||||||
|
i += 1
|
||||||
|
except StopIteration as stop:
|
||||||
|
coros.remove(coro)
|
||||||
|
|
||||||
|
table = Table()
|
||||||
|
measured_coro_manager(check_life(table.philosophers),
|
||||||
|
*[philosopher.behave() for
|
||||||
|
philosopher in
|
||||||
|
table.philosophers])
|
||||||
|
|
||||||
|
And you can play with this a lot, typically in the `behave` method,
|
||||||
|
you can remove the fork order and always start by taking the left
|
||||||
|
fork, you can add or remove, increment or decrements `Sleep`s, and so
|
||||||
|
on...
|
||||||
|
|
||||||
|
# I/O
|
||||||
|
|
||||||
|
Now, the next step is almost obviously networking: Why not rewriting
|
||||||
|
`measured_coro_manager` so it can not only sleep by also use `select`,
|
||||||
|
`poll` to wait for network event, and combine this with asnchronous
|
||||||
|
`read` and `write` syscalls? That's exactly what's `asyncio` is, see
|
||||||
|
`selector_events.py` in the `asyncio` module. I hope now the
|
||||||
|
separation between `asyncio`, `async` and `await` is clearer.
|
38
content/blog/automating-gnu-screen-startup.md
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
---
|
||||||
|
Title: Automating GNU screen startup
|
||||||
|
Date: 2011-11-18 00:13:58
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
At work I use GNU screen with one window per server (ssh connection),
|
||||||
|
and when I loose my screen, it takes minutes to rebuild the naming and
|
||||||
|
the ssh connections ... So I searched and found a PHP version on
|
||||||
|
[Jon's blog](http://snowulf.com/2011/09/13/automated-screen-launch/)
|
||||||
|
but I don't like PHP and don't want a PHP cli on my machine (even to
|
||||||
|
start screen !) So I rewrote it in bash (to have brace expansion !)
|
||||||
|
Enjoy:
|
||||||
|
|
||||||
|
:::bash
|
||||||
|
#!/bin/bash -f
|
||||||
|
|
||||||
|
SCREEN_NAME=julien
|
||||||
|
SERVERS=$(echo {julien,root}@dev root@{www,sql}{1,2} root@media{1,2,3,4,5,6}
|
||||||
|
|
||||||
|
screen -dmS "$SCREEN_NAME"
|
||||||
|
NUM=0
|
||||||
|
for SERVER in $SERVERS
|
||||||
|
do
|
||||||
|
NUM=$((NUM + 1))
|
||||||
|
screen -S "$SCREEN_NAME" -X screen
|
||||||
|
if [ z"$SERVER" != z"" ]
|
||||||
|
then
|
||||||
|
screen -S "$SCREEN_NAME" -p $NUM -X title "$SERVER"
|
||||||
|
screen -S "$SCREEN_NAME" -p $NUM -X stuff "ssh $SERVER $(printf \\r)"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
printf "Done, now you can join your screen with :\n"
|
||||||
|
printf "$ screen -dr -S $SCREEN_NAME\n"
|
||||||
|
|
||||||
|
Don't forgot to start your ssh-agent just before starting this script!
|
||||||
|
PS: If you don't have an ssh-agent, you may want to remove the `$(printf
|
||||||
|
\\r)` and press enter yourself.
|
|
@ -0,0 +1,32 @@
|
||||||
|
---
|
||||||
|
Title: [Bashism] How to generate random number without $RANDOM ?
|
||||||
|
Date: 2011-04-07 14:00:55
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
There is a common bashism, that is to use `$RANDOM`. Typically you'll
|
||||||
|
have to remove bashism while rewriting your scripts for dash or sh.
|
||||||
|
There is a lot of solutions to generate random numbers in many different
|
||||||
|
ways, but I'm not here to pollute the internet demonstrating 42
|
||||||
|
differents ways to do this, i'll only show you the one I think is the
|
||||||
|
best, and let you comment it if you can do better :-) My solution is to
|
||||||
|
replace `$RANDOM` by :
|
||||||
|
|
||||||
|
:::bash
|
||||||
|
$(($(dd if=/dev/urandom count=1 2> /dev/null | cksum | cut -d' ' -f1) % 32768))
|
||||||
|
|
||||||
|
Pros :
|
||||||
|
|
||||||
|
- Not so long
|
||||||
|
- Yield a different number each call (not all replacement for
|
||||||
|
`$RANDOM` do)
|
||||||
|
- Excatly like in bash, it yield a number between 0 and 32767
|
||||||
|
|
||||||
|
Cons :
|
||||||
|
|
||||||
|
- Longer than `$RANDOM` :p
|
||||||
|
- /dev/urandom is not present on every systems ...
|
||||||
|
|
||||||
|
You should simplify it if the \[0, 32767\] rule has no importance for
|
||||||
|
you, typically if you want a number between 0 and 10, don't do ... %
|
||||||
|
32768)) % 11)) ...
|
34
content/blog/c-sharp-using-alias-directives.md
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
---
|
||||||
|
Title: C# Using alias directives
|
||||||
|
Date: 2009-03-25 11:49:50
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Just found in section 9.4.1 of the C# language specification: The
|
||||||
|
`using` keyword can be used to alias a namespace or a type name:
|
||||||
|
|
||||||
|
*using-alias-directive: using identifier = namespace-or-type-name ;*
|
||||||
|
|
||||||
|
You can read more about that here : [csharp language
|
||||||
|
specification.doc](http://download.microsoft.com/download/3/8/8/388e7205-bc10-4226-b2a8-75351c669b09/csharp%20language%20specification.doc),
|
||||||
|
Or just try to use it:
|
||||||
|
|
||||||
|
:::csharp
|
||||||
|
// As the specification show it :
|
||||||
|
namespace N1.N2
|
||||||
|
{
|
||||||
|
class A {}
|
||||||
|
}
|
||||||
|
namespace N3
|
||||||
|
{
|
||||||
|
using A = N1.N2.A;
|
||||||
|
class B: A {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// My foobar exemple :
|
||||||
|
namespace Foo
|
||||||
|
{
|
||||||
|
using Bar = Dictionary;
|
||||||
|
}
|
||||||
|
|
||||||
|
Enjoy!
|
11
content/blog/check-if-a-string-is-valid-utf8.md
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
Title: How to check if a string is valid utf-8
|
||||||
|
Date: 2012-05-17 15:09:44
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Every day (at least) I'm facing a problem: how to check if a string is
|
||||||
|
valid in utf-8 ? So I wrote [a little C program, that I put on my
|
||||||
|
github](https://github.com/JulienPalard/is_utf8). Just be aware that
|
||||||
|
pure ASCII is valid UTF-8 and that's not a bug: my program is checking
|
||||||
|
if a string is valid utf-8, not if the string is in utf-8. Enjoy :-)
|
220
content/blog/cisco-cheatsheet.md
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
Title: Cisco CheatSheet
|
||||||
|
Date: 2008-04-03
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
|
||||||
|
## Get privileges
|
||||||
|
|
||||||
|
router>enable
|
||||||
|
router#
|
||||||
|
|
||||||
|
## Enter configuration mode
|
||||||
|
|
||||||
|
router#configure terminal
|
||||||
|
Enter configuration commands, one per line. End with CNTL/Z.
|
||||||
|
router(config)#
|
||||||
|
|
||||||
|
## Reset
|
||||||
|
|
||||||
|
router#copy flash:clean-config startup-config
|
||||||
|
router#reload
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
router(config)#router <protocol> <nbr>
|
||||||
|
router(config)#show ip protocols
|
||||||
|
router(config)#show running-config
|
||||||
|
|
||||||
|
## auto completion
|
||||||
|
|
||||||
|
Utiliser ? pour expand une commande
|
||||||
|
ex :
|
||||||
|
lab2-ro2621(config-if)#ip a?
|
||||||
|
access-group accounting address authentication
|
||||||
|
|
||||||
|
## Voir le status des interfaces
|
||||||
|
|
||||||
|
router#show interfaces
|
||||||
|
|
||||||
|
|
||||||
|
## Disable DNS resolution
|
||||||
|
|
||||||
|
router(config)#no ip domain-lookup
|
||||||
|
|
||||||
|
## Cancel a traceroute
|
||||||
|
|
||||||
|
C-^
|
||||||
|
|
||||||
|
## Supprimer toutes les routes
|
||||||
|
|
||||||
|
router(config)#no ip routing
|
||||||
|
|
||||||
|
## Quitter proprement
|
||||||
|
|
||||||
|
M-A
|
||||||
|
(Alt shift A pour les non emacsiens)
|
||||||
|
|
||||||
|
# Configuration des interfaces
|
||||||
|
|
||||||
|
## Ethernet
|
||||||
|
|
||||||
|
router(config)#interface fastEthernet 0/0
|
||||||
|
router(config)#ip address 192.168.2.1 255.255.255.252 /* /30 */
|
||||||
|
router(config)#no shutdown
|
||||||
|
|
||||||
|
## Loopback
|
||||||
|
|
||||||
|
router(config)#interface loopback ?
|
||||||
|
router(config)#ip address 192.168.2.1 255.255.255.252 /* /30 */
|
||||||
|
router(config)#no shutdown
|
||||||
|
|
||||||
|
## Serie
|
||||||
|
|
||||||
|
/!\ DTE a GAUCHE - DCE a DROITE/!\
|
||||||
|
/!\ Clock rate sur le s0/0 /!\
|
||||||
|
router(config)#interface serial 0/0
|
||||||
|
router(config)#ip address 192.168.2.1 255.255.255.252 /* /30 */
|
||||||
|
router(config)#clock rate 1000000 /* Cote 0/0 seulement */
|
||||||
|
router(config)#encapsulation hdlc /* Cote 0/0 seulement */
|
||||||
|
router(config)#no shutdown
|
||||||
|
|
||||||
|
# Routage
|
||||||
|
|
||||||
|
## Route par defaut
|
||||||
|
|
||||||
|
router(config)#ip route 0.0.0.0 0.0.0.0 <ip address | interface>
|
||||||
|
|
||||||
|
## Ajouter une route statique
|
||||||
|
|
||||||
|
router(config)#ip routing router(config)#ip route <network>
|
||||||
|
<netmask> <ip address | interface> [distance]
|
||||||
|
|
||||||
|
## RIP
|
||||||
|
|
||||||
|
### V1 (classfull/ pas de ss reseau)
|
||||||
|
|
||||||
|
router(config)# router rip
|
||||||
|
router(config-router)# network <x.x.x.x>
|
||||||
|
|
||||||
|
### V2 (classless)
|
||||||
|
|
||||||
|
router(config)# router rip
|
||||||
|
/* Activation globale */
|
||||||
|
router(config-router)# version 2
|
||||||
|
/* Activation sur un network */
|
||||||
|
router(config-if)# ip rip send version 2
|
||||||
|
router(config-if)# ip rip reciev version 2
|
||||||
|
/* Ajouter ses networks */
|
||||||
|
router(config-if)# network <x.x.x.x>
|
||||||
|
|
||||||
|
### authentification
|
||||||
|
|
||||||
|
router(config)# key chain <name>
|
||||||
|
router(config-keychain)# key <nbr>
|
||||||
|
router(config-keychain-key)# key-string <pass>
|
||||||
|
router(config-if)#ip rip authentication key-chain <name>
|
||||||
|
router(config- if)#ip rip authentication mode {text | md5}
|
||||||
|
router(config-router)# neighbor <x.x.x.x>
|
||||||
|
router(config-router)# passive-interface serial 0/0
|
||||||
|
|
||||||
|
## IGRP (classfull/pas de ss reseau)
|
||||||
|
|
||||||
|
router(config)# router igrp 1
|
||||||
|
router(config-router)# network <x.x.x.x>
|
||||||
|
|
||||||
|
timer basic <update> <invalid> <hold-down> <flush>
|
||||||
|
|
||||||
|
### Metric
|
||||||
|
|
||||||
|
M = (K1*bp + K2*bp/(256-charge) + K3 * delay) * (K5/(fiabilite + K4))
|
||||||
|
default K1 = K3 = 1 K2 = K4 = K5 = 0
|
||||||
|
router(config-if)# bandwidth <1-10000000>
|
||||||
|
router(config-if)# delay <1-16777215>
|
||||||
|
router(config-router)# metric weight 0 K1 K2 K3 K4 K5
|
||||||
|
|
||||||
|
### repartition de charge
|
||||||
|
|
||||||
|
// rapartion entre les metric < metrique min * variance
|
||||||
|
router(config-router)# maximum paths <1-6>
|
||||||
|
router(config-router)# variance <1-128>
|
||||||
|
router(config-router)# trafic-share balanced
|
||||||
|
|
||||||
|
## VLAN
|
||||||
|
|
||||||
|
### Static
|
||||||
|
|
||||||
|
#### creation
|
||||||
|
|
||||||
|
# vlan database
|
||||||
|
(vlan)# vlan <nbr> name <name> // vlan 1 = tout les prot par defaut ne pas utiliser
|
||||||
|
|
||||||
|
#### ajout port
|
||||||
|
|
||||||
|
router(config-if)# switchport acces vlan <nbr>
|
||||||
|
|
||||||
|
#### management lan
|
||||||
|
|
||||||
|
router(config)# interface vlan <nbr>
|
||||||
|
router(config-subif)# ip add x.x.x.x z.z.z.z
|
||||||
|
router(config-subif)# manegement //config le vtypour le telnet
|
||||||
|
|
||||||
|
#### affichage conf
|
||||||
|
|
||||||
|
show vlan brief
|
||||||
|
|
||||||
|
## SECURITY PORT
|
||||||
|
|
||||||
|
router(config-if)# port security max-mac-count <nbr>
|
||||||
|
router(config-if)# port security action shutnown
|
||||||
|
router(config-if)# end #show port security
|
||||||
|
|
||||||
|
## ETHERCHANNEL
|
||||||
|
|
||||||
|
router(config-if)# port group <nbr> distribution destination
|
||||||
|
router(config-if)# no shutdown // repeat on each interface of the group
|
||||||
|
# show etherchannel summary
|
||||||
|
|
||||||
|
## ACL
|
||||||
|
|
||||||
|
### numerotation(ip)
|
||||||
|
|
||||||
|
standard: 0-99 1300-1999 etendu 100-199 2000-2699
|
||||||
|
|
||||||
|
### wildcard
|
||||||
|
|
||||||
|
mask de bit 0=checked 1=not checked
|
||||||
|
|
||||||
|
### standard
|
||||||
|
|
||||||
|
a placer pres de la destination
|
||||||
|
router(config)# accesc-list <nbr> {permit|deny} <source> <wildcard>
|
||||||
|
|
||||||
|
### etendues
|
||||||
|
|
||||||
|
a placer pres de la source
|
||||||
|
router(config)# access-list <nbr> {permit|deny} <protocol> <source> <wildcard> <destination> <wildcard> <operateut port> [established] [log]
|
||||||
|
protocol = ip | tcp | udp | icmp | ospf | igrp...
|
||||||
|
protocol = lt | gt | eq | neq
|
||||||
|
|
||||||
|
### nomee
|
||||||
|
|
||||||
|
router(config)#ip access-list {standard|extended} <nom>
|
||||||
|
router(config-ext-nacl)# premit tcp <x.x.x.x> <y.y.y.y> <x.x.x.x> <y.y.y.y> <port> www
|
||||||
|
|
||||||
|
### application
|
||||||
|
|
||||||
|
router(config-if)#ip access-group <nbr> {in|out}
|
||||||
|
|
||||||
|
## OSPF
|
||||||
|
|
||||||
|
### Conf
|
||||||
|
|
||||||
|
router(config)#router ospf 4
|
||||||
|
router(config-router)#network 192.168.4.0 255.255.255.252 area 4
|
||||||
|
router(config-router)#area 4 authenticatio
|
||||||
|
router(config-if)#ip ospf hello-interval 5
|
||||||
|
router(config-if)#ip ospf dead-interval 20
|
||||||
|
|
||||||
|
### Authentification
|
||||||
|
|
||||||
|
router(config-if)#ip ospf authentication-key toto
|
115
content/blog/combinatory-logic-from-scratch.md
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
---
|
||||||
|
Title: Combinatory logic from scratch
|
||||||
|
Date: 2008-11-28 01:56:32
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Cause it's sooooo sexy, let's speak about Combinatory Logic!
|
||||||
|
|
||||||
|
- Rule 1: You don't talk about Combinatory Logic
|
||||||
|
- Rule 2: You don't talk about Combinatory Logic
|
||||||
|
- Rule 3: Combinatory Logic is based on Lambda Calculus
|
||||||
|
(see Wikipedia for both)
|
||||||
|
- Rule 4: A combinator is a Lambda expression taking One and only One combinator as parameter, and returning a Combinator.
|
||||||
|
|
||||||
|
As i'm speaking to developers, I'LL use the `C#` Lambda
|
||||||
|
syntax which is: `(parameter) => statement` Let's now try our first
|
||||||
|
Combinator, named the Identity Combinator `I = (a) => a`; I named it `I`,
|
||||||
|
it takes one parameter, localy named `a` and return the parameter as is.
|
||||||
|
|
||||||
|
Important point: How to build combinator taking more than one parameter
|
||||||
|
? In *C#* you should use `(a, b, c) => blah blah...` but the *Rule 4*
|
||||||
|
forbid us to give more than one paraneter, so let's cheat, imagine : `K =
|
||||||
|
(x) => (y) => x`; `K` is a combinator taking `x`, returning a
|
||||||
|
combinator taking `y` and returning `x`. so we have `K(x) = (y) => x` and
|
||||||
|
`K(x)(y) = x`! So `K` take two arguments, `x` and `y`, and returns `x`, but! `K`
|
||||||
|
can take only one argument, look at the `K(x) = (y) => x` ...
|
||||||
|
|
||||||
|
Let's try with three arguments:
|
||||||
|
|
||||||
|
S = (x) => (y) => (z) => x(z)(y(z))
|
||||||
|
|
||||||
|
can be called with one,
|
||||||
|
|
||||||
|
S(x) returns (y) => (z) => x(z)(y(z))
|
||||||
|
|
||||||
|
two,
|
||||||
|
|
||||||
|
S(x)(y) returns (z) => x(z)(y(z))
|
||||||
|
|
||||||
|
or three arguments:
|
||||||
|
|
||||||
|
s(x)(y)(z) returns x(z)(y(z))
|
||||||
|
|
||||||
|
In combinatory logic, they write:
|
||||||
|
|
||||||
|
- `I a = a`
|
||||||
|
- `K x y = x`
|
||||||
|
- `S x y z = x(z)(y(z))`
|
||||||
|
|
||||||
|
then they say that in fact, `I` can be build from `S` and `K`:
|
||||||
|
|
||||||
|
I = SKK
|
||||||
|
|
||||||
|
Ok but what does that means?
|
||||||
|
|
||||||
|
Where are arguments? it's easy: `I = S(K)(K)`; `S` can take 2
|
||||||
|
parameters `S(x)(y)` returns `(z) => x(z)(y(z))`, so: `I = (z) =>
|
||||||
|
K(z)(K(z))` We have to execute it from left to right, remember, `K(a)(b)`
|
||||||
|
returns `a`, so (with `a == z` and `b == K(z))`: `I = (z) => z`;
|
||||||
|
|
||||||
|
Do you want more?
|
||||||
|
|
||||||
|
Let's try to understand
|
||||||
|
|
||||||
|
B = S (K S) K x y z
|
||||||
|
|
||||||
|
`B` stands for Barbara, from "Syllogism Barbara" (Wikipedia explains:
|
||||||
|
|
||||||
|
- All men are animals.
|
||||||
|
- All animals are mortal.
|
||||||
|
-All men are mortal.
|
||||||
|
|
||||||
|
So before all, write `B` as we understand it, and for readability
|
||||||
|
reasons, currently executed combinator and it's arguments will be emphased:
|
||||||
|
|
||||||
|
- B = __S (K(S)) K (x)__ (y) (z)
|
||||||
|
|
||||||
|
We have to execute it from left to right, and we have a `S` with three parameters:
|
||||||
|
`S(a)(b)(c)` returns `a(c)(b(c))`:
|
||||||
|
|
||||||
|
- B = __K (S) (x)__ (K(x)) (y) (z)
|
||||||
|
|
||||||
|
From left to right we have a `K` with two parameters, `S` and `x`, it will
|
||||||
|
return `S`:
|
||||||
|
|
||||||
|
- B = __S (K(x)) (y) (z)__
|
||||||
|
|
||||||
|
Calling `S` with three parameters `(K(x))`, `(y), and `(z)` returns
|
||||||
|
`(K(x))(z)((y)(z))`:
|
||||||
|
|
||||||
|
- B = **K (x) (z)** ((y)(z))
|
||||||
|
|
||||||
|
Calling `K` with two parameters `(x)`, and `(z)`, it returns `x`:
|
||||||
|
|
||||||
|
- B = x((y)(z))
|
||||||
|
|
||||||
|
Which can be simplified to:
|
||||||
|
|
||||||
|
- B = x(y(z))
|
||||||
|
|
||||||
|
It's time to try it !
|
||||||
|
|
||||||
|
:::csharp
|
||||||
|
delegate C C(C c);
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
C K = (a) => (b) => a;
|
||||||
|
C S = (a) => (b) => (c) => a(c)(b(c));
|
||||||
|
C I = S(K)(K);
|
||||||
|
C B = S(K(S))(K);
|
||||||
|
}
|
||||||
|
|
||||||
|
It works! Enjoy!! Next time, we will try a Swap combinator, a
|
||||||
|
Combinator reducing to himself and progressing step to the Y
|
||||||
|
Combinator! *dramatic chord*
|
67
content/blog/covariance-and-contravariance-in-c-sharp-3.md
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
---
|
||||||
|
Title: Covariance and Contravariance in C#3
|
||||||
|
Date: 2009-03-09 21:19:51
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
A short introduction to Covariance and Contravariance in *C# 3* preparing
|
||||||
|
you to an article about that in *C# 4*. So what is covariance?
|
||||||
|
Covariance is basically using a method which returns something derived
|
||||||
|
from the expected type. An exemple? It's safe to have a method
|
||||||
|
returning a cat when you expect it to return an animal. In C sharp it's
|
||||||
|
|
||||||
|
:::csharp
|
||||||
|
public class Animal
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Cat : Animal
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Dog : Animal
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's safe to say that something returns a Animal when in fact this thing returns a Cat
|
||||||
|
class Covariance
|
||||||
|
{
|
||||||
|
void test()
|
||||||
|
{
|
||||||
|
Func a = Method; // OK
|
||||||
|
Func b = delegate { return new Cat(); }; // OK
|
||||||
|
Func c = () => new Cat(); // OK
|
||||||
|
}
|
||||||
|
|
||||||
|
Cat Method()
|
||||||
|
{
|
||||||
|
return new Cat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
So Funcs `a`, `b`, and `c` are returning animals which in fact are
|
||||||
|
cats, which is true. And, what is contravariance? Contravariance is
|
||||||
|
basically using a method which takes something which is a parent of
|
||||||
|
the expected type. An exemple? It's safe to give a method an animal
|
||||||
|
when it expects to receive a cat.
|
||||||
|
|
||||||
|
:::csharp
|
||||||
|
// It's safe to say that something can take a Cat if in fact this thing can take any Animal
|
||||||
|
class Contravariance
|
||||||
|
{
|
||||||
|
static void test()
|
||||||
|
{
|
||||||
|
Action a = Method; // OK
|
||||||
|
Action b = delegate(Animal value) { }; // ERROR
|
||||||
|
// From C#3 Specification :
|
||||||
|
// $7.14.1 Anonymous function signatures :
|
||||||
|
// [...] contra-variance of anonymous function parameter types is not supported.
|
||||||
|
Action d = (Animal value) => { }; // idem... anonymous... not supported.
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Method(Animal value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
So `Action` `a` take `Cats`, but in fact can take any `Animals`, so it's safe.
|
|
@ -0,0 +1,45 @@
|
||||||
|
---
|
||||||
|
Title: echo and backslash-escaped caracters / new lines: how to write portable scripts ?
|
||||||
|
Date: 2011-04-08 13:59:45
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
While writing shell scripts you are using a lot of `echo` but did you
|
||||||
|
think about portability of this simple statement? Can you say what will
|
||||||
|
be diplayed, without testing, on your shell, the following tests:
|
||||||
|
|
||||||
|
:::bash
|
||||||
|
echo \n \c '\n' '\c' "\n" "\c"
|
||||||
|
echo -e \n \c '\n' '\c' "\n" "\c"
|
||||||
|
|
||||||
|
? I can't, cause I know that the `echo` behavior is very implementation
|
||||||
|
dependent, typically in `dash`, `echo -e foo` actually print `-e foo` because
|
||||||
|
the dash's echo don't parses any options... Here is the bug I found on
|
||||||
|
one of my shell scripts, simplified to this 9 bytes shell script:
|
||||||
|
|
||||||
|
:::bash
|
||||||
|
$ cat /tmp/test.sh
|
||||||
|
#!/bin/sh
|
||||||
|
echo "$*"
|
||||||
|
$ /tmp/test.sh '1\n2'
|
||||||
|
1
|
||||||
|
2
|
||||||
|
|
||||||
|
I'm running Debian Squeeze so my `sh` is a `dash`, and the '\\n' is
|
||||||
|
interpreted by the dash's echo ... but I don't want it! The only
|
||||||
|
portable workaround I found is:
|
||||||
|
|
||||||
|
:::bash
|
||||||
|
$ cat /tmp/test.sh
|
||||||
|
#!/bin/sh
|
||||||
|
printf "%s\n" "$*"
|
||||||
|
$ /tmp/test.sh '1\n2'
|
||||||
|
1\n2
|
||||||
|
|
||||||
|
Conclusion: Keep a look at your input, if you don't want
|
||||||
|
backslash-escaped chars to be interpreted and want to be portable, use
|
||||||
|
printf! You can keep using echo when you have a full control on the
|
||||||
|
input, so the `sh` Hello World will forever stay:
|
||||||
|
|
||||||
|
:::bash
|
||||||
|
echo "Hello world"
|
10
content/blog/emacs-replace-tabs-with-spaces.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
Title: Emacs: replace tabs with spaces
|
||||||
|
Date: 2011-05-06 18:27:59
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
When you want to replace tab with spaces or vice versa don't use `M-%`
|
||||||
|
*(query-replace)* but `M-x tabify` or `M-x untabify`. They work on the
|
||||||
|
current selection so if you want it to be applied to a whole buffer,
|
||||||
|
try `C-x h` *(mark-whole-buffer)* before to select the whole buffer.
|
41
content/blog/emacs-standard-input-is-not-a-tty.md
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
---
|
||||||
|
Title: emacs: standard input is not a TTY
|
||||||
|
Date: 2011-12-11 13:54:02
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Did you ever tried something like :
|
||||||
|
|
||||||
|
:::bash
|
||||||
|
$ find -name '*.c' | xargs emacs
|
||||||
|
or
|
||||||
|
$ grep -rl snmp . | xargs emacs
|
||||||
|
|
||||||
|
and got the error "emacs: standard input is not a tty" ? That's normal,
|
||||||
|
as the stdin for emacs is here the pipe, not your tty, you need a
|
||||||
|
workaround to leave the normal stdin to your emacs. There are different
|
||||||
|
approches, the one I used for a long time was a command substitution :
|
||||||
|
|
||||||
|
:::bash
|
||||||
|
$ emacs $(find -name '*.c')
|
||||||
|
|
||||||
|
But other approches exists, redirecting /dev/tty to emacs' stdin :
|
||||||
|
|
||||||
|
:::bash
|
||||||
|
$ find -name '*.c' | xargs sh -c 'emacs "$@" < /dev/tty' emacs
|
||||||
|
|
||||||
|
|
||||||
|
And if you are searching for a specific pattern with grep, you should
|
||||||
|
want to jump directly to the right line using the '+line file' syntax of
|
||||||
|
emacs, and the shell substitution :
|
||||||
|
|
||||||
|
:::bash
|
||||||
|
$ emacs $(grep -rn snmp services/ | sed -r 's/([^:]*):([0-9]*):.*/+\2 \1/g')
|
||||||
|
|
||||||
|
It's good while having only one occurence of the pattern in each file,
|
||||||
|
but if many occurences exists, the file is oppened only once, with a
|
||||||
|
while you can open one emacs for each occurence of the searched pattern
|
||||||
|
and the /dev/tty redirection :
|
||||||
|
|
||||||
|
:::bash
|
||||||
|
$ grep -rn snmp services/ | sed -r 's/([^:]*):([0-9]*):.*/+\2 \1/g' | while read line file; do emacs $line $file < /dev/tty; done
|
74
content/blog/emacs-syntax-error-highlighting.md
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
---
|
||||||
|
Title: emacs: Highlighting errors for c, python, and other languages
|
||||||
|
Date: 2011-06-11 13:54:12
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**This is a deprecated article about flymake, you should check for
|
||||||
|
flycheck instead.**
|
||||||
|
|
||||||
|
Hi! Today we'll see how to highlight syntax errors in emacs, with
|
||||||
|
exemples for C and Python. First you should learn about
|
||||||
|
[flymake-mode](http://www.emacswiki.org/emacs/FlyMake) In a nutshell
|
||||||
|
Flymake is a minor mode to perform on the fly checks on your files. It
|
||||||
|
can run any external syntax checker by different means, I let you
|
||||||
|
check out the documentation. Quick and easy setup to highlight C
|
||||||
|
syntax : You already have a Makefile, that's good, so you just have to
|
||||||
|
add a new rule to your Makefile, named 'check-syntax':
|
||||||
|
|
||||||
|
:::makefile
|
||||||
|
check-syntax:
|
||||||
|
gcc -o /dev/null -D$(DEFINE) $(CFLAGS) -S ${CHK_SOURCES}
|
||||||
|
|
||||||
|
You can fix my -D\$(DEFINE) \$(CFLAGS) to match your compile options ...
|
||||||
|
Then open a .c file in your project, and if you .emacs file don't
|
||||||
|
automatically start flymake-mode, type 'M-x flymake-mode' and enjoy
|
||||||
|
error highlighting ! Next trick is, if you're using a non graphical
|
||||||
|
emacs, you don't have, by default, the error message, so i's a bit
|
||||||
|
anying... So you'll add some lines in you .emacs and a file in you
|
||||||
|
.emacs.d First, download flymake-cursor.el here
|
||||||
|
http://www.emacswiki.org/emacs/download/flymake-cursor.el and put it in
|
||||||
|
your \~/.emacs.d/ Then in your .emacs, add :
|
||||||
|
|
||||||
|
:::lisp
|
||||||
|
(require 'cl)
|
||||||
|
(require 'flymake-cursor)
|
||||||
|
|
||||||
|
Now, when you stop your cursor on an error, the message should appear in
|
||||||
|
the minibuffer. Last trick, for Python developers, how to use
|
||||||
|
flymake-mode with pyflakes ? Just add this to you .emacs file, and tweak
|
||||||
|
it if you want. You should install pyflakes in order to make it work.
|
||||||
|
|
||||||
|
:::lisp
|
||||||
|
;; aptitude install pyflakes to check python code
|
||||||
|
(require 'flymake-cursor)
|
||||||
|
(global-set-key [f4] 'flymake-goto-next-error)
|
||||||
|
|
||||||
|
(when (load "flymake" t)
|
||||||
|
(defun flymake-pyflakes-init ()
|
||||||
|
(let* ((temp-file (flymake-init-create-temp-buffer-copy
|
||||||
|
'flymake-create-temp-inplace))
|
||||||
|
(local-file (file-relative-name
|
||||||
|
temp-file
|
||||||
|
(file-name-directory buffer-file-name))))
|
||||||
|
(list "pyflakes" (list local-file))))
|
||||||
|
|
||||||
|
(add-to-list 'flymake-allowed-file-name-masks
|
||||||
|
'("\\.py\\'" flymake-pyflakes-init)))
|
||||||
|
|
||||||
|
(add-hook 'find-file-hook 'flymake-find-file-hook)
|
||||||
|
|
||||||
|
Bonus trick you should try : Replace "pyflakes" in (list "pyflakes"
|
||||||
|
(list local-file)))) to a shell script of you own, running pyflakes,
|
||||||
|
pep8, etc...as I just found here :
|
||||||
|
<http://stackoverflow.com/questions/1259873/how-can-i-use-emacs-flymake-mode-for-python-with-pyflakes-and-pylint-checking-cod>
|
||||||
|
|
||||||
|
:::bash
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
epylint "$1" 2>/dev/null
|
||||||
|
pyflakes "$1"
|
||||||
|
pep8 --ignore=E221,E701,E202 --repeat "$1"
|
||||||
|
true
|
||||||
|
|
||||||
|
Enjoy!
|
34
content/blog/emacsnumeric-arguments-in.md
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
---
|
||||||
|
Title: Numeric arguments in emacs
|
||||||
|
Date: 2011-05-02 15:47:31
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
I'm starting an 'emacs trick of the day' sequence with:
|
||||||
|
|
||||||
|
- Function name: *universal-argument*
|
||||||
|
- Typical Key binding: `C-u`
|
||||||
|
- How to get help: `C-h f universal-argument`
|
||||||
|
- Usage: `C-u`
|
||||||
|
|
||||||
|
Receive a numeric argument that is given to the next called function,
|
||||||
|
when no numeric argument is typed, the value defaults to `4`. So today
|
||||||
|
you can try:
|
||||||
|
|
||||||
|
- `C-u 9 C-n`, that move cursor vertically down 9 lines
|
||||||
|
- `C-u C-k` which kills 4 lines
|
||||||
|
- `C-u C-u C-k` which kills 4 × 4, 16 lines
|
||||||
|
- `C-u 10 n` which enters `nnnnnnnnnn`
|
||||||
|
|
||||||
|
You may ask, what about if I want to input 25 '6' ? `C-u 256` can't work
|
||||||
|
... so you just have to separate with another `C-u`: `C-u 25 C-u 1` gives
|
||||||
|
`6666666666666666666666666`.
|
||||||
|
|
||||||
|
Some functions does not have the simple 'repeating' effect of
|
||||||
|
receiving a numeric parameter, for example, running `C-u C-l` does not
|
||||||
|
recenter 4 times your screen! but the help page of
|
||||||
|
*recenter-top-bottom* states that:
|
||||||
|
|
||||||
|
> A prefix argument is handled like 'recenter':
|
||||||
|
> With numeric prefix ARG, move current line to window-line ARG.
|
||||||
|
> With plain `C-u`, move current line to window center. A negative argument to C-l move the current line to the line ARG from the bottom of the screen.
|
50
content/blog/emacssearching-string-in.md
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
---
|
||||||
|
Title: Searching and replacing in emacs
|
||||||
|
Date: 2011-05-03 19:16:16
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Day two of my serie about emacs, about searching and replacing.
|
||||||
|
|
||||||
|
- Function name: *isearch-forward*
|
||||||
|
- Typical Key binding: `C-s`
|
||||||
|
- How to get help: `C-h f isearch-forward`
|
||||||
|
|
||||||
|
*isearch-forward* let you type a string to be searched incrementally
|
||||||
|
in the current buffer, successive following `C-s` will jump to the next
|
||||||
|
match.
|
||||||
|
|
||||||
|
- Function name: *isearch-forward-regexp*
|
||||||
|
- Typical Key sequence: `C-M-s` or `C-u C-s`
|
||||||
|
- How to get help : `C-h f isearch-forward-regexp`
|
||||||
|
|
||||||
|
*isearch-forward-regexp* let you type a regexp to be searched
|
||||||
|
incrementally in the current buffer, successive following `C-s` will
|
||||||
|
jump to the next match.
|
||||||
|
|
||||||
|
- Function name: *query-replace*
|
||||||
|
- Typical key binding: `M-%`
|
||||||
|
- How to get help: `C-h f query-replace`
|
||||||
|
- Usage: `M-%` *search* `RET` *replace* `RET`
|
||||||
|
|
||||||
|
Then, for each term found, *query-replace* will ask you what to do:
|
||||||
|
`space` or `y` to replace, `delete` or `n` to skip, `RET` or `q` to
|
||||||
|
exit, `!` for "yes for all", `?` to get help about how to enter
|
||||||
|
recursive edit / delete match and recursive edit / edit replacement
|
||||||
|
string / ... Then you should read about *replace-string*,
|
||||||
|
*replace-regexp*, *occur*, *list-matching-lines*, *multi-occur*,
|
||||||
|
*multi-occur-in-matching-buffers*, *how-many*, *flush-lines*, and
|
||||||
|
*keep-lines*.
|
||||||
|
|
||||||
|
Case sensitivity: A search is by defaut case
|
||||||
|
insensitive, but if you input an upper case letter, it become case
|
||||||
|
sensitive. `M-c` during a search toggle the case
|
||||||
|
sensitivity. Configuration variables: You may consult the
|
||||||
|
documentation about those variable typing : `C-h v *variable*` or `M-x
|
||||||
|
apropos-variable RET case-fold-search RET`
|
||||||
|
|
||||||
|
- *case-fold-search* (Non-nil if searches and matches should
|
||||||
|
ignore case.)
|
||||||
|
- *default-case-fold-search* (Default value of \`case-fold-search')
|
||||||
|
- *tags-case-fold-search* (Whether tags operations should
|
||||||
|
be case-sensitive.)
|
|
@ -0,0 +1,17 @@
|
||||||
|
---
|
||||||
|
Title: Exclude directories from recursive grep
|
||||||
|
Date: 2008-11-16 16:20:13
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
How often are you using grep in subversionned folders like that:
|
||||||
|
|
||||||
|
:::bash
|
||||||
|
grep -rni foobar . | grep -v .svn
|
||||||
|
|
||||||
|
Upgrade to grep 2.5.3 and use (alias it ?)
|
||||||
|
|
||||||
|
:::bash
|
||||||
|
grep -rni --exclude-dir .svn foobar .
|
||||||
|
|
||||||
|
(or ... stop using SVN !!!)
|
104
content/blog/howto-invoke-an-event-via-reflexion.md
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
---
|
||||||
|
Title: Howto invoke an event via reflection
|
||||||
|
Date: 2008-08-29 23:14:53
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Why this article ? Because of this note found on the MSDN's `EventInfo`
|
||||||
|
page:
|
||||||
|
|
||||||
|
> EventInfo is not intended to be used to raise events. An object
|
||||||
|
> raises events as dictated by its internal state.
|
||||||
|
|
||||||
|
Let's try to raise an event with reflection ... Firstly, let's search,
|
||||||
|
but not in `GetEvent`, in `GetField` : [Type.GetField(String,
|
||||||
|
BindingFlags)](http://msdn.microsoft.com/en-us/library/4ek9c21e.aspx)
|
||||||
|
`String` is the name of the field to get and
|
||||||
|
[BindingFlags](http://msdn.microsoft.com/en-us/library/system.reflection.bindingflags.aspx)
|
||||||
|
a bitmask of serarching flags. Note: To use reflexion, use
|
||||||
|
"System.Reflection" Let's try a `GetField`:
|
||||||
|
|
||||||
|
:::csharp
|
||||||
|
FieldInfo my_event_FieldInfo = this.GetType().GetField("my_event",
|
||||||
|
BindingFlags.NonPublic
|
||||||
|
| BindingFlags.Instance);
|
||||||
|
|
||||||
|
Yeah! It's not `null`! we have now the `FieldInfo` of our event. What to
|
||||||
|
do now ? in a `FieldInfo`, we do not have something like "Fire the event",
|
||||||
|
huh But what about "GetValue" ? The "Value" of a "FieldInfo" is the
|
||||||
|
field, so the Value of an event's `FieldInfo` isn't the Event?
|
||||||
|
[FieldInfo.GetValue(object)](http://msdn.microsoft.com/en-us/library/system.reflection.fieldinfo.getvalue.aspx) let's try:
|
||||||
|
|
||||||
|
:::csharp
|
||||||
|
object my_event_by_reflection = my_event_FieldInfo.GetValue(this);
|
||||||
|
|
||||||
|
Is `null` ... ): Ohhhh but, while not registered, an event is `null`... so,
|
||||||
|
let's try adding a handler... Is not null!! Yeah, so we have our event
|
||||||
|
by reflection now.
|
||||||
|
|
||||||
|
Note for those who just said "Why giving an object to `GetValue`? And
|
||||||
|
why giving 'this'":
|
||||||
|
|
||||||
|
- Take a look at the first "this.getType()"
|
||||||
|
- Deduce that it ask the Object to give you its Type, an Object knows
|
||||||
|
its Type.
|
||||||
|
- Note that a Type can't know its Objects...
|
||||||
|
- Finally to get a Field of your Object, you ask the Type to give it
|
||||||
|
or your Object, giving a reference to your Object, here : 'this';
|
||||||
|
|
||||||
|
|
||||||
|
Now, we have an object, which is the event to call, but, how to call
|
||||||
|
it? By reflection? but... where to search? TRICK: Put a
|
||||||
|
breakpoint just after the `GetValue`, when breaked, add a watch on
|
||||||
|
`my_event_by_reflection.GetType()` and browse it... try
|
||||||
|
`my_event_by_reflection.GetType().GetFields()`... nothing... try
|
||||||
|
`my_event_by_reflection.GetType().GetMethods()`... browse it... OH
|
||||||
|
? What is `Invoke` ?
|
||||||
|
|
||||||
|
:::csharp
|
||||||
|
var my_event_invoke = my_event_type.GetMethod("Invoke");
|
||||||
|
|
||||||
|
Searching how to call the Invoke... by reflection? Invoking invoke?
|
||||||
|
|
||||||
|
Let's try:
|
||||||
|
|
||||||
|
:::csharp
|
||||||
|
my_event_invoke.Invoke(my_event_by_reflection, new object[] {this, new EventArgs()} );
|
||||||
|
|
||||||
|
Invoke take the instance of this type, so the object where GetType where
|
||||||
|
called, and in second parameter an array of object to be given as
|
||||||
|
parameter to the method called, we have to give an object and an
|
||||||
|
eventArgs. It Works ! here the full working source code:
|
||||||
|
|
||||||
|
:::csharp
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
class Cage_en_metal
|
||||||
|
{
|
||||||
|
public event EventHandler ecraser;
|
||||||
|
|
||||||
|
public Cage_en_metal()
|
||||||
|
{
|
||||||
|
ecraser += new EventHandler(Libellule_ecraser);
|
||||||
|
fireEvent("ecraser", new EventArgs());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Libellule_ecraser(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Splatch !");
|
||||||
|
}
|
||||||
|
|
||||||
|
void fireEvent(string handler, EventArgs eventArgs)
|
||||||
|
{
|
||||||
|
var eventInfo = this.GetType().GetField(handler,
|
||||||
|
BindingFlags.Instance
|
||||||
|
| BindingFlags.NonPublic);
|
||||||
|
if (eventInfo != null)
|
||||||
|
{
|
||||||
|
var event_member = eventInfo.GetValue(this);
|
||||||
|
// Note : If event_member is null, nobody registered to the event, you can't call it.
|
||||||
|
if (event_member != null)
|
||||||
|
event_member.GetType().GetMethod("Invoke").Invoke(event_member, new object[] { this, eventArgs });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
Title: Integrating google bookmarks in google chrome
|
||||||
|
Date: 2009-04-16 17:56:18
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
As every developer, you have 42 computers, 8 browsers, and spend a lot
|
||||||
|
of time asking why Google Chrome does not integrate Google Bookmarks?
|
||||||
|
Here is a solution: First add the "Add to Google Bookmarks" bookmarklet
|
||||||
|
from here
|
||||||
|
<http://www.google.com/support/chrome/bin/answer.py?hl=en&answer=100215>
|
||||||
|
And then go to chrome's options -> base tab -> Default search
|
||||||
|
engine -> Manage Click "Add" and fill:
|
||||||
|
|
||||||
|
- Name: Google Bookmarks
|
||||||
|
- Keyword: The keyword you wanna enter before a bookmark search in the
|
||||||
|
chrome's address bar
|
||||||
|
- URL: http://www.google.com/bookmarks/find?q=%s
|
||||||
|
|
||||||
|
To search 42, if your keyword is, like mine 'b', type "b 42" in the
|
||||||
|
chrome's address bar and 42 will be searched in your bookmarks.
|
||||||
|
|
||||||
|
Enjoy!
|
58
content/blog/javascript-foncteur.md
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
---
|
||||||
|
Title: Javascript Foncteur
|
||||||
|
Date: 2008-05-08 12:43:30
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
I just discovered, this morning, how to create a Visitor in Javascript:
|
||||||
|
A visitor is an objet who can be used like a function:
|
||||||
|
|
||||||
|
:::javascript
|
||||||
|
var my_foncteur = new A_Foncteur();
|
||||||
|
my_foncteur.can_have_methods(42);
|
||||||
|
my_foncteur("Can be called like a function");
|
||||||
|
|
||||||
|
Implementing it in `C++` is extremly easy, using operator overloading, so
|
||||||
|
overloading the `() operator` of an object, we have a visitor, but in
|
||||||
|
Javascript, in the current version, we do not have operator overloading.
|
||||||
|
So we have the following trick:
|
||||||
|
|
||||||
|
:::javascript
|
||||||
|
/* Don't pollute global scope too much. */
|
||||||
|
window.your_scope = {};
|
||||||
|
|
||||||
|
your_scope.A_Function_Object = function()
|
||||||
|
{
|
||||||
|
/* Prepare a closure */
|
||||||
|
var that = this;
|
||||||
|
this.some_data = "";
|
||||||
|
|
||||||
|
this.foncteur = function()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
** Here, `this` is from the caller, we don't care about it,
|
||||||
|
** but the `that` is from the closure, so it's our `this`.
|
||||||
|
*/
|
||||||
|
alert(that.some_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Add any function you need.
|
||||||
|
*/
|
||||||
|
this.foncteur.set_data = function(data)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
** Same way to get "our" this from the closure.
|
||||||
|
*/
|
||||||
|
that.some_data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (this.foncteur);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enjoy */
|
||||||
|
var test = new your_scope.A_Function_Object();
|
||||||
|
test.set_data(42);
|
||||||
|
test();
|
||||||
|
|
||||||
|
Enjoy!
|
22
content/blog/lazy-loading-in-php-with-spl_autload.md
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
---
|
||||||
|
Title: Lazy Loading in php with spl_autload
|
||||||
|
Date: 2008-11-16 20:40:44
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Today, a very short post about the lazy loading in PHP: `spl_autoload`.
|
||||||
|
I'll not expose everything about it here, cause it's already done here:
|
||||||
|
[http://php.net/autoload](http://php.net/autoload).
|
||||||
|
|
||||||
|
Basically, a Lazy Loading allow you to predifine some paths where PHP
|
||||||
|
should seek for classes to include, this allow you to directly
|
||||||
|
instantiate an object without having included its file.
|
||||||
|
|
||||||
|
:::php
|
||||||
|
public static function lazyLoad($strClassName)
|
||||||
|
{
|
||||||
|
/* some work to find the file to include mixing strClassName */
|
||||||
|
|
||||||
|
/* include your files here... */
|
||||||
|
}
|
||||||
|
spl_autoload_register("lazyLoad");
|
42
content/blog/nfsmount_rpc_failed_2.md
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
---
|
||||||
|
Title: nfsmount: rpc failed: 2
|
||||||
|
Date: 2011-04-18 14:45:03
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
For those, here on the internet, asking themselves what is this fscking
|
||||||
|
`rpc failed: 2` while mounting an NFS, it's possible that the response
|
||||||
|
is here: Your NFS client trying to mount the NFS share will use RPC to
|
||||||
|
communicate with the serveur, il will go like:
|
||||||
|
|
||||||
|
> PORTMAP GETPORT(Program: NFS, Version: 3, Proto: TCP)
|
||||||
|
< PORTMAP Port: 2049
|
||||||
|
> PORTMAP GETPORT(Program: MOUNT, Version: 3, Proto: TCP)
|
||||||
|
< PORTMAP Port 49066
|
||||||
|
> MOUNT MNT(Program Version: 3, Path: /srv/nfsroot/ )
|
||||||
|
< MOUNT Reply error 2, "remote can't support version \#", Program Version (Minimum): 1, Program Version (Maximum): 2
|
||||||
|
|
||||||
|
You can see that the response is "remote can't support version \#" and
|
||||||
|
we should have found this solution in the [RFC 1831 (RPCv2)](http://www.ietf.org/rfc/rfc1831.txt):
|
||||||
|
|
||||||
|
> Given that a call message was accepted, the following is the status
|
||||||
|
> of an attempt to call a remote procedure.
|
||||||
|
>
|
||||||
|
> enum accept_stat {
|
||||||
|
> SUCCESS = 0, /* RPC executed successfully */
|
||||||
|
> PROG_UNAVAIL = 1, /* remote hasn't exported program */
|
||||||
|
> PROG_MISMATCH = 2, /* remote can't support version # */
|
||||||
|
> PROC_UNAVAIL = 3, /* program can't support procedure */
|
||||||
|
> GARBAGE_ARGS = 4, /* procedure can't decode params */
|
||||||
|
> SYSTEM_ERR = 5 /* errors like memory allocation failure */
|
||||||
|
> };
|
||||||
|
|
||||||
|
So the problem is you client asking for a NFS version greater that
|
||||||
|
your server runs... but if your server is running NFS v3, check a `ps
|
||||||
|
aux | grep \[r\]pc.mountd\` for: `root 1411 0.0 0.0 18808 1036 ? Ss
|
||||||
|
Apr15 0:00 /usr/sbin/rpc.mountd --manage-gids --no-nfs-version 3` Did you
|
||||||
|
catch the `--no-nfs-version 3`? If your server is compiled with `NFSv3`
|
||||||
|
support, drop the `--no-nfs-version 3` in your configuration and it should
|
||||||
|
work!
|
||||||
|
|
||||||
|
Enjoy!
|
97
content/blog/pipe-infix-syntax-for-python.md
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
---
|
||||||
|
Title: Pipe: Infix syntax for Python
|
||||||
|
Date: 2011-03-28 20:18:24
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Pipe is a Python module enabling infix syntax in Python. For those
|
||||||
|
asking "Why ?" let's take an example: Compare the readability of the
|
||||||
|
classical prefix syntax:
|
||||||
|
|
||||||
|
:::python
|
||||||
|
sum(select(where(take_while(fib(), lambda x: x < 1000000) lambda x: x % 2), lambda x: x * x))
|
||||||
|
|
||||||
|
And the infix syntax:
|
||||||
|
|
||||||
|
:::python
|
||||||
|
fib() | take_while(lambda x: x < 1000000) \
|
||||||
|
| where(lambda x: x % 2) \
|
||||||
|
| select(lambda x: x * x) \
|
||||||
|
| sum()
|
||||||
|
|
||||||
|
Isn't the infix syntax more readable? The base class of Pipe is kept
|
||||||
|
simple (7 lines of python) and is usable as a decorator permitting you
|
||||||
|
to create new 'pipeable' functions easily. The module provides like 30
|
||||||
|
prepared pipes functions like `where`, `group_by`, `sort`,
|
||||||
|
`take_while`... A pipeable function takes an iterable (`tuple`, `list`,
|
||||||
|
`generator`) and yields to be itself an iterator, so pipeable function can
|
||||||
|
be piped together. Let me introduce the basic usage of the `Pipe` module,
|
||||||
|
then I'll write some bits on how to build new ones: To start, get it
|
||||||
|
from PyPI http://pypi.python.org/pypi/pipe/1.3 and install it, open a
|
||||||
|
REPL, import pipe, and play:
|
||||||
|
|
||||||
|
:::pycon
|
||||||
|
Python 2.6.6 (r266:84292, Dec 26 2010, 22:31:48)
|
||||||
|
[GCC 4.4.5] on linux2
|
||||||
|
Type "help", "copyright", "credits" or "license" for more information.
|
||||||
|
>>> from pipe import *
|
||||||
|
>>> [1, 2, 3, 4, 5] | add
|
||||||
|
15
|
||||||
|
>>> [5, 4, 3, 2, 1] | sort
|
||||||
|
[1, 2, 3, 4, 5]
|
||||||
|
|
||||||
|
Until here it's easy, to know more about available pipes, just read the
|
||||||
|
`help(pipe)` in the REPL, all are explained with an example as a doctest
|
||||||
|
Now as we know that pipeable functions use iterables, we can try to pipe
|
||||||
|
together two or more pipeables:
|
||||||
|
|
||||||
|
:::pycon
|
||||||
|
>>> [1, 2, 3, 4, 5] | where(lambda x: x % 2) | concat
|
||||||
|
'1, 3, 5'
|
||||||
|
>>> [1, 2, 3, 4, 5] | where(lambda x: x % 2) | tail(2) | concat
|
||||||
|
'3, 5'
|
||||||
|
>>> [1, 2, 3, 4, 5] | where(lambda x: x % 2) | tail(2) | select(lambda x: x * x) | concat
|
||||||
|
'9, 25'
|
||||||
|
>>> [1, 2, 3, 4, 5] | where(lambda x: x % 2) | tail(2) | select(lambda x: x * x) | add
|
||||||
|
34
|
||||||
|
|
||||||
|
Now, a bit about lazyness, as Pipe use iterables, the evaluation of a
|
||||||
|
whole Pipe is lazy, so we can play with infinite generators like this
|
||||||
|
one :
|
||||||
|
|
||||||
|
:::pycon
|
||||||
|
>>> def fib():
|
||||||
|
... a, b = 0, 1
|
||||||
|
... while True:
|
||||||
|
... yield a
|
||||||
|
... a, b = b, a + b
|
||||||
|
|
||||||
|
Now we can do every kind of stuff into the fibonacci sequence, like
|
||||||
|
solving the 2nd problem of http://projecteuler.net in a readable one
|
||||||
|
liner:
|
||||||
|
|
||||||
|
> Find the sum of all the even-valued terms in Fibonacci which do not
|
||||||
|
> exceed four million.
|
||||||
|
|
||||||
|
:::pycon
|
||||||
|
>>> euler2 = fib() | where(lambda x: x % 2 == 0) | take_while(lambda x: x < 4000000) | add
|
||||||
|
>>> assert euler2 == 4613732
|
||||||
|
|
||||||
|
Isn't it pretty? Let now see how to create new pipeable functions using
|
||||||
|
the `@pipe` decorator: You want to create a function that yields the
|
||||||
|
first x elements from its input You want its usage to be `(1, 2, 3, 4, 5)
|
||||||
|
| take(2)` to take the fist 2 elements. I know that you are thinking
|
||||||
|
about a basic implementation like:
|
||||||
|
|
||||||
|
:::python
|
||||||
|
def take(iterable, qte):
|
||||||
|
for item in iterable:
|
||||||
|
if qte > 0:
|
||||||
|
qte -= 1
|
||||||
|
yield item
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
Right? You take an iterable, a qantity, and while the quantity is not
|
||||||
|
reached, you just have to yield? OK, just add `@pipe` to you take
|
||||||
|
function and it's pipeable :-)
|
76
content/blog/post-data-lost-on-301-moved-permanently.md
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
---
|
||||||
|
Title: Post data lost on 301 Moved Permanently
|
||||||
|
Date: 2009-05-15 12:50:05
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
What the hell with 301 Moved Permanently HTTP header!? I'll take an
|
||||||
|
exemple to explain my ugly problem, take, a (very ugly cause it's PHP)
|
||||||
|
`index.php`, it could be retrieved by using:
|
||||||
|
|
||||||
|
- http://example.com/directory/index.php `Got the page, 200 OK` or
|
||||||
|
- http://example.com/directory/ `Got the page, 200 OK` or
|
||||||
|
- http://example.com/directory `Got a 301 Moved Permanently Location:...`
|
||||||
|
- http://example.com/directory/ `Just like expected ... but...`
|
||||||
|
|
||||||
|
As you can see, on the captured HTTP headers below, when you POST data
|
||||||
|
on a 301 target, you'll be redirected, but unfortunately you'll lost
|
||||||
|
your POST data, even worse, your request can be reforged as a GET
|
||||||
|
request! Let me show you an example: Request:
|
||||||
|
|
||||||
|
POST /directory HTTP/1.1
|
||||||
|
Host: example.com
|
||||||
|
[user agent, referer, cache control, origin, content type, accept, ...]
|
||||||
|
Content-Length: 7 foo=bar
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
HTTP/1.0 301 Moved Permanently
|
||||||
|
Location: http://example.com/directory/
|
||||||
|
...
|
||||||
|
|
||||||
|
Reforged request:
|
||||||
|
|
||||||
|
GET /directory/ HTTP/1.1
|
||||||
|
Host: example.com
|
||||||
|
|
||||||
|
Why my data isn't kept in the reforged one!? So let's read The `RFC 2616`
|
||||||
|
(about HTTP...)
|
||||||
|
|
||||||
|
> 10.3.2 301 Moved Permanently \[...\] The new permanent URI SHOULD be
|
||||||
|
> given by the Location field in the response. Unless the request method
|
||||||
|
> was HEAD, the entity of the response SHOULD contain a short hypertext
|
||||||
|
> note with a hyperlink to the new URI(s). If the 301 status code is
|
||||||
|
> received in response to a request other than GET or HEAD, the user
|
||||||
|
> agent MUST NOT automatically redirect the request unless it can be
|
||||||
|
> confirmed by the user, since this might change the conditions under
|
||||||
|
> which the request was issued. Note: When automatically redirecting a
|
||||||
|
> POST request after receiving a 301 status code, some existing HTTP/1.0
|
||||||
|
> user agents will erroneously change it into a GET request.
|
||||||
|
|
||||||
|
Ahh, ok, so, for request other than `GET` or `HEAD`, the user agent
|
||||||
|
`MUST NOT` automatically redirect to the request? Ugh, it's not the
|
||||||
|
case in IE 6, 7, 8, Firefox, nor Chrome. And, about the security,
|
||||||
|
while the server recieves the data, it can do everything, for example
|
||||||
|
send it to another server directly. Then I'm wondering, why asking to
|
||||||
|
the user if he allows his data to be transfered? Then, the RFC says
|
||||||
|
an interesting thing...
|
||||||
|
|
||||||
|
> Note: When automatically redirecting a POST request after receiving a
|
||||||
|
> 301 status code, some existing HTTP/1.0 user agents will erroneously
|
||||||
|
> change it into a GET request.
|
||||||
|
|
||||||
|
But, not only HTTP/1.0 user agents, but HTTP/1.1 user agents like
|
||||||
|
browsers and frameworks (as, I encountred the problem firstly in the
|
||||||
|
.NET Framework 3.5, in `HttpWebRequest`) )o:
|
||||||
|
|
||||||
|
Reforging as a GET is clearly not a good idea, but on the other hand,
|
||||||
|
as `POST` requests are not idempotent, we're still happy they're not
|
||||||
|
executed twice: Imagine the POST is "Pay for that shiny new laptop",
|
||||||
|
the payment is executed, but later in the request execution, a 301 to
|
||||||
|
another server is generated, if your client re-POST the same request
|
||||||
|
on the other server, your payment may be executed
|
||||||
|
twice... outch. Respecting idempotency looks clearly more important
|
||||||
|
than generating dumb `GET`, harmless, requests.
|
||||||
|
|
||||||
|
Hope it helps...
|
194
content/blog/python-introducing-ppipe-parallel-pipe.md
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
---
|
||||||
|
Title: Python: Introducing ppipe : Parallel Pipe
|
||||||
|
Date: 2011-04-15 14:07:47
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> /!\ this was highly experimental code written in 2011.
|
||||||
|
> Today you should _NOT_ use it, just look at it if the subject amuses you.
|
||||||
|
> Better take a look at `asyncio` if you want this kind of tools.
|
||||||
|
|
||||||
|
I'll speak about my pipe python module so if you didn't know it, you
|
||||||
|
should first read [the first aricle about
|
||||||
|
pipes](http://dev-tricks.net/pipe-infix-syntax-for-python). The idea
|
||||||
|
behind `ppipe` (parallel pipe) is to transparently make an
|
||||||
|
asynchronous pipe, multithreaded or not. As multithreading isn't an
|
||||||
|
easy piece of code for everybody, with loads of pollutions like locks,
|
||||||
|
queues, giving code far away from the actual simple task you tried to
|
||||||
|
do... The idea is that one kind of multithreading can be nicely
|
||||||
|
handled with a simple design pattern well implemented in python: the
|
||||||
|
queue. The queue handles all the locking part so you don't have to
|
||||||
|
worry about it, just make your workers work, enqueue, dequeue, work
|
||||||
|
... but you still have to create workers! As pipe is not far away from
|
||||||
|
the concept of queue, as, every part of a pipe command works on a
|
||||||
|
piece of data and then git it to the next worker, it's not hard to
|
||||||
|
imagine an asynchronous pipe in which every part of a pipe command can
|
||||||
|
work at the same time. Then it's not hard to imagine that n threads
|
||||||
|
can be started for a single step of a pipe command, leading to a
|
||||||
|
completly multithreaded application having \~0 lines of code bloat for
|
||||||
|
the tread generation / synchronization in your actual code. So I tried
|
||||||
|
to implement it, keeping the actual contract which is very simple that
|
||||||
|
is : Every pipe should take an iterable as input. (I was tempted to
|
||||||
|
change it to 'every pipe must take a Queue as input' ... but if I
|
||||||
|
don't change the contract, normal pipes and parallel pipes should be
|
||||||
|
mixed.), so I created a branch you'll found on
|
||||||
|
[github](https://github.com/julienpalard/pipe/tree/parallel_pipe) with
|
||||||
|
a single new file 'ppipe.py' that, actually, is not 'importable' it's
|
||||||
|
only a proof of concept, that can be launched. Here is the test I
|
||||||
|
wrote using ppipe :
|
||||||
|
|
||||||
|
:::python
|
||||||
|
print "Normal execution :"
|
||||||
|
xrange(4) | where(fat_big_condition1) \
|
||||||
|
| where(fat_big_condition2) \
|
||||||
|
| add | lineout
|
||||||
|
|
||||||
|
print "Parallel with 1 worker"
|
||||||
|
xrange(4) | parallel_where(fat_big_condition1) \
|
||||||
|
| where(fat_big_condition2) \
|
||||||
|
| add | lineout
|
||||||
|
|
||||||
|
print "Parallel with 2 workers"
|
||||||
|
xrange(4) | parallel_where(fat_big_condition1, qte_of_workers=2) \
|
||||||
|
| parallel_where(fat_big_condition2, qte_of_workers=2) | add | stdout
|
||||||
|
|
||||||
|
print "Parallel with 4 workers"
|
||||||
|
xrange(4) | parallel_where(fat_big_condition1, qte_of_workers=4) \
|
||||||
|
| parallel_where(fat_big_condition2, qte_of_workers=4) | add | stdout
|
||||||
|
|
||||||
|
The idea is to compare normal pipe (Normal execution) with asynchronous
|
||||||
|
pipe (Parallel with 1 worker), as 1 worker is the default, and then 2
|
||||||
|
and 4 workers that can be given to a ppipe using 'qte\_of\_workers='.
|
||||||
|
fat\_big\_condition1 and 2 are just f\*cking long running piece of code
|
||||||
|
like fetching something far far away in the internet ... but for our
|
||||||
|
tests, let's use time.sleep:
|
||||||
|
|
||||||
|
:::python
|
||||||
|
def fat_big_condition1(x):
|
||||||
|
log(1, "Working...")
|
||||||
|
time.sleep(2)
|
||||||
|
log(1, "Done !")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def fat_big_condition2(x):
|
||||||
|
log(2, "Working...")
|
||||||
|
time.sleep(2)
|
||||||
|
log(2, "Done !")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
They always return 1... and they log using a simple log function that
|
||||||
|
make fat\_big\_condition1 to log in the left column and
|
||||||
|
fat\_big\_condition2 to log in the right column:
|
||||||
|
|
||||||
|
:::python
|
||||||
|
stdoutlock = Lock()
|
||||||
|
def log(column, text):
|
||||||
|
stdoutlock.acquire()
|
||||||
|
print ' ' * column * 10,
|
||||||
|
print str(datetime.now().time().strftime("%S")),
|
||||||
|
print text
|
||||||
|
stdoutlock.release()
|
||||||
|
|
||||||
|
And that is the output (integers are the current second, so the times
|
||||||
|
didn't start at 0...):
|
||||||
|
|
||||||
|
Normal execution :
|
||||||
|
57 Working...
|
||||||
|
59 Done !
|
||||||
|
59 Working...
|
||||||
|
01 Done !
|
||||||
|
01 Working...
|
||||||
|
03 Done !
|
||||||
|
03 Working...
|
||||||
|
05 Done !
|
||||||
|
05 Working...
|
||||||
|
07 Done !
|
||||||
|
07 Working...
|
||||||
|
09 Done !
|
||||||
|
09 Working...
|
||||||
|
11 Done !
|
||||||
|
11 Working...
|
||||||
|
13 Done !
|
||||||
|
|
||||||
|
// As you can see here, only one condition is executed at a time,
|
||||||
|
// that is a normal behavior for a non-threaded program.
|
||||||
|
|
||||||
|
Parallel with 1 worker
|
||||||
|
13 Working...
|
||||||
|
15 Done !
|
||||||
|
15 Working...
|
||||||
|
15 Working...
|
||||||
|
17 Done !
|
||||||
|
17 Done !
|
||||||
|
17 Working...
|
||||||
|
17 Working...
|
||||||
|
19 Done !
|
||||||
|
19 Done !
|
||||||
|
19 Working...
|
||||||
|
19 Working...
|
||||||
|
21 Done !
|
||||||
|
21 Done !
|
||||||
|
21 Working...
|
||||||
|
23 Done !
|
||||||
|
|
||||||
|
// Just adding parallel_ to the first where, you now see that it's
|
||||||
|
// asynchronous and that the two conditions can work at the
|
||||||
|
// same time, interlacing a bit the output.
|
||||||
|
|
||||||
|
Parallel with 2 workers
|
||||||
|
23 Working...
|
||||||
|
23 Working...
|
||||||
|
25 Done !
|
||||||
|
25 Working...
|
||||||
|
25 Done !
|
||||||
|
25 Working...
|
||||||
|
25 Working...
|
||||||
|
25 Working...
|
||||||
|
27 Done !
|
||||||
|
27 Done !
|
||||||
|
27 Done !
|
||||||
|
27 Working...
|
||||||
|
27 Done !
|
||||||
|
27 Working...
|
||||||
|
29 Done !
|
||||||
|
29 Done !
|
||||||
|
|
||||||
|
|
||||||
|
Parallel with 4 workers
|
||||||
|
55 Working...
|
||||||
|
55 Working...
|
||||||
|
55 Working...
|
||||||
|
55 Working...
|
||||||
|
57 Done !
|
||||||
|
57 Done !
|
||||||
|
57 Done !
|
||||||
|
57 Done !
|
||||||
|
57 Working...
|
||||||
|
57 Working...
|
||||||
|
57 Working...
|
||||||
|
57 Working...
|
||||||
|
59 Done !
|
||||||
|
59 Done !
|
||||||
|
59 Done !
|
||||||
|
59 Done !
|
||||||
|
|
||||||
|
// And now with 2 and 4 workers you can clearly see what
|
||||||
|
// happens, with 2 workers, input is computed by pairs,
|
||||||
|
// and with 4 threads, all the input can be computed at once
|
||||||
|
// but the 4 workers of the 2nd condition have to wait the data
|
||||||
|
// before starting to work, so in the last test, you have 8 threads,
|
||||||
|
// only the 4 firsts are working the 2 first second, then only the 4
|
||||||
|
// others works.
|
||||||
|
|
||||||
|
To make the creation of ppipe simple, I excluded all the 'threading'
|
||||||
|
part in a function usable as a decorator, so writing a parallel\_where
|
||||||
|
give :
|
||||||
|
|
||||||
|
:::python
|
||||||
|
@Pipe
|
||||||
|
@Threaded
|
||||||
|
def parallel_where(item, output, condition):
|
||||||
|
if condition(item):
|
||||||
|
output.put(item)
|
||||||
|
|
||||||
|
You can see the queue here! :-) Enjoy!
|
23
content/blog/reading-peps-from-command-line.md
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
Title: Python: Consulting PEPs from command line, while being offline
|
||||||
|
Date: 2011-04-13 14:20:11
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
One day I wished I could read PEPs in the tube on my laptop... so I
|
||||||
|
searched for a convenient way to do so, and I didn't found ... So I
|
||||||
|
wrote a very simple shell script you can found here :
|
||||||
|
https://github.com/julienpalard/pep I'm currently packaging it for
|
||||||
|
Debian and trying to put it on PyPI, (help is welcome :-) I don't have
|
||||||
|
so much time) but you can make it work just by downloading the script
|
||||||
|
here : https://github.com/JulienPalard/pep/raw/master/pep The script is
|
||||||
|
very simple to use, first you can change a bit its configuration,
|
||||||
|
typically change the LOCAL\_PEP\_PATH to something writeable for a use
|
||||||
|
to don't have to be root to update you PEPs (As running an unknown
|
||||||
|
script as root is a bit scary ) Then you should run \`./pep upgrade with
|
||||||
|
progress\` to download PEPs to you LOCAL\_PEP\_PATH, and then just do a
|
||||||
|
'./pep 8' to read the PEP 8 ! Others features include searching using
|
||||||
|
regex, you can read about it here reading the README the -h or the
|
||||||
|
manpage.
|
||||||
|
|
||||||
|
Hope you'll enjoy it!
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
Title: squid: (101) Network is unreachable when DNS returns IPv6
|
||||||
|
Date: 2011-06-24 17:32:38
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
If you have a Squid proxy configured on a machine that have no IPv6
|
||||||
|
connectivity, and try to reach an IPv6 compatible site, you squid will
|
||||||
|
try to reach the site using IPv6 (I use squid 3.1.6 from Debian Squeeze)
|
||||||
|
and will fail without even trying IPv4, displaying a nice:
|
||||||
|
|
||||||
|
> (101) Network is unreachable.
|
||||||
|
|
||||||
|
The only trick I found to force squid to use IPv4 (After disabling
|
||||||
|
IPv6 on the interface, after disabling IPv6 in the kernel that leads
|
||||||
|
to nothing better...) is:
|
||||||
|
|
||||||
|
tcp_outgoing_address [YOUR PUBLIC IP HERE]
|
||||||
|
|
||||||
|
And can enjoy again your plain old IPv4 network!
|
18
content/blog/the-art-of-events.md
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
---
|
||||||
|
Title: The art of Events
|
||||||
|
Date: 2008-08-29 23:32:55
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
The art of using events to build more independent classes. /\* Found a
|
||||||
|
better example \*/ Imagine you have a class A and a class B. A builds B,
|
||||||
|
and B have to communicate with A (call methods ... ?) Some developers
|
||||||
|
(Boooo (I've done it ... (Booo >> me))) will pass a reference of A
|
||||||
|
to B "A(){B my\_B = new B(this);}" /\* Please note the newB private joke
|
||||||
|
\*/ But what happens when you want an other class, C, who don't know A
|
||||||
|
to build B ? So we have to remove the A's reference in the B ctor. How B
|
||||||
|
should communicate now ? - Using Events ! B exposes an event, the
|
||||||
|
builder of B can register on it. - B can speak to A throwing this event.
|
||||||
|
- Every class can build a B, and can, if it needs, register on its
|
||||||
|
events, doing whatever he wants when the event is thrown. B is now fully
|
||||||
|
reusable!
|
37
content/blog/the-operator-aka-null-coalescing-operator.md
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
---
|
||||||
|
Title: The ?? operator aka the Null Coalescing Operator
|
||||||
|
Date: 2008-11-23 18:01:40
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
If are familiar to the use of ternary operators, you must have
|
||||||
|
encountered several situations like this one :
|
||||||
|
|
||||||
|
:::csharp
|
||||||
|
string pageTitle = getTitle() ? getTitle() : "Default Title";
|
||||||
|
|
||||||
|
You would want to call **getTitle()** only once, but then you wouldn't
|
||||||
|
have a simple one-lined initialization of you variable. Actually there
|
||||||
|
is a simple solution that most langages implements, the **null
|
||||||
|
coalescing operator**; let's replace the above C\# code with this one:
|
||||||
|
|
||||||
|
:::csharp
|
||||||
|
string pageTitle = getTitle() ?? "Default Title";
|
||||||
|
|
||||||
|
Now you have the same behaviour, but with only one call to your
|
||||||
|
function. The syntax is simple :
|
||||||
|
` possibly_null_value ?? value_if_null` the "??" operator is
|
||||||
|
implemented in C\# since C\# 2.0. You also have it in C and C++ as a GNU
|
||||||
|
extension using the "?:" operator :
|
||||||
|
|
||||||
|
:::cpp
|
||||||
|
string pageTitle = getTitle() ?: "Default Title";
|
||||||
|
|
||||||
|
You can get the same behaviour in javascript using the "||" operator :
|
||||||
|
|
||||||
|
:::javascript
|
||||||
|
pageTitle = getTitle() || "Default Title";
|
||||||
|
|
||||||
|
You can read more about this operator
|
||||||
|
[here](http://en.wikipedia.org/wiki/Coalescing_Operator) and
|
||||||
|
[here](http://en.wikipedia.org/wiki/%3F:)
|
76
content/blog/yauib-yet-another-useless-irc-bot.md
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
---
|
||||||
|
Title: YAUIB : Yet another useless IRC Bot !
|
||||||
|
Date: 2011-03-27 23:40:58
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
After 2 years of... non blogging... I'm back! This time I stopped C\#
|
||||||
|
(Oh yeah !) and I'm writing a lot of Python! (Oh YEAH !) So to say
|
||||||
|
HELLO I'll present something useless: My Python IRC Bot. But this
|
||||||
|
article should be usefull, so I'll speak about the Unix Philosophy: As
|
||||||
|
Doug McIlroy said:
|
||||||
|
|
||||||
|
> This is the Unix philosophy: Write programs that do one thing and do
|
||||||
|
> it well. Write programs to work together. Write programs to handle
|
||||||
|
> text streams, because that is a universal interface.
|
||||||
|
|
||||||
|
So my Python Bot is wrote like this, only \~200 lines of Python it has
|
||||||
|
only two interfaces, and they are simple. The first step is to start the
|
||||||
|
bot:
|
||||||
|
|
||||||
|
:::bash
|
||||||
|
./ircbot.py connect 'server' '#chan' 'nickname'
|
||||||
|
|
||||||
|
Ok the bot is connected to a chan, now you have to write some hooks, in
|
||||||
|
yauib every action raise a hook in the 'hooks' directory, you can write
|
||||||
|
a hook in any language you want. As a good start point I wrote a default
|
||||||
|
hook for received messages in hook/pubmsg, simplified like this:
|
||||||
|
|
||||||
|
:::bash
|
||||||
|
#!/bin/sh -f
|
||||||
|
s_login="$(echo "$1" | sed 's#/#__SLASH__#g')"
|
||||||
|
s_host="$2"
|
||||||
|
t_login="$3"
|
||||||
|
t_host="$4"
|
||||||
|
shift 4
|
||||||
|
arguments="$*"
|
||||||
|
command=$(echo "${1%% *}" | sed 's#/#__SLASH__#g')
|
||||||
|
if [ -x "commands/$command" ]
|
||||||
|
then
|
||||||
|
args=$(echo "$1" | sed 's/^ *[^ ]* *//g' )
|
||||||
|
commands/$command $args
|
||||||
|
fi
|
||||||
|
|
||||||
|
You should read : "When a message is received, the command in
|
||||||
|
commands/\[1st word of the message\] is executed." So now you can start
|
||||||
|
to write simple commands in the commands folder, like the command say:
|
||||||
|
|
||||||
|
:::bash
|
||||||
|
#!/bin/sh
|
||||||
|
echo "$*"
|
||||||
|
|
||||||
|
This command is 17 chars long, and now, without restarting your bot, try
|
||||||
|
to make it say something on the channel : you> say hello bot>
|
||||||
|
hello An now you can start to write dauting ones .... like ... display a
|
||||||
|
readeable calendar of the current month like:
|
||||||
|
|
||||||
|
March 2011
|
||||||
|
Su Mo Tu We Th Fr Sa
|
||||||
|
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
|
||||||
|
|
||||||
|
Ready ?
|
||||||
|
|
||||||
|
:::bash
|
||||||
|
#!/bin/sh
|
||||||
|
cal
|
||||||
|
|
||||||
|
As the binary cal is installed on you machine, (windows user, you can
|
||||||
|
leave, now), that's all, your're done ... sorry, it just work :p Et
|
||||||
|
voilà ! You have to keep the UNIX philosophy in mind : - Everything is a
|
||||||
|
file - Write programs that do one thing and do it well And you'll be
|
||||||
|
happy developers ! PS: You can download / contribute to Yauib on
|
||||||
|
https://github.com/JulienPalard/yauib
|
656
content/media/css/github-markdown.css
Normal file
|
@ -0,0 +1,656 @@
|
||||||
|
@font-face {
|
||||||
|
font-family: octicons-anchor;
|
||||||
|
src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAYcAA0AAAAACjQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABMAAAABwAAAAca8vGTk9TLzIAAAFMAAAARAAAAFZG1VHVY21hcAAAAZAAAAA+AAABQgAP9AdjdnQgAAAB0AAAAAQAAAAEACICiGdhc3AAAAHUAAAACAAAAAj//wADZ2x5ZgAAAdwAAADRAAABEKyikaNoZWFkAAACsAAAAC0AAAA2AtXoA2hoZWEAAALgAAAAHAAAACQHngNFaG10eAAAAvwAAAAQAAAAEAwAACJsb2NhAAADDAAAAAoAAAAKALIAVG1heHAAAAMYAAAAHwAAACABEAB2bmFtZQAAAzgAAALBAAAFu3I9x/Nwb3N0AAAF/AAAAB0AAAAvaoFvbwAAAAEAAAAAzBdyYwAAAADP2IQvAAAAAM/bz7t4nGNgZGFgnMDAysDB1Ml0hoGBoR9CM75mMGLkYGBgYmBlZsAKAtJcUxgcPsR8iGF2+O/AEMPsznAYKMwIkgMA5REMOXicY2BgYGaAYBkGRgYQsAHyGMF8FgYFIM0ChED+h5j//yEk/3KoSgZGNgYYk4GRCUgwMaACRoZhDwCs7QgGAAAAIgKIAAAAAf//AAJ4nHWMMQrCQBBF/0zWrCCIKUQsTDCL2EXMohYGSSmorScInsRGL2DOYJe0Ntp7BK+gJ1BxF1stZvjz/v8DRghQzEc4kIgKwiAppcA9LtzKLSkdNhKFY3HF4lK69ExKslx7Xa+vPRVS43G98vG1DnkDMIBUgFN0MDXflU8tbaZOUkXUH0+U27RoRpOIyCKjbMCVejwypzJJG4jIwb43rfl6wbwanocrJm9XFYfskuVC5K/TPyczNU7b84CXcbxks1Un6H6tLH9vf2LRnn8Ax7A5WQAAAHicY2BkYGAA4teL1+yI57f5ysDNwgAC529f0kOmWRiYVgEpDgYmEA8AUzEKsQAAAHicY2BkYGB2+O/AEMPCAAJAkpEBFbAAADgKAe0EAAAiAAAAAAQAAAAEAAAAAAAAKgAqACoAiAAAeJxjYGRgYGBhsGFgYgABEMkFhAwM/xn0QAIAD6YBhwB4nI1Ty07cMBS9QwKlQapQW3VXySvEqDCZGbGaHULiIQ1FKgjWMxknMfLEke2A+IJu+wntrt/QbVf9gG75jK577Lg8K1qQPCfnnnt8fX1NRC/pmjrk/zprC+8D7tBy9DHgBXoWfQ44Av8t4Bj4Z8CLtBL9CniJluPXASf0Lm4CXqFX8Q84dOLnMB17N4c7tBo1AS/Qi+hTwBH4rwHHwN8DXqQ30XXAS7QaLwSc0Gn8NuAVWou/gFmnjLrEaEh9GmDdDGgL3B4JsrRPDU2hTOiMSuJUIdKQQayiAth69r6akSSFqIJuA19TrzCIaY8sIoxyrNIrL//pw7A2iMygkX5vDj+G+kuoLdX4GlGK/8Lnlz6/h9MpmoO9rafrz7ILXEHHaAx95s9lsI7AHNMBWEZHULnfAXwG9/ZqdzLI08iuwRloXE8kfhXYAvE23+23DU3t626rbs8/8adv+9DWknsHp3E17oCf+Z48rvEQNZ78paYM38qfk3v/u3l3u3GXN2Dmvmvpf1Srwk3pB/VSsp512bA/GG5i2WJ7wu430yQ5K3nFGiOqgtmSB5pJVSizwaacmUZzZhXLlZTq8qGGFY2YcSkqbth6aW1tRmlaCFs2016m5qn36SbJrqosG4uMV4aP2PHBmB3tjtmgN2izkGQyLWprekbIntJFing32a5rKWCN/SdSoga45EJykyQ7asZvHQ8PTm6cslIpwyeyjbVltNikc2HTR7YKh9LBl9DADC0U/jLcBZDKrMhUBfQBvXRzLtFtjU9eNHKin0x5InTqb8lNpfKv1s1xHzTXRqgKzek/mb7nB8RZTCDhGEX3kK/8Q75AmUM/eLkfA+0Hi908Kx4eNsMgudg5GLdRD7a84npi+YxNr5i5KIbW5izXas7cHXIMAau1OueZhfj+cOcP3P8MNIWLyYOBuxL6DRylJ4cAAAB4nGNgYoAALjDJyIAOWMCiTIxMLDmZedkABtIBygAAAA==) format('woff');
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body {
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
text-size-adjust: 100%;
|
||||||
|
color: #333;
|
||||||
|
font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.6;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body a {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body a:active,
|
||||||
|
.markdown-body a:hover {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
margin: 0.67em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body img {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body hr {
|
||||||
|
box-sizing: content-box;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body code,
|
||||||
|
.markdown-body kbd,
|
||||||
|
.markdown-body pre {
|
||||||
|
font-family: monospace, monospace;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body input {
|
||||||
|
color: inherit;
|
||||||
|
font: inherit;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body html input[disabled] {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body input {
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body input[type="checkbox"] {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body td,
|
||||||
|
.markdown-body th {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body * {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body input {
|
||||||
|
font: 13px/1.4 Helvetica, arial, nimbussansl, liberationsans, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol";
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body a {
|
||||||
|
color: #4078c0;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body a:hover,
|
||||||
|
.markdown-body a:active {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body hr {
|
||||||
|
height: 0;
|
||||||
|
margin: 15px 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body hr:before {
|
||||||
|
display: table;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body hr:after {
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1,
|
||||||
|
.markdown-body h2,
|
||||||
|
.markdown-body h3,
|
||||||
|
.markdown-body h4,
|
||||||
|
.markdown-body h5,
|
||||||
|
.markdown-body h6 {
|
||||||
|
margin-top: 15px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1 {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h2 {
|
||||||
|
font-size: 21px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h3 {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h4 {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h5 {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h6 {
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body blockquote {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body ul,
|
||||||
|
.markdown-body ol {
|
||||||
|
padding: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body ol ol,
|
||||||
|
.markdown-body ul ol {
|
||||||
|
list-style-type: lower-roman;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body ul ul ol,
|
||||||
|
.markdown-body ul ol ol,
|
||||||
|
.markdown-body ol ul ol,
|
||||||
|
.markdown-body ol ol ol {
|
||||||
|
list-style-type: lower-alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body dd {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body code {
|
||||||
|
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .select::-ms-expand {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .octicon {
|
||||||
|
font: normal normal normal 16px/1 octicons-anchor;
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: none;
|
||||||
|
text-rendering: auto;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .octicon-link:before {
|
||||||
|
content: '\f05c';
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body>*:first-child {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body>*:last-child {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body a:not([href]) {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .anchor {
|
||||||
|
display: inline-block;
|
||||||
|
padding-right: 2px;
|
||||||
|
margin-left: -18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .anchor:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1,
|
||||||
|
.markdown-body h2,
|
||||||
|
.markdown-body h3,
|
||||||
|
.markdown-body h4,
|
||||||
|
.markdown-body h5,
|
||||||
|
.markdown-body h6 {
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1 .octicon-link,
|
||||||
|
.markdown-body h2 .octicon-link,
|
||||||
|
.markdown-body h3 .octicon-link,
|
||||||
|
.markdown-body h4 .octicon-link,
|
||||||
|
.markdown-body h5 .octicon-link,
|
||||||
|
.markdown-body h6 .octicon-link {
|
||||||
|
color: #000;
|
||||||
|
vertical-align: middle;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1:hover .anchor,
|
||||||
|
.markdown-body h2:hover .anchor,
|
||||||
|
.markdown-body h3:hover .anchor,
|
||||||
|
.markdown-body h4:hover .anchor,
|
||||||
|
.markdown-body h5:hover .anchor,
|
||||||
|
.markdown-body h6:hover .anchor {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1:hover .anchor .octicon-link,
|
||||||
|
.markdown-body h2:hover .anchor .octicon-link,
|
||||||
|
.markdown-body h3:hover .anchor .octicon-link,
|
||||||
|
.markdown-body h4:hover .anchor .octicon-link,
|
||||||
|
.markdown-body h5:hover .anchor .octicon-link,
|
||||||
|
.markdown-body h6:hover .anchor .octicon-link {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1 {
|
||||||
|
padding-bottom: 0.3em;
|
||||||
|
font-size: 2.25em;
|
||||||
|
line-height: 1.2;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1 .anchor {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h2 {
|
||||||
|
padding-bottom: 0.3em;
|
||||||
|
font-size: 1.75em;
|
||||||
|
line-height: 1.225;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h2 .anchor {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h3 {
|
||||||
|
font-size: 1.5em;
|
||||||
|
line-height: 1.43;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h3 .anchor {
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h4 {
|
||||||
|
font-size: 1.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h4 .anchor {
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h5 {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h5 .anchor {
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h6 {
|
||||||
|
font-size: 1em;
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h6 .anchor {
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body p,
|
||||||
|
.markdown-body blockquote,
|
||||||
|
.markdown-body ul,
|
||||||
|
.markdown-body ol,
|
||||||
|
.markdown-body dl,
|
||||||
|
.markdown-body table,
|
||||||
|
.markdown-body pre {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body hr {
|
||||||
|
height: 4px;
|
||||||
|
padding: 0;
|
||||||
|
margin: 16px 0;
|
||||||
|
background-color: #e7e7e7;
|
||||||
|
border: 0 none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body ul,
|
||||||
|
.markdown-body ol {
|
||||||
|
padding-left: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body ul ul,
|
||||||
|
.markdown-body ul ol,
|
||||||
|
.markdown-body ol ol,
|
||||||
|
.markdown-body ol ul {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body li>p {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body dl {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body dl dt {
|
||||||
|
padding: 0;
|
||||||
|
margin-top: 16px;
|
||||||
|
font-size: 1em;
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body dl dd {
|
||||||
|
padding: 0 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body blockquote {
|
||||||
|
padding: 0 15px;
|
||||||
|
color: #777;
|
||||||
|
border-left: 4px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body blockquote>:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body blockquote>:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body table {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
word-break: normal;
|
||||||
|
word-break: keep-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body table th {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body table th,
|
||||||
|
.markdown-body table td {
|
||||||
|
padding: 6px 13px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body table tr {
|
||||||
|
background-color: #fff;
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body table tr:nth-child(2n) {
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body img {
|
||||||
|
max-width: 100%;
|
||||||
|
box-sizing: content-box;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body code {
|
||||||
|
padding: 0;
|
||||||
|
padding-top: 0.2em;
|
||||||
|
padding-bottom: 0.2em;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 85%;
|
||||||
|
background-color: rgba(0,0,0,0.04);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body code:before,
|
||||||
|
.markdown-body code:after {
|
||||||
|
letter-spacing: -0.2em;
|
||||||
|
content: "\00a0";
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre>code {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
word-break: normal;
|
||||||
|
white-space: pre;
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .highlight {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .highlight pre,
|
||||||
|
.markdown-body pre {
|
||||||
|
padding: 16px;
|
||||||
|
overflow: auto;
|
||||||
|
font-size: 85%;
|
||||||
|
line-height: 1.45;
|
||||||
|
background-color: #f7f7f7;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .highlight pre {
|
||||||
|
margin-bottom: 0;
|
||||||
|
word-break: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre {
|
||||||
|
word-wrap: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre code {
|
||||||
|
display: inline;
|
||||||
|
max-width: initial;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
overflow: initial;
|
||||||
|
line-height: inherit;
|
||||||
|
word-wrap: normal;
|
||||||
|
background-color: transparent;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre code:before,
|
||||||
|
.markdown-body pre code:after {
|
||||||
|
content: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body kbd {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 3px 5px;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 10px;
|
||||||
|
color: #555;
|
||||||
|
vertical-align: middle;
|
||||||
|
background-color: #fcfcfc;
|
||||||
|
border: solid 1px #ccc;
|
||||||
|
border-bottom-color: #bbb;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: inset 0 -1px 0 #bbb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-c {
|
||||||
|
color: #969896;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-c1,
|
||||||
|
.markdown-body .pl-s .pl-v {
|
||||||
|
color: #0086b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-e,
|
||||||
|
.markdown-body .pl-en {
|
||||||
|
color: #795da3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-s .pl-s1,
|
||||||
|
.markdown-body .pl-smi {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-ent {
|
||||||
|
color: #63a35c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-k {
|
||||||
|
color: #a71d5d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-pds,
|
||||||
|
.markdown-body .pl-s,
|
||||||
|
.markdown-body .pl-s .pl-pse .pl-s1,
|
||||||
|
.markdown-body .pl-sr,
|
||||||
|
.markdown-body .pl-sr .pl-cce,
|
||||||
|
.markdown-body .pl-sr .pl-sra,
|
||||||
|
.markdown-body .pl-sr .pl-sre {
|
||||||
|
color: #183691;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-v {
|
||||||
|
color: #ed6a43;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-id {
|
||||||
|
color: #b52a1d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-ii {
|
||||||
|
background-color: #b52a1d;
|
||||||
|
color: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-sr .pl-cce {
|
||||||
|
color: #63a35c;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-ml {
|
||||||
|
color: #693a17;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mh,
|
||||||
|
.markdown-body .pl-mh .pl-en,
|
||||||
|
.markdown-body .pl-ms {
|
||||||
|
color: #1d3e81;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mq {
|
||||||
|
color: #008080;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mi {
|
||||||
|
color: #333;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mb {
|
||||||
|
color: #333;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-md {
|
||||||
|
background-color: #ffecec;
|
||||||
|
color: #bd2c00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mi1 {
|
||||||
|
background-color: #eaffea;
|
||||||
|
color: #55a532;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mdr {
|
||||||
|
color: #795da3;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mo {
|
||||||
|
color: #1d3e81;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body kbd {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 3px 5px;
|
||||||
|
font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||||
|
line-height: 10px;
|
||||||
|
color: #555;
|
||||||
|
vertical-align: middle;
|
||||||
|
background-color: #fcfcfc;
|
||||||
|
border: solid 1px #ccc;
|
||||||
|
border-bottom-color: #bbb;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: inset 0 -1px 0 #bbb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body:before {
|
||||||
|
display: table;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body:after {
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .task-list-item {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .task-list-item+.task-list-item {
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .task-list-item input {
|
||||||
|
margin: 0 0.35em 0.25em -1.6em;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body :checked+.radio-label {
|
||||||
|
z-index: 1;
|
||||||
|
position: relative;
|
||||||
|
border-color: #4078c0;
|
||||||
|
}
|
469
content/media/css/site.css
Normal file
|
@ -0,0 +1,469 @@
|
||||||
|
article,aside,details,figcaption,figure,
|
||||||
|
footer,header,hgroup,menu,nav,section {
|
||||||
|
display:block;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-moz-focus-inner {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clearfix */
|
||||||
|
.clearfix:after {
|
||||||
|
content: ".";
|
||||||
|
display: block;
|
||||||
|
clear: both;
|
||||||
|
visibility: hidden;
|
||||||
|
line-height: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clearfix {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
* html .clearfix {
|
||||||
|
height: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #37e;
|
||||||
|
text-decoration: underline;
|
||||||
|
text-shadow: 0px 2px 0px #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover{
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
body{
|
||||||
|
font-family: PT Sans, DejaVu Sans, Arial, sans;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
text-shadow: 0px 2px 0px #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
#container{
|
||||||
|
width: 640px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 12px;
|
||||||
|
-moz-box-shadow: 0px 4px 12px #ccc; /* FF3.5+ */
|
||||||
|
-webkit-box-shadow: 0px 4px 12px #ccc; /* Saf3.0+, Chrome */
|
||||||
|
box-shadow: 0px 4px 12px #ccc; /* Opera 10.5, IE 9.0 */
|
||||||
|
filter: progid:DXImageTransform.Microsoft.dropshadow(OffX=12px, OffY=12px, Color='#ccc'); /* IE6,IE7 */
|
||||||
|
-ms-filter: "progid:DXImageTransform.Microsoft.dropshadow(OffX=12px, OffY=12px, Color='#ccc')"; /* IE8 */
|
||||||
|
}
|
||||||
|
|
||||||
|
footer{
|
||||||
|
font-size: 10px;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 24px;
|
||||||
|
text-shadow: 0px 2px 0px #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Button styles from the awesome: http://www.webdesignerwall.com/demo/css-buttons.html */
|
||||||
|
|
||||||
|
.button {
|
||||||
|
display: inline-block;
|
||||||
|
zoom: 1; /* zoom and *display = ie7 hack for display:inline-block */
|
||||||
|
*display: inline;
|
||||||
|
vertical-align: baseline;
|
||||||
|
margin: 0 2px;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
font: 14px/100% Arial, Helvetica, sans-serif;
|
||||||
|
padding: .5em 2em .55em;
|
||||||
|
text-shadow: 0 1px 1px rgba(0,0,0,.3);
|
||||||
|
-webkit-border-radius: .5em;
|
||||||
|
-moz-border-radius: .5em;
|
||||||
|
border-radius: .5em;
|
||||||
|
-webkit-box-shadow: 0 1px 2px rgba(0,0,0,.2);
|
||||||
|
-moz-box-shadow: 0 1px 2px rgba(0,0,0,.2);
|
||||||
|
box-shadow: 0 1px 2px rgba(0,0,0,.2);
|
||||||
|
}
|
||||||
|
.button:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.button:active {
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bigrounded {
|
||||||
|
-webkit-border-radius: 2em;
|
||||||
|
-moz-border-radius: 2em;
|
||||||
|
border-radius: 2em;
|
||||||
|
}
|
||||||
|
.medium {
|
||||||
|
font-size: 12px;
|
||||||
|
padding: .4em 1.5em .42em;
|
||||||
|
}
|
||||||
|
.small {
|
||||||
|
font-size: 11px;
|
||||||
|
padding: .2em 1em .275em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* white */
|
||||||
|
.white {
|
||||||
|
color: #606060;
|
||||||
|
border: solid 1px #b7b7b7;
|
||||||
|
background: #fff;
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#ededed));
|
||||||
|
background: -moz-linear-gradient(top, #fff, #ededed);
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#ededed');
|
||||||
|
}
|
||||||
|
.white:hover {
|
||||||
|
background: #ededed;
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#dcdcdc));
|
||||||
|
background: -moz-linear-gradient(top, #fff, #dcdcdc);
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dcdcdc');
|
||||||
|
}
|
||||||
|
.white:active {
|
||||||
|
color: #999;
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, from(#ededed), to(#fff));
|
||||||
|
background: -moz-linear-gradient(top, #ededed, #fff);
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ededed', endColorstr='#ffffff');
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner{
|
||||||
|
border-bottom: 12px solid #222;
|
||||||
|
padding: 0 12px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner h1{
|
||||||
|
font-weight: 100;
|
||||||
|
font-size: 32px;
|
||||||
|
line-height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.banner h3{
|
||||||
|
color: #666;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner nav{
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner nav li{
|
||||||
|
list-style-type: none;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner nav li a.button{
|
||||||
|
margin:0;
|
||||||
|
-webkit-border-bottom-left-radius: 0;
|
||||||
|
-webkit-border-bottom-right-radius: 0;
|
||||||
|
-moz-border-radius-bottomleft: 0;
|
||||||
|
-moz-border-radius-bottomright: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner nav li a.button:hover{
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.banner nav li a.button.active{
|
||||||
|
color: #d7d7d7;
|
||||||
|
border: solid 1px #333;
|
||||||
|
background: #333;
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, from(#666), to(#000));
|
||||||
|
background: -moz-linear-gradient(top, #666, #000);
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#666666', endColorstr='#000000');
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog_excerpt{
|
||||||
|
padding-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog_excerpt .post time{
|
||||||
|
float: none;
|
||||||
|
clear: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog_excerpt .button{
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog_excerpt h3,
|
||||||
|
h1.title{
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 36px;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog_excerpt h3{
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.content{
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* listing */
|
||||||
|
|
||||||
|
.listing{
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listing img{
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listing li{
|
||||||
|
background-color: #ededed;
|
||||||
|
list-style-type: none;
|
||||||
|
float: left;
|
||||||
|
width: 272px;
|
||||||
|
margin-right: 24px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
padding: 12px;
|
||||||
|
-moz-box-shadow: 0px 4px 12px #ccc; /* FF3.5+ */
|
||||||
|
-webkit-box-shadow: 0px 4px 12px #ccc; /* Saf3.0+, Chrome */
|
||||||
|
box-shadow: 0px 4px 12px #ccc; /* Opera 10.5, IE 9.0 */
|
||||||
|
filter: progid:DXImageTransform.Microsoft.dropshadow(OffX=12px, OffY=12px, Color='#ccc'); /* IE6,IE7 */
|
||||||
|
-ms-filter: "progid:DXImageTransform.Microsoft.dropshadow(OffX=12px, OffY=12px, Color='#ccc')"; /* IE8 */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.listing li:nth-child(2){
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listing li:nth-child(3){
|
||||||
|
clear: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listing li p{
|
||||||
|
font-size: 10px;
|
||||||
|
line-height: 12px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.listing h3{
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 18px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listing time{
|
||||||
|
display:block;
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
padding-top: 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Content */
|
||||||
|
|
||||||
|
article.post p{
|
||||||
|
line-height: 24px;
|
||||||
|
margin: 6px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
article.post img{
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post time{
|
||||||
|
font-size: 12px;
|
||||||
|
color: #999;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tags{
|
||||||
|
margin-bottom: 24px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tags li{
|
||||||
|
list-style-type: none;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tags li a{
|
||||||
|
color: #999;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.tag:before,
|
||||||
|
ul.tags li a:before{
|
||||||
|
content: '\00AB';
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.tag:after,
|
||||||
|
ul.tags li a:after{
|
||||||
|
content: '\00BB';
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tags li a:hover{
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 a, h2 a, h3 a{
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav.post_nav{
|
||||||
|
background-color: #efefef;
|
||||||
|
position: fixed;
|
||||||
|
width: 124px;
|
||||||
|
margin-left: -186px;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
padding-right: 24px;
|
||||||
|
-moz-box-shadow: 0px 2px 4px #ccc; /* FF3.5+ */
|
||||||
|
-webkit-box-shadow: 0px 2px 4px #ccc; /* Saf3.0+, Chrome */
|
||||||
|
box-shadow: 0px 2px 4px #ccc; /* Opera 10.5, IE 9.0 */
|
||||||
|
filter: progid:DXImageTransform.Microsoft.dropshadow(OffX=12px, OffY=12px, Color='#ccc'); /* IE6,IE7 */
|
||||||
|
-ms-filter: "progid:DXImageTransform.Microsoft.dropshadow(OffX=12px, OffY=12px, Color='#ccc')"; /* IE8 */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
a.backlink{
|
||||||
|
display:block;
|
||||||
|
line-height: 24px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.backlink:before{
|
||||||
|
content: '\2190';
|
||||||
|
}
|
||||||
|
|
||||||
|
a.prev:before{
|
||||||
|
content: '\00AB';
|
||||||
|
}
|
||||||
|
|
||||||
|
a.next:after{
|
||||||
|
content: '\00BB';
|
||||||
|
}
|
||||||
|
|
||||||
|
a.prev{
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.prev,
|
||||||
|
a.next{
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.next{ float: right };
|
||||||
|
|
||||||
|
a.backlink:hover, a.prev:hover, a.next:hover{
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post_nav a.disabled{
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post_nav a{
|
||||||
|
color: #666;
|
||||||
|
text-decoration: none;
|
||||||
|
text-shadow: 0px 2px 0px #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post_nav div{
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
width: 58px;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#facebook_like{
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.archives ul.posts{
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.archives li.post{
|
||||||
|
list-style-type: none;
|
||||||
|
border-bottom: 1px dotted #ccc;
|
||||||
|
padding: 12px 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.archives li.post time{
|
||||||
|
color: #999;
|
||||||
|
text-shadow: 0px 2px 0px #fff;
|
||||||
|
margin-right: 24px;
|
||||||
|
display:block;
|
||||||
|
float: left;
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.archives li.post a{
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.archives ul.tags{
|
||||||
|
float: right;
|
||||||
|
margin-bottom:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.codebox {
|
||||||
|
margin-top: 8px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-family: Consolas, Monaco, monospace;
|
||||||
|
background-color: rgba(0,0,0,0.04);
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 0;
|
||||||
|
padding-top: 0.2em;
|
||||||
|
padding-bottom: 0.2em;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 85%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.codehilite {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
padding: 1em;
|
||||||
|
font: normal 10pt Consolas, Monaco, monospace;
|
||||||
|
overflow-x: auto;
|
||||||
|
background-color: #F0F3F3;
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.code figcaption {
|
||||||
|
font-size: 10px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 3px;
|
||||||
|
right: 12px;
|
||||||
|
color: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
article {
|
||||||
|
color: #333;
|
||||||
|
}
|
59
content/media/css/syntax.css
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
.c, .cm { color: #998; font-style: italic } /* Comments */
|
||||||
|
.err { color: #a61717; background-color: #e3d2d2 } /* Error */
|
||||||
|
.k { font-weight: bold } /* Keyword */
|
||||||
|
.o { font-weight: bold } /* Operator */
|
||||||
|
.cp { color: #999; font-weight: bold } /* Comment.Preproc */
|
||||||
|
.c1 { color: #998; font-style: italic } /* Comment.Single */
|
||||||
|
.cs { color: #999; font-weight: bold; font-style: italic } /* Comment.Special */
|
||||||
|
.gd { color: #000; background-color: #ffdddd } /* Generic.Deleted */
|
||||||
|
.gd .x { color: #000; background-color: #ffaaaa } /* Generic.Deleted.Specific */
|
||||||
|
.ge { font-style: italic } /* Generic.Emph */
|
||||||
|
.gr { color: #a00 } /* Generic.Error */
|
||||||
|
.gh { color: #999 } /* Generic.Heading */
|
||||||
|
.gi { color: #000; background-color: #ddffdd } /* Generic.Inserted */
|
||||||
|
.gi .x { color: #000; background-color: #aaffaa } /* Generic.Inserted.Specific */
|
||||||
|
.go { color: #888 } /* Generic.Output */
|
||||||
|
.gp { color: #555 } /* Generic.Prompt */
|
||||||
|
.gs { font-weight: bold } /* Generic.Strong */
|
||||||
|
.gu { color: #aaaaaa } /* Generic.Subheading */
|
||||||
|
.gt { color: #a00 } /* Generic.Traceback */
|
||||||
|
.kc { font-weight: bold } /* Keyword.Constant */
|
||||||
|
.kd { font-weight: bold } /* Keyword.Declaration */
|
||||||
|
.kp { font-weight: bold } /* Keyword.Pseudo */
|
||||||
|
.kr { font-weight: bold } /* Keyword.Reserved */
|
||||||
|
.kt { color: #445588; font-weight: bold } /* Keyword.Type */
|
||||||
|
.m { color: #099 } /* Literal.Number */
|
||||||
|
.s { color: #d14 } /* Literal.String */
|
||||||
|
.na { color: #008080 } /* Name.Attribute */
|
||||||
|
.nb { color: #0086B3 } /* Name.Builtin */
|
||||||
|
.nc { color: #445588; font-weight: bold } /* Name.Class */
|
||||||
|
.no { color: #008080 } /* Name.Constant */
|
||||||
|
.ni { color: #800080 } /* Name.Entity */
|
||||||
|
.ne { color: #900; font-weight: bold } /* Name.Exception */
|
||||||
|
.nf { color: #900; font-weight: bold } /* Name.Function */
|
||||||
|
.nn { color: #555 } /* Name.Namespace */
|
||||||
|
.nt { color: #000080 } /* Name.Tag */
|
||||||
|
.nv { color: #008080 } /* Name.Variable */
|
||||||
|
.ow { font-weight: bold } /* Operator.Word */
|
||||||
|
.w { color: #bbb } /* Text.Whitespace */
|
||||||
|
.mf { color: #099 } /* Literal.Number.Float */
|
||||||
|
.mh { color: #099 } /* Literal.Number.Hex */
|
||||||
|
.mi { color: #099 } /* Literal.Number.Integer */
|
||||||
|
.mo { color: #099 } /* Literal.Number.Oct */
|
||||||
|
.sb { color: #d14 } /* Literal.String.Backtick */
|
||||||
|
.sc { color: #d14 } /* Literal.String.Char */
|
||||||
|
.sd { color: #d14 } /* Literal.String.Doc */
|
||||||
|
.s2 { color: #d14 } /* Literal.String.Double */
|
||||||
|
.se { color: #d14 } /* Literal.String.Escape */
|
||||||
|
.sh { color: #d14 } /* Literal.String.Heredoc */
|
||||||
|
.si { color: #d14 } /* Literal.String.Interpol */
|
||||||
|
.sx { color: #d14 } /* Literal.String.Other */
|
||||||
|
.sr { color: #009926 } /* Literal.String.Regex */
|
||||||
|
.s1 { color: #d14 } /* Literal.String.Single */
|
||||||
|
.ss { color: #990073 } /* Literal.String.Symbol */
|
||||||
|
.bp { color: #999 } /* Name.Builtin.Pseudo */
|
||||||
|
.vc { color: #008080 } /* Name.Variable.Class */
|
||||||
|
.vg { color: #008080 } /* Name.Variable.Global */
|
||||||
|
.vi { color: #008080 } /* Name.Variable.Instance */
|
||||||
|
.il { color: #099 } /* Literal.Number.Integer.Long */
|
||||||
|
|
BIN
content/media/images/airport.png
Normal file
After Width: | Height: | Size: 453 KiB |
BIN
content/media/images/apple-touch-icon.png
Normal file
After Width: | Height: | Size: 640 B |
BIN
content/media/images/dark.png
Normal file
After Width: | Height: | Size: 516 KiB |
BIN
content/media/images/favicon.ico
Normal file
After Width: | Height: | Size: 894 B |
13
content/media/js/libs/dd_belatedpng.js
Normal file
16
content/media/js/libs/jquery-1.5.1.min.js
vendored
Normal file
1
content/media/js/libs/meta.yaml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
uses_template: false
|
2
content/media/js/libs/modernizr-1.7.min.js
vendored
Normal file
5
content/pages/about-palard-julien.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
Title: About Julien
|
||||||
|
Date: 2008-08-14 19:25:52
|
||||||
|
status: hidden
|
||||||
|
|
||||||
|
Just check out [mdk.fr](mdk.fr)!
|
66
content/pages/image_resolution.md
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
status: hidden
|
||||||
|
Title: image-quality
|
||||||
|
robots: noindex
|
||||||
|
|
||||||
|
<style>
|
||||||
|
img {width: 700px}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
# Possible steps of compression
|
||||||
|
|
||||||
|
|
||||||
|
## Original photo: `22MB`
|
||||||
|
|
||||||
|
![100](https://mdk.fr/jpg-compress/Photo3.jpg)
|
||||||
|
|
||||||
|
|
||||||
|
## Pre-processed image from melty media server: `16MB`
|
||||||
|
|
||||||
|
mogrify -resize '25000000@>' "$file" # Limit the size to ~ 5000 * 5000 px
|
||||||
|
jpegoptim -p --strip-all -m100 "$file"
|
||||||
|
|
||||||
|
![100](https://mdk.fr/jpg-compress/melty-so.jpg)
|
||||||
|
|
||||||
|
|
||||||
|
## Base image with a 75% quality, `3.5MB`
|
||||||
|
|
||||||
|
cp Photo3.jpg Photo3-75pct.jpg
|
||||||
|
jpegoptim -p --strip-all -m75 Photo3-75pct.jpg
|
||||||
|
Photo3-75pct.jpg 5184x3310 24bit N Exiff IPTC ICC XMP Adobe [OK] 22460774 --> 3618936 bytes (83.89%), optimized.
|
||||||
|
|
||||||
|
![75](https://mdk.fr/jpg-compress/Photo3-75pct.jpg)
|
||||||
|
|
||||||
|
|
||||||
|
## Base image, resized to 1400px 100%: `2.3MB`
|
||||||
|
|
||||||
|
gm convert -resize 1400x892 -quality 100 Photo3.jpg Photo3-1400px.jpg
|
||||||
|
|
||||||
|
![100](https://mdk.fr/jpg-compress/Photo3-1400px.jpg)
|
||||||
|
|
||||||
|
|
||||||
|
## Base image, resized to 700px 100%: `677KB`
|
||||||
|
|
||||||
|
gm convert -resize 700x446 -quality 100 Photo3.jpg Photo3-700px.jpg
|
||||||
|
|
||||||
|
![100](https://mdk.fr/jpg-compress/Photo3-700px.jpg)
|
||||||
|
|
||||||
|
|
||||||
|
## Base image, resized to 1400px 75%: `356K`
|
||||||
|
|
||||||
|
gm convert -resize 1400x892 -quality 75 Photo3.jpg Photo3-1400px-75pct.jpg
|
||||||
|
|
||||||
|
![100](https://mdk.fr/jpg-compress/Photo3-1400px-75pct.jpg)
|
||||||
|
|
||||||
|
|
||||||
|
## Base image, resized to 700 75%: `152K`
|
||||||
|
|
||||||
|
gm convert -resize 700x446 -quality 75 Photo3.jpg Photo3-700px-75pct.jpg
|
||||||
|
|
||||||
|
![100](https://mdk.fr/jpg-compress/Photo3-700px-75pct.jpg)
|
||||||
|
|
||||||
|
|
||||||
|
## melty mediaserver image 75%, 700px, `82KB`
|
||||||
|
|
||||||
|
wget http://media.melty.fr/pmedia-3287063-ajust_700-f1469549124/jacky-mornai-et-loup-pendant-amazing-summer.jpg
|
||||||
|
|
||||||
|
![75](https://mdk.fr/jpg-compress/melty-ajust700.jpg)
|
26
content/pages/index.md
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
Title: Julien Palard
|
||||||
|
Date: 2016-05-28
|
||||||
|
description: Julien Palard - mdk.fr
|
||||||
|
URL:
|
||||||
|
save_as: index.html
|
||||||
|
status: hidden
|
||||||
|
|
||||||
|
Senior lead software architect at [meltygroup](http://www.meltygroup.com).
|
||||||
|
|
||||||
|
- My projects
|
||||||
|
- [Translating python doc in French](http://www.afpy.org/doc/python/3.5/).
|
||||||
|
- [logtop](http://julienpalard.github.io/logtop/) a realtime log line analzer.
|
||||||
|
- [Pipe](//julienpalard.github.io/Pipe/) a python module to use | like in a shell ([on Github](https://github.com/JulienPalard/Pipe), [on PyPI](//pypi.python.org/pypi/pipe/1.3)).
|
||||||
|
- [ashttp](//julienpalard.github.io/ashttp/) a way to expose shell command output as http.
|
||||||
|
- [yauib](//julienpalard.github.io/yauib/) an IRC bot allowing you to write modules in any languages.
|
||||||
|
- If you're reading Knuth, a python [mix_machine](https://github.com/JulienPalard/mix-machine) may be usefull.
|
||||||
|
- [kisspush](http://www.kisspush.net/) is an app to easily get notifications.
|
||||||
|
|
||||||
|
- Join me on [IRC quakenet or freenode, I'm `mdk`](//irc.lc/freenode/)
|
||||||
|
- [My gpg key](//mdk.fr/gpg.pub) and [ssh key](//mdk.fr/id_ed25519.pub)
|
||||||
|
|
||||||
|
> "Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning." - Rick Cook - The Wizardry Compiled (1989) -
|
||||||
|
|
||||||
|
> "Walking on water and developing software from a specification are easy if both are frozen." - Edward V. Berard -
|
||||||
|
|
||||||
|
> "Refactoring is like doing the washing up after cooking." - @tobyparkins -
|
91
content/pages/python.md
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
status: hidden
|
||||||
|
Title: Python chez Sup'Internet
|
||||||
|
Slug: python-sup-internet
|
||||||
|
robots: noindex
|
||||||
|
|
||||||
|
[TOC]
|
||||||
|
# Survol des 6 cours
|
||||||
|
|
||||||
|
- Introduction de python, de l'environnement de python, de moi, puis coder quelques lignes
|
||||||
|
- Se familiariser avec le langage
|
||||||
|
- Premier projet pour commencer à écrire un bon volume de code et se rendre compte qu'il faut de l'organisation
|
||||||
|
- Organisation d'un projet (git / tests / documentation / github / intégration continue / ...)
|
||||||
|
- Présentation et utilisation de Jupyter et son environnement proche: les graphiques, le machine learning, les maths ...
|
||||||
|
- Le dernier cours ouvre les portes sur comment continuer, comment, et quels outils utiliser.
|
||||||
|
|
||||||
|
|
||||||
|
# Les rendus
|
||||||
|
|
||||||
|
- Au cours 1, un rendu par mail pour me faire une idée du niveau de chacun
|
||||||
|
- Au cours 3, un rendu par mail par groupe, sans correction
|
||||||
|
- Au cours 4, un rendu sur github par groupe
|
||||||
|
- Au cours 5, un rendu par mail sous forme de Jupyter notebook
|
||||||
|
|
||||||
|
|
||||||
|
# Cours 1: Introduction
|
||||||
|
|
||||||
|
Objectif: Me présenter, présenter Python et son environnement, jusqu'a coder quelques lignes.
|
||||||
|
|
||||||
|
|
||||||
|
## Python
|
||||||
|
|
||||||
|
- 2 vs 3: ça fait 9 ans que les cours commencent par ça.
|
||||||
|
- Utilisent Python : YouTube, Dropbox, Reddit, [data scientists](https://twitter.com/enthought/status/842016365133344788), …
|
||||||
|
- [Python en tête des langages open source utilisés pour le Big Data et l’IA (slide 15)](https://speakerdeck.com/sfermigier/ia-aupres-des-poles-de-competitivite)
|
||||||
|
- Open source et cross platform
|
||||||
|
|
||||||
|
|
||||||
|
## Installation de l'interpréteur
|
||||||
|
|
||||||
|
Anaconda pour windows, Atom ou Pycharm EDU pour les indécis, éditeur au choix pour les autres,
|
||||||
|
repl.it pour ceux qui sont à la rache.
|
||||||
|
|
||||||
|
- [Using on Windows](https://docs.python.org/3/using/windows.html)
|
||||||
|
- [Using on Mac](https://docs.python.org/3/using/mac.html)
|
||||||
|
|
||||||
|
|
||||||
|
## Utiliser le REPL
|
||||||
|
|
||||||
|
- Utiliser le REPL comme une calculatrice
|
||||||
|
- Introduire les strings et les opérateurs binaires compatibles
|
||||||
|
|
||||||
|
|
||||||
|
## La syntaxe
|
||||||
|
|
||||||
|
- Les structures de données `int`, `str`, `list` et `dict`.
|
||||||
|
- Les structure de contrôle `if`, `for`
|
||||||
|
- Les variables
|
||||||
|
- Les appels de fonctions, les builtins `range`, `print`
|
||||||
|
|
||||||
|
|
||||||
|
## Exercices
|
||||||
|
|
||||||
|
- Hello World
|
||||||
|
- Project euler
|
||||||
|
- Checkio sur (PyCharm ou sur le site)
|
||||||
|
|
||||||
|
|
||||||
|
## La communauté, les ressources
|
||||||
|
|
||||||
|
- La doc, la doc fr, IRC
|
||||||
|
- Le BDFL, les PEPs
|
||||||
|
- Les conférences (pyconfr, …), les meetups.
|
||||||
|
|
||||||
|
|
||||||
|
## Exercice à rendre par mail
|
||||||
|
|
||||||
|
Afficher, un par ligne, tous les nombres pairs compris dans l'intervalle `[0; 50]`. L'expéditeur doit être votre mail d'étudiant. Le code doit utiliser une fonction `is_even` pour déterminer si le nombre est pair ou pas.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Cours 2: Language
|
||||||
|
|
||||||
|
Objectif: Se familiariser avec le langage, dédiaboliser des concepts, autremment dit le "Zen of Python".
|
||||||
|
|
||||||
|
|
||||||
|
## Cours sur les fonctions
|
||||||
|
|
||||||
|
## Exercices sur les fonctions
|
||||||
|
|
||||||
|
## Cours sur les classes: Les données avant les algorithmes
|
||||||
|
|
7
content/robots.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
User-Agent: *
|
||||||
|
Disallow: /photos
|
||||||
|
Disallow: /gallery
|
||||||
|
Disallow: /fun
|
||||||
|
Disallow: /doc
|
||||||
|
Disallow: /epitech
|
||||||
|
Disallow: /x
|
49
pelicanconf.py
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*- #
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
AUTHOR = 'Julien Palard'
|
||||||
|
SITENAME = 'mdk.fr'
|
||||||
|
SITEURL = 'https://mdk.fr'
|
||||||
|
|
||||||
|
PATH = 'content'
|
||||||
|
|
||||||
|
TIMEZONE = 'Europe/Paris'
|
||||||
|
|
||||||
|
DEFAULT_LANG = 'fr'
|
||||||
|
|
||||||
|
# Feed generation is usually not desired when developing
|
||||||
|
FEED_ALL_ATOM = 'feeds/all.atom.xml'
|
||||||
|
CATEGORY_FEED_ATOM = 'feeds/%s.atom.xml'
|
||||||
|
TRANSLATION_FEED_ATOM = None
|
||||||
|
AUTHOR_FEED_ATOM = 'feeds/%s.atom.xml'
|
||||||
|
AUTHOR_FEED_RSS = 'feeds/%s.rss.xml'
|
||||||
|
|
||||||
|
# Blogroll
|
||||||
|
# LINKS = (('Pelican', 'http://getpelican.com/'),
|
||||||
|
# ('Python.org', 'http://python.org/'),
|
||||||
|
# ('Jinja2', 'http://jinja.pocoo.org/'),
|
||||||
|
# ('You can modify those links in your config file', '#'),)
|
||||||
|
|
||||||
|
# Social widget
|
||||||
|
SOCIAL = (('twitter', 'https://twitter.com/sizeof'),
|
||||||
|
('github', 'https://github.com/julienpalard'),
|
||||||
|
('so', 'http://stackoverflow.com/users/232831/julien-palard')
|
||||||
|
)
|
||||||
|
|
||||||
|
DEFAULT_PAGINATION = 10
|
||||||
|
|
||||||
|
THEME = 'theme'
|
||||||
|
THEME_STATIC_DIR = 'theme'
|
||||||
|
ARTICLE_URL = '{category}/{slug}.html'
|
||||||
|
STATIC_PATHS = ['images']
|
||||||
|
ARTICLE_SAVE_AS = '{category}/{slug}.html'
|
||||||
|
CATEGORY_URL = '{slug}/'
|
||||||
|
CATEGORY_SAVE_AS = '{slug}/index.html'
|
||||||
|
|
||||||
|
# Uncomment following line if you want document-relative URLs when developing
|
||||||
|
#RELATIVE_URLS = True
|
||||||
|
|
||||||
|
MARKDOWN = {
|
||||||
|
'extensions': ['toc', 'markdown.extensions.codehilite']
|
||||||
|
}
|
24
publishconf.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*- #
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
# This file is only used if you use `make publish` or
|
||||||
|
# explicitly specify it as your config file.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
sys.path.append(os.curdir)
|
||||||
|
from pelicanconf import *
|
||||||
|
|
||||||
|
SITEURL = ''
|
||||||
|
RELATIVE_URLS = False
|
||||||
|
|
||||||
|
FEED_ALL_ATOM = 'feeds/all.atom.xml'
|
||||||
|
CATEGORY_FEED_ATOM = 'feeds/%s.atom.xml'
|
||||||
|
|
||||||
|
DELETE_OUTPUT_DIRECTORY = True
|
||||||
|
|
||||||
|
# Following items are often useful when publishing
|
||||||
|
|
||||||
|
#DISQUS_SITENAME = ""
|
||||||
|
#GOOGLE_ANALYTICS = ""
|
13
requirements.rst
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
blinker==1.4
|
||||||
|
docutils==0.13.1
|
||||||
|
feedgenerator==1.9
|
||||||
|
Jinja2==2.9.6
|
||||||
|
Markdown==2.6.8
|
||||||
|
MarkupSafe==1.0
|
||||||
|
pelican==3.7.1
|
||||||
|
pkg-resources==0.0.0
|
||||||
|
Pygments==2.2.0
|
||||||
|
python-dateutil==2.6.0
|
||||||
|
pytz==2017.2
|
||||||
|
six==1.10.0
|
||||||
|
Unidecode==0.4.20
|
BIN
theme/static/images/icons/aboutme.png
Normal file
After Width: | Height: | Size: 751 B |
BIN
theme/static/images/icons/bitbucket.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
theme/static/images/icons/delicious.png
Normal file
After Width: | Height: | Size: 958 B |
BIN
theme/static/images/icons/facebook.png
Normal file
After Width: | Height: | Size: 202 B |
BIN
theme/static/images/icons/github.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
theme/static/images/icons/gitorious.png
Normal file
After Width: | Height: | Size: 227 B |
BIN
theme/static/images/icons/gittip.png
Normal file
After Width: | Height: | Size: 487 B |
BIN
theme/static/images/icons/google-groups.png
Normal file
After Width: | Height: | Size: 803 B |
BIN
theme/static/images/icons/google-plus.png
Normal file
After Width: | Height: | Size: 527 B |
BIN
theme/static/images/icons/hackernews.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
theme/static/images/icons/lastfm.png
Normal file
After Width: | Height: | Size: 975 B |
BIN
theme/static/images/icons/linkedin.png
Normal file
After Width: | Height: | Size: 896 B |
BIN
theme/static/images/icons/reddit.png
Normal file
After Width: | Height: | Size: 693 B |
BIN
theme/static/images/icons/rss.png
Normal file
After Width: | Height: | Size: 879 B |
BIN
theme/static/images/icons/slideshare.png
Normal file
After Width: | Height: | Size: 535 B |
BIN
theme/static/images/icons/speakerdeck.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
theme/static/images/icons/stackoverflow.png
Normal file
After Width: | Height: | Size: 916 B |
BIN
theme/static/images/icons/twitter.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
theme/static/images/icons/vimeo.png
Normal file
After Width: | Height: | Size: 544 B |
BIN
theme/static/images/icons/youtube.png
Normal file
After Width: | Height: | Size: 458 B |
46
theme/templates/analytics.html
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
{% if GOOGLE_ANALYTICS %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
var _gaq = _gaq || [];
|
||||||
|
_gaq.push(['_setAccount', '{{GOOGLE_ANALYTICS}}']);
|
||||||
|
_gaq.push(['_trackPageview']);
|
||||||
|
(function() {
|
||||||
|
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||||
|
ga.src = 'https://ssl.google-analytics.com/ga.js';
|
||||||
|
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
|
{% if GAUGES %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
var _gauges = _gauges || [];
|
||||||
|
(function() {
|
||||||
|
var t = document.createElement('script');
|
||||||
|
t.type = 'text/javascript';
|
||||||
|
t.async = true;
|
||||||
|
t.id = 'gauges-tracker';
|
||||||
|
t.setAttribute('data-site-id', '{{GAUGES}}');
|
||||||
|
t.src = '//secure.gaug.es/track.js';
|
||||||
|
var s = document.getElementsByTagName('script')[0];
|
||||||
|
s.parentNode.insertBefore(t, s);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
|
{% if PIWIK_URL and PIWIK_SITE_ID %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
{% if PIWIK_SSL_URL %}
|
||||||
|
var pkBaseURL = "{{ PIWIK_SSL_URL }}";
|
||||||
|
{% else %}
|
||||||
|
var pkBaseURL = "{{ PIWIK_URL }}";
|
||||||
|
{% endif %}
|
||||||
|
var _paq = _paq || [];
|
||||||
|
_paq.push(["trackPageView"]);
|
||||||
|
_paq.push(["enableLinkTracking"]);
|
||||||
|
(function() {
|
||||||
|
var u=(("https:" == document.location.protocol) ? "https" : "http")+"://"+pkBaseURL+"/";
|
||||||
|
_paq.push(["setTrackerUrl", u+"piwik.php"]);
|
||||||
|
_paq.push(["setSiteId", "{{ PIWIK_SITE_ID }}"]);
|
||||||
|
var d=document, g=d.createElement("script"), s=d.getElementsByTagName("script")[0]; g.type="text/javascript";
|
||||||
|
g.defer=true; g.async=true; g.src=u+"piwik.js"; s.parentNode.insertBefore(g,s);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
13
theme/templates/archives.html
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block content %}
|
||||||
|
<section id="content" class="body">
|
||||||
|
<h1>Archives for {{ SITENAME }}</h1>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
{% for article in dates %}
|
||||||
|
<dt>{{ article.locale_date }}</dt>
|
||||||
|
<dd><a href="{{ SITEURL }}/{{ article.url }}">{{ article.title }}</a></dd>
|
||||||
|
{% endfor %}
|
||||||
|
</dl>
|
||||||
|
</section>
|
||||||
|
{% endblock %}
|
37
theme/templates/article.html
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block title %}{{ article.title|striptags }}{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<section id="content" class="body">
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<h1 class="entry-title">
|
||||||
|
<a href="{{ SITEURL }}/{{ article.url }}" rel="bookmark"
|
||||||
|
title="Permalink to {{ article.title|striptags }}">{{ article.title }}</a></h1>
|
||||||
|
{% include 'twitter.html' %}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="entry-content">
|
||||||
|
{% include 'article_infos.html' %}
|
||||||
|
{{ article.content }}
|
||||||
|
</div><!-- /.entry-content -->
|
||||||
|
{% if DISQUS_SITENAME and SITEURL and article.status != "draft" %}
|
||||||
|
<div class="comments">
|
||||||
|
<h2>Comments !</h2>
|
||||||
|
<div id="disqus_thread"></div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var disqus_shortname = '{{ DISQUS_SITENAME }}';
|
||||||
|
var disqus_identifier = '{{ article.url }}';
|
||||||
|
var disqus_url = '{{ SITEURL }}/{{ article.url }}';
|
||||||
|
(function() {
|
||||||
|
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
|
||||||
|
dsq.src = '//{{ DISQUS_SITENAME }}.disqus.com/embed.js';
|
||||||
|
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<noscript>Please enable JavaScript to view the comments.</noscript>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
{% endblock %}
|
23
theme/templates/article_infos.html
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<footer class="post-info">
|
||||||
|
<abbr class="published" title="{{ article.date.isoformat() }}">
|
||||||
|
Published: {{ article.locale_date }}
|
||||||
|
</abbr>
|
||||||
|
{% if article.modified %}
|
||||||
|
<br />
|
||||||
|
<abbr class="modified" title="{{ article.modified.isoformat() }}">
|
||||||
|
Updated: {{ article.locale_modified }}
|
||||||
|
</abbr>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if article.authors %}
|
||||||
|
<address class="vcard author">
|
||||||
|
By {% for author in article.authors %}
|
||||||
|
<a class="url fn" href="{{ SITEURL }}/{{ author.url }}">{{ author }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</address>
|
||||||
|
{% endif %}
|
||||||
|
<p>In <a href="{{ SITEURL }}/{{ article.category.url }}">{{ article.category }}</a>.</p>
|
||||||
|
{% include 'taglist.html' %}
|
||||||
|
{% import 'translations.html' as translations with context %}
|
||||||
|
{{ translations.translations_for(article) }}
|
||||||
|
</footer><!-- /.post-info -->
|
2
theme/templates/author.html
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
{% extends "index.html" %}
|
||||||
|
{% block title %}{{ SITENAME }} - {{ author }}{% endblock %}
|
16
theme/templates/authors.html
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}{{ SITENAME }} - Authors{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<section id="content" class="body">
|
||||||
|
<h1>Authors on {{ SITENAME }}</h1>
|
||||||
|
<ul>
|
||||||
|
{% for author, articles in authors|sort %}
|
||||||
|
<li><a href="{{ SITEURL }}/{{ author.url }}">{{ author }}</a> ({{ articles|count }})</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{% endblock %}
|
91
theme/templates/base.html
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="{{ DEFAULT_LANG }}">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
|
||||||
|
<title>{% block title %}{{ SITENAME }}{%endblock%}</title>
|
||||||
|
<meta name="viewport" content="width=800">
|
||||||
|
<style>
|
||||||
|
{% include "reset.css" %}
|
||||||
|
|
||||||
|
{% include "monokai.css" %}
|
||||||
|
|
||||||
|
{% include "typogrify.css" %}
|
||||||
|
|
||||||
|
{% include "main.css" %}
|
||||||
|
|
||||||
|
{% include "github-markdown.css" %}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
{% if FEED_ALL_ATOM %}
|
||||||
|
<link href="{{ FEED_DOMAIN }}/{{ FEED_ALL_ATOM }}" type="application/atom+xml" rel="alternate" title="{{ SITENAME }} Atom Feed" />
|
||||||
|
{% endif %}
|
||||||
|
{% if FEED_ALL_RSS %}
|
||||||
|
<link href="{{ FEED_DOMAIN }}/{{ FEED_ALL_RSS }}" type="application/rss+xml" rel="alternate" title="{{ SITENAME }} RSS Feed" />
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!--[if IE]>
|
||||||
|
<script src="https://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
{% block header %}{%endblock%}
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body id="index" class="markdown-body home">
|
||||||
|
{% include 'github.html' %}
|
||||||
|
<header id="banner" class="body">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="title"><a href="{{ SITEURL }}/">{{ SITENAME }} {% if SITESUBTITLE %} <strong>{{ SITESUBTITLE }}</strong>{% endif %}</a></h1>
|
||||||
|
<nav><ul>
|
||||||
|
{% for title, link in MENUITEMS %}
|
||||||
|
<li><a href="{{ link }}">{{ title }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
{% if DISPLAY_PAGES_ON_MENU -%}
|
||||||
|
{% for pg in PAGES %}
|
||||||
|
<li{% if pg == page %} class="active"{% endif %}><a href="{{ SITEURL }}/{{ pg.url }}">{{ pg.title }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if DISPLAY_CATEGORIES_ON_MENU -%}
|
||||||
|
{% for cat, null in categories %}
|
||||||
|
<li{% if cat == category %} class="active"{% endif %}><a href="{{ SITEURL }}/{{ cat.url }}">{{ cat }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if SOCIAL or FEED_ALL_ATOM or FEED_ALL_RSS %}
|
||||||
|
{% if FEED_ALL_ATOM %}
|
||||||
|
<li class="social"><a href="{{ FEED_DOMAIN }}/{{ FEED_ALL_ATOM }}" type="application/atom+xml" rel="alternate"></a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if FEED_ALL_RSS %}
|
||||||
|
<li class="social"><a href="{{ FEED_DOMAIN }}/{{ FEED_ALL_RSS }}" type="application/rss+xml" rel="alternate"></a></li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% for name, link in SOCIAL %}
|
||||||
|
<li class="social"><a href="{{ link }}"></a></li>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</ul></nav>
|
||||||
|
</div>
|
||||||
|
</header><!-- /#banner -->
|
||||||
|
{% block content %}
|
||||||
|
{% endblock %}
|
||||||
|
<section id="extras" class="body">
|
||||||
|
{% if LINKS %}
|
||||||
|
<div class="blogroll">
|
||||||
|
<h2>blogroll</h2>
|
||||||
|
<ul>
|
||||||
|
{% for name, link in LINKS %}
|
||||||
|
<li><a href="{{ link }}">{{ name }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div><!-- /.blogroll -->
|
||||||
|
{% endif %}
|
||||||
|
</section><!-- /#extras -->
|
||||||
|
|
||||||
|
<footer id="contentinfo" class="body">
|
||||||
|
<address id="about" class="vcard body">
|
||||||
|
Proudly powered by <a href="http://getpelican.com/">Pelican</a>, which takes great advantage of <a href="http://python.org">Python</a>.
|
||||||
|
</address><!-- /#about -->
|
||||||
|
</footer><!-- /#contentinfo -->
|
||||||
|
|
||||||
|
{% include 'analytics.html' %}
|
||||||
|
{% include 'disqus_script.html' %}
|
||||||
|
</body>
|
||||||
|
</html>
|
2
theme/templates/category.html
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
{% extends "index.html" %}
|
||||||
|
{% block title %}{{ SITENAME }} - {{ category }}{% endblock %}
|
1
theme/templates/comments.html
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{% if DISQUS_SITENAME %}<p>There are <a href="{{ SITEURL }}/{{ article.url }}#disqus_thread">comments</a>.</p>{% endif %}
|
11
theme/templates/disqus_script.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{% if DISQUS_SITENAME %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
var disqus_shortname = '{{ DISQUS_SITENAME }}';
|
||||||
|
(function () {
|
||||||
|
var s = document.createElement('script'); s.async = true;
|
||||||
|
s.type = 'text/javascript';
|
||||||
|
s.src = 'https://' + disqus_shortname + '.disqus.com/count.js';
|
||||||
|
(document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
|
||||||
|
}());
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
655
theme/templates/github-markdown.css
Normal file
|
@ -0,0 +1,655 @@
|
||||||
|
@font-face {
|
||||||
|
font-family: octicons-anchor;
|
||||||
|
src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAYcAA0AAAAACjQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABMAAAABwAAAAca8vGTk9TLzIAAAFMAAAARAAAAFZG1VHVY21hcAAAAZAAAAA+AAABQgAP9AdjdnQgAAAB0AAAAAQAAAAEACICiGdhc3AAAAHUAAAACAAAAAj//wADZ2x5ZgAAAdwAAADRAAABEKyikaNoZWFkAAACsAAAAC0AAAA2AtXoA2hoZWEAAALgAAAAHAAAACQHngNFaG10eAAAAvwAAAAQAAAAEAwAACJsb2NhAAADDAAAAAoAAAAKALIAVG1heHAAAAMYAAAAHwAAACABEAB2bmFtZQAAAzgAAALBAAAFu3I9x/Nwb3N0AAAF/AAAAB0AAAAvaoFvbwAAAAEAAAAAzBdyYwAAAADP2IQvAAAAAM/bz7t4nGNgZGFgnMDAysDB1Ml0hoGBoR9CM75mMGLkYGBgYmBlZsAKAtJcUxgcPsR8iGF2+O/AEMPsznAYKMwIkgMA5REMOXicY2BgYGaAYBkGRgYQsAHyGMF8FgYFIM0ChED+h5j//yEk/3KoSgZGNgYYk4GRCUgwMaACRoZhDwCs7QgGAAAAIgKIAAAAAf//AAJ4nHWMMQrCQBBF/0zWrCCIKUQsTDCL2EXMohYGSSmorScInsRGL2DOYJe0Ntp7BK+gJ1BxF1stZvjz/v8DRghQzEc4kIgKwiAppcA9LtzKLSkdNhKFY3HF4lK69ExKslx7Xa+vPRVS43G98vG1DnkDMIBUgFN0MDXflU8tbaZOUkXUH0+U27RoRpOIyCKjbMCVejwypzJJG4jIwb43rfl6wbwanocrJm9XFYfskuVC5K/TPyczNU7b84CXcbxks1Un6H6tLH9vf2LRnn8Ax7A5WQAAAHicY2BkYGAA4teL1+yI57f5ysDNwgAC529f0kOmWRiYVgEpDgYmEA8AUzEKsQAAAHicY2BkYGB2+O/AEMPCAAJAkpEBFbAAADgKAe0EAAAiAAAAAAQAAAAEAAAAAAAAKgAqACoAiAAAeJxjYGRgYGBhsGFgYgABEMkFhAwM/xn0QAIAD6YBhwB4nI1Ty07cMBS9QwKlQapQW3VXySvEqDCZGbGaHULiIQ1FKgjWMxknMfLEke2A+IJu+wntrt/QbVf9gG75jK577Lg8K1qQPCfnnnt8fX1NRC/pmjrk/zprC+8D7tBy9DHgBXoWfQ44Av8t4Bj4Z8CLtBL9CniJluPXASf0Lm4CXqFX8Q84dOLnMB17N4c7tBo1AS/Qi+hTwBH4rwHHwN8DXqQ30XXAS7QaLwSc0Gn8NuAVWou/gFmnjLrEaEh9GmDdDGgL3B4JsrRPDU2hTOiMSuJUIdKQQayiAth69r6akSSFqIJuA19TrzCIaY8sIoxyrNIrL//pw7A2iMygkX5vDj+G+kuoLdX4GlGK/8Lnlz6/h9MpmoO9rafrz7ILXEHHaAx95s9lsI7AHNMBWEZHULnfAXwG9/ZqdzLI08iuwRloXE8kfhXYAvE23+23DU3t626rbs8/8adv+9DWknsHp3E17oCf+Z48rvEQNZ78paYM38qfk3v/u3l3u3GXN2Dmvmvpf1Srwk3pB/VSsp512bA/GG5i2WJ7wu430yQ5K3nFGiOqgtmSB5pJVSizwaacmUZzZhXLlZTq8qGGFY2YcSkqbth6aW1tRmlaCFs2016m5qn36SbJrqosG4uMV4aP2PHBmB3tjtmgN2izkGQyLWprekbIntJFing32a5rKWCN/SdSoga45EJykyQ7asZvHQ8PTm6cslIpwyeyjbVltNikc2HTR7YKh9LBl9DADC0U/jLcBZDKrMhUBfQBvXRzLtFtjU9eNHKin0x5InTqb8lNpfKv1s1xHzTXRqgKzek/mb7nB8RZTCDhGEX3kK/8Q75AmUM/eLkfA+0Hi908Kx4eNsMgudg5GLdRD7a84npi+YxNr5i5KIbW5izXas7cHXIMAau1OueZhfj+cOcP3P8MNIWLyYOBuxL6DRylJ4cAAAB4nGNgYoAALjDJyIAOWMCiTIxMLDmZedkABtIBygAAAA==) format('woff');
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body {
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
text-size-adjust: 100%;
|
||||||
|
color: #333;
|
||||||
|
font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.6;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body a {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body a:active,
|
||||||
|
.markdown-body a:hover {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
margin: 0.67em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body img {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body hr {
|
||||||
|
box-sizing: content-box;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body code,
|
||||||
|
.markdown-body kbd,
|
||||||
|
.markdown-body pre {
|
||||||
|
font-family: monospace, monospace;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body input {
|
||||||
|
color: inherit;
|
||||||
|
font: inherit;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body html input[disabled] {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body input {
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body input[type="checkbox"] {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body td,
|
||||||
|
.markdown-body th {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body * {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body input {
|
||||||
|
font: 13px/1.4 Helvetica, arial, nimbussansl, liberationsans, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol";
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body a {
|
||||||
|
color: #4078c0;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body a:hover,
|
||||||
|
.markdown-body a:active {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body hr {
|
||||||
|
height: 0;
|
||||||
|
margin: 15px 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body hr:before {
|
||||||
|
display: table;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body hr:after {
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1,
|
||||||
|
.markdown-body h2,
|
||||||
|
.markdown-body h3,
|
||||||
|
.markdown-body h4,
|
||||||
|
.markdown-body h5,
|
||||||
|
.markdown-body h6 {
|
||||||
|
margin-top: 15px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1 {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h2 {
|
||||||
|
font-size: 21px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h3 {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h4 {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h5 {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h6 {
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body blockquote {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body ul,
|
||||||
|
.markdown-body ol {
|
||||||
|
padding: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body ol ol,
|
||||||
|
.markdown-body ul ol {
|
||||||
|
list-style-type: lower-roman;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body ul ul ol,
|
||||||
|
.markdown-body ul ol ol,
|
||||||
|
.markdown-body ol ul ol,
|
||||||
|
.markdown-body ol ol ol {
|
||||||
|
list-style-type: lower-alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body dd {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body code {
|
||||||
|
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .select::-ms-expand {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .octicon {
|
||||||
|
font: normal normal normal 16px/1 octicons-anchor;
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: none;
|
||||||
|
text-rendering: auto;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .octicon-link:before {
|
||||||
|
content: '\f05c';
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body>*:first-child {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body>*:last-child {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body a:not([href]) {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .anchor {
|
||||||
|
display: inline-block;
|
||||||
|
padding-right: 2px;
|
||||||
|
margin-left: -18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .anchor:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1,
|
||||||
|
.markdown-body h2,
|
||||||
|
.markdown-body h3,
|
||||||
|
.markdown-body h4,
|
||||||
|
.markdown-body h5,
|
||||||
|
.markdown-body h6 {
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1 .octicon-link,
|
||||||
|
.markdown-body h2 .octicon-link,
|
||||||
|
.markdown-body h3 .octicon-link,
|
||||||
|
.markdown-body h4 .octicon-link,
|
||||||
|
.markdown-body h5 .octicon-link,
|
||||||
|
.markdown-body h6 .octicon-link {
|
||||||
|
color: #000;
|
||||||
|
vertical-align: middle;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1:hover .anchor,
|
||||||
|
.markdown-body h2:hover .anchor,
|
||||||
|
.markdown-body h3:hover .anchor,
|
||||||
|
.markdown-body h4:hover .anchor,
|
||||||
|
.markdown-body h5:hover .anchor,
|
||||||
|
.markdown-body h6:hover .anchor {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1:hover .anchor .octicon-link,
|
||||||
|
.markdown-body h2:hover .anchor .octicon-link,
|
||||||
|
.markdown-body h3:hover .anchor .octicon-link,
|
||||||
|
.markdown-body h4:hover .anchor .octicon-link,
|
||||||
|
.markdown-body h5:hover .anchor .octicon-link,
|
||||||
|
.markdown-body h6:hover .anchor .octicon-link {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1 {
|
||||||
|
padding-bottom: 0.3em;
|
||||||
|
font-size: 2.25em;
|
||||||
|
line-height: 1.2;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1 .anchor {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h2 {
|
||||||
|
padding-bottom: 0.3em;
|
||||||
|
font-size: 1.75em;
|
||||||
|
line-height: 1.225;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h2 .anchor {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h3 {
|
||||||
|
font-size: 1.5em;
|
||||||
|
line-height: 1.43;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h3 .anchor {
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h4 {
|
||||||
|
font-size: 1.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h4 .anchor {
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h5 {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h5 .anchor {
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h6 {
|
||||||
|
font-size: 1em;
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h6 .anchor {
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body p,
|
||||||
|
.markdown-body blockquote,
|
||||||
|
.markdown-body ul,
|
||||||
|
.markdown-body ol,
|
||||||
|
.markdown-body dl,
|
||||||
|
.markdown-body table,
|
||||||
|
.markdown-body pre {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body hr {
|
||||||
|
height: 4px;
|
||||||
|
padding: 0;
|
||||||
|
margin: 16px 0;
|
||||||
|
background-color: #e7e7e7;
|
||||||
|
border: 0 none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body ul,
|
||||||
|
.markdown-body ol {
|
||||||
|
padding-left: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body ul ul,
|
||||||
|
.markdown-body ul ol,
|
||||||
|
.markdown-body ol ol,
|
||||||
|
.markdown-body ol ul {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body li>p {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body dl {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body dl dt {
|
||||||
|
padding: 0;
|
||||||
|
margin-top: 16px;
|
||||||
|
font-size: 1em;
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body dl dd {
|
||||||
|
padding: 0 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body blockquote {
|
||||||
|
padding: 0 15px;
|
||||||
|
color: #777;
|
||||||
|
border-left: 4px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body blockquote>:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body blockquote>:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body table {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
word-break: normal;
|
||||||
|
word-break: keep-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body table th {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body table th,
|
||||||
|
.markdown-body table td {
|
||||||
|
padding: 6px 13px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body table tr {
|
||||||
|
background-color: #fff;
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body table tr:nth-child(2n) {
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body img {
|
||||||
|
max-width: 100%;
|
||||||
|
box-sizing: content-box;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body code {
|
||||||
|
padding: 0;
|
||||||
|
padding-top: 0.2em;
|
||||||
|
padding-bottom: 0.2em;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 85%;
|
||||||
|
background-color: rgba(0,0,0,0.04);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body code:before,
|
||||||
|
.markdown-body code:after {
|
||||||
|
letter-spacing: -0.2em;
|
||||||
|
content: "\00a0";
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre>code {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
word-break: normal;
|
||||||
|
white-space: pre;
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .highlight {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .highlight pre,
|
||||||
|
.markdown-body pre {
|
||||||
|
padding: 16px;
|
||||||
|
overflow: auto;
|
||||||
|
font-size: 85%;
|
||||||
|
line-height: 1.45;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .highlight pre {
|
||||||
|
margin-bottom: 0;
|
||||||
|
word-break: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre {
|
||||||
|
word-wrap: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre code {
|
||||||
|
display: inline;
|
||||||
|
max-width: initial;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
overflow: initial;
|
||||||
|
line-height: inherit;
|
||||||
|
word-wrap: normal;
|
||||||
|
background-color: transparent;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre code:before,
|
||||||
|
.markdown-body pre code:after {
|
||||||
|
content: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body kbd {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 3px 5px;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 10px;
|
||||||
|
color: #555;
|
||||||
|
vertical-align: middle;
|
||||||
|
background-color: #fcfcfc;
|
||||||
|
border: solid 1px #ccc;
|
||||||
|
border-bottom-color: #bbb;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: inset 0 -1px 0 #bbb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-c {
|
||||||
|
color: #969896;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-c1,
|
||||||
|
.markdown-body .pl-s .pl-v {
|
||||||
|
color: #0086b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-e,
|
||||||
|
.markdown-body .pl-en {
|
||||||
|
color: #795da3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-s .pl-s1,
|
||||||
|
.markdown-body .pl-smi {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-ent {
|
||||||
|
color: #63a35c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-k {
|
||||||
|
color: #a71d5d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-pds,
|
||||||
|
.markdown-body .pl-s,
|
||||||
|
.markdown-body .pl-s .pl-pse .pl-s1,
|
||||||
|
.markdown-body .pl-sr,
|
||||||
|
.markdown-body .pl-sr .pl-cce,
|
||||||
|
.markdown-body .pl-sr .pl-sra,
|
||||||
|
.markdown-body .pl-sr .pl-sre {
|
||||||
|
color: #183691;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-v {
|
||||||
|
color: #ed6a43;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-id {
|
||||||
|
color: #b52a1d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-ii {
|
||||||
|
background-color: #b52a1d;
|
||||||
|
color: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-sr .pl-cce {
|
||||||
|
color: #63a35c;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-ml {
|
||||||
|
color: #693a17;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mh,
|
||||||
|
.markdown-body .pl-mh .pl-en,
|
||||||
|
.markdown-body .pl-ms {
|
||||||
|
color: #1d3e81;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mq {
|
||||||
|
color: #008080;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mi {
|
||||||
|
color: #333;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mb {
|
||||||
|
color: #333;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-md {
|
||||||
|
background-color: #ffecec;
|
||||||
|
color: #bd2c00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mi1 {
|
||||||
|
background-color: #eaffea;
|
||||||
|
color: #55a532;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mdr {
|
||||||
|
color: #795da3;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .pl-mo {
|
||||||
|
color: #1d3e81;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body kbd {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 3px 5px;
|
||||||
|
font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||||
|
line-height: 10px;
|
||||||
|
color: #555;
|
||||||
|
vertical-align: middle;
|
||||||
|
background-color: #fcfcfc;
|
||||||
|
border: solid 1px #ccc;
|
||||||
|
border-bottom-color: #bbb;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: inset 0 -1px 0 #bbb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body:before {
|
||||||
|
display: table;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body:after {
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .task-list-item {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .task-list-item+.task-list-item {
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body .task-list-item input {
|
||||||
|
margin: 0 0.35em 0.25em -1.6em;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body :checked+.radio-label {
|
||||||
|
z-index: 1;
|
||||||
|
position: relative;
|
||||||
|
border-color: #4078c0;
|
||||||
|
}
|
9
theme/templates/github.html
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{% if GITHUB_URL %}
|
||||||
|
<a href="{{ GITHUB_URL }}">
|
||||||
|
{% if GITHUB_POSITION != "left" %}
|
||||||
|
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
|
||||||
|
{% else %}
|
||||||
|
<img style="position: absolute; top: 0; left: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_left_white_ffffff.png" alt="Fork me on GitHub" />
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
59
theme/templates/index.html
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block content_title %}{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
{% if articles %}
|
||||||
|
{% for article in articles_page.object_list %}
|
||||||
|
|
||||||
|
{# First item #}
|
||||||
|
{% if loop.first and not articles_page.has_previous() %}
|
||||||
|
<aside id="featured" class="body">
|
||||||
|
<article>
|
||||||
|
<h1 class="entry-title"><a href="{{ SITEURL }}/{{ article.url }}">{{ article.title }}</a></h1>
|
||||||
|
{% include 'article_infos.html' %}{{ article.content }}{% include 'comments.html' %}
|
||||||
|
</article>
|
||||||
|
</aside><!-- /#featured -->
|
||||||
|
{% if loop.length > 1 %}
|
||||||
|
<section id="content" class="body">
|
||||||
|
<h1>Other articles</h1>
|
||||||
|
<hr />
|
||||||
|
<ol id="posts-list" class="hfeed">
|
||||||
|
{% endif %}
|
||||||
|
{# other items #}
|
||||||
|
{% else %}
|
||||||
|
{% if loop.first %}
|
||||||
|
<section id="content" class="body">
|
||||||
|
<ol id="posts-list" class="hfeed" start="{{ articles_paginator.per_page -1 }}">
|
||||||
|
{% endif %}
|
||||||
|
<li><article class="hentry">
|
||||||
|
<header>
|
||||||
|
<h1><a href="{{ SITEURL }}/{{ article.url }}" rel="bookmark"
|
||||||
|
title="Permalink to {{ article.title|striptags }}">{{ article.title }}</a></h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="entry-content">
|
||||||
|
{% include 'article_infos.html' %}
|
||||||
|
{{ article.summary }}
|
||||||
|
<a class="readmore" href="{{ SITEURL }}/{{ article.url }}">read more</a>
|
||||||
|
{% include 'comments.html' %}
|
||||||
|
</div><!-- /.entry-content -->
|
||||||
|
</article></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if loop.last %}
|
||||||
|
{% if loop.length > 1 or articles_page.has_other_pages() %}
|
||||||
|
</ol><!-- /#posts-list -->
|
||||||
|
{% if articles_page.has_other_pages() %}
|
||||||
|
{% include 'pagination.html' %}
|
||||||
|
{% endif %}
|
||||||
|
</section><!-- /#content -->
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<section id="content" class="body">
|
||||||
|
<h2>Pages</h2>
|
||||||
|
{% for page in PAGES %}
|
||||||
|
<li><a href="{{ SITEURL }}/{{ page.url }}">{{ page.title }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</section>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock content %}
|
379
theme/templates/main.css
Normal file
|
@ -0,0 +1,379 @@
|
||||||
|
@import url(https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz&subset=latin);
|
||||||
|
|
||||||
|
/***** Global *****/
|
||||||
|
/* Paragraphs */
|
||||||
|
div.line-block,
|
||||||
|
p { margin-top: 1em;
|
||||||
|
margin-bottom: 1em;}
|
||||||
|
|
||||||
|
em, i {font-style: italic;}
|
||||||
|
|
||||||
|
div.highlight pre {
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-info {
|
||||||
|
float:right;
|
||||||
|
margin:10px;
|
||||||
|
padding:5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-info p{
|
||||||
|
margin-top: 1px;
|
||||||
|
margin-bottom: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.readmore { float: right }
|
||||||
|
|
||||||
|
dl {margin: 0 0 1.5em 0;}
|
||||||
|
dt {font-weight: bold;}
|
||||||
|
dd {margin-left: 1.5em;}
|
||||||
|
|
||||||
|
pre{color: #f8f8f2; padding: 10px; margin: 10px; overflow: auto;}
|
||||||
|
|
||||||
|
/* Quotes */
|
||||||
|
blockquote {
|
||||||
|
margin: 20px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
cite {}
|
||||||
|
|
||||||
|
q {}
|
||||||
|
|
||||||
|
div.note {
|
||||||
|
float: right;
|
||||||
|
margin: 5px;
|
||||||
|
font-size: 85%;
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tables */
|
||||||
|
table {margin: .5em auto 1.5em auto; width: 98%;}
|
||||||
|
|
||||||
|
/* Thead */
|
||||||
|
thead th {padding: .5em .4em; text-align: left;}
|
||||||
|
thead td {}
|
||||||
|
|
||||||
|
/* Tbody */
|
||||||
|
tbody td {padding: .5em .4em;}
|
||||||
|
tbody th {}
|
||||||
|
|
||||||
|
tbody .alt td {}
|
||||||
|
tbody .alt th {}
|
||||||
|
|
||||||
|
/* Tfoot */
|
||||||
|
tfoot th {}
|
||||||
|
tfoot td {}
|
||||||
|
|
||||||
|
/* HTML5 tags */
|
||||||
|
header, section, footer,
|
||||||
|
aside, nav, article, figure {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Layout *****/
|
||||||
|
.body {clear: both; margin: 0 auto;}
|
||||||
|
img.right, figure.right {float: right; margin: 0 0 2em 2em;}
|
||||||
|
img.left, figure.left {float: left; margin: 0 2em 2em 0;}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Header
|
||||||
|
*****************/
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 970px;
|
||||||
|
padding-right: 15px;
|
||||||
|
padding-left: 15px;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body h1.title {
|
||||||
|
margin-top: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#banner {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
padding: 30px 0;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2.5em 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Banner */
|
||||||
|
#banner h1 {font-size: 3.571em; line-height: 0;}
|
||||||
|
#banner h1 a:link, #banner h1 a:visited {
|
||||||
|
color: #000305;
|
||||||
|
display: block;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0 0 .6em .2em;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
#banner h1 a:hover, #banner h1 a:active {
|
||||||
|
background: none;
|
||||||
|
text-decoration: underline;
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#banner h1 strong {font-size: 0.36em; font-weight: normal;}
|
||||||
|
|
||||||
|
/* Main Nav */
|
||||||
|
#banner nav {
|
||||||
|
font-size: 1.143em;
|
||||||
|
height: 40px;
|
||||||
|
line-height: 30px;
|
||||||
|
margin: 0 auto 2em auto;
|
||||||
|
padding: 0;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
border-radius: 5px;
|
||||||
|
-moz-border-radius: 5px;
|
||||||
|
-webkit-border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#banner nav ul {list-style: none; margin: 0 auto; width: 800px;}
|
||||||
|
#banner nav li {float: left; display: inline; margin: 0;}
|
||||||
|
|
||||||
|
#banner nav a:link, #banner nav a:visited {
|
||||||
|
color: #333;
|
||||||
|
display: inline-block;
|
||||||
|
height: 30px;
|
||||||
|
padding: 5px 1.5em;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
#banner nav a:hover, #banner nav a:active,
|
||||||
|
#banner nav .active a:link, #banner nav .active a:visited {
|
||||||
|
text-decoration: underline;
|
||||||
|
color: #333;
|
||||||
|
text-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#banner nav li:first-child a {
|
||||||
|
border-top-left-radius: 5px;
|
||||||
|
-moz-border-radius-topleft: 5px;
|
||||||
|
-webkit-border-top-left-radius: 5px;
|
||||||
|
|
||||||
|
border-bottom-left-radius: 5px;
|
||||||
|
-moz-border-radius-bottomleft: 5px;
|
||||||
|
-webkit-border-bottom-left-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Featured
|
||||||
|
*****************/
|
||||||
|
#featured {
|
||||||
|
background: #fff;
|
||||||
|
margin-bottom: 2em;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 20px;
|
||||||
|
width: 760px;
|
||||||
|
|
||||||
|
border-radius: 10px;
|
||||||
|
-moz-border-radius: 10px;
|
||||||
|
-webkit-border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#featured figure {
|
||||||
|
border: 2px solid #eee;
|
||||||
|
float: right;
|
||||||
|
margin: 0.786em 2em 0 5em;
|
||||||
|
width: 248px;
|
||||||
|
}
|
||||||
|
#featured figure img {display: block; float: right;}
|
||||||
|
|
||||||
|
#featured h2 {color: #C74451; font-size: 1.714em; margin-bottom: 0.333em;}
|
||||||
|
#featured h3 {font-size: 1.429em; margin-bottom: .5em;}
|
||||||
|
|
||||||
|
#featured h3 a:link, #featured h3 a:visited {color: #000305; text-decoration: none;}
|
||||||
|
#featured h3 a:hover, #featured h3 a:active {color: #fff;}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Body
|
||||||
|
*****************/
|
||||||
|
#content {
|
||||||
|
min-width: 200px;
|
||||||
|
width: 1020px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 30px;
|
||||||
|
|
||||||
|
background: #fff;
|
||||||
|
margin-bottom: 2em;
|
||||||
|
overflow: hidden;
|
||||||
|
#padding: 20px 20px;
|
||||||
|
|
||||||
|
border-radius: 10px;
|
||||||
|
-moz-border-radius: 10px;
|
||||||
|
-webkit-border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Extras
|
||||||
|
*****************/
|
||||||
|
#extras {margin: 0 auto 3em auto; overflow: hidden;}
|
||||||
|
|
||||||
|
#extras ul {list-style: none; margin: 0;}
|
||||||
|
#extras li {border-bottom: 1px solid #fff;}
|
||||||
|
#extras h2 {
|
||||||
|
color: #C74350;
|
||||||
|
font-size: 1.429em;
|
||||||
|
margin-bottom: .25em;
|
||||||
|
padding: 0 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#extras a:link, #extras a:visited {
|
||||||
|
color: #444;
|
||||||
|
display: block;
|
||||||
|
border-bottom: 1px solid #F4E3E3;
|
||||||
|
text-decoration: none;
|
||||||
|
padding: .3em .25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#extras a:hover, #extras a:active {color: #fff;}
|
||||||
|
|
||||||
|
/* Blogroll */
|
||||||
|
#extras .blogroll {
|
||||||
|
float: left;
|
||||||
|
width: 615px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#extras .blogroll li {float: left; margin: 0 20px 0 0; width: 185px;}
|
||||||
|
|
||||||
|
#banner .social a {
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: bottom;
|
||||||
|
padding-left: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icons */
|
||||||
|
.social a[href*='github.com'] { background-image: url('theme/images/icons/github.png'); background-size: 16px 16px;}
|
||||||
|
.social a[type$='atom+xml'], .social a[type$='rss+xml'] {background-image: url('theme/images/icons/rss.png');}
|
||||||
|
.social a[href*='stackoverflow.com'] {background-image: url('theme/images/icons/stackoverflow.png');}
|
||||||
|
.social a[href*='twitter.com'] {background-image: url('theme/images/icons/twitter.png');}
|
||||||
|
|
||||||
|
/*
|
||||||
|
About
|
||||||
|
*****************/
|
||||||
|
#about {
|
||||||
|
background: #fff;
|
||||||
|
font-style: normal;
|
||||||
|
margin-bottom: 2em;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: left;
|
||||||
|
width: 760px;
|
||||||
|
|
||||||
|
border-radius: 10px;
|
||||||
|
-moz-border-radius: 10px;
|
||||||
|
-webkit-border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#about .primary {float: left; width: 165px;}
|
||||||
|
#about .primary strong {color: #C64350; display: block; font-size: 1.286em;}
|
||||||
|
#about .photo {float: left; margin: 5px 20px;}
|
||||||
|
|
||||||
|
#about .url:link, #about .url:visited {text-decoration: none;}
|
||||||
|
|
||||||
|
#about .bio {float: right; width: 500px;}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Footer
|
||||||
|
*****************/
|
||||||
|
#contentinfo {padding-bottom: 2em; text-align: right;}
|
||||||
|
|
||||||
|
/***** Sections *****/
|
||||||
|
/* Blog */
|
||||||
|
.hentry {
|
||||||
|
display: block;
|
||||||
|
clear: both;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
padding: 1.5em 0;
|
||||||
|
}
|
||||||
|
li:last-child .hentry, #content > .hentry {border: 0; margin: 0;}
|
||||||
|
#content > .hentry {padding: 1em 0;}
|
||||||
|
.hentry img{display : none ;}
|
||||||
|
.entry-title {font-size: 3em; margin-bottom: 10px; margin-top: 0;}
|
||||||
|
.entry-title a:link, .entry-title a:visited {text-decoration: none; color: #333;}
|
||||||
|
.entry-title a:visited {background-color: #fff;}
|
||||||
|
|
||||||
|
.hentry .post-info * {font-style: normal;}
|
||||||
|
|
||||||
|
/* Content */
|
||||||
|
.hentry footer {margin-bottom: 2em;}
|
||||||
|
.hentry footer address {display: inline;}
|
||||||
|
#posts-list footer address {display: block;}
|
||||||
|
|
||||||
|
/* Blog Index */
|
||||||
|
#posts-list {list-style: none; margin: 0;}
|
||||||
|
#posts-list .hentry {padding-left: 10px; position: relative;}
|
||||||
|
|
||||||
|
#posts-list footer {
|
||||||
|
left: 10px;
|
||||||
|
position: relative;
|
||||||
|
float: left;
|
||||||
|
top: 0.5em;
|
||||||
|
width: 190px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* About the Author */
|
||||||
|
#about-author {
|
||||||
|
background: #f9f9f9;
|
||||||
|
clear: both;
|
||||||
|
font-style: normal;
|
||||||
|
margin: 2em 0;
|
||||||
|
padding: 10px 20px 15px 20px;
|
||||||
|
|
||||||
|
border-radius: 5px;
|
||||||
|
-moz-border-radius: 5px;
|
||||||
|
-webkit-border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#about-author strong {
|
||||||
|
color: #C64350;
|
||||||
|
clear: both;
|
||||||
|
display: block;
|
||||||
|
font-size: 1.429em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#about-author .photo {border: 1px solid #ddd; float: left; margin: 5px 1em 0 0;}
|
||||||
|
|
||||||
|
/* Comments */
|
||||||
|
#comments-list {list-style: none; margin: 0 1em;}
|
||||||
|
#comments-list blockquote {
|
||||||
|
background: #f8f8f8;
|
||||||
|
clear: both;
|
||||||
|
font-style: normal;
|
||||||
|
margin: 0;
|
||||||
|
padding: 15px 20px;
|
||||||
|
|
||||||
|
border-radius: 5px;
|
||||||
|
-moz-border-radius: 5px;
|
||||||
|
-webkit-border-radius: 5px;
|
||||||
|
}
|
||||||
|
#comments-list footer {color: #888; padding: .5em 1em 0 0; text-align: right;}
|
||||||
|
|
||||||
|
#comments-list li:nth-child(2n) blockquote {background: #F5f5f5;}
|
||||||
|
|
||||||
|
/* Add a Comment */
|
||||||
|
#add-comment label {clear: left; float: left; text-align: left; width: 150px;}
|
||||||
|
#add-comment input[type='text'],
|
||||||
|
#add-comment input[type='email'],
|
||||||
|
#add-comment input[type='url'] {float: left; width: 200px;}
|
||||||
|
|
||||||
|
#add-comment textarea {float: left; height: 150px; width: 495px;}
|
||||||
|
|
||||||
|
#add-comment p.req {clear: both; margin: 0 .5em 1em 0; text-align: right;}
|
||||||
|
|
||||||
|
#add-comment input[type='submit'] {float: right; margin: 0 .5em;}
|
||||||
|
#add-comment * {margin-bottom: .5em;}
|
||||||
|
|
||||||
|
div.codehilite {
|
||||||
|
# position: relative;
|
||||||
|
# display: block;
|
||||||
|
# padding: 1em;
|
||||||
|
# font: normal 10pt Consolas, Monaco, monospace;
|
||||||
|
# overflow-x: auto;
|
||||||
|
background-color: #002B36;
|
||||||
|
# margin-top: 1em;
|
||||||
|
# margin-bottom: 1em;
|
||||||
|
|
||||||
|
}
|
64
theme/templates/monokai.css
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
.hll { background-color: #49483e }
|
||||||
|
.c { color: #75715e } /* Comment */
|
||||||
|
.err { color: #960050; background-color: #1e0010 } /* Error */
|
||||||
|
.k { color: #66d9ef } /* Keyword */
|
||||||
|
.l { color: #ae81ff } /* Literal */
|
||||||
|
.n { color: #f8f8f2 } /* Name */
|
||||||
|
.o { color: #f92672 } /* Operator */
|
||||||
|
.p { color: #f8f8f2 } /* Punctuation */
|
||||||
|
.cm { color: #75715e } /* Comment.Multiline */
|
||||||
|
.cp { color: #75715e } /* Comment.Preproc */
|
||||||
|
.c1 { color: #75715e } /* Comment.Single */
|
||||||
|
.cs { color: #75715e } /* Comment.Special */
|
||||||
|
.ge { font-style: italic } /* Generic.Emph */
|
||||||
|
.gs { font-weight: bold } /* Generic.Strong */
|
||||||
|
.kc { color: #66d9ef } /* Keyword.Constant */
|
||||||
|
.kd { color: #66d9ef } /* Keyword.Declaration */
|
||||||
|
.kn { color: #f92672 } /* Keyword.Namespace */
|
||||||
|
.kp { color: #66d9ef } /* Keyword.Pseudo */
|
||||||
|
.kr { color: #66d9ef } /* Keyword.Reserved */
|
||||||
|
.kt { color: #66d9ef } /* Keyword.Type */
|
||||||
|
.ld { color: #e6db74 } /* Literal.Date */
|
||||||
|
.m { color: #ae81ff } /* Literal.Number */
|
||||||
|
.s { color: #e6db74 } /* Literal.String */
|
||||||
|
.na { color: #a6e22e } /* Name.Attribute */
|
||||||
|
.nb { color: #f8f8f2 } /* Name.Builtin */
|
||||||
|
.nc { color: #a6e22e } /* Name.Class */
|
||||||
|
.no { color: #66d9ef } /* Name.Constant */
|
||||||
|
.nd { color: #a6e22e } /* Name.Decorator */
|
||||||
|
.ni { color: #f8f8f2 } /* Name.Entity */
|
||||||
|
.ne { color: #a6e22e } /* Name.Exception */
|
||||||
|
.nf { color: #a6e22e } /* Name.Function */
|
||||||
|
.nl { color: #f8f8f2 } /* Name.Label */
|
||||||
|
.nn { color: #f8f8f2 } /* Name.Namespace */
|
||||||
|
.nx { color: #a6e22e } /* Name.Other */
|
||||||
|
.py { color: #f8f8f2 } /* Name.Property */
|
||||||
|
.nt { color: #f92672 } /* Name.Tag */
|
||||||
|
.nv { color: #f8f8f2 } /* Name.Variable */
|
||||||
|
.ow { color: #f92672 } /* Operator.Word */
|
||||||
|
.w { color: #f8f8f2 } /* Text.Whitespace */
|
||||||
|
.mf { color: #ae81ff } /* Literal.Number.Float */
|
||||||
|
.mh { color: #ae81ff } /* Literal.Number.Hex */
|
||||||
|
.mi { color: #ae81ff } /* Literal.Number.Integer */
|
||||||
|
.mo { color: #ae81ff } /* Literal.Number.Oct */
|
||||||
|
.sb { color: #e6db74 } /* Literal.String.Backtick */
|
||||||
|
.sc { color: #e6db74 } /* Literal.String.Char */
|
||||||
|
.sd { color: #e6db74 } /* Literal.String.Doc */
|
||||||
|
.s2 { color: #e6db74 } /* Literal.String.Double */
|
||||||
|
.se { color: #ae81ff } /* Literal.String.Escape */
|
||||||
|
.sh { color: #e6db74 } /* Literal.String.Heredoc */
|
||||||
|
.si { color: #e6db74 } /* Literal.String.Interpol */
|
||||||
|
.sx { color: #e6db74 } /* Literal.String.Other */
|
||||||
|
.sr { color: #e6db74 } /* Literal.String.Regex */
|
||||||
|
.s1 { color: #e6db74 } /* Literal.String.Single */
|
||||||
|
.ss { color: #e6db74 } /* Literal.String.Symbol */
|
||||||
|
.bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
|
||||||
|
.vc { color: #f8f8f2 } /* Name.Variable.Class */
|
||||||
|
.vg { color: #f8f8f2 } /* Name.Variable.Global */
|
||||||
|
.vi { color: #f8f8f2 } /* Name.Variable.Instance */
|
||||||
|
.il { color: #ae81ff } /* Literal.Number.Integer.Long */
|
||||||
|
|
||||||
|
.gh { } /* Generic Heading & Diff Header */
|
||||||
|
.gu { color: #75715e; } /* Generic.Subheading & Diff Unified/Comment? */
|
||||||
|
.gd { color: #f92672; } /* Generic.Deleted & Diff Deleted */
|
||||||
|
.gi { color: #a6e22e; } /* Generic.Inserted & Diff Inserted */
|
15
theme/templates/page.html
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block header %}
|
||||||
|
{% if page.robots is defined %}
|
||||||
|
<meta name="robots" content="{{page.robots}}" />
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
{% block title %}{{ page.title }}{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<section id="content" class="body">
|
||||||
|
<h1 class="entry-title">{{ page.title }}</h1>
|
||||||
|
{% import 'translations.html' as translations with context %}
|
||||||
|
{{ translations.translations_for(page) }}
|
||||||
|
{{ page.content }}
|
||||||
|
</section>
|
||||||
|
{% endblock %}
|
13
theme/templates/period_archives.html
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block content %}
|
||||||
|
<section id="content" class="body">
|
||||||
|
<h1>Archives for {{ period | reverse | join(' ') }}</h1>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
{% for article in dates %}
|
||||||
|
<dt>{{ article.locale_date }}</dt>
|
||||||
|
<dd><a href="{{ SITEURL }}/{{ article.url }}">{{ article.title }}</a></dd>
|
||||||
|
{% endfor %}
|
||||||
|
</dl>
|
||||||
|
</section>
|
||||||
|
{% endblock %}
|
205
theme/templates/pygment.css
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
.hll {
|
||||||
|
background-color:#eee;
|
||||||
|
}
|
||||||
|
.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;
|
||||||
|
}
|
50
theme/templates/reset.css
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
Name: Reset Stylesheet
|
||||||
|
Description: Resets browser's default CSS
|
||||||
|
Author: Eric Meyer
|
||||||
|
Author URI: http://meyerweb.com/eric/tools/css/reset/
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* v1.0 | 20080212 */
|
||||||
|
html, body, div, span, applet, object, iframe,
|
||||||
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||||
|
a, abbr, acronym, address, big, cite, code,
|
||||||
|
del, dfn, em, font, img, ins, kbd, q, s, samp,
|
||||||
|
small, strike, strong, sub, sup, tt, var,
|
||||||
|
b, u, i, center,
|
||||||
|
dl, dt, dd, ol, ul, li,
|
||||||
|
fieldset, form, label, legend,
|
||||||
|
table, caption, tbody, tfoot, thead, tr, th, td {
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
margin: 0;
|
||||||
|
outline: 0;
|
||||||
|
padding: 0;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {line-height: 1;}
|
||||||
|
|
||||||
|
blockquote, q {quotes: none;}
|
||||||
|
|
||||||
|
blockquote:before, blockquote:after,
|
||||||
|
q:before, q:after {
|
||||||
|
content: '';
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remember to define focus styles! */
|
||||||
|
:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remember to highlight inserts somehow! */
|
||||||
|
ins {text-decoration: none;}
|
||||||
|
del {text-decoration: line-through;}
|
||||||
|
|
||||||
|
/* tables still need 'cellspacing="0"' in the markup */
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
469
theme/templates/site.css
Normal file
|
@ -0,0 +1,469 @@
|
||||||
|
article,aside,details,figcaption,figure,
|
||||||
|
footer,header,hgroup,menu,nav,section {
|
||||||
|
display:block;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-moz-focus-inner {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clearfix */
|
||||||
|
.clearfix:after {
|
||||||
|
content: ".";
|
||||||
|
display: block;
|
||||||
|
clear: both;
|
||||||
|
visibility: hidden;
|
||||||
|
line-height: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clearfix {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
* html .clearfix {
|
||||||
|
height: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #37e;
|
||||||
|
text-decoration: underline;
|
||||||
|
text-shadow: 0px 2px 0px #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover{
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
body{
|
||||||
|
font-family: PT Sans, DejaVu Sans, Arial, sans;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
text-shadow: 0px 2px 0px #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
#container{
|
||||||
|
width: 640px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 12px;
|
||||||
|
-moz-box-shadow: 0px 4px 12px #ccc; /* FF3.5+ */
|
||||||
|
-webkit-box-shadow: 0px 4px 12px #ccc; /* Saf3.0+, Chrome */
|
||||||
|
box-shadow: 0px 4px 12px #ccc; /* Opera 10.5, IE 9.0 */
|
||||||
|
filter: progid:DXImageTransform.Microsoft.dropshadow(OffX=12px, OffY=12px, Color='#ccc'); /* IE6,IE7 */
|
||||||
|
-ms-filter: "progid:DXImageTransform.Microsoft.dropshadow(OffX=12px, OffY=12px, Color='#ccc')"; /* IE8 */
|
||||||
|
}
|
||||||
|
|
||||||
|
footer{
|
||||||
|
font-size: 10px;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 24px;
|
||||||
|
text-shadow: 0px 2px 0px #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Button styles from the awesome: http://www.webdesignerwall.com/demo/css-buttons.html */
|
||||||
|
|
||||||
|
.button {
|
||||||
|
display: inline-block;
|
||||||
|
zoom: 1; /* zoom and *display = ie7 hack for display:inline-block */
|
||||||
|
*display: inline;
|
||||||
|
vertical-align: baseline;
|
||||||
|
margin: 0 2px;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
font: 14px/100% Arial, Helvetica, sans-serif;
|
||||||
|
padding: .5em 2em .55em;
|
||||||
|
text-shadow: 0 1px 1px rgba(0,0,0,.3);
|
||||||
|
-webkit-border-radius: .5em;
|
||||||
|
-moz-border-radius: .5em;
|
||||||
|
border-radius: .5em;
|
||||||
|
-webkit-box-shadow: 0 1px 2px rgba(0,0,0,.2);
|
||||||
|
-moz-box-shadow: 0 1px 2px rgba(0,0,0,.2);
|
||||||
|
box-shadow: 0 1px 2px rgba(0,0,0,.2);
|
||||||
|
}
|
||||||
|
.button:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.button:active {
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bigrounded {
|
||||||
|
-webkit-border-radius: 2em;
|
||||||
|
-moz-border-radius: 2em;
|
||||||
|
border-radius: 2em;
|
||||||
|
}
|
||||||
|
.medium {
|
||||||
|
font-size: 12px;
|
||||||
|
padding: .4em 1.5em .42em;
|
||||||
|
}
|
||||||
|
.small {
|
||||||
|
font-size: 11px;
|
||||||
|
padding: .2em 1em .275em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* white */
|
||||||
|
.white {
|
||||||
|
color: #606060;
|
||||||
|
border: solid 1px #b7b7b7;
|
||||||
|
background: #fff;
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#ededed));
|
||||||
|
background: -moz-linear-gradient(top, #fff, #ededed);
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#ededed');
|
||||||
|
}
|
||||||
|
.white:hover {
|
||||||
|
background: #ededed;
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#dcdcdc));
|
||||||
|
background: -moz-linear-gradient(top, #fff, #dcdcdc);
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dcdcdc');
|
||||||
|
}
|
||||||
|
.white:active {
|
||||||
|
color: #999;
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, from(#ededed), to(#fff));
|
||||||
|
background: -moz-linear-gradient(top, #ededed, #fff);
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ededed', endColorstr='#ffffff');
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner{
|
||||||
|
border-bottom: 12px solid #222;
|
||||||
|
padding: 0 12px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner h1{
|
||||||
|
font-weight: 100;
|
||||||
|
font-size: 32px;
|
||||||
|
line-height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.banner h3{
|
||||||
|
color: #666;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner nav{
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner nav li{
|
||||||
|
list-style-type: none;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner nav li a.button{
|
||||||
|
margin:0;
|
||||||
|
-webkit-border-bottom-left-radius: 0;
|
||||||
|
-webkit-border-bottom-right-radius: 0;
|
||||||
|
-moz-border-radius-bottomleft: 0;
|
||||||
|
-moz-border-radius-bottomright: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner nav li a.button:hover{
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.banner nav li a.button.active{
|
||||||
|
color: #d7d7d7;
|
||||||
|
border: solid 1px #333;
|
||||||
|
background: #333;
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, from(#666), to(#000));
|
||||||
|
background: -moz-linear-gradient(top, #666, #000);
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#666666', endColorstr='#000000');
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog_excerpt{
|
||||||
|
padding-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog_excerpt .post time{
|
||||||
|
float: none;
|
||||||
|
clear: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog_excerpt .button{
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog_excerpt h3,
|
||||||
|
h1.title{
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 36px;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog_excerpt h3{
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.content{
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* listing */
|
||||||
|
|
||||||
|
.listing{
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listing img{
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listing li{
|
||||||
|
background-color: #ededed;
|
||||||
|
list-style-type: none;
|
||||||
|
float: left;
|
||||||
|
width: 272px;
|
||||||
|
margin-right: 24px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
padding: 12px;
|
||||||
|
-moz-box-shadow: 0px 4px 12px #ccc; /* FF3.5+ */
|
||||||
|
-webkit-box-shadow: 0px 4px 12px #ccc; /* Saf3.0+, Chrome */
|
||||||
|
box-shadow: 0px 4px 12px #ccc; /* Opera 10.5, IE 9.0 */
|
||||||
|
filter: progid:DXImageTransform.Microsoft.dropshadow(OffX=12px, OffY=12px, Color='#ccc'); /* IE6,IE7 */
|
||||||
|
-ms-filter: "progid:DXImageTransform.Microsoft.dropshadow(OffX=12px, OffY=12px, Color='#ccc')"; /* IE8 */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.listing li:nth-child(2){
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listing li:nth-child(3){
|
||||||
|
clear: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listing li p{
|
||||||
|
font-size: 10px;
|
||||||
|
line-height: 12px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.listing h3{
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 18px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listing time{
|
||||||
|
display:block;
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
padding-top: 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Content */
|
||||||
|
|
||||||
|
article.post p{
|
||||||
|
line-height: 24px;
|
||||||
|
margin: 6px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
article.post img{
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post time{
|
||||||
|
font-size: 12px;
|
||||||
|
color: #999;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tags{
|
||||||
|
margin-bottom: 24px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tags li{
|
||||||
|
list-style-type: none;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tags li a{
|
||||||
|
color: #999;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.tag:before,
|
||||||
|
ul.tags li a:before{
|
||||||
|
content: '\00AB';
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.tag:after,
|
||||||
|
ul.tags li a:after{
|
||||||
|
content: '\00BB';
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tags li a:hover{
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 a, h2 a, h3 a{
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav.post_nav{
|
||||||
|
background-color: #efefef;
|
||||||
|
position: fixed;
|
||||||
|
width: 124px;
|
||||||
|
margin-left: -186px;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
padding-right: 24px;
|
||||||
|
-moz-box-shadow: 0px 2px 4px #ccc; /* FF3.5+ */
|
||||||
|
-webkit-box-shadow: 0px 2px 4px #ccc; /* Saf3.0+, Chrome */
|
||||||
|
box-shadow: 0px 2px 4px #ccc; /* Opera 10.5, IE 9.0 */
|
||||||
|
filter: progid:DXImageTransform.Microsoft.dropshadow(OffX=12px, OffY=12px, Color='#ccc'); /* IE6,IE7 */
|
||||||
|
-ms-filter: "progid:DXImageTransform.Microsoft.dropshadow(OffX=12px, OffY=12px, Color='#ccc')"; /* IE8 */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
a.backlink{
|
||||||
|
display:block;
|
||||||
|
line-height: 24px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.backlink:before{
|
||||||
|
content: '\2190';
|
||||||
|
}
|
||||||
|
|
||||||
|
a.prev:before{
|
||||||
|
content: '\00AB';
|
||||||
|
}
|
||||||
|
|
||||||
|
a.next:after{
|
||||||
|
content: '\00BB';
|
||||||
|
}
|
||||||
|
|
||||||
|
a.prev{
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.prev,
|
||||||
|
a.next{
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.next{ float: right };
|
||||||
|
|
||||||
|
a.backlink:hover, a.prev:hover, a.next:hover{
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post_nav a.disabled{
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post_nav a{
|
||||||
|
color: #666;
|
||||||
|
text-decoration: none;
|
||||||
|
text-shadow: 0px 2px 0px #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post_nav div{
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
width: 58px;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#facebook_like{
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.archives ul.posts{
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.archives li.post{
|
||||||
|
list-style-type: none;
|
||||||
|
border-bottom: 1px dotted #ccc;
|
||||||
|
padding: 12px 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.archives li.post time{
|
||||||
|
color: #999;
|
||||||
|
text-shadow: 0px 2px 0px #fff;
|
||||||
|
margin-right: 24px;
|
||||||
|
display:block;
|
||||||
|
float: left;
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.archives li.post a{
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.archives ul.tags{
|
||||||
|
float: right;
|
||||||
|
margin-bottom:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.codebox {
|
||||||
|
margin-top: 8px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-family: Consolas, Monaco, monospace;
|
||||||
|
background-color: rgba(0,0,0,0.04);
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 0;
|
||||||
|
padding-top: 0.2em;
|
||||||
|
padding-bottom: 0.2em;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 85%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.codehilite {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
padding: 1em;
|
||||||
|
font: normal 10pt Consolas, Monaco, monospace;
|
||||||
|
overflow-x: auto;
|
||||||
|
background-color: #F0F3F3;
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.code figcaption {
|
||||||
|
font-size: 10px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 3px;
|
||||||
|
right: 12px;
|
||||||
|
color: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
article {
|
||||||
|
color: #333;
|
||||||
|
}
|
2
theme/templates/tag.html
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
{% extends "index.html" %}
|
||||||
|
{% block title %}{{ SITENAME }} - {{ tag }}{% endblock %}
|
1
theme/templates/taglist.html
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{% if article.tags %}<p>tags: {% for tag in article.tags %}<a href="{{ SITEURL }}/{{ tag.url }}">{{ tag | escape }}</a> {% endfor %}</p>{% endif %}
|
16
theme/templates/tags.html
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}{{ SITENAME }} - Tags{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<section id="content" class="body">
|
||||||
|
<h1>Tags for {{ SITENAME }}</h1>
|
||||||
|
<ul>
|
||||||
|
{% for tag, articles in tags|sort %}
|
||||||
|
<li><a href="{{ SITEURL }}/{{ tag.url }}">{{ tag }}</a> ({{ articles|count }})</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{% endblock %}
|
8
theme/templates/translations.html
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{% macro translations_for(article) %}
|
||||||
|
{% if article.translations %}
|
||||||
|
Translations:
|
||||||
|
{% for translation in article.translations %}
|
||||||
|
<a href="{{ SITEURL }}/{{ translation.url }}">{{ translation.lang }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
3
theme/templates/twitter.html
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{% if TWITTER_USERNAME %}
|
||||||
|
<a href="https://twitter.com/share" class="twitter-share-button" data-count="horizontal" data-via="{{TWITTER_USERNAME}}">Tweet</a><script type="text/javascript" src="https://platform.twitter.com/widgets.js"></script>
|
||||||
|
{% endif %}
|
3
theme/templates/typogrify.css
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.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;}
|
48
theme/templates/wide.css
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
@import url("main.css");
|
||||||
|
|
||||||
|
body {
|
||||||
|
font:1.3em/1.3 "Hoefler Text","Georgia",Georgia,serif,sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-info{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#banner nav {
|
||||||
|
display: none;
|
||||||
|
-moz-border-radius: 0px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: 1em;
|
||||||
|
background: #F5F4EF;
|
||||||
|
}
|
||||||
|
|
||||||
|
#banner nav ul{
|
||||||
|
padding-right: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#banner nav li{
|
||||||
|
float: right;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#banner nav li a {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#banner h1 {
|
||||||
|
margin-bottom: -18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#featured, #extras {
|
||||||
|
padding: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#featured {
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#extras {
|
||||||
|
padding-top: 0px;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
}
|