Initial commit

This commit is contained in:
Julien Palard 2017-04-04 23:11:23 +02:00
commit fd5f51ec4a
98 changed files with 6050 additions and 0 deletions

127
Makefile Normal file
View 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
View File

@ -0,0 +1 @@
{}

View 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).

View File

@ -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
View 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.

View 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.

View File

@ -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)) ...

View 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!

View 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 :-)

View 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

View 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*

View 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.

View File

@ -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"

View 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.

View 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

View 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!

View 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.

View 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.)

View File

@ -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 !!!)

View 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 });
}
}
}

View File

@ -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!

View 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!

View 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");

View 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!

View 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 :-)

View 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...

View 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!

View 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!

View File

@ -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!

View 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 &gt;&gt; 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!

View 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:)

View 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&gt; say hello bot&gt;
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

View 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
View 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;
}

View 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 */

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 516 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 894 B

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
uses_template: false

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,5 @@
Title: About Julien
Date: 2008-08-14 19:25:52
status: hidden
Just check out [mdk.fr](mdk.fr)!

View 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
View 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
View 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 lIA (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
View File

@ -0,0 +1,7 @@
User-Agent: *
Disallow: /photos
Disallow: /gallery
Disallow: /fun
Disallow: /doc
Disallow: /epitech
Disallow: /x

49
pelicanconf.py Normal file
View 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
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 751 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 958 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 803 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 975 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 896 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 693 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 916 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 458 B

View 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 %}

View 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 %}

View 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 %}

View 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 -->

View File

@ -0,0 +1,2 @@
{% extends "index.html" %}
{% block title %}{{ SITENAME }} - {{ author }}{% endblock %}

View 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
View 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>

View File

@ -0,0 +1,2 @@
{% extends "index.html" %}
{% block title %}{{ SITENAME }} - {{ category }}{% endblock %}

View File

@ -0,0 +1 @@
{% if DISQUS_SITENAME %}<p>There are <a href="{{ SITEURL }}/{{ article.url }}#disqus_thread">comments</a>.</p>{% endif %}

View 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 %}

View 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;
}

View 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 %}

View 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
View 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;
}

View 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
View 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 %}

View 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
View 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
View 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
View 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
View File

@ -0,0 +1,2 @@
{% extends "index.html" %}
{% block title %}{{ SITENAME }} - {{ tag }}{% endblock %}

View 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
View 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 %}

View 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 %}

View 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 %}

View 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
View 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;
}