Initial commit
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -0,0 +1,109 @@
|
|||
---
|
||||
Title: A JustInTime class
|
||||
Date: 2008-08-30 00:10:55
|
||||
|
||||
---
|
||||
|
||||
I discovered in my code a redundant pattern :
|
||||
|
||||
:::csharp
|
||||
private SomeType _something;
|
||||
private SomeType something { get { if (_something == null) _something = new SomeType(....); return _something;} }
|
||||
|
||||
Usefull in Silverlight, when your Blender always say "Can't compile !
|
||||
Strange errors ! but compiles when i comment your WebClient... in ctor
|
||||
of that class..." So i use it to have members builded the first time
|
||||
they are used, "Just in time". /!\\ It's not a Singleton ! i can have
|
||||
others instance of this class new-ing it directly ! /!\\ Singleton is
|
||||
Evil // feed the Troll So i factorized it :
|
||||
|
||||
:::csharp
|
||||
public class Jit
|
||||
{
|
||||
T _instance;
|
||||
object[] _ctor_params;
|
||||
|
||||
public Jit(object[] ctor_params)
|
||||
{
|
||||
_ctor_params = ctor_params;
|
||||
}
|
||||
|
||||
public Jit()
|
||||
{
|
||||
}
|
||||
|
||||
public T create(object[] ctor_params)
|
||||
{
|
||||
Type[] param_types = ctor_params.Aggregate>(
|
||||
new List(),
|
||||
(List lt, object o) =>
|
||||
{
|
||||
lt.Add(o.GetType());
|
||||
return lt;
|
||||
}).ToArray();
|
||||
var ctor = typeof(T).GetConstructor(param_types);
|
||||
if (ctor == null)
|
||||
throw new Exception(param_types.Aggregate(
|
||||
"No constructor found for " + typeof(T).Name + " taking",
|
||||
(string i, Type t) => { return i + " " + t.Name; }));
|
||||
return (T)ctor.Invoke(_ctor_params);
|
||||
}
|
||||
|
||||
public T create()
|
||||
{
|
||||
return (_ctor_params == null)
|
||||
? create(new object[] { })
|
||||
: create(_ctor_params);
|
||||
}
|
||||
|
||||
public T single()
|
||||
{
|
||||
if (_instance == null)
|
||||
_instance = create();
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
A usage demo:
|
||||
|
||||
:::csharp
|
||||
public class Test
|
||||
{
|
||||
Test(string foo, int bar)
|
||||
{
|
||||
Console.WriteLine("Test ctor with : " + foo + " and " + bar);
|
||||
}
|
||||
|
||||
public void foo()
|
||||
{
|
||||
Console.WriteLine("bar");
|
||||
}
|
||||
}
|
||||
|
||||
public partial class Page : UserControl
|
||||
{
|
||||
public event EventHandler my_event;
|
||||
private Jit test = new Jit(new object[]{"42", 42});
|
||||
|
||||
public Page()
|
||||
{
|
||||
InitializeComponent();
|
||||
// test is not yet built
|
||||
test.single().foo(); // Whill build a Test and call foo()
|
||||
test.single().foo(); // Whill call foo on the same Test.
|
||||
}
|
||||
}
|
||||
|
||||
So a:
|
||||
|
||||
:::csharp
|
||||
private SomeType _something;
|
||||
private SomeType something { get { if (_something == null) _something = new SomeType(....); return _something;} }
|
||||
|
||||
become:
|
||||
|
||||
:::csharp
|
||||
private Jit something = new Jit(new object[]{...});
|
||||
|
||||
Note the Jit ctor, taking a array of objects, it's the objects to pass
|
||||
to your ctor's class (found by reflection using their types).
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
Title: ashttp: vt100 screen scraping exported over HTTP
|
||||
Date: 2011-08-27 15:08:21
|
||||
|
||||
---
|
||||
Originally written for
|
||||
[logtop](https://github.com/JulienPalard/logtop) I just wrote a vt100
|
||||
screen scraper that listen to a port and serve the screen over
|
||||
HTTP. Basically, you want a `top` (or logtop ;-) ) to be displayed in
|
||||
your website back office ? But top outputs in your terminal and you
|
||||
don't know how to capture it ? Use
|
||||
[ashttp](http://dev-tricks.net/wp-content/uploads/2011/08/ashttp1.png),
|
||||
like this:
|
||||
|
||||
:::bash
|
||||
$ ashttp -p 8080 top
|
||||
|
||||
And then just open the port 8080 with an HTTP client and enjoy (typing
|
||||
some F5...). You can find the code on [my
|
||||
github](https://github.com/JulienPalard/ashttp).
|
|
@ -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.
|
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
Title: Automating GNU screen startup
|
||||
Date: 2011-11-18 00:13:58
|
||||
|
||||
---
|
||||
|
||||
At work I use GNU screen with one window per server (ssh connection),
|
||||
and when I loose my screen, it takes minutes to rebuild the naming and
|
||||
the ssh connections ... So I searched and found a PHP version on
|
||||
[Jon's blog](http://snowulf.com/2011/09/13/automated-screen-launch/)
|
||||
but I don't like PHP and don't want a PHP cli on my machine (even to
|
||||
start screen !) So I rewrote it in bash (to have brace expansion !)
|
||||
Enjoy:
|
||||
|
||||
:::bash
|
||||
#!/bin/bash -f
|
||||
|
||||
SCREEN_NAME=julien
|
||||
SERVERS=$(echo {julien,root}@dev root@{www,sql}{1,2} root@media{1,2,3,4,5,6}
|
||||
|
||||
screen -dmS "$SCREEN_NAME"
|
||||
NUM=0
|
||||
for SERVER in $SERVERS
|
||||
do
|
||||
NUM=$((NUM + 1))
|
||||
screen -S "$SCREEN_NAME" -X screen
|
||||
if [ z"$SERVER" != z"" ]
|
||||
then
|
||||
screen -S "$SCREEN_NAME" -p $NUM -X title "$SERVER"
|
||||
screen -S "$SCREEN_NAME" -p $NUM -X stuff "ssh $SERVER $(printf \\r)"
|
||||
fi
|
||||
done
|
||||
printf "Done, now you can join your screen with :\n"
|
||||
printf "$ screen -dr -S $SCREEN_NAME\n"
|
||||
|
||||
Don't forgot to start your ssh-agent just before starting this script!
|
||||
PS: If you don't have an ssh-agent, you may want to remove the `$(printf
|
||||
\\r)` and press enter yourself.
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
Title: [Bashism] How to generate random number without $RANDOM ?
|
||||
Date: 2011-04-07 14:00:55
|
||||
|
||||
---
|
||||
|
||||
There is a common bashism, that is to use `$RANDOM`. Typically you'll
|
||||
have to remove bashism while rewriting your scripts for dash or sh.
|
||||
There is a lot of solutions to generate random numbers in many different
|
||||
ways, but I'm not here to pollute the internet demonstrating 42
|
||||
differents ways to do this, i'll only show you the one I think is the
|
||||
best, and let you comment it if you can do better :-) My solution is to
|
||||
replace `$RANDOM` by :
|
||||
|
||||
:::bash
|
||||
$(($(dd if=/dev/urandom count=1 2> /dev/null | cksum | cut -d' ' -f1) % 32768))
|
||||
|
||||
Pros :
|
||||
|
||||
- Not so long
|
||||
- Yield a different number each call (not all replacement for
|
||||
`$RANDOM` do)
|
||||
- Excatly like in bash, it yield a number between 0 and 32767
|
||||
|
||||
Cons :
|
||||
|
||||
- Longer than `$RANDOM` :p
|
||||
- /dev/urandom is not present on every systems ...
|
||||
|
||||
You should simplify it if the \[0, 32767\] rule has no importance for
|
||||
you, typically if you want a number between 0 and 10, don't do ... %
|
||||
32768)) % 11)) ...
|
|
@ -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!
|
|
@ -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 :-)
|
|
@ -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
|
|
@ -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*
|
|
@ -0,0 +1,67 @@
|
|||
---
|
||||
Title: Covariance and Contravariance in C#3
|
||||
Date: 2009-03-09 21:19:51
|
||||
|
||||
---
|
||||
|
||||
A short introduction to Covariance and Contravariance in *C# 3* preparing
|
||||
you to an article about that in *C# 4*. So what is covariance?
|
||||
Covariance is basically using a method which returns something derived
|
||||
from the expected type. An exemple? It's safe to have a method
|
||||
returning a cat when you expect it to return an animal. In C sharp it's
|
||||
|
||||
:::csharp
|
||||
public class Animal
|
||||
{
|
||||
}
|
||||
|
||||
public class Cat : Animal
|
||||
{
|
||||
}
|
||||
|
||||
public class Dog : Animal
|
||||
{
|
||||
}
|
||||
|
||||
// It's safe to say that something returns a Animal when in fact this thing returns a Cat
|
||||
class Covariance
|
||||
{
|
||||
void test()
|
||||
{
|
||||
Func a = Method; // OK
|
||||
Func b = delegate { return new Cat(); }; // OK
|
||||
Func c = () => new Cat(); // OK
|
||||
}
|
||||
|
||||
Cat Method()
|
||||
{
|
||||
return new Cat();
|
||||
}
|
||||
}
|
||||
|
||||
So Funcs `a`, `b`, and `c` are returning animals which in fact are
|
||||
cats, which is true. And, what is contravariance? Contravariance is
|
||||
basically using a method which takes something which is a parent of
|
||||
the expected type. An exemple? It's safe to give a method an animal
|
||||
when it expects to receive a cat.
|
||||
|
||||
:::csharp
|
||||
// It's safe to say that something can take a Cat if in fact this thing can take any Animal
|
||||
class Contravariance
|
||||
{
|
||||
static void test()
|
||||
{
|
||||
Action a = Method; // OK
|
||||
Action b = delegate(Animal value) { }; // ERROR
|
||||
// From C#3 Specification :
|
||||
// $7.14.1 Anonymous function signatures :
|
||||
// [...] contra-variance of anonymous function parameter types is not supported.
|
||||
Action d = (Animal value) => { }; // idem... anonymous... not supported.
|
||||
}
|
||||
|
||||
public static void Method(Animal value)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
So `Action` `a` take `Cats`, but in fact can take any `Animals`, so it's safe.
|
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
Title: echo and backslash-escaped caracters / new lines: how to write portable scripts ?
|
||||
Date: 2011-04-08 13:59:45
|
||||
|
||||
---
|
||||
|
||||
While writing shell scripts you are using a lot of `echo` but did you
|
||||
think about portability of this simple statement? Can you say what will
|
||||
be diplayed, without testing, on your shell, the following tests:
|
||||
|
||||
:::bash
|
||||
echo \n \c '\n' '\c' "\n" "\c"
|
||||
echo -e \n \c '\n' '\c' "\n" "\c"
|
||||
|
||||
? I can't, cause I know that the `echo` behavior is very implementation
|
||||
dependent, typically in `dash`, `echo -e foo` actually print `-e foo` because
|
||||
the dash's echo don't parses any options... Here is the bug I found on
|
||||
one of my shell scripts, simplified to this 9 bytes shell script:
|
||||
|
||||
:::bash
|
||||
$ cat /tmp/test.sh
|
||||
#!/bin/sh
|
||||
echo "$*"
|
||||
$ /tmp/test.sh '1\n2'
|
||||
1
|
||||
2
|
||||
|
||||
I'm running Debian Squeeze so my `sh` is a `dash`, and the '\\n' is
|
||||
interpreted by the dash's echo ... but I don't want it! The only
|
||||
portable workaround I found is:
|
||||
|
||||
:::bash
|
||||
$ cat /tmp/test.sh
|
||||
#!/bin/sh
|
||||
printf "%s\n" "$*"
|
||||
$ /tmp/test.sh '1\n2'
|
||||
1\n2
|
||||
|
||||
Conclusion: Keep a look at your input, if you don't want
|
||||
backslash-escaped chars to be interpreted and want to be portable, use
|
||||
printf! You can keep using echo when you have a full control on the
|
||||
input, so the `sh` Hello World will forever stay:
|
||||
|
||||
:::bash
|
||||
echo "Hello world"
|
|
@ -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.
|
|
@ -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
|
|
@ -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!
|
|
@ -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.
|
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
Title: Searching and replacing in emacs
|
||||
Date: 2011-05-03 19:16:16
|
||||
|
||||
---
|
||||
|
||||
Day two of my serie about emacs, about searching and replacing.
|
||||
|
||||
- Function name: *isearch-forward*
|
||||
- Typical Key binding: `C-s`
|
||||
- How to get help: `C-h f isearch-forward`
|
||||
|
||||
*isearch-forward* let you type a string to be searched incrementally
|
||||
in the current buffer, successive following `C-s` will jump to the next
|
||||
match.
|
||||
|
||||
- Function name: *isearch-forward-regexp*
|
||||
- Typical Key sequence: `C-M-s` or `C-u C-s`
|
||||
- How to get help : `C-h f isearch-forward-regexp`
|
||||
|
||||
*isearch-forward-regexp* let you type a regexp to be searched
|
||||
incrementally in the current buffer, successive following `C-s` will
|
||||
jump to the next match.
|
||||
|
||||
- Function name: *query-replace*
|
||||
- Typical key binding: `M-%`
|
||||
- How to get help: `C-h f query-replace`
|
||||
- Usage: `M-%` *search* `RET` *replace* `RET`
|
||||
|
||||
Then, for each term found, *query-replace* will ask you what to do:
|
||||
`space` or `y` to replace, `delete` or `n` to skip, `RET` or `q` to
|
||||
exit, `!` for "yes for all", `?` to get help about how to enter
|
||||
recursive edit / delete match and recursive edit / edit replacement
|
||||
string / ... Then you should read about *replace-string*,
|
||||
*replace-regexp*, *occur*, *list-matching-lines*, *multi-occur*,
|
||||
*multi-occur-in-matching-buffers*, *how-many*, *flush-lines*, and
|
||||
*keep-lines*.
|
||||
|
||||
Case sensitivity: A search is by defaut case
|
||||
insensitive, but if you input an upper case letter, it become case
|
||||
sensitive. `M-c` during a search toggle the case
|
||||
sensitivity. Configuration variables: You may consult the
|
||||
documentation about those variable typing : `C-h v *variable*` or `M-x
|
||||
apropos-variable RET case-fold-search RET`
|
||||
|
||||
- *case-fold-search* (Non-nil if searches and matches should
|
||||
ignore case.)
|
||||
- *default-case-fold-search* (Default value of \`case-fold-search')
|
||||
- *tags-case-fold-search* (Whether tags operations should
|
||||
be case-sensitive.)
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
Title: Exclude directories from recursive grep
|
||||
Date: 2008-11-16 16:20:13
|
||||
|
||||
---
|
||||
|
||||
How often are you using grep in subversionned folders like that:
|
||||
|
||||
:::bash
|
||||
grep -rni foobar . | grep -v .svn
|
||||
|
||||
Upgrade to grep 2.5.3 and use (alias it ?)
|
||||
|
||||
:::bash
|
||||
grep -rni --exclude-dir .svn foobar .
|
||||
|
||||
(or ... stop using SVN !!!)
|
|
@ -0,0 +1,104 @@
|
|||
---
|
||||
Title: Howto invoke an event via reflection
|
||||
Date: 2008-08-29 23:14:53
|
||||
|
||||
---
|
||||
|
||||
Why this article ? Because of this note found on the MSDN's `EventInfo`
|
||||
page:
|
||||
|
||||
> EventInfo is not intended to be used to raise events. An object
|
||||
> raises events as dictated by its internal state.
|
||||
|
||||
Let's try to raise an event with reflection ... Firstly, let's search,
|
||||
but not in `GetEvent`, in `GetField` : [Type.GetField(String,
|
||||
BindingFlags)](http://msdn.microsoft.com/en-us/library/4ek9c21e.aspx)
|
||||
`String` is the name of the field to get and
|
||||
[BindingFlags](http://msdn.microsoft.com/en-us/library/system.reflection.bindingflags.aspx)
|
||||
a bitmask of serarching flags. Note: To use reflexion, use
|
||||
"System.Reflection" Let's try a `GetField`:
|
||||
|
||||
:::csharp
|
||||
FieldInfo my_event_FieldInfo = this.GetType().GetField("my_event",
|
||||
BindingFlags.NonPublic
|
||||
| BindingFlags.Instance);
|
||||
|
||||
Yeah! It's not `null`! we have now the `FieldInfo` of our event. What to
|
||||
do now ? in a `FieldInfo`, we do not have something like "Fire the event",
|
||||
huh But what about "GetValue" ? The "Value" of a "FieldInfo" is the
|
||||
field, so the Value of an event's `FieldInfo` isn't the Event?
|
||||
[FieldInfo.GetValue(object)](http://msdn.microsoft.com/en-us/library/system.reflection.fieldinfo.getvalue.aspx) let's try:
|
||||
|
||||
:::csharp
|
||||
object my_event_by_reflection = my_event_FieldInfo.GetValue(this);
|
||||
|
||||
Is `null` ... ): Ohhhh but, while not registered, an event is `null`... so,
|
||||
let's try adding a handler... Is not null!! Yeah, so we have our event
|
||||
by reflection now.
|
||||
|
||||
Note for those who just said "Why giving an object to `GetValue`? And
|
||||
why giving 'this'":
|
||||
|
||||
- Take a look at the first "this.getType()"
|
||||
- Deduce that it ask the Object to give you its Type, an Object knows
|
||||
its Type.
|
||||
- Note that a Type can't know its Objects...
|
||||
- Finally to get a Field of your Object, you ask the Type to give it
|
||||
or your Object, giving a reference to your Object, here : 'this';
|
||||
|
||||
|
||||
Now, we have an object, which is the event to call, but, how to call
|
||||
it? By reflection? but... where to search? TRICK: Put a
|
||||
breakpoint just after the `GetValue`, when breaked, add a watch on
|
||||
`my_event_by_reflection.GetType()` and browse it... try
|
||||
`my_event_by_reflection.GetType().GetFields()`... nothing... try
|
||||
`my_event_by_reflection.GetType().GetMethods()`... browse it... OH
|
||||
? What is `Invoke` ?
|
||||
|
||||
:::csharp
|
||||
var my_event_invoke = my_event_type.GetMethod("Invoke");
|
||||
|
||||
Searching how to call the Invoke... by reflection? Invoking invoke?
|
||||
|
||||
Let's try:
|
||||
|
||||
:::csharp
|
||||
my_event_invoke.Invoke(my_event_by_reflection, new object[] {this, new EventArgs()} );
|
||||
|
||||
Invoke take the instance of this type, so the object where GetType where
|
||||
called, and in second parameter an array of object to be given as
|
||||
parameter to the method called, we have to give an object and an
|
||||
eventArgs. It Works ! here the full working source code:
|
||||
|
||||
:::csharp
|
||||
using System.Reflection;
|
||||
|
||||
class Cage_en_metal
|
||||
{
|
||||
public event EventHandler ecraser;
|
||||
|
||||
public Cage_en_metal()
|
||||
{
|
||||
ecraser += new EventHandler(Libellule_ecraser);
|
||||
fireEvent("ecraser", new EventArgs());
|
||||
}
|
||||
|
||||
void Libellule_ecraser(object sender, EventArgs e)
|
||||
{
|
||||
Console.WriteLine("Splatch !");
|
||||
}
|
||||
|
||||
void fireEvent(string handler, EventArgs eventArgs)
|
||||
{
|
||||
var eventInfo = this.GetType().GetField(handler,
|
||||
BindingFlags.Instance
|
||||
| BindingFlags.NonPublic);
|
||||
if (eventInfo != null)
|
||||
{
|
||||
var event_member = eventInfo.GetValue(this);
|
||||
// Note : If event_member is null, nobody registered to the event, you can't call it.
|
||||
if (event_member != null)
|
||||
event_member.GetType().GetMethod("Invoke").Invoke(event_member, new object[] { this, eventArgs });
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
Title: Integrating google bookmarks in google chrome
|
||||
Date: 2009-04-16 17:56:18
|
||||
|
||||
---
|
||||
|
||||
As every developer, you have 42 computers, 8 browsers, and spend a lot
|
||||
of time asking why Google Chrome does not integrate Google Bookmarks?
|
||||
Here is a solution: First add the "Add to Google Bookmarks" bookmarklet
|
||||
from here
|
||||
<http://www.google.com/support/chrome/bin/answer.py?hl=en&answer=100215>
|
||||
And then go to chrome's options -> base tab -> Default search
|
||||
engine -> Manage Click "Add" and fill:
|
||||
|
||||
- Name: Google Bookmarks
|
||||
- Keyword: The keyword you wanna enter before a bookmark search in the
|
||||
chrome's address bar
|
||||
- URL: http://www.google.com/bookmarks/find?q=%s
|
||||
|
||||
To search 42, if your keyword is, like mine 'b', type "b 42" in the
|
||||
chrome's address bar and 42 will be searched in your bookmarks.
|
||||
|
||||
Enjoy!
|
|
@ -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!
|
|
@ -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");
|
|
@ -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!
|
|
@ -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 :-)
|
|
@ -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...
|
|
@ -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!
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
Title: Python: Consulting PEPs from command line, while being offline
|
||||
Date: 2011-04-13 14:20:11
|
||||
|
||||
---
|
||||
|
||||
One day I wished I could read PEPs in the tube on my laptop... so I
|
||||
searched for a convenient way to do so, and I didn't found ... So I
|
||||
wrote a very simple shell script you can found here :
|
||||
https://github.com/julienpalard/pep I'm currently packaging it for
|
||||
Debian and trying to put it on PyPI, (help is welcome :-) I don't have
|
||||
so much time) but you can make it work just by downloading the script
|
||||
here : https://github.com/JulienPalard/pep/raw/master/pep The script is
|
||||
very simple to use, first you can change a bit its configuration,
|
||||
typically change the LOCAL\_PEP\_PATH to something writeable for a use
|
||||
to don't have to be root to update you PEPs (As running an unknown
|
||||
script as root is a bit scary ) Then you should run \`./pep upgrade with
|
||||
progress\` to download PEPs to you LOCAL\_PEP\_PATH, and then just do a
|
||||
'./pep 8' to read the PEP 8 ! Others features include searching using
|
||||
regex, you can read about it here reading the README the -h or the
|
||||
manpage.
|
||||
|
||||
Hope you'll enjoy it!
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
Title: squid: (101) Network is unreachable when DNS returns IPv6
|
||||
Date: 2011-06-24 17:32:38
|
||||
|
||||
---
|
||||
|
||||
If you have a Squid proxy configured on a machine that have no IPv6
|
||||
connectivity, and try to reach an IPv6 compatible site, you squid will
|
||||
try to reach the site using IPv6 (I use squid 3.1.6 from Debian Squeeze)
|
||||
and will fail without even trying IPv4, displaying a nice:
|
||||
|
||||
> (101) Network is unreachable.
|
||||
|
||||
The only trick I found to force squid to use IPv4 (After disabling
|
||||
IPv6 on the interface, after disabling IPv6 in the kernel that leads
|
||||
to nothing better...) is:
|
||||
|
||||
tcp_outgoing_address [YOUR PUBLIC IP HERE]
|
||||
|
||||
And can enjoy again your plain old IPv4 network!
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
Title: The art of Events
|
||||
Date: 2008-08-29 23:32:55
|
||||
|
||||
---
|
||||
|
||||
The art of using events to build more independent classes. /\* Found a
|
||||
better example \*/ Imagine you have a class A and a class B. A builds B,
|
||||
and B have to communicate with A (call methods ... ?) Some developers
|
||||
(Boooo (I've done it ... (Booo >> me))) will pass a reference of A
|
||||
to B "A(){B my\_B = new B(this);}" /\* Please note the newB private joke
|
||||
\*/ But what happens when you want an other class, C, who don't know A
|
||||
to build B ? So we have to remove the A's reference in the B ctor. How B
|
||||
should communicate now ? - Using Events ! B exposes an event, the
|
||||
builder of B can register on it. - B can speak to A throwing this event.
|
||||
- Every class can build a B, and can, if it needs, register on its
|
||||
events, doing whatever he wants when the event is thrown. B is now fully
|
||||
reusable!
|
|
@ -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:)
|
|
@ -0,0 +1,76 @@
|
|||
---
|
||||
Title: YAUIB : Yet another useless IRC Bot !
|
||||
Date: 2011-03-27 23:40:58
|
||||
|
||||
---
|
||||
|
||||
After 2 years of... non blogging... I'm back! This time I stopped C\#
|
||||
(Oh yeah !) and I'm writing a lot of Python! (Oh YEAH !) So to say
|
||||
HELLO I'll present something useless: My Python IRC Bot. But this
|
||||
article should be usefull, so I'll speak about the Unix Philosophy: As
|
||||
Doug McIlroy said:
|
||||
|
||||
> This is the Unix philosophy: Write programs that do one thing and do
|
||||
> it well. Write programs to work together. Write programs to handle
|
||||
> text streams, because that is a universal interface.
|
||||
|
||||
So my Python Bot is wrote like this, only \~200 lines of Python it has
|
||||
only two interfaces, and they are simple. The first step is to start the
|
||||
bot:
|
||||
|
||||
:::bash
|
||||
./ircbot.py connect 'server' '#chan' 'nickname'
|
||||
|
||||
Ok the bot is connected to a chan, now you have to write some hooks, in
|
||||
yauib every action raise a hook in the 'hooks' directory, you can write
|
||||
a hook in any language you want. As a good start point I wrote a default
|
||||
hook for received messages in hook/pubmsg, simplified like this:
|
||||
|
||||
:::bash
|
||||
#!/bin/sh -f
|
||||
s_login="$(echo "$1" | sed 's#/#__SLASH__#g')"
|
||||
s_host="$2"
|
||||
t_login="$3"
|
||||
t_host="$4"
|
||||
shift 4
|
||||
arguments="$*"
|
||||
command=$(echo "${1%% *}" | sed 's#/#__SLASH__#g')
|
||||
if [ -x "commands/$command" ]
|
||||
then
|
||||
args=$(echo "$1" | sed 's/^ *[^ ]* *//g' )
|
||||
commands/$command $args
|
||||
fi
|
||||
|
||||
You should read : "When a message is received, the command in
|
||||
commands/\[1st word of the message\] is executed." So now you can start
|
||||
to write simple commands in the commands folder, like the command say:
|
||||
|
||||
:::bash
|
||||
#!/bin/sh
|
||||
echo "$*"
|
||||
|
||||
This command is 17 chars long, and now, without restarting your bot, try
|
||||
to make it say something on the channel : you> say hello bot>
|
||||
hello An now you can start to write dauting ones .... like ... display a
|
||||
readeable calendar of the current month like:
|
||||
|
||||
March 2011
|
||||
Su Mo Tu We Th Fr Sa
|
||||
1 2 3 4 5
|
||||
6 7 8 9 10 11 12
|
||||
13 14 15 16 17 18 19
|
||||
20 21 22 23 24 25 26
|
||||
27 28 29 30 31
|
||||
|
||||
Ready ?
|
||||
|
||||
:::bash
|
||||
#!/bin/sh
|
||||
cal
|
||||
|
||||
As the binary cal is installed on you machine, (windows user, you can
|
||||
leave, now), that's all, your're done ... sorry, it just work :p Et
|
||||
voilà ! You have to keep the UNIX philosophy in mind : - Everything is a
|
||||
file - Write programs that do one thing and do it well And you'll be
|
||||
happy developers ! PS: You can download / contribute to Yauib on
|
||||
https://github.com/JulienPalard/yauib
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
||||
|
After Width: | Height: | Size: 453 KiB |
After Width: | Height: | Size: 640 B |
After Width: | Height: | Size: 516 KiB |
After Width: | Height: | Size: 894 B |
|
@ -0,0 +1 @@
|
|||
uses_template: false
|
|
@ -0,0 +1,5 @@
|
|||
Title: About Julien
|
||||
Date: 2008-08-14 19:25:52
|
||||
status: hidden
|
||||
|
||||
Just check out [mdk.fr](mdk.fr)!
|
|
@ -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)
|
|
@ -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 -
|
|
@ -0,0 +1,91 @@
|
|||
status: hidden
|
||||
Title: Python chez Sup'Internet
|
||||
Slug: python-sup-internet
|
||||
robots: noindex
|
||||
|
||||
[TOC]
|
||||
# Survol des 6 cours
|
||||
|
||||
- Introduction de python, de l'environnement de python, de moi, puis coder quelques lignes
|
||||
- Se familiariser avec le langage
|
||||
- Premier projet pour commencer à écrire un bon volume de code et se rendre compte qu'il faut de l'organisation
|
||||
- Organisation d'un projet (git / tests / documentation / github / intégration continue / ...)
|
||||
- Présentation et utilisation de Jupyter et son environnement proche: les graphiques, le machine learning, les maths ...
|
||||
- Le dernier cours ouvre les portes sur comment continuer, comment, et quels outils utiliser.
|
||||
|
||||
|
||||
# Les rendus
|
||||
|
||||
- Au cours 1, un rendu par mail pour me faire une idée du niveau de chacun
|
||||
- Au cours 3, un rendu par mail par groupe, sans correction
|
||||
- Au cours 4, un rendu sur github par groupe
|
||||
- Au cours 5, un rendu par mail sous forme de Jupyter notebook
|
||||
|
||||
|
||||
# Cours 1: Introduction
|
||||
|
||||
Objectif: Me présenter, présenter Python et son environnement, jusqu'a coder quelques lignes.
|
||||
|
||||
|
||||
## Python
|
||||
|
||||
- 2 vs 3: ça fait 9 ans que les cours commencent par ça.
|
||||
- Utilisent Python : YouTube, Dropbox, Reddit, [data scientists](https://twitter.com/enthought/status/842016365133344788), …
|
||||
- [Python en tête des langages open source utilisés pour le Big Data et l’IA (slide 15)](https://speakerdeck.com/sfermigier/ia-aupres-des-poles-de-competitivite)
|
||||
- Open source et cross platform
|
||||
|
||||
|
||||
## Installation de l'interpréteur
|
||||
|
||||
Anaconda pour windows, Atom ou Pycharm EDU pour les indécis, éditeur au choix pour les autres,
|
||||
repl.it pour ceux qui sont à la rache.
|
||||
|
||||
- [Using on Windows](https://docs.python.org/3/using/windows.html)
|
||||
- [Using on Mac](https://docs.python.org/3/using/mac.html)
|
||||
|
||||
|
||||
## Utiliser le REPL
|
||||
|
||||
- Utiliser le REPL comme une calculatrice
|
||||
- Introduire les strings et les opérateurs binaires compatibles
|
||||
|
||||
|
||||
## La syntaxe
|
||||
|
||||
- Les structures de données `int`, `str`, `list` et `dict`.
|
||||
- Les structure de contrôle `if`, `for`
|
||||
- Les variables
|
||||
- Les appels de fonctions, les builtins `range`, `print`
|
||||
|
||||
|
||||
## Exercices
|
||||
|
||||
- Hello World
|
||||
- Project euler
|
||||
- Checkio sur (PyCharm ou sur le site)
|
||||
|
||||
|
||||
## La communauté, les ressources
|
||||
|
||||
- La doc, la doc fr, IRC
|
||||
- Le BDFL, les PEPs
|
||||
- Les conférences (pyconfr, …), les meetups.
|
||||
|
||||
|
||||
## Exercice à rendre par mail
|
||||
|
||||
Afficher, un par ligne, tous les nombres pairs compris dans l'intervalle `[0; 50]`. L'expéditeur doit être votre mail d'étudiant. Le code doit utiliser une fonction `is_even` pour déterminer si le nombre est pair ou pas.
|
||||
|
||||
|
||||
|
||||
# Cours 2: Language
|
||||
|
||||
Objectif: Se familiariser avec le langage, dédiaboliser des concepts, autremment dit le "Zen of Python".
|
||||
|
||||
|
||||
## Cours sur les fonctions
|
||||
|
||||
## Exercices sur les fonctions
|
||||
|
||||
## Cours sur les classes: Les données avant les algorithmes
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
User-Agent: *
|
||||
Disallow: /photos
|
||||
Disallow: /gallery
|
||||
Disallow: /fun
|
||||
Disallow: /doc
|
||||
Disallow: /epitech
|
||||
Disallow: /x
|
|
@ -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']
|
||||
}
|
|
@ -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 = ""
|
|
@ -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
|
After Width: | Height: | Size: 751 B |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 958 B |
After Width: | Height: | Size: 202 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 227 B |
After Width: | Height: | Size: 487 B |
After Width: | Height: | Size: 803 B |
After Width: | Height: | Size: 527 B |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 975 B |
After Width: | Height: | Size: 896 B |
After Width: | Height: | Size: 693 B |
After Width: | Height: | Size: 879 B |
After Width: | Height: | Size: 535 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 916 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 544 B |
After Width: | Height: | Size: 458 B |
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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 -->
|
|
@ -0,0 +1,2 @@
|
|||
{% extends "index.html" %}
|
||||
{% block title %}{{ SITENAME }} - {{ author }}{% endblock %}
|
|
@ -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 %}
|
|
@ -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>
|
|
@ -0,0 +1,2 @@
|
|||
{% extends "index.html" %}
|
||||
{% block title %}{{ SITENAME }} - {{ category }}{% endblock %}
|
|
@ -0,0 +1 @@
|
|||
{% if DISQUS_SITENAME %}<p>There are <a href="{{ SITEURL }}/{{ article.url }}#disqus_thread">comments</a>.</p>{% endif %}
|
|
@ -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 %}
|
|
@ -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;
|
||||
}
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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 */
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
{% extends "index.html" %}
|
||||
{% block title %}{{ SITENAME }} - {{ tag }}{% endblock %}
|
|
@ -0,0 +1 @@
|
|||
{% if article.tags %}<p>tags: {% for tag in article.tags %}<a href="{{ SITEURL }}/{{ tag.url }}">{{ tag | escape }}</a> {% endfor %}</p>{% endif %}
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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;}
|
|
@ -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;
|
||||
}
|