commit fd5f51ec4ad8a80ae63b7922843fe5c5a410de2a Author: Julien Palard Date: Tue Apr 4 23:11:23 2017 +0200 Initial commit diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4c0e97d --- /dev/null +++ b/Makefile @@ -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 diff --git a/content/blog/.hyde_deps b/content/blog/.hyde_deps new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/content/blog/.hyde_deps @@ -0,0 +1 @@ +{} diff --git a/content/blog/a-justintime-class.md b/content/blog/a-justintime-class.md new file mode 100644 index 0000000..b35453d --- /dev/null +++ b/content/blog/a-justintime-class.md @@ -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). diff --git a/content/blog/ashttp-vt100-screen-scraping-exported-over-http.md b/content/blog/ashttp-vt100-screen-scraping-exported-over-http.md new file mode 100644 index 0000000..99b61f9 --- /dev/null +++ b/content/blog/ashttp-vt100-screen-scraping-exported-over-http.md @@ -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). diff --git a/content/blog/asyncio-0.md b/content/blog/asyncio-0.md new file mode 100644 index 0000000..8781059 --- /dev/null +++ b/content/blog/asyncio-0.md @@ -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() + + +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 "", line 1, in + 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 "".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 "".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. diff --git a/content/blog/automating-gnu-screen-startup.md b/content/blog/automating-gnu-screen-startup.md new file mode 100644 index 0000000..7e2f2d4 --- /dev/null +++ b/content/blog/automating-gnu-screen-startup.md @@ -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. diff --git a/content/blog/bashism-how-to-generate-random-number-without-random.md b/content/blog/bashism-how-to-generate-random-number-without-random.md new file mode 100644 index 0000000..2f5f516 --- /dev/null +++ b/content/blog/bashism-how-to-generate-random-number-without-random.md @@ -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)) ... diff --git a/content/blog/c-sharp-using-alias-directives.md b/content/blog/c-sharp-using-alias-directives.md new file mode 100644 index 0000000..8becab8 --- /dev/null +++ b/content/blog/c-sharp-using-alias-directives.md @@ -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! diff --git a/content/blog/check-if-a-string-is-valid-utf8.md b/content/blog/check-if-a-string-is-valid-utf8.md new file mode 100644 index 0000000..12f7586 --- /dev/null +++ b/content/blog/check-if-a-string-is-valid-utf8.md @@ -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 :-) diff --git a/content/blog/cisco-cheatsheet.md b/content/blog/cisco-cheatsheet.md new file mode 100644 index 0000000..1de05a1 --- /dev/null +++ b/content/blog/cisco-cheatsheet.md @@ -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 + 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 + +## Ajouter une route statique + + router(config)#ip routing router(config)#ip route + [distance] + +## RIP + +### V1 (classfull/ pas de ss reseau) + + router(config)# router rip + router(config-router)# network + +### 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 + +### authentification + + router(config)# key chain + router(config-keychain)# key + router(config-keychain-key)# key-string + router(config-if)#ip rip authentication key-chain + router(config- if)#ip rip authentication mode {text | md5} + router(config-router)# neighbor + router(config-router)# passive-interface serial 0/0 + +## IGRP (classfull/pas de ss reseau) + + router(config)# router igrp 1 + router(config-router)# network + + timer basic + +### 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 name // vlan 1 = tout les prot par defaut ne pas utiliser + +#### ajout port + + router(config-if)# switchport acces vlan + +#### management lan + + router(config)# interface vlan + 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 + router(config-if)# port security action shutnown + router(config-if)# end #show port security + +## ETHERCHANNEL + + router(config-if)# port group 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 {permit|deny} + +### etendues + + a placer pres de la source + router(config)# access-list {permit|deny} [established] [log] + protocol = ip | tcp | udp | icmp | ospf | igrp... + protocol = lt | gt | eq | neq + +### nomee + + router(config)#ip access-list {standard|extended} + router(config-ext-nacl)# premit tcp www + +### application + + router(config-if)#ip access-group {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 diff --git a/content/blog/combinatory-logic-from-scratch.md b/content/blog/combinatory-logic-from-scratch.md new file mode 100644 index 0000000..d6ce812 --- /dev/null +++ b/content/blog/combinatory-logic-from-scratch.md @@ -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* diff --git a/content/blog/covariance-and-contravariance-in-c-sharp-3.md b/content/blog/covariance-and-contravariance-in-c-sharp-3.md new file mode 100644 index 0000000..d0c7ea0 --- /dev/null +++ b/content/blog/covariance-and-contravariance-in-c-sharp-3.md @@ -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. diff --git a/content/blog/echo-and-backslash-escaped-characters-new-lines.md b/content/blog/echo-and-backslash-escaped-characters-new-lines.md new file mode 100644 index 0000000..f633e53 --- /dev/null +++ b/content/blog/echo-and-backslash-escaped-characters-new-lines.md @@ -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" diff --git a/content/blog/emacs-replace-tabs-with-spaces.md b/content/blog/emacs-replace-tabs-with-spaces.md new file mode 100644 index 0000000..7f1e2bd --- /dev/null +++ b/content/blog/emacs-replace-tabs-with-spaces.md @@ -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. diff --git a/content/blog/emacs-standard-input-is-not-a-tty.md b/content/blog/emacs-standard-input-is-not-a-tty.md new file mode 100644 index 0000000..06f9641 --- /dev/null +++ b/content/blog/emacs-standard-input-is-not-a-tty.md @@ -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 diff --git a/content/blog/emacs-syntax-error-highlighting.md b/content/blog/emacs-syntax-error-highlighting.md new file mode 100644 index 0000000..99ce9b9 --- /dev/null +++ b/content/blog/emacs-syntax-error-highlighting.md @@ -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 : + + + :::bash + #!/bin/bash + + epylint "$1" 2>/dev/null + pyflakes "$1" + pep8 --ignore=E221,E701,E202 --repeat "$1" + true + +Enjoy! diff --git a/content/blog/emacsnumeric-arguments-in.md b/content/blog/emacsnumeric-arguments-in.md new file mode 100644 index 0000000..f167b32 --- /dev/null +++ b/content/blog/emacsnumeric-arguments-in.md @@ -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. diff --git a/content/blog/emacssearching-string-in.md b/content/blog/emacssearching-string-in.md new file mode 100644 index 0000000..eaa2c21 --- /dev/null +++ b/content/blog/emacssearching-string-in.md @@ -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.) diff --git a/content/blog/exclude-directories-matching-from-recursive-grep.md b/content/blog/exclude-directories-matching-from-recursive-grep.md new file mode 100644 index 0000000..b04ab25 --- /dev/null +++ b/content/blog/exclude-directories-matching-from-recursive-grep.md @@ -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 !!!) diff --git a/content/blog/howto-invoke-an-event-via-reflexion.md b/content/blog/howto-invoke-an-event-via-reflexion.md new file mode 100644 index 0000000..13d6e4a --- /dev/null +++ b/content/blog/howto-invoke-an-event-via-reflexion.md @@ -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 }); + } + } + } diff --git a/content/blog/integrating-google-bookmarks-in-google-chrome.md b/content/blog/integrating-google-bookmarks-in-google-chrome.md new file mode 100644 index 0000000..97aafb1 --- /dev/null +++ b/content/blog/integrating-google-bookmarks-in-google-chrome.md @@ -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 + +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! diff --git a/content/blog/javascript-foncteur.md b/content/blog/javascript-foncteur.md new file mode 100644 index 0000000..9a7ef84 --- /dev/null +++ b/content/blog/javascript-foncteur.md @@ -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! diff --git a/content/blog/lazy-loading-in-php-with-spl_autload.md b/content/blog/lazy-loading-in-php-with-spl_autload.md new file mode 100644 index 0000000..138af58 --- /dev/null +++ b/content/blog/lazy-loading-in-php-with-spl_autload.md @@ -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"); diff --git a/content/blog/nfsmount_rpc_failed_2.md b/content/blog/nfsmount_rpc_failed_2.md new file mode 100644 index 0000000..7e93b02 --- /dev/null +++ b/content/blog/nfsmount_rpc_failed_2.md @@ -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! diff --git a/content/blog/pipe-infix-syntax-for-python.md b/content/blog/pipe-infix-syntax-for-python.md new file mode 100644 index 0000000..899ef40 --- /dev/null +++ b/content/blog/pipe-infix-syntax-for-python.md @@ -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 :-) diff --git a/content/blog/post-data-lost-on-301-moved-permanently.md b/content/blog/post-data-lost-on-301-moved-permanently.md new file mode 100644 index 0000000..9ddcc2f --- /dev/null +++ b/content/blog/post-data-lost-on-301-moved-permanently.md @@ -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... diff --git a/content/blog/python-introducing-ppipe-parallel-pipe.md b/content/blog/python-introducing-ppipe-parallel-pipe.md new file mode 100644 index 0000000..f1fedf6 --- /dev/null +++ b/content/blog/python-introducing-ppipe-parallel-pipe.md @@ -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! diff --git a/content/blog/reading-peps-from-command-line.md b/content/blog/reading-peps-from-command-line.md new file mode 100644 index 0000000..61d329e --- /dev/null +++ b/content/blog/reading-peps-from-command-line.md @@ -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! diff --git a/content/blog/squid-101-network-is-unreachable-when-dns-returns-ipv6.md b/content/blog/squid-101-network-is-unreachable-when-dns-returns-ipv6.md new file mode 100644 index 0000000..625d3ce --- /dev/null +++ b/content/blog/squid-101-network-is-unreachable-when-dns-returns-ipv6.md @@ -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! diff --git a/content/blog/the-art-of-events.md b/content/blog/the-art-of-events.md new file mode 100644 index 0000000..a8f6b24 --- /dev/null +++ b/content/blog/the-art-of-events.md @@ -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! diff --git a/content/blog/the-operator-aka-null-coalescing-operator.md b/content/blog/the-operator-aka-null-coalescing-operator.md new file mode 100644 index 0000000..cfe7569 --- /dev/null +++ b/content/blog/the-operator-aka-null-coalescing-operator.md @@ -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:) diff --git a/content/blog/yauib-yet-another-useless-irc-bot.md b/content/blog/yauib-yet-another-useless-irc-bot.md new file mode 100644 index 0000000..394cce7 --- /dev/null +++ b/content/blog/yauib-yet-another-useless-irc-bot.md @@ -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 diff --git a/content/media/css/github-markdown.css b/content/media/css/github-markdown.css new file mode 100644 index 0000000..60261e8 --- /dev/null +++ b/content/media/css/github-markdown.css @@ -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; +} diff --git a/content/media/css/site.css b/content/media/css/site.css new file mode 100644 index 0000000..17cf709 --- /dev/null +++ b/content/media/css/site.css @@ -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; +} diff --git a/content/media/css/syntax.css b/content/media/css/syntax.css new file mode 100644 index 0000000..fa3dfc3 --- /dev/null +++ b/content/media/css/syntax.css @@ -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 */ + diff --git a/content/media/images/airport.png b/content/media/images/airport.png new file mode 100644 index 0000000..55a5c0c Binary files /dev/null and b/content/media/images/airport.png differ diff --git a/content/media/images/apple-touch-icon.png b/content/media/images/apple-touch-icon.png new file mode 100644 index 0000000..6d2fc39 Binary files /dev/null and b/content/media/images/apple-touch-icon.png differ diff --git a/content/media/images/dark.png b/content/media/images/dark.png new file mode 100644 index 0000000..7380014 Binary files /dev/null and b/content/media/images/dark.png differ diff --git a/content/media/images/favicon.ico b/content/media/images/favicon.ico new file mode 100644 index 0000000..ba85778 Binary files /dev/null and b/content/media/images/favicon.ico differ diff --git a/content/media/js/libs/dd_belatedpng.js b/content/media/js/libs/dd_belatedpng.js new file mode 100644 index 0000000..6062fb3 --- /dev/null +++ b/content/media/js/libs/dd_belatedpng.js @@ -0,0 +1,13 @@ +/** +* DD_belatedPNG: Adds IE6 support: PNG images for CSS background-image and HTML . +* Author: Drew Diller +* Email: drew.diller@gmail.com +* URL: http://www.dillerdesign.com/experiment/DD_belatedPNG/ +* Version: 0.0.8a +* Licensed under the MIT License: http://dillerdesign.com/experiment/DD_belatedPNG/#license +* +* Example usage: +* DD_belatedPNG.fix('.png_bg'); // argument is a CSS selector +* DD_belatedPNG.fixPng( someNode ); // argument is an HTMLDomElement +**/ +var DD_belatedPNG={ns:"DD_belatedPNG",imgSize:{},delay:10,nodesFixed:0,createVmlNameSpace:function(){if(document.namespaces&&!document.namespaces[this.ns]){document.namespaces.add(this.ns,"urn:schemas-microsoft-com:vml")}},createVmlStyleSheet:function(){var b,a;b=document.createElement("style");b.setAttribute("media","screen");document.documentElement.firstChild.insertBefore(b,document.documentElement.firstChild.firstChild);if(b.styleSheet){b=b.styleSheet;b.addRule(this.ns+"\\:*","{behavior:url(#default#VML)}");b.addRule(this.ns+"\\:shape","position:absolute;");b.addRule("img."+this.ns+"_sizeFinder","behavior:none; border:none; position:absolute; z-index:-1; top:-10000px; visibility:hidden;");this.screenStyleSheet=b;a=document.createElement("style");a.setAttribute("media","print");document.documentElement.firstChild.insertBefore(a,document.documentElement.firstChild.firstChild);a=a.styleSheet;a.addRule(this.ns+"\\:*","{display: none !important;}");a.addRule("img."+this.ns+"_sizeFinder","{display: none !important;}")}},readPropertyChange:function(){var b,c,a;b=event.srcElement;if(!b.vmlInitiated){return}if(event.propertyName.search("background")!=-1||event.propertyName.search("border")!=-1){DD_belatedPNG.applyVML(b)}if(event.propertyName=="style.display"){c=(b.currentStyle.display=="none")?"none":"block";for(a in b.vml){if(b.vml.hasOwnProperty(a)){b.vml[a].shape.style.display=c}}}if(event.propertyName.search("filter")!=-1){DD_belatedPNG.vmlOpacity(b)}},vmlOpacity:function(b){if(b.currentStyle.filter.search("lpha")!=-1){var a=b.currentStyle.filter;a=parseInt(a.substring(a.lastIndexOf("=")+1,a.lastIndexOf(")")),10)/100;b.vml.color.shape.style.filter=b.currentStyle.filter;b.vml.image.fill.opacity=a}},handlePseudoHover:function(a){setTimeout(function(){DD_belatedPNG.applyVML(a)},1)},fix:function(a){if(this.screenStyleSheet){var c,b;c=a.split(",");for(b=0;bn.H){i.B=n.H}d.vml.image.shape.style.clip="rect("+i.T+"px "+(i.R+a)+"px "+i.B+"px "+(i.L+a)+"px)"}else{d.vml.image.shape.style.clip="rect("+f.T+"px "+f.R+"px "+f.B+"px "+f.L+"px)"}},figurePercentage:function(d,c,f,a){var b,e;e=true;b=(f=="X");switch(a){case"left":case"top":d[f]=0;break;case"center":d[f]=0.5;break;case"right":case"bottom":d[f]=1;break;default:if(a.search("%")!=-1){d[f]=parseInt(a,10)/100}else{e=false}}d[f]=Math.ceil(e?((c[b?"W":"H"]*d[f])-(c[b?"w":"h"]*d[f])):parseInt(a,10));if(d[f]%2===0){d[f]++}return d[f]},fixPng:function(c){c.style.behavior="none";var g,b,f,a,d;if(c.nodeName=="BODY"||c.nodeName=="TD"||c.nodeName=="TR"){return}c.isImg=false;if(c.nodeName=="IMG"){if(c.src.toLowerCase().search(/\.png$/)!=-1){c.isImg=true;c.style.visibility="hidden"}else{return}}else{if(c.currentStyle.backgroundImage.toLowerCase().search(".png")==-1){return}}g=DD_belatedPNG;c.vml={color:{},image:{}};b={shape:{},fill:{}};for(a in c.vml){if(c.vml.hasOwnProperty(a)){for(d in b){if(b.hasOwnProperty(d)){f=g.ns+":"+d;c.vml[a][d]=document.createElement(f)}}c.vml[a].shape.stroked=false;c.vml[a].shape.appendChild(c.vml[a].fill);c.parentNode.insertBefore(c.vml[a].shape,c)}}c.vml.image.shape.fillcolor="none";c.vml.image.fill.type="tile";c.vml.color.fill.on=false;g.attachHandlers(c);g.giveLayout(c);g.giveLayout(c.offsetParent);c.vmlInitiated=true;g.applyVML(c)}};try{document.execCommand("BackgroundImageCache",false,true)}catch(r){}DD_belatedPNG.createVmlNameSpace();DD_belatedPNG.createVmlStyleSheet(); \ No newline at end of file diff --git a/content/media/js/libs/jquery-1.5.1.min.js b/content/media/js/libs/jquery-1.5.1.min.js new file mode 100644 index 0000000..14fd647 --- /dev/null +++ b/content/media/js/libs/jquery-1.5.1.min.js @@ -0,0 +1,16 @@ +/*! + * jQuery JavaScript Library v1.5.1 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Wed Feb 23 13:55:29 2011 -0500 + */ +(function(a,b){function cg(a){return d.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cd(a){if(!bZ[a]){var b=d("<"+a+">").appendTo("body"),c=b.css("display");b.remove();if(c==="none"||c==="")c="block";bZ[a]=c}return bZ[a]}function cc(a,b){var c={};d.each(cb.concat.apply([],cb.slice(0,b)),function(){c[this]=a});return c}function bY(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function bX(){try{return new a.XMLHttpRequest}catch(b){}}function bW(){d(a).unload(function(){for(var a in bU)bU[a](0,1)})}function bQ(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var e=a.dataTypes,f={},g,h,i=e.length,j,k=e[0],l,m,n,o,p;for(g=1;g=0===c})}function N(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function F(a,b){return(a&&a!=="*"?a+".":"")+b.replace(r,"`").replace(s,"&")}function E(a){var b,c,e,f,g,h,i,j,k,l,m,n,o,q=[],r=[],s=d._data(this,"events");if(a.liveFired!==this&&s&&s.live&&!a.target.disabled&&(!a.button||a.type!=="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var t=s.live.slice(0);for(i=0;ic)break;a.currentTarget=f.elem,a.data=f.handleObj.data,a.handleObj=f.handleObj,o=f.handleObj.origHandler.apply(f.elem,arguments);if(o===!1||a.isPropagationStopped()){c=f.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function C(a,c,e){var f=d.extend({},e[0]);f.type=a,f.originalEvent={},f.liveFired=b,d.event.handle.call(c,f),f.isDefaultPrevented()&&e[0].preventDefault()}function w(){return!0}function v(){return!1}function g(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function f(a,c,f){if(f===b&&a.nodeType===1){f=a.getAttribute("data-"+c);if(typeof f==="string"){try{f=f==="true"?!0:f==="false"?!1:f==="null"?null:d.isNaN(f)?e.test(f)?d.parseJSON(f):f:parseFloat(f)}catch(g){}d.data(a,c,f)}else f=b}return f}var c=a.document,d=function(){function I(){if(!d.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(I,1);return}d.ready()}}var d=function(a,b){return new d.fn.init(a,b,g)},e=a.jQuery,f=a.$,g,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,i=/\S/,j=/^\s+/,k=/\s+$/,l=/\d/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=navigator.userAgent,w,x=!1,y,z="then done fail isResolved isRejected promise".split(" "),A,B=Object.prototype.toString,C=Object.prototype.hasOwnProperty,D=Array.prototype.push,E=Array.prototype.slice,F=String.prototype.trim,G=Array.prototype.indexOf,H={};d.fn=d.prototype={constructor:d,init:function(a,e,f){var g,i,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!e&&c.body){this.context=c,this[0]=c.body,this.selector="body",this.length=1;return this}if(typeof a==="string"){g=h.exec(a);if(!g||!g[1]&&e)return!e||e.jquery?(e||f).find(a):this.constructor(e).find(a);if(g[1]){e=e instanceof d?e[0]:e,k=e?e.ownerDocument||e:c,j=m.exec(a),j?d.isPlainObject(e)?(a=[c.createElement(j[1])],d.fn.attr.call(a,e,!0)):a=[k.createElement(j[1])]:(j=d.buildFragment([g[1]],[k]),a=(j.cacheable?d.clone(j.fragment):j.fragment).childNodes);return d.merge(this,a)}i=c.getElementById(g[2]);if(i&&i.parentNode){if(i.id!==g[2])return f.find(a);this.length=1,this[0]=i}this.context=c,this.selector=a;return this}if(d.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return d.makeArray(a,this)},selector:"",jquery:"1.5.1",length:0,size:function(){return this.length},toArray:function(){return E.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var e=this.constructor();d.isArray(a)?D.apply(e,a):d.merge(e,a),e.prevObject=this,e.context=this.context,b==="find"?e.selector=this.selector+(this.selector?" ":"")+c:b&&(e.selector=this.selector+"."+b+"("+c+")");return e},each:function(a,b){return d.each(this,a,b)},ready:function(a){d.bindReady(),y.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(E.apply(this,arguments),"slice",E.call(arguments).join(","))},map:function(a){return this.pushStack(d.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:D,sort:[].sort,splice:[].splice},d.fn.init.prototype=d.fn,d.extend=d.fn.extend=function(){var a,c,e,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i==="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!=="object"&&!d.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;y.resolveWith(c,[d]),d.fn.trigger&&d(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!x){x=!0;if(c.readyState==="complete")return setTimeout(d.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",A,!1),a.addEventListener("load",d.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",A),a.attachEvent("onload",d.ready);var b=!1;try{b=a.frameElement==null}catch(e){}c.documentElement.doScroll&&b&&I()}}},isFunction:function(a){return d.type(a)==="function"},isArray:Array.isArray||function(a){return d.type(a)==="array"},isWindow:function(a){return a&&typeof a==="object"&&"setInterval"in a},isNaN:function(a){return a==null||!l.test(a)||isNaN(a)},type:function(a){return a==null?String(a):H[B.call(a)]||"object"},isPlainObject:function(a){if(!a||d.type(a)!=="object"||a.nodeType||d.isWindow(a))return!1;if(a.constructor&&!C.call(a,"constructor")&&!C.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a){}return c===b||C.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!=="string"||!b)return null;b=d.trim(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return a.JSON&&a.JSON.parse?a.JSON.parse(b):(new Function("return "+b))();d.error("Invalid JSON: "+b)},parseXML:function(b,c,e){a.DOMParser?(e=new DOMParser,c=e.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),e=c.documentElement,(!e||!e.nodeName||e.nodeName==="parsererror")&&d.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(a){if(a&&i.test(a)){var b=c.head||c.getElementsByTagName("head")[0]||c.documentElement,e=c.createElement("script");d.support.scriptEval()?e.appendChild(c.createTextNode(a)):e.text=a,b.insertBefore(e,b.firstChild),b.removeChild(e)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,e){var f,g=0,h=a.length,i=h===b||d.isFunction(a);if(e){if(i){for(f in a)if(c.apply(a[f],e)===!1)break}else for(;g1){var f=E.call(arguments,0),g=b,h=function(a){return function(b){f[a]=arguments.length>1?E.call(arguments,0):b,--g||c.resolveWith(e,f)}};while(b--)a=f[b],a&&d.isFunction(a.promise)?a.promise().then(h(b),c.reject):--g;g||c.resolveWith(e,f)}else c!==a&&c.resolve(a);return e},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}d.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.subclass=this.subclass,a.fn.init=function b(b,c){c&&c instanceof d&&!(c instanceof a)&&(c=a(c));return d.fn.init.call(this,b,c,e)},a.fn.init.prototype=a.fn;var e=a(c);return a},browser:{}}),y=d._Deferred(),d.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){H["[object "+b+"]"]=b.toLowerCase()}),w=d.uaMatch(v),w.browser&&(d.browser[w.browser]=!0,d.browser.version=w.version),d.browser.webkit&&(d.browser.safari=!0),G&&(d.inArray=function(a,b){return G.call(b,a)}),i.test(" ")&&(j=/^[\s\xA0]+/,k=/[\s\xA0]+$/),g=d(c),c.addEventListener?A=function(){c.removeEventListener("DOMContentLoaded",A,!1),d.ready()}:c.attachEvent&&(A=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",A),d.ready())});return d}();(function(){d.support={};var b=c.createElement("div");b.style.display="none",b.innerHTML="
a";var e=b.getElementsByTagName("*"),f=b.getElementsByTagName("a")[0],g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=b.getElementsByTagName("input")[0];if(e&&e.length&&f){d.support={leadingWhitespace:b.firstChild.nodeType===3,tbody:!b.getElementsByTagName("tbody").length,htmlSerialize:!!b.getElementsByTagName("link").length,style:/red/.test(f.getAttribute("style")),hrefNormalized:f.getAttribute("href")==="/a",opacity:/^0.55$/.test(f.style.opacity),cssFloat:!!f.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,deleteExpando:!0,optDisabled:!1,checkClone:!1,noCloneEvent:!0,noCloneChecked:!0,boxModel:null,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableHiddenOffsets:!0},i.checked=!0,d.support.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,d.support.optDisabled=!h.disabled;var j=null;d.support.scriptEval=function(){if(j===null){var b=c.documentElement,e=c.createElement("script"),f="script"+d.now();try{e.appendChild(c.createTextNode("window."+f+"=1;"))}catch(g){}b.insertBefore(e,b.firstChild),a[f]?(j=!0,delete a[f]):j=!1,b.removeChild(e),b=e=f=null}return j};try{delete b.test}catch(k){d.support.deleteExpando=!1}!b.addEventListener&&b.attachEvent&&b.fireEvent&&(b.attachEvent("onclick",function l(){d.support.noCloneEvent=!1,b.detachEvent("onclick",l)}),b.cloneNode(!0).fireEvent("onclick")),b=c.createElement("div"),b.innerHTML="";var m=c.createDocumentFragment();m.appendChild(b.firstChild),d.support.checkClone=m.cloneNode(!0).cloneNode(!0).lastChild.checked,d(function(){var a=c.createElement("div"),b=c.getElementsByTagName("body")[0];if(b){a.style.width=a.style.paddingLeft="1px",b.appendChild(a),d.boxModel=d.support.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,d.support.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
",d.support.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
t
";var e=a.getElementsByTagName("td");d.support.reliableHiddenOffsets=e[0].offsetHeight===0,e[0].style.display="",e[1].style.display="none",d.support.reliableHiddenOffsets=d.support.reliableHiddenOffsets&&e[0].offsetHeight===0,a.innerHTML="",b.removeChild(a).style.display="none",a=e=null}});var n=function(a){var b=c.createElement("div");a="on"+a;if(!b.attachEvent)return!0;var d=a in b;d||(b.setAttribute(a,"return;"),d=typeof b[a]==="function"),b=null;return d};d.support.submitBubbles=n("submit"),d.support.changeBubbles=n("change"),b=e=f=null}})();var e=/^(?:\{.*\}|\[.*\])$/;d.extend({cache:{},uuid:0,expando:"jQuery"+(d.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?d.cache[a[d.expando]]:a[d.expando];return!!a&&!g(a)},data:function(a,c,e,f){if(d.acceptData(a)){var g=d.expando,h=typeof c==="string",i,j=a.nodeType,k=j?d.cache:a,l=j?a[d.expando]:a[d.expando]&&d.expando;if((!l||f&&l&&!k[l][g])&&h&&e===b)return;l||(j?a[d.expando]=l=++d.uuid:l=d.expando),k[l]||(k[l]={},j||(k[l].toJSON=d.noop));if(typeof c==="object"||typeof c==="function")f?k[l][g]=d.extend(k[l][g],c):k[l]=d.extend(k[l],c);i=k[l],f&&(i[g]||(i[g]={}),i=i[g]),e!==b&&(i[c]=e);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[c]:i}},removeData:function(b,c,e){if(d.acceptData(b)){var f=d.expando,h=b.nodeType,i=h?d.cache:b,j=h?b[d.expando]:d.expando;if(!i[j])return;if(c){var k=e?i[j][f]:i[j];if(k){delete k[c];if(!g(k))return}}if(e){delete i[j][f];if(!g(i[j]))return}var l=i[j][f];d.support.deleteExpando||i!=a?delete i[j]:i[j]=null,l?(i[j]={},h||(i[j].toJSON=d.noop),i[j][f]=l):h&&(d.support.deleteExpando?delete b[d.expando]:b.removeAttribute?b.removeAttribute(d.expando):b[d.expando]=null)}},_data:function(a,b,c){return d.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=d.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),d.fn.extend({data:function(a,c){var e=null;if(typeof a==="undefined"){if(this.length){e=d.data(this[0]);if(this[0].nodeType===1){var g=this[0].attributes,h;for(var i=0,j=g.length;i-1)return!0;return!1},val:function(a){if(!arguments.length){var c=this[0];if(c){if(d.nodeName(c,"option")){var e=c.attributes.value;return!e||e.specified?c.value:c.text}if(d.nodeName(c,"select")){var f=c.selectedIndex,g=[],h=c.options,i=c.type==="select-one";if(f<0)return null;for(var k=i?f:0,l=i?f+1:h.length;k=0;else if(d.nodeName(this,"select")){var f=d.makeArray(e);d("option",this).each(function(){this.selected=d.inArray(d(this).val(),f)>=0}),f.length||(this.selectedIndex=-1)}else this.value=e}})}}),d.extend({attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,e,f){if(!a||a.nodeType===3||a.nodeType===8||a.nodeType===2)return b;if(f&&c in d.attrFn)return d(a)[c](e);var g=a.nodeType!==1||!d.isXMLDoc(a),h=e!==b;c=g&&d.props[c]||c;if(a.nodeType===1){var i=k.test(c);if(c==="selected"&&!d.support.optSelected){var j=a.parentNode;j&&(j.selectedIndex,j.parentNode&&j.parentNode.selectedIndex)}if((c in a||a[c]!==b)&&g&&!i){h&&(c==="type"&&l.test(a.nodeName)&&a.parentNode&&d.error("type property can't be changed"),e===null?a.nodeType===1&&a.removeAttribute(c):a[c]=e);if(d.nodeName(a,"form")&&a.getAttributeNode(c))return a.getAttributeNode(c).nodeValue;if(c==="tabIndex"){var o=a.getAttributeNode("tabIndex");return o&&o.specified?o.value:m.test(a.nodeName)||n.test(a.nodeName)&&a.href?0:b}return a[c]}if(!d.support.style&&g&&c==="style"){h&&(a.style.cssText=""+e);return a.style.cssText}h&&a.setAttribute(c,""+e);if(!a.attributes[c]&&(a.hasAttribute&&!a.hasAttribute(c)))return b;var p=!d.support.hrefNormalized&&g&&i?a.getAttribute(c,2):a.getAttribute(c);return p===null?b:p}h&&(a[c]=e);return a[c]}});var p=/\.(.*)$/,q=/^(?:textarea|input|select)$/i,r=/\./g,s=/ /g,t=/[^\w\s.|`]/g,u=function(a){return a.replace(t,"\\$&")};d.event={add:function(c,e,f,g){if(c.nodeType!==3&&c.nodeType!==8){try{d.isWindow(c)&&(c!==a&&!c.frameElement)&&(c=a)}catch(h){}if(f===!1)f=v;else if(!f)return;var i,j;f.handler&&(i=f,f=i.handler),f.guid||(f.guid=d.guid++);var k=d._data(c);if(!k)return;var l=k.events,m=k.handle;l||(k.events=l={}),m||(k.handle=m=function(){return typeof d!=="undefined"&&!d.event.triggered?d.event.handle.apply(m.elem,arguments):b}),m.elem=c,e=e.split(" ");var n,o=0,p;while(n=e[o++]){j=i?d.extend({},i):{handler:f,data:g},n.indexOf(".")>-1?(p=n.split("."),n=p.shift(),j.namespace=p.slice(0).sort().join(".")):(p=[],j.namespace=""),j.type=n,j.guid||(j.guid=f.guid);var q=l[n],r=d.event.special[n]||{};if(!q){q=l[n]=[];if(!r.setup||r.setup.call(c,g,p,m)===!1)c.addEventListener?c.addEventListener(n,m,!1):c.attachEvent&&c.attachEvent("on"+n,m)}r.add&&(r.add.call(c,j),j.handler.guid||(j.handler.guid=f.guid)),q.push(j),d.event.global[n]=!0}c=null}},global:{},remove:function(a,c,e,f){if(a.nodeType!==3&&a.nodeType!==8){e===!1&&(e=v);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=d.hasData(a)&&d._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(e=c.handler,c=c.type);if(!c||typeof c==="string"&&c.charAt(0)==="."){c=c||"";for(h in t)d.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+d.map(m.slice(0).sort(),u).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!e){for(j=0;j=0&&(a.type=f=f.slice(0,-1),a.exclusive=!0),e||(a.stopPropagation(),d.event.global[f]&&d.each(d.cache,function(){var b=d.expando,e=this[b];e&&e.events&&e.events[f]&&d.event.trigger(a,c,e.handle.elem)}));if(!e||e.nodeType===3||e.nodeType===8)return b;a.result=b,a.target=e,c=d.makeArray(c),c.unshift(a)}a.currentTarget=e;var h=d._data(e,"handle");h&&h.apply(e,c);var i=e.parentNode||e.ownerDocument;try{e&&e.nodeName&&d.noData[e.nodeName.toLowerCase()]||e["on"+f]&&e["on"+f].apply(e,c)===!1&&(a.result=!1,a.preventDefault())}catch(j){}if(!a.isPropagationStopped()&&i)d.event.trigger(a,c,i,!0);else if(!a.isDefaultPrevented()){var k,l=a.target,m=f.replace(p,""),n=d.nodeName(l,"a")&&m==="click",o=d.event.special[m]||{};if((!o._default||o._default.call(e,a)===!1)&&!n&&!(l&&l.nodeName&&d.noData[l.nodeName.toLowerCase()])){try{l[m]&&(k=l["on"+m],k&&(l["on"+m]=null),d.event.triggered=!0,l[m]())}catch(q){}k&&(l["on"+m]=k),d.event.triggered=!1}}},handle:function(c){var e,f,g,h,i,j=[],k=d.makeArray(arguments);c=k[0]=d.event.fix(c||a.event),c.currentTarget=this,e=c.type.indexOf(".")<0&&!c.exclusive,e||(g=c.type.split("."),c.type=g.shift(),j=g.slice(0).sort(),h=new RegExp("(^|\\.)"+j.join("\\.(?:.*\\.)?")+"(\\.|$)")),c.namespace=c.namespace||j.join("."),i=d._data(this,"events"),f=(i||{})[c.type];if(i&&f){f=f.slice(0);for(var l=0,m=f.length;l-1?d.map(a.options,function(a){return a.selected}).join("-"):"":a.nodeName.toLowerCase()==="select"&&(c=a.selectedIndex);return c},B=function B(a){var c=a.target,e,f;if(q.test(c.nodeName)&&!c.readOnly){e=d._data(c,"_change_data"),f=A(c),(a.type!=="focusout"||c.type!=="radio")&&d._data(c,"_change_data",f);if(e===b||f===e)return;if(e!=null||f)a.type="change",a.liveFired=b,d.event.trigger(a,arguments[1],c)}};d.event.special.change={filters:{focusout:B,beforedeactivate:B,click:function(a){var b=a.target,c=b.type;(c==="radio"||c==="checkbox"||b.nodeName.toLowerCase()==="select")&&B.call(this,a)},keydown:function(a){var b=a.target,c=b.type;(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&B.call(this,a)},beforeactivate:function(a){var b=a.target;d._data(b,"_change_data",A(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in z)d.event.add(this,c+".specialChange",z[c]);return q.test(this.nodeName)},teardown:function(a){d.event.remove(this,".specialChange");return q.test(this.nodeName)}},z=d.event.special.change.filters,z.focus=z.beforeactivate}c.addEventListener&&d.each({focus:"focusin",blur:"focusout"},function(a,b){function c(a){a=d.event.fix(a),a.type=b;return d.event.handle.call(this,a)}d.event.special[b]={setup:function(){this.addEventListener(a,c,!0)},teardown:function(){this.removeEventListener(a,c,!0)}}}),d.each(["bind","one"],function(a,c){d.fn[c]=function(a,e,f){if(typeof a==="object"){for(var g in a)this[c](g,e,a[g],f);return this}if(d.isFunction(e)||e===!1)f=e,e=b;var h=c==="one"?d.proxy(f,function(a){d(this).unbind(a,h);return f.apply(this,arguments)}):f;if(a==="unload"&&c!=="one")this.one(a,e,f);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},d.attrFn&&(d.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,e,g){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!=="string")return e;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(f.call(n)==="[object Array]")if(u)if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&e.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&e.push(j[t]);else e.push.apply(e,n);else p(n,e);o&&(k(o,h,e,g),k.uniqueSort(e));return e};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b==="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){return"text"===a.getAttribute("type")},radio:function(a){return"radio"===a.type},checkbox:function(a){return"checkbox"===a.type},file:function(a){return"file"===a.type},password:function(a){return"password"===a.type},submit:function(a){return"submit"===a.type},image:function(a){return"image"===a.type},reset:function(a){return"reset"===a.type},button:function(a){return"button"===a.type||a.nodeName.toLowerCase()==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(f.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length==="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!=="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!=="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!=="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!=="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector,d=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(e){d=!0}b&&(k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(d||!l.match.PSEUDO.test(c)&&!/!=/.test(c))return b.call(a,c)}catch(e){}return k(c,null,null,[a]).length>0})}(),function(){var a=c.createElement("div");a.innerHTML="
";if(a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!=="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(var g=c;g0},closest:function(a,b){var c=[],e,f,g=this[0];if(d.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(e=0,f=a.length;e-1:d(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=L.test(a)?d(a,b||this.context):null;for(e=0,f=this.length;e-1:d.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b)break}}c=c.length>1?d.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a==="string")return d.inArray(this[0],a?d(a):this.parent().children());return d.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a==="string"?d(a,b):d.makeArray(a),e=d.merge(this.get(),c);return this.pushStack(N(c[0])||N(e[0])?e:d.unique(e))},andSelf:function(){return this.add(this.prevObject)}}),d.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return d.dir(a,"parentNode")},parentsUntil:function(a,b,c){return d.dir(a,"parentNode",c)},next:function(a){return d.nth(a,2,"nextSibling")},prev:function(a){return d.nth(a,2,"previousSibling")},nextAll:function(a){return d.dir(a,"nextSibling")},prevAll:function(a){return d.dir(a,"previousSibling")},nextUntil:function(a,b,c){return d.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return d.dir(a,"previousSibling",c)},siblings:function(a){return d.sibling(a.parentNode.firstChild,a)},children:function(a){return d.sibling(a.firstChild)},contents:function(a){return d.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:d.makeArray(a.childNodes)}},function(a,b){d.fn[a]=function(c,e){var f=d.map(this,b,c),g=K.call(arguments);G.test(a)||(e=c),e&&typeof e==="string"&&(f=d.filter(e,f)),f=this.length>1&&!M[a]?d.unique(f):f,(this.length>1||I.test(e))&&H.test(a)&&(f=f.reverse());return this.pushStack(f,a,g.join(","))}}),d.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?d.find.matchesSelector(b[0],a)?[b[0]]:[]:d.find.matches(a,b)},dir:function(a,c,e){var f=[],g=a[c];while(g&&g.nodeType!==9&&(e===b||g.nodeType!==1||!d(g).is(e)))g.nodeType===1&&f.push(g),g=g[c];return f},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var P=/ jQuery\d+="(?:\d+|null)"/g,Q=/^\s+/,R=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,S=/<([\w:]+)/,T=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};X.optgroup=X.option,X.tbody=X.tfoot=X.colgroup=X.caption=X.thead,X.th=X.td,d.support.htmlSerialize||(X._default=[1,"div
","
"]),d.fn.extend({text:function(a){if(d.isFunction(a))return this.each(function(b){var c=d(this);c.text(a.call(this,b,c.text()))});if(typeof a!=="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return d.text(this)},wrapAll:function(a){if(d.isFunction(a))return this.each(function(b){d(this).wrapAll(a.call(this,b))});if(this[0]){var b=d(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(d.isFunction(a))return this.each(function(b){d(this).wrapInner(a.call(this,b))});return this.each(function(){var b=d(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){d(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){d.nodeName(this,"body")||d(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=d(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,d(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,e;(e=this[c])!=null;c++)if(!a||d.filter(a,[e]).length)!b&&e.nodeType===1&&(d.cleanData(e.getElementsByTagName("*")),d.cleanData([e])),e.parentNode&&e.parentNode.removeChild(e);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&d.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return d.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(P,""):null;if(typeof a!=="string"||V.test(a)||!d.support.leadingWhitespace&&Q.test(a)||X[(S.exec(a)||["",""])[1].toLowerCase()])d.isFunction(a)?this.each(function(b){var c=d(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);else{a=a.replace(R,"<$1>");try{for(var c=0,e=this.length;c1&&l0?this.clone(!0):this).get();d(f[h])[b](j),e=e.concat(j)}return this.pushStack(e,a,f.selector)}}),d.extend({clone:function(a,b,c){var e=a.cloneNode(!0),f,g,h;if((!d.support.noCloneEvent||!d.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!d.isXMLDoc(a)){$(a,e),f=_(a),g=_(e);for(h=0;f[h];++h)$(f[h],g[h])}if(b){Z(a,e);if(c){f=_(a),g=_(e);for(h=0;f[h];++h)Z(f[h],g[h])}}return e},clean:function(a,b,e,f){b=b||c,typeof b.createElement==="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var g=[];for(var h=0,i;(i=a[h])!=null;h++){typeof i==="number"&&(i+="");if(!i)continue;if(typeof i!=="string"||U.test(i)){if(typeof i==="string"){i=i.replace(R,"<$1>");var j=(S.exec(i)||["",""])[1].toLowerCase(),k=X[j]||X._default,l=k[0],m=b.createElement("div");m.innerHTML=k[1]+i+k[2];while(l--)m=m.lastChild;if(!d.support.tbody){var n=T.test(i),o=j==="table"&&!n?m.firstChild&&m.firstChild.childNodes:k[1]===""&&!n?m.childNodes:[];for(var p=o.length-1;p>=0;--p)d.nodeName(o[p],"tbody")&&!o[p].childNodes.length&&o[p].parentNode.removeChild(o[p])}!d.support.leadingWhitespace&&Q.test(i)&&m.insertBefore(b.createTextNode(Q.exec(i)[0]),m.firstChild),i=m.childNodes}}else i=b.createTextNode(i);i.nodeType?g.push(i):g=d.merge(g,i)}if(e)for(h=0;g[h];h++)!f||!d.nodeName(g[h],"script")||g[h].type&&g[h].type.toLowerCase()!=="text/javascript"?(g[h].nodeType===1&&g.splice.apply(g,[h+1,0].concat(d.makeArray(g[h].getElementsByTagName("script")))),e.appendChild(g[h])):f.push(g[h].parentNode?g[h].parentNode.removeChild(g[h]):g[h]);return g},cleanData:function(a){var b,c,e=d.cache,f=d.expando,g=d.event.special,h=d.support.deleteExpando;for(var i=0,j;(j=a[i])!=null;i++){if(j.nodeName&&d.noData[j.nodeName.toLowerCase()])continue;c=j[d.expando];if(c){b=e[c]&&e[c][f];if(b&&b.events){for(var k in b.events)g[k]?d.event.remove(j,k):d.removeEvent(j,k,b.handle);b.handle&&(b.handle.elem=null)}h?delete j[d.expando]:j.removeAttribute&&j.removeAttribute(d.expando),delete e[c]}}}});var bb=/alpha\([^)]*\)/i,bc=/opacity=([^)]*)/,bd=/-([a-z])/ig,be=/([A-Z])/g,bf=/^-?\d+(?:px)?$/i,bg=/^-?\d/,bh={position:"absolute",visibility:"hidden",display:"block"},bi=["Left","Right"],bj=["Top","Bottom"],bk,bl,bm,bn=function(a,b){return b.toUpperCase()};d.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return d.access(this,a,c,!0,function(a,c,e){return e!==b?d.style(a,c,e):d.css(a,c)})},d.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bk(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{zIndex:!0,fontWeight:!0,opacity:!0,zoom:!0,lineHeight:!0},cssProps:{"float":d.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,e,f){if(a&&a.nodeType!==3&&a.nodeType!==8&&a.style){var g,h=d.camelCase(c),i=a.style,j=d.cssHooks[h];c=d.cssProps[h]||h;if(e===b){if(j&&"get"in j&&(g=j.get(a,!1,f))!==b)return g;return i[c]}if(typeof e==="number"&&isNaN(e)||e==null)return;typeof e==="number"&&!d.cssNumber[h]&&(e+="px");if(!j||!("set"in j)||(e=j.set(a,e))!==b)try{i[c]=e}catch(k){}}},css:function(a,c,e){var f,g=d.camelCase(c),h=d.cssHooks[g];c=d.cssProps[g]||g;if(h&&"get"in h&&(f=h.get(a,!0,e))!==b)return f;if(bk)return bk(a,c,g)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]},camelCase:function(a){return a.replace(bd,bn)}}),d.curCSS=d.css,d.each(["height","width"],function(a,b){d.cssHooks[b]={get:function(a,c,e){var f;if(c){a.offsetWidth!==0?f=bo(a,b,e):d.swap(a,bh,function(){f=bo(a,b,e)});if(f<=0){f=bk(a,b,b),f==="0px"&&bm&&(f=bm(a,b,b));if(f!=null)return f===""||f==="auto"?"0px":f}if(f<0||f==null){f=a.style[b];return f===""||f==="auto"?"0px":f}return typeof f==="string"?f:f+"px"}},set:function(a,b){if(!bf.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),d.support.opacity||(d.cssHooks.opacity={get:function(a,b){return bc.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style;c.zoom=1;var e=d.isNaN(b)?"":"alpha(opacity="+b*100+")",f=c.filter||"";c.filter=bb.test(f)?f.replace(bb,e):c.filter+" "+e}}),c.defaultView&&c.defaultView.getComputedStyle&&(bl=function(a,c,e){var f,g,h;e=e.replace(be,"-$1").toLowerCase();if(!(g=a.ownerDocument.defaultView))return b;if(h=g.getComputedStyle(a,null))f=h.getPropertyValue(e),f===""&&!d.contains(a.ownerDocument.documentElement,a)&&(f=d.style(a,e));return f}),c.documentElement.currentStyle&&(bm=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bf.test(d)&&bg.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bk=bl||bm,d.expr&&d.expr.filters&&(d.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!d.support.reliableHiddenOffsets&&(a.style.display||d.css(a,"display"))==="none"},d.expr.filters.visible=function(a){return!d.expr.filters.hidden(a)});var bp=/%20/g,bq=/\[\]$/,br=/\r?\n/g,bs=/#.*$/,bt=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bu=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bv=/(?:^file|^widget|\-extension):$/,bw=/^(?:GET|HEAD)$/,bx=/^\/\//,by=/\?/,bz=/)<[^<]*)*<\/script>/gi,bA=/^(?:select|textarea)/i,bB=/\s+/,bC=/([?&])_=[^&]*/,bD=/(^|\-)([a-z])/g,bE=function(a,b,c){return b+c.toUpperCase()},bF=/^([\w\+\.\-]+:)\/\/([^\/?#:]*)(?::(\d+))?/,bG=d.fn.load,bH={},bI={},bJ,bK;try{bJ=c.location.href}catch(bL){bJ=c.createElement("a"),bJ.href="",bJ=bJ.href}bK=bF.exec(bJ.toLowerCase()),d.fn.extend({load:function(a,c,e){if(typeof a!=="string"&&bG)return bG.apply(this,arguments);if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var g=a.slice(f,a.length);a=a.slice(0,f)}var h="GET";c&&(d.isFunction(c)?(e=c,c=b):typeof c==="object"&&(c=d.param(c,d.ajaxSettings.traditional),h="POST"));var i=this;d.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?d("
").append(c.replace(bz,"")).find(g):c)),e&&i.each(e,[c,b,a])}});return this},serialize:function(){return d.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?d.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bA.test(this.nodeName)||bu.test(this.type))}).map(function(a,b){var c=d(this).val();return c==null?null:d.isArray(c)?d.map(c,function(a,c){return{name:b.name,value:a.replace(br,"\r\n")}}):{name:b.name,value:c.replace(br,"\r\n")}}).get()}}),d.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){d.fn[b]=function(a){return this.bind(b,a)}}),d.each(["get","post"],function(a,c){d[c]=function(a,e,f,g){d.isFunction(e)&&(g=g||f,f=e,e=b);return d.ajax({type:c,url:a,data:e,success:f,dataType:g})}}),d.extend({getScript:function(a,c){return d.get(a,b,c,"script")},getJSON:function(a,b,c){return d.get(a,b,c,"json")},ajaxSetup:function(a,b){b?d.extend(!0,a,d.ajaxSettings,b):(b=a,a=d.extend(!0,d.ajaxSettings,b));for(var c in {context:1,url:1})c in b?a[c]=b[c]:c in d.ajaxSettings&&(a[c]=d.ajaxSettings[c]);return a},ajaxSettings:{url:bJ,isLocal:bv.test(bK[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":d.parseJSON,"text xml":d.parseXML}},ajaxPrefilter:bM(bH),ajaxTransport:bM(bI),ajax:function(a,c){function v(a,c,l,n){if(r!==2){r=2,p&&clearTimeout(p),o=b,m=n||"",u.readyState=a?4:0;var q,t,v,w=l?bP(e,u,l):b,x,y;if(a>=200&&a<300||a===304){if(e.ifModified){if(x=u.getResponseHeader("Last-Modified"))d.lastModified[k]=x;if(y=u.getResponseHeader("Etag"))d.etag[k]=y}if(a===304)c="notmodified",q=!0;else try{t=bQ(e,w),c="success",q=!0}catch(z){c="parsererror",v=z}}else{v=c;if(!c||a)c="error",a<0&&(a=0)}u.status=a,u.statusText=c,q?h.resolveWith(f,[t,c,u]):h.rejectWith(f,[u,c,v]),u.statusCode(j),j=b,s&&g.trigger("ajax"+(q?"Success":"Error"),[u,e,q?t:v]),i.resolveWith(f,[u,c]),s&&(g.trigger("ajaxComplete",[u,e]),--d.active||d.event.trigger("ajaxStop"))}}typeof a==="object"&&(c=a,a=b),c=c||{};var e=d.ajaxSetup({},c),f=e.context||e,g=f!==e&&(f.nodeType||f instanceof d)?d(f):d.event,h=d.Deferred(),i=d._Deferred(),j=e.statusCode||{},k,l={},m,n,o,p,q,r=0,s,t,u={readyState:0,setRequestHeader:function(a,b){r||(l[a.toLowerCase().replace(bD,bE)]=b);return this},getAllResponseHeaders:function(){return r===2?m:null},getResponseHeader:function(a){var c;if(r===2){if(!n){n={};while(c=bt.exec(m))n[c[1].toLowerCase()]=c[2]}c=n[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){r||(e.mimeType=a);return this},abort:function(a){a=a||"abort",o&&o.abort(a),v(0,a);return this}};h.promise(u),u.success=u.done,u.error=u.fail,u.complete=i.done,u.statusCode=function(a){if(a){var b;if(r<2)for(b in a)j[b]=[j[b],a[b]];else b=a[u.status],u.then(b,b)}return this},e.url=((a||e.url)+"").replace(bs,"").replace(bx,bK[1]+"//"),e.dataTypes=d.trim(e.dataType||"*").toLowerCase().split(bB),e.crossDomain||(q=bF.exec(e.url.toLowerCase()),e.crossDomain=q&&(q[1]!=bK[1]||q[2]!=bK[2]||(q[3]||(q[1]==="http:"?80:443))!=(bK[3]||(bK[1]==="http:"?80:443)))),e.data&&e.processData&&typeof e.data!=="string"&&(e.data=d.param(e.data,e.traditional)),bN(bH,e,c,u);if(r===2)return!1;s=e.global,e.type=e.type.toUpperCase(),e.hasContent=!bw.test(e.type),s&&d.active++===0&&d.event.trigger("ajaxStart");if(!e.hasContent){e.data&&(e.url+=(by.test(e.url)?"&":"?")+e.data),k=e.url;if(e.cache===!1){var w=d.now(),x=e.url.replace(bC,"$1_="+w);e.url=x+(x===e.url?(by.test(e.url)?"&":"?")+"_="+w:"")}}if(e.data&&e.hasContent&&e.contentType!==!1||c.contentType)l["Content-Type"]=e.contentType;e.ifModified&&(k=k||e.url,d.lastModified[k]&&(l["If-Modified-Since"]=d.lastModified[k]),d.etag[k]&&(l["If-None-Match"]=d.etag[k])),l.Accept=e.dataTypes[0]&&e.accepts[e.dataTypes[0]]?e.accepts[e.dataTypes[0]]+(e.dataTypes[0]!=="*"?", */*; q=0.01":""):e.accepts["*"];for(t in e.headers)u.setRequestHeader(t,e.headers[t]);if(e.beforeSend&&(e.beforeSend.call(f,u,e)===!1||r===2)){u.abort();return!1}for(t in {success:1,error:1,complete:1})u[t](e[t]);o=bN(bI,e,c,u);if(o){u.readyState=1,s&&g.trigger("ajaxSend",[u,e]),e.async&&e.timeout>0&&(p=setTimeout(function(){u.abort("timeout")},e.timeout));try{r=1,o.send(l,v)}catch(y){status<2?v(-1,y):d.error(y)}}else v(-1,"No Transport");return u},param:function(a,c){var e=[],f=function(a,b){b=d.isFunction(b)?b():b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=d.ajaxSettings.traditional);if(d.isArray(a)||a.jquery&&!d.isPlainObject(a))d.each(a,function(){f(this.name,this.value)});else for(var g in a)bO(g,a[g],c,f);return e.join("&").replace(bp,"+")}}),d.extend({active:0,lastModified:{},etag:{}});var bR=d.now(),bS=/(\=)\?(&|$)|()\?\?()/i;d.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return d.expando+"_"+bR++}}),d.ajaxPrefilter("json jsonp",function(b,c,e){var f=typeof b.data==="string";if(b.dataTypes[0]==="jsonp"||c.jsonpCallback||c.jsonp!=null||b.jsonp!==!1&&(bS.test(b.url)||f&&bS.test(b.data))){var g,h=b.jsonpCallback=d.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2",m=function(){a[h]=i,g&&d.isFunction(i)&&a[h](g[0])};b.jsonp!==!1&&(j=j.replace(bS,l),b.url===j&&(f&&(k=k.replace(bS,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},e.then(m,m),b.converters["script json"]=function(){g||d.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),d.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){d.globalEval(a);return a}}}),d.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),d.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var bT=d.now(),bU,bV;d.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&bX()||bY()}:bX,bV=d.ajaxSettings.xhr(),d.support.ajax=!!bV,d.support.cors=bV&&"withCredentials"in bV,bV=b,d.support.ajax&&d.ajaxTransport(function(a){if(!a.crossDomain||d.support.cors){var c;return{send:function(e,f){var g=a.xhr(),h,i;a.username?g.open(a.type,a.url,a.async,a.username,a.password):g.open(a.type,a.url,a.async);if(a.xhrFields)for(i in a.xhrFields)g[i]=a.xhrFields[i];a.mimeType&&g.overrideMimeType&&g.overrideMimeType(a.mimeType),(!a.crossDomain||a.hasContent)&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(i in e)g.setRequestHeader(i,e[i])}catch(j){}g.send(a.hasContent&&a.data||null),c=function(e,i){var j,k,l,m,n;try{if(c&&(i||g.readyState===4)){c=b,h&&(g.onreadystatechange=d.noop,delete bU[h]);if(i)g.readyState!==4&&g.abort();else{j=g.status,l=g.getAllResponseHeaders(),m={},n=g.responseXML,n&&n.documentElement&&(m.xml=n),m.text=g.responseText;try{k=g.statusText}catch(o){k=""}j||!a.isLocal||a.crossDomain?j===1223&&(j=204):j=m.text?200:404}}}catch(p){i||f(-1,p)}m&&f(j,k,m,l)},a.async&&g.readyState!==4?(bU||(bU={},bW()),h=bT++,g.onreadystatechange=bU[h]=c):c()},abort:function(){c&&c(0,1)}}}});var bZ={},b$=/^(?:toggle|show|hide)$/,b_=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,ca,cb=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];d.fn.extend({show:function(a,b,c){var e,f;if(a||a===0)return this.animate(cc("show",3),a,b,c);for(var g=0,h=this.length;g=0;a--)c[a].elem===this&&(b&&c[a](!0),c.splice(a,1))}),b||this.dequeue();return this}}),d.each({slideDown:cc("show",1),slideUp:cc("hide",1),slideToggle:cc("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){d.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),d.extend({speed:function(a,b,c){var e=a&&typeof a==="object"?d.extend({},a):{complete:c||!c&&b||d.isFunction(a)&&a,duration:a,easing:c&&b||b&&!d.isFunction(b)&&b};e.duration=d.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in d.fx.speeds?d.fx.speeds[e.duration]:d.fx.speeds._default,e.old=e.complete,e.complete=function(){e.queue!==!1&&d(this).dequeue(),d.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig||(b.orig={})}}),d.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(d.fx.step[this.prop]||d.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=d.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,b,c){function g(a){return e.step(a)}var e=this,f=d.fx;this.startTime=d.now(),this.start=a,this.end=b,this.unit=c||this.unit||(d.cssNumber[this.prop]?"":"px"),this.now=this.start,this.pos=this.state=0,g.elem=this.elem,g()&&d.timers.push(g)&&!ca&&(ca=setInterval(f.tick,f.interval))},show:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.show=!0,this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),d(this.elem).show()},hide:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b=d.now(),c=!0;if(a||b>=this.options.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),this.options.curAnim[this.prop]=!0;for(var e in this.options.curAnim)this.options.curAnim[e]!==!0&&(c=!1);if(c){if(this.options.overflow!=null&&!d.support.shrinkWrapBlocks){var f=this.elem,g=this.options;d.each(["","X","Y"],function(a,b){f.style["overflow"+b]=g.overflow[a]})}this.options.hide&&d(this.elem).hide();if(this.options.hide||this.options.show)for(var h in this.options.curAnim)d.style(this.elem,h,this.options.orig[h]);this.options.complete.call(this.elem)}return!1}var i=b-this.startTime;this.state=i/this.options.duration;var j=this.options.specialEasing&&this.options.specialEasing[this.prop],k=this.options.easing||(d.easing.swing?"swing":"linear");this.pos=d.easing[j||k](this.state,i,0,1,this.options.duration),this.now=this.start+(this.end-this.start)*this.pos,this.update();return!0}},d.extend(d.fx,{tick:function(){var a=d.timers;for(var b=0;b
";d.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),e=b.firstChild,f=e.firstChild,h=e.nextSibling.firstChild.firstChild,this.doesNotAddBorder=f.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,f.style.position="fixed",f.style.top="20px",this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15,f.style.position=f.style.top="",e.style.overflow="hidden",e.style.position="relative",this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),a=b=e=f=g=h=null,d.offset.initialize=d.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;d.offset.initialize(),d.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(d.css(a,"marginTop"))||0,c+=parseFloat(d.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var e=d.css(a,"position");e==="static"&&(a.style.position="relative");var f=d(a),g=f.offset(),h=d.css(a,"top"),i=d.css(a,"left"),j=e==="absolute"&&d.inArray("auto",[h,i])>-1,k={},l={},m,n;j&&(l=f.position()),m=j?l.top:parseInt(h,10)||0,n=j?l.left:parseInt(i,10)||0,d.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):f.css(k)}},d.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),e=cf.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(d.css(a,"marginTop"))||0,c.left-=parseFloat(d.css(a,"marginLeft"))||0,e.top+=parseFloat(d.css(b[0],"borderTopWidth"))||0,e.left+=parseFloat(d.css(b[0],"borderLeftWidth"))||0;return{top:c.top-e.top,left:c.left-e.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&(!cf.test(a.nodeName)&&d.css(a,"position")==="static"))a=a.offsetParent;return a})}}),d.each(["Left","Top"],function(a,c){var e="scroll"+c;d.fn[e]=function(c){var f=this[0],g;if(!f)return null;if(c!==b)return this.each(function(){g=cg(this),g?g.scrollTo(a?d(g).scrollLeft():c,a?c:d(g).scrollTop()):this[e]=c});g=cg(f);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:d.support.boxModel&&g.document.documentElement[e]||g.document.body[e]:f[e]}}),d.each(["Height","Width"],function(a,c){var e=c.toLowerCase();d.fn["inner"+c]=function(){return this[0]?parseFloat(d.css(this[0],e,"padding")):null},d.fn["outer"+c]=function(a){return this[0]?parseFloat(d.css(this[0],e,a?"margin":"border")):null},d.fn[e]=function(a){var f=this[0];if(!f)return a==null?null:this;if(d.isFunction(a))return this.each(function(b){var c=d(this);c[e](a.call(this,b,c[e]()))});if(d.isWindow(f)){var g=f.document.documentElement["client"+c];return f.document.compatMode==="CSS1Compat"&&g||f.document.body["client"+c]||g}if(f.nodeType===9)return Math.max(f.documentElement["client"+c],f.body["scroll"+c],f.documentElement["scroll"+c],f.body["offset"+c],f.documentElement["offset"+c]);if(a===b){var h=d.css(f,e),i=parseFloat(h);return d.isNaN(i)?h:i}return this.css(e,typeof a==="string"?a:a+"px")}}),a.jQuery=a.$=d})(window); \ No newline at end of file diff --git a/content/media/js/libs/meta.yaml b/content/media/js/libs/meta.yaml new file mode 100644 index 0000000..2a0d491 --- /dev/null +++ b/content/media/js/libs/meta.yaml @@ -0,0 +1 @@ +uses_template: false \ No newline at end of file diff --git a/content/media/js/libs/modernizr-1.7.min.js b/content/media/js/libs/modernizr-1.7.min.js new file mode 100644 index 0000000..6f54850 --- /dev/null +++ b/content/media/js/libs/modernizr-1.7.min.js @@ -0,0 +1,2 @@ +// Modernizr v1.7 www.modernizr.com +window.Modernizr=function(a,b,c){function G(){e.input=function(a){for(var b=0,c=a.length;b7)},r.history=function(){return !!(a.history&&history.pushState)},r.draganddrop=function(){return x("dragstart")&&x("drop")},r.websockets=function(){return"WebSocket"in a},r.rgba=function(){A("background-color:rgba(150,255,150,.5)");return D(k.backgroundColor,"rgba")},r.hsla=function(){A("background-color:hsla(120,40%,100%,.5)");return D(k.backgroundColor,"rgba")||D(k.backgroundColor,"hsla")},r.multiplebgs=function(){A("background:url(//:),url(//:),red url(//:)");return(new RegExp("(url\\s*\\(.*?){3}")).test(k.background)},r.backgroundsize=function(){return F("backgroundSize")},r.borderimage=function(){return F("borderImage")},r.borderradius=function(){return F("borderRadius","",function(a){return D(a,"orderRadius")})},r.boxshadow=function(){return F("boxShadow")},r.textshadow=function(){return b.createElement("div").style.textShadow===""},r.opacity=function(){B("opacity:.55");return/^0.55$/.test(k.opacity)},r.cssanimations=function(){return F("animationName")},r.csscolumns=function(){return F("columnCount")},r.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";A((a+o.join(b+a)+o.join(c+a)).slice(0,-a.length));return D(k.backgroundImage,"gradient")},r.cssreflections=function(){return F("boxReflect")},r.csstransforms=function(){return!!E(["transformProperty","WebkitTransform","MozTransform","OTransform","msTransform"])},r.csstransforms3d=function(){var a=!!E(["perspectiveProperty","WebkitPerspective","MozPerspective","OPerspective","msPerspective"]);a&&"webkitPerspective"in g.style&&(a=w("@media ("+o.join("transform-3d),(")+"modernizr)"));return a},r.csstransitions=function(){return F("transitionProperty")},r.fontface=function(){var a,c,d=h||g,e=b.createElement("style"),f=b.implementation||{hasFeature:function(){return!1}};e.type="text/css",d.insertBefore(e,d.firstChild),a=e.sheet||e.styleSheet;var i=f.hasFeature("CSS2","")?function(b){if(!a||!b)return!1;var c=!1;try{a.insertRule(b,0),c=/src/i.test(a.cssRules[0].cssText),a.deleteRule(a.cssRules.length-1)}catch(d){}return c}:function(b){if(!a||!b)return!1;a.cssText=b;return a.cssText.length!==0&&/src/i.test(a.cssText)&&a.cssText.replace(/\r+|\n+/g,"").indexOf(b.split(" ")[0])===0};c=i('@font-face { font-family: "font"; src: url(data:,); }'),d.removeChild(e);return c},r.video=function(){var a=b.createElement("video"),c=!!a.canPlayType;if(c){c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"');var d='video/mp4; codecs="avc1.42E01E';c.h264=a.canPlayType(d+'"')||a.canPlayType(d+', mp4a.40.2"'),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"')}return c},r.audio=function(){var a=b.createElement("audio"),c=!!a.canPlayType;c&&(c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"'),c.mp3=a.canPlayType("audio/mpeg;"),c.wav=a.canPlayType('audio/wav; codecs="1"'),c.m4a=a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;"));return c},r.localstorage=function(){try{return!!localStorage.getItem}catch(a){return!1}},r.sessionstorage=function(){try{return!!sessionStorage.getItem}catch(a){return!1}},r.webWorkers=function(){return!!a.Worker},r.applicationcache=function(){return!!a.applicationCache},r.svg=function(){return!!b.createElementNS&&!!b.createElementNS(q.svg,"svg").createSVGRect},r.inlinesvg=function(){var a=b.createElement("div");a.innerHTML="";return(a.firstChild&&a.firstChild.namespaceURI)==q.svg},r.smil=function(){return!!b.createElementNS&&/SVG/.test(n.call(b.createElementNS(q.svg,"animate")))},r.svgclippaths=function(){return!!b.createElementNS&&/SVG/.test(n.call(b.createElementNS(q.svg,"clipPath")))};for(var H in r)z(r,H)&&(v=H.toLowerCase(),e[v]=r[H](),u.push((e[v]?"":"no-")+v));e.input||G(),e.crosswindowmessaging=e.postmessage,e.historymanagement=e.history,e.addTest=function(a,b){a=a.toLowerCase();if(!e[a]){b=!!b(),g.className+=" "+(b?"":"no-")+a,e[a]=b;return e}},A(""),j=l=null,f&&a.attachEvent&&function(){var a=b.createElement("div");a.innerHTML="";return a.childNodes.length!==1}()&&function(a,b){function p(a,b){var c=-1,d=a.length,e,f=[];while(++c