关于如何做好一个文件上传——fileUpload
目录
DOM-FileUpload 对象
在网页上传文件,最核心元素就是这个HTML DOM的FileUpload对象——input[type="file"]。
<form id="uploadForm" method="POST" action="/ajax/upload_file" enctype="multipart/form-data" multiple accept>
<input type="file" id="inputFile" name="file"></input>
<input type="submit" value="提交"></input>
</form>
在 HTML 文档中该标签每出现一次,一个 FileUpload 对象就会被创建。
- 该标签包含一个按钮,用来打开文件选择对话框
- 一段文字显示选中的文件名或提示没有文件被选中。
把这个标签放在<form>标签内,设置form的action为服务器目标上传地址,并点击submit按钮或通过JS调用form的submit()方法就可以实现最简单的文件上传。
这样就完成功能吗?没错。但是你要是敢提交这样的代码,估计脸要被打肿。这个面临N多问题:
- 作为一个爱美和创造美好界面的前端,怎么能忍受如此朴素的造型的上传组件:
- 这样上传完是会刷新页面的,思考下为什么?
- 别人"酷炫吊炸天"拖拽上传、图片预览、图片截取、保存本地都是怎么完成的?
- 这么大众化的常用功能,有哪些API,怎么造个轮子造福后人,贡献开源...
input-file 换造型
input-file按钮文字及UI定制化比较蛋疼,这是浏览器内置的文字,可以思考下怎么hack
<form action="/ajax/upload_file" method="post" enctype="multipart/form-data">
<span>选择文件</span>
<input type="file" name="file">
</form>
form {
display: inline-block;
position: relative;
overflow: hidden;
}
input[type="file"] {
position: absolute;
top: 0;
right: 0;
_zoom:30;
margin: 0;
padding: 0;
height: 100%;
_height:auto;
font-size: 3000px \9;
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0);
opacity: 0;
cursor: pointer;
}
虽然说是「隐藏」,但只是让原生上传控件「不可见」而已,它还是妥妥地在表单中占据着空间位置。当点击所看到的「按钮」时,实际点击的是原生上传控件,这样一来就触发了浏览器默认行为,即打开选择文件对话框。
多文件支持
一个一个添加文件太麻烦?别急,打开一个开关就好了————multiple属性。只要这样
<input id="myFile" type="file" multiple>
我们就能在打开的文件选择对话框中选中多个文件了。然后你在代码里拿到的FileUpload对象的files属性就是一个选中的多文件的数组, 这个数组和arguments、nodelist等类数组不同。
var fileInput = document.getElementById("myFile");
var files = fileInput.files;
var formData = new FormData();
for(var i = 0; i < files.length; i++) {
var file = files[i]; // 此为blob格式
formData.append('files[]', file, file.name);
}
FormData的append方法提供第三个可选参数用于指定文件名,这样就可以使用同一个表单项名,然后用文件名区分上传的多个文件。这样也方便前后台的循环操作。
file相关元素API
<form id="uploadForm" method="POST" action="/ajax/upload_file" enctype="multipart/form-data" multiple accept>
<input type="file" id="inputFile" name="file"></input>
<input type="submit" value="提交"></input>
</form>
// var inputFile = document.createElement('input');
// inputFile.type = 'file';
var $ = document.querySelector
form = $('#uploadForm')
inputFile = $('#inputFile');
file = inputFile.files[0];
console.log('form === > ', form);
console.log('inputFile === > ', inputFile);
console.log('file === > ', file);
-
input[type="file"]标签:- multiple属性: 允许用户选择多个文件;
- accept属性 : 支持上传的格式;
-
<form></form>标签:- action属性 : 提交目标地址
- enctype属性: 提交编码,上传"multipart/form-data"
- method属性 : 提交方法,上传一般"post"
- target属性 : 提交完定位的页面(一般对应iframe id), 做无刷新
-
file对象的属性:- name : 文件名,不包含路径。
- type : 控制上传文件MIME(Multipurpose Internet Mail Extensions)类型。
- size : 控制文件大小。可以根据文件大小来进行其他操作。
- lastModified: 文件最后修改的时间, 时间戳一般和name配合。
[发散一下]: MIME type
text/plain text/html text/css text/javascript
image/jpeg image/png image/gif image/bmp image/x-icon image/svg+xml image/webp
audio/mpeg audio/ogg audio/*
video/mp4
application/* application/json application/javascript application/ecmascript application/octet-stream application/xml application/pdf
multipart/form-data multipart/byteranges
image/png || gif || jepg || svg+xml
Multipart =>>>multipart/form-data multipart/byteranges 类型表示细分领域的文件类型的种类,经常对应不同的 MIME 类型。这是复合文件的一种表现方式
很多web服务器使用默认的 application/octet-stream 来发送未知类型。出于一些安全原因,对于这些资源浏览器不允许设置一些自定义默认操作
更优雅HTML5上传
现代HTML5网页通过什么来实现用户与服务器的无刷新交互?
XMLHttpRequestFormDataFileReaderBlobdragjsonp
XMLHttpRequest
这个你很熟悉的家伙但又感觉很陌生。如果你开发的产品支持的浏览器是现代浏览器,那么恭喜你,文件上传就是这么easy!特别强调强调现代浏览器是因为我们接下来讨论的XMLHttpRequest指的是XMLHttpRequest Level 2。
那什么是Level 1?为什么不行?因为它有如下限制:
-
仅支持文本数据传输, 无法传输二进制数据.
-
传输数据时, 没有进度信息提示, 只能提示是否完成.
-
受浏览器 同源策略 限制, 只能请求同域资源.
-
没有超时机制, 不方便掌控ajax请求节奏.
而XMLHttpRequest Level 2针对这些缺陷做出了改进:
-
支持二进制数据, 可以上传文件, 可以使用FormData对象管理表单.
-
提供进度提示, 可通过 xhr.upload.onprogress 事件回调方法获取传输进度.
-
依然受 同源策略 限制, 这个安全机制不会变. XHR2新提供 Access-Control-Allow-Origin 等headers, 设置为 * 时表示允许任何域名请求, 从而实现跨域CORS访问(有关CORS详细介绍请耐心往下读).
-
可以设置timeout 及 ontimeout, 方便设置超时时长和超时后续处理.
关于XMLHttpRequest的细节就不在这里赘述了。目前, 主流浏览器基本上都支持XHR2, 除了IE系列需要IE10及更高版本. 因此IE10以下是不支持XHR2的.
上面提到的FormData就是我们最常用的一种方式。通过在脚本里新建FormData对象,把File对象设置到表单项中,然后利用XMLHttpRequest异步上传到服务器:
var xhr = new XMLHttpRequest();
var formData = new FormData();
var fileInput = document.getElementById("myFile");
var file = fileInput.files[0];
formdata.append('myFile', file);
xhr.open("POST", "/upload.php");
xhr.onload = function(){
if(this.status === 200){
//对请求成功的处理
}
}
xhr.send(formData);
xhr = null;
完成最基本的需求无法满足我们对用户体验的追求,所以我们还想要支持上传进度显示和上传图片预览。
上传进度-progress
因为是XMLHttpRequest Level 2, 所以很容易就可以支持对上传进度的监听。细心地小伙伴会发现在chrome的developer tools的console里new一个XMLHttpRequest对象,就会发现实例xhr下挂载有onprogress事件,那是不是我们只要绑定XHR对象的progress事件就可以了呢?
很接近了,但是XHR对象的直属progress事件并不是用来监听上传资源(其实是下载)的进度的。XHR对象还有一个属性upload, 它返回一个XMLHttpRequestUpload 对象,xhr.upload 对象拥有下列方法:
onloadstart
onprogress
onabort
onerror
onload
onloadend
ontimeout
XMLHttpRequestUpload挂载在XMLHttpRequest,两个下面都存在同名方法,区别是后者是用于加载资源时,而前者用于资源上传时。 其中onprogress 事件回调方法可用于跟踪资源上传的进度,它的event参数对象包含两个重要的属性loaded和total。分别代表当前已上传的字节数(number of bytes)和文件的总字节数。比如我们可以这样计算进度百分比:
xhr.upload.onprogress = function(event) {
if (event.lengthComputable) {
var percentComplete = (event.loaded / event.total) * 100;
// 对进度进行处理
}
}
其中事件的lengthComputable属性代表文件总大小是否可知。如果 lengthComputable 属性的值是 false,那么意味着总字节数是未知并且 total 的值为零。
如果是现代HTML5浏览器,可以直接配合HTML5提供的<progress>
<progress id="myProgress" value="50" max="100">
</progress>
其value属性绑定上面代码中的percentComplete的值即可。再进一步我们还可以对<progress>的样式统一调整,实现优雅降级方案。
测试progress事件时可能遇到一个问题。一开始我设在onprogress事件回调里的断点总是只能走一次,并且loaded值始终等于total。觉得有点诡异,改用console.log打印loaded值不见效,当直接加大上传文件的大小到50MB,终于看到了5个不同的百分比值。
因为xhr.upload.onprogress在上传阶段(即xhr.send()之后,xhr.readystate=2之前)触发,每50ms触发一次。所以文件太小网络环境好的时候是直接到100%的。
[补充一下] xhr.readystate主要有四个状态(这个是挂载在XMLHttpRequest对象上的静态属性):
UNSENT : 0,
OPENED : 1,
HEADERS_RECEIVED : 2,
LOADING : 3,
DONE : 4
预览(主要针对图片预览)
普通青年的图片预览方式是待文件上传成功后,后台返回上传文件的url,然后把预览图片的img元素的src指向该url。这其实达不到预览的效果和目的。
属于文艺青年的现代浏览器又登场了:“使用HTML5的FileReader API吧!” 让我们直接上代码,直奔主题:
方法1: reader.onload回调的result指向image的src
function handleImageFile(file) {
var previewArea = document.getElementById('previewArea');
var img = document.createElement('img');
var fileInput = document.getElementById("myFile");
var file = fileInput.files[0];
// img.file = file;
previewArea.appendChild(img);
var reader = new FileReader();
// 下面的闭包比较难理解
reader.onload = (function(aImg) {
return function(e) {
// 此处的e是reader, 也可以this, 将result返回给src
aImg.src = e.target.result;
}
})(img);
reader.onprogress = function(e) {
// e.loaded/e.total
}
reader.readAsDataURL(file);
}
FileReader实例有以下方法:
- abort : 中断读取操作;
- readAsArrayBuffer : 读取文件内容到ArrayBuffer对象中;
- readAsBinaryString : 将文件读取为二进制数据;
- readAsDataURL : 将文件读取为data : URL格式的字符串;
- readAsText : 将文件读取为文本;
- onprogress : 文件读取进度;
- onload : 文件读取加载;
使用FileReader来处理图片的异步加载,在创建新的FileReader对象之后,我们建立了onload函数,然后调用readAsDataURL()开始在后台进行读取操作。当图像文件加载后,转换成一个 data: URL 保存在result属性上,并传递到onload回调函数中设置给img的src。
方法2: 无需FileReader, 直接将file转换URL
file本来就是就继承自Blob对象,可以URL.createObjectURL()函数创建URl
var img = document.createElement("img");
// 全局函数URL生成一个网络地址————createObjectURL, revokeObjectURL
img.src = window.URL.createObjectURL(file);
img.onload = function() {
// 明确地通过调用释放
window.URL.revokeObjectURL(this.src);
}
previewArea.appendChild(img);
二进制上传
有了FileReader,其实我们还有一种上传的途径,读取文件内容后直接以二进制格式上传。
var reader = new FileReader();
reader.onload = function(){
xhr.sendAsBinary(this.result);
}
// 把从input里读取的文件内容,放到fileReader的result字段里
reader.readAsBinaryString(file);
不过chrome已经把XMLHttpRequest的sendAsBinary方法移除了【已证实】。 所以得自行实现一个pollify。
XMLHttpRequest.prototype.sendAsBinary = function(text){
var data = new ArrayBuffer(text.length);
var ui8a = new Uint8Array(data, 0);
for (var i = 0; i < text.length; i++){
ui8a[i] = (text.charCodeAt(i) & 0xff);
}
this.send(ui8a);
}
这段代码将字符串转成8位无符号整型,然后存放到一个8位无符号整型数组里面,再把整个数组发送出去。
blob格式上传
Blob 对象相当于一个容器,可以用于存放二进制数据。它有两个属性,size 属性表示字节长度,type 属性表示 MIME 类型。 file 对象是特殊类型的 Blob,且可以用在任意的 Blob 类型的上下文中。比如说, FileReader, URL.createObjectURL(), createImageBitmap(), 及 XMLHttpRequest.send() 都能处理 Blob 和 File。
// 第一个参数是一个数组,可以存放 ArrayBuffer对象、ArrayBufferView 对象、Blob对象和字符串
// 第二个参数是 Blob 对象的 MIME 类型。
var blob = new Blob(['hello'], {type:"text/plain"});
// Blob 对象可以通过 slice() 方法来返回一个新的 Blob 对象。
var newblob = blob.slice(0,5, {type:"text/plain"});
// canvas.toBlob() 也可以创建 Blob 对象
// toBlob() 使用三个参数,第一个为回调函数,第二个为图片类型,默认为 image/png,第三个为图片质量,值在0到1之间。
var canvas = document.getElementById('canvas');
canvas.toBlob(
function(blob){
console.log(blob);
},
"image/jpeg",
0.5 // 图片质量
);
可以利用blob进行下载、备份操作 比如:将canvas下载为一个图片文件【前端下载】
var canvas = document.getElementById('canvas');
canvas.toBlob((blob) => {
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.download = 'canvas';
a.href = url;
a.click();
URL.revokeObjectURL(url); //下载完后告诉浏览器不需要保持这个文件的引用
})
将字符串保存一个文件
var blob = new Blob(['hello world,'])
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.download = 'canvas';
a.href = url;
a.click();
URL.revokeObjectURL(url); //下载完后告诉浏览器不需要保持这个文件的引用
FileReader 对象的 readAsText() 可以读取文件的文本,结合 Blob 对象下载文件的功能,那就可以实现将数据导出文件备份到本地,当数据要恢复时,通过 input 把备份文件上传,使用 readAsText() 读取文本,恢复数据。
base64上传类似
在 HTML5 中新增了 atob 和 btoa 方法来支持 Base64 编码。它们的命名也很简单,b to a 和 a to b,即代表着编码和解码。
var a = "https://hibop.github.io";
var b = btoa(a);
var c = atob(b);
console.log(a); // https://lin-xin.github.io
console.log(b); // aHR0cHM6Ly9saW4teGluLmdpdGh1Yi5pbw==
console.log(c); // https://lin-xin.github.io
btoa 方法对字符串 a 进行编码,不会改变 a 的值,返回一个编码后的值。 atob 方法对编码后的字符串进行解码。
但是参数中带中文,已经超出了8位ASCII编码的字符范围,浏览器就会报错。所以需要先对中文进行 encodeURIComponent 编码处理。
var a = "哈喽 世界";
var b = btoa(encodeURIComponent(a));
var c = decodeURIComponent(atob(b));
console.log(b); // JUU1JTkzJTg4JUU1JTk2JUJEJTIwJUU0JUI4JTk2JUU3JTk1JThD
console.log(c); // 哈喽 世界
拖拽和裁剪的支持
拖拽上传和图片裁剪处理功能,这是高科技功能,可以帮你上传组件增加不少亮点; 其实主要是利用HTML5的drag & drop事件,我们可以很快实现对拖拽的支持。首先我们可能需要确定一个允许拖拽的区域,然后绑定相应的事件进行处理。
看代码
var dropArea;
dropArea = document.getElementById("dropArea");
dropArea.addEventListener("dragenter", handleDragenter, false);
dropArea.addEventListener("dragover", handleDragover, false);
dropArea.addEventListener("drop", handleDrop, false);
// 阻止dragenter和dragover的默认行为,这样才能使drop事件被触发
function handleDragenter(e) {
e.stopPropagation();
e.preventDefault();
}
function handleDragover(e) {
e.stopPropagation();
e.preventDefault();
}
function handleDrop(e) {
e.stopPropagation();
e.preventDefault();
var dt = e.dataTransfer;
var files = dt.files;
// handle files ...
}
这里可以把通过事件对象的dataTransfer拿到的files数组和之前相同处理,以实现预览上传等功能。有了这些事件回调,我们也可以在不同的事件给我们UI元素添加不同的class来实现更好交互效果。
裁剪
mousedown
mouseup
mousemove
canvas
借用iframe 做无刷新兼容
一个比较优雅的上传组件可以进入生产模式了。 但是这些高科技Api在IE9面前都是都是渣渣了。 什么?还要支持IE9?好吧,让我们来看看IE10以下的浏览器如何实现无刷新上传。
之前说了要实现文件上传使用FileUpload对象即可。这在低版本的IE里也是适用的。那我们为什么还要用iframe呢?
因为在现代浏览器中我们可以用XMLHttpRequest Level 2来支持二进制数据,异步文件上传,并且动态创建FormData。而低版本的IE里的XMLHttpRequest是Level 1。所以我们通过XHR异步向服务器发上传请求的路走不通了。只能老老实实的用form的submit。
而form的submit会导致页面的刷新。原因分析好了,那么答案就近在咫尺了。我们能不能让form的submit不刷新整个页面呢?答案就是利用iframe。把form的target指定到一个看不见的iframe,那么返回的数据就会被这个iframe接受,于是乎就只有这个iframe会刷新。而它又是看不见的,用户自然就感知不到了。
window.__iframeCount = 0;
var hiddenframe = document.createElement("iframe");
var frameName = "upload-iframe" + ++window.__iframeCount;
hiddenframe.name = frameName;
hiddenframe.id = frameName;
hiddenframe.setAttribute("style", "width:0;height:0;display:none");
document.body.appendChild(hiddenframe);
var form = document.getElementById("myForm");
// 将form 的target指向iframe
form.target = frameName;
// 然后响应iframe的onload事件,获取response
hiddenframe.onload = function(){
// 获取iframe的内容,即服务返回的数据
var resData = this.contentDocument.body.textContent || this.contentWindow.document.body.textContent;
// 处理数据 。。。
//删除iframe
setTimeout(function(){
var _frame = document.getElementById(frameName);
_frame.parentNode.removeChild(_frame);
}, 100);
}
iframe的实现大致如此,但是如果文件上传的地址与当前页面不在同一个域下就会出现跨域问题。导致iframe的onload回调里的访问服务返回的数据失败。
这时我们再祭出JSONP这把'大宝剑',来解决跨域问题。首先在上传之前注册一个全局的函数,把函数名发给服务器。服务器需要配合在response里让浏览器直接调用这个函数。
// 生成全局函数名,避免冲突
var CALLBACK_NAME = 'CALLBACK_NAME';
var genCallbackName = (function () {
var i = 0;
return function () {
return CALLBACK_NAME + ++i;
};
})();
var curCallbackName = genCallbackName();
window[curCallbackName] = function(res) {
// 处理response 。。。
// 删除iframe
var _frame = document.getElementById(frameName);
_frame.parentNode.removeChild(_frame);
// 删除全局函数本身
window[curCallbackName] = undefined;
}
// 如果已有其他参数,这里需要判断一下,改为拼接 &callback= form.action = form.action + '?callback=' + curCallbackName; 好了,实现一个文件上传组件的基本知识点大致总结了一下。
总结一波
文件上传其实涉及到的知识相当的多, 如果放在考试中可以是个答题或者压轴题, 我们在实际开发一般是使用别人做好的"轮子", 但是其中细节应该好好理解便于我们高效开发,并知其所以然;
整理下相关技术以及API:
<form>``<input type="file">标签使用, css定制化原生表单;file对象XMLHttpRequest和XMLHttpRequestUploadFormDataFileReaderBlob/ArrayBuffer...drag/mousemovejsonp
一个fileUpload插件封装
function fileUpload(options) {
var opts = options || {};
var func = function() {};
var hofn = function(f) {return f;}; // 高阶函数
this.fileInput = opts.fileInput || null;
this.url = opts.url || '';
this.fileList = [];
this.onFilter = opts.onFilter || hofn; // 选择文件组的过滤方法
this.onSelect = opts.onSelect || func; // 文件选择后回调
this.onProgress = opts.onProgress || func; // 文件上传进度回调
this.onSuccess = opts.onSuccess || func; // 文件上传成功时回调
this.onFailure = opts.onFailure || func; // 文件上传失败时回调;
this.onComplete = opts.onComplete || func; // 文件全部上传完毕时回调
this.init();
}
fileUpload.prototype = {
constructor: fileUpload,
dealFiles: function(e) { //获取要上传的文件数组(用户选择文件后执行)
var files = e.target.files || e.dataTransfer.files;
this.fileList = this.onFilter(files);
for(var i = 0, file; file = this.fileList[i]; i++){ //增加唯一索引值
file.index = i;
}
this.onSelect(this.fileList);
return this;
},
removeFile: function(fileDelete) { //删除某一个文件
var arrFile = [];
for(var i = 0, file; file = this.fileList[i]; i++){
if (file != fileDelete) {
arrFile.push(file);
}
}
this.fileList = arrFile;
return this;
},
removeAll: function() { //清空文件队列
this.fileList = [];
return this;
},
uploadFile: function() { //上传文件
var me = this;
for(var i = 0, file; file = this.fileList[i]; i++){
(function(file) {
var formData = new FormData();
var xhr = new XMLHttpRequest();
if (xhr.upload) {
xhr.upload.addEventListener("progress", function(e) { // 上传中
me.onProgress(file, e.loaded, e.total);
}, false);
xhr.onreadystatechange = function(e) { // 文件上传成功或是失败
if (xhr.readyState == 4) {
if (xhr.status == 200) {
me.onSuccess(file, xhr.responseText);
me.removeFile(file);
if (!me.fileList.length) {
me.onComplete(); //上传全部完毕。执行回调
}
} else {
me.onFailure(file, xhr.responseText);
}
}
};
// 开始上传
formData.append('file', file);
xhr.open("POST", me.url, true);
xhr.send(formData);
}
})(file);
}
},
init: function() {
var me = this;
//文件选择控件选择
if (me.fileInput) {
me.fileInput.addEventListener("change", function(e) { me.dealFiles(e); }, false);
}
}
};
FRONT VIEW:
d^b _,,ddP"""Ybb,,_ d^b
d ,dP"' `"Yb, b
b,d" "b,d
d" ,d""YgP""b, "b
d' 8 o g o 8 `b
8 d,gPPPPRg,b 8
8 dP' 'Yb 8
8 8) 8 8 (8 8
Y, Yb dP ,P
Ya "8ggggg8" aP
"Ya b,,,d aP"
8"Yb,_ _,dP"8
8 8YbbgggddP8 8
d b d b
"""""" """"""
SIDE VIEW:
,
,db,_,,ddP"""Ybb,,_
d ,dP"' `"Yb,
bd" "b,
d"b "b
d'd b `b
,d88888, ,' 8
d 8 " 8 ,b,
d 8 8b b b
d Y, ,P b b b
"d88888Ya aP "bbb
d"Ya aP" 'cc,
8"Yb,_ _,dP"8
8 8YbbgggddP8 8
d b d b
"""""" """"""
_
,.-" "-.,
/ === \
/ ======= \
__| (o) (0) |__
/ _| .---. |_ \
| /.----/ O O \----.\ |
\/ | | \/
| |
| |
| |
_\ -.,_____,.- /_
,.-" "-.,_________,.-" "-.,
/ | | \
| l. .l |
| | | |
l. | | .l
| l. .l | \,
l. | | .l \,
| | | | \,
l. | | .l |
| | | | |
| |---| | |
| | | | |
/"-.,__,.-"\ /"-.,__,.-"\"-.,_,.-"\
| \ / | |
| | | |
\__|__|__|__/ \__|__|__|__/ \_|__|__/
! !
! ! ! !
! . ! ! . !
^^^^^^^^^ ^
^ ^
^ (0) (0) ^
^ "" ^
^ *************** ^
^ * * ^
^ * /\ /\ /\ * ^
^ * * ^
^ * /\ /\ /\ /\ * ^
^ * * ^
^ * * ^
^ * * ^
^ * * ^
^* * ^
^ * * ^
^ * * ^
^ * ) ( * ^
^^^^^^^^ ^^^^^^^^^
.
1
1
1
M
M
M
M
\M/
. ' M ` .
\##-#####-##/
\# ##### #/
###############
###############
\ ! ! ! ! ! /
)! ! ! ! !(
+---------+
+! ! ! ! !+
+----*----+
+`. .':`. .'+
+ .^. : .^. +
+:...:*:...:+
+`. .':`. .'+
+ .^. : .^. +
+:...:*:...:+
+`. .':`. .'+
+. ^. : .^ .+
+:....:*:....:+
+` . ':` . '+
+ .^. : .^. +
+:....:*:....:+
+` .. ':` .. '+
+. '` .:. '` .+
+:....:*:....:+
+ `. .':`. .' +
+ X : X +
+.' `.:.' `.+
+:......*......:+
+`. .':`. .'+
+ X : X +
+ .' `. : .' `. +
+.......*.......+
+` . . ':` . . '+
+ X : X +
+ ' ` : ' ` +
+../########....+
+`/#########\ .'+
+ ############ +
+ '############` +
+:.......*.......:+
+ ` . ' : ` . ' +
+ X : X +
+ .' `.:.' `. +
+:.......*.......:+
+` ':` '+
+ ` ' : ` ' +
+ X : : X +
+ ' ` : : ' ` +
+:.......*.*.......:+
+` ': :` '+
+ ` ' : : ` ' +
+ X : X : X +
+ ' ` :' `: ' ` +
+:.......*...*.......:+
+` ':` ':` '+
+ ` ' : X : ` ' +
+ X : : X +
+ ' ` :/ \: ' ` +
+:.......*.....*.......:+
+` ':` ':` '+
+ ` ' : `.' : ` ' +
+ X : ' ` : X +
+ ' ` :' `: ' ` +
+:.......*.......*.......:+
+ ` ':` ':` ' +
+ ` . ' : `.' : ` . ' +
+ ' ` : ' ` : ' ` +
+. ' ` : ' ` : ' ` .+
+..........*.........*..........+
+ ########################### +
+ ########################### +
+ ########################### +
#########################################
###########################################
\ 1 1 1 1 1 1 1 1 1 /
) 1 1 1 1 1 1 1 1 1 (
+-----:-----+-------------+-----:-----+
+ : + + : +
*------*-----*-------------*-----*------*
+XXXXXXXXXXX+XXXXXXXXXXXXXXX+XXXXXXXXXXX+
*-----*-----*---------------*-----*-----*
+ `. : . '+ +` . : .' +
+ . : ' + + ` : . +
+ . *. + + .* . +
+ . ' : `. + + .' : ` . +
*:......*....:* *:....*......:*
+ `. : . '+ +` . : .' +
+ `.:. ' + + ` .:.' +
+ . '* `. + + .' *` . +
+ . ' : `.+ +.' : ` . +
*:.....*.......* *.......*.....:*
+ ` .. : .. ' + + ` .. : .. ' +
+ . *' + + `* . +
+ .. ' : ` . + + . ' : ` .. +
*.:....*.......:* *:.......*....:.*
+ ` ..: . - ' + + ` - . :.. ' +
+ .. * .. + + .. * .. +
-------------------------------------------------------------------
1 +: : +: : : :+ : :+ 1
1+ : : +: : : :+ : : +1
###################################################################
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+---------------------------------------------------------------+
+! . ! . ! . ! . !+. ! . ! . ! . ! . ! . ! . ! .+! . ! . ! . ! . !+
+:!: :!: :!: :!: :!+ :!: :!: :!: :!: :!: :!: :!: +!: :!: :!: :!: :!:+
+.!.:.!.:.!.:.!.:.!+:.!.:.!.:.!.:.!.:.!.:.!.:.!.:+!.:.!.:.!.:.!.:.!.+
+XXXXXXXXXXXXXXXXXX+\ \ ..-#######-.. / /+XXXXXXXXXXXXXXXXXX+
*-------------------* \ .-' \ 1 1 1 / `-. / *-------------------*
+ ` . : .. ' + \.-' \ .-------. / `-./ + ` .. : . ' +
+.......:.*:........+ .-' \ .-'' ``-. / `-. +........:*.:.......+
+ . ' : ` . +\: \ -' `- / :/+ . ' : ` . +
+..:.......:.....:..+/ \ .-' `-. / \+..:.....:.......:..+
+ ` . : . ' + \.' `./ + ` . : . ' +
+.........:.*..:.....+ / \ +.....:..*.:.........+
+ . ' : ` . + / \ + . ' : ` . +
+...:......:........:+ / \ +:........:..........+
+ ` . : . ' +/ \+ ` . : . ' +
+...........*.........+ +.........*...........+
+ . ' : ` . + + . ' : ` . +
+...:.......:.........:+ +:.........:.......:...+
+ ` . : . ' + + ` . : . ' +
+..........:.*.:........+ +........:.*.:..........+
+ . ' : ` . + + . ' : ` . +
+...:.........:.........:+ +:.........:.........:...+
+ ` . : . ' + + ` . : . ' +
+...........:.*..:........+ +........:..*.:...........+
+ . ' : ` . + + . ' : ` . +
+...:.........:..........:.+ +.:..........:.........:...+
+ ` . : . ' + + ` . : . ' +
+ ` * - ' + + ` - * ' +
-----------------------------------------------------------------------------------------------------------------
1 1
/ \ / \
/ \ / \
1==*1 1===1
.------------------------------. .------------------------------.
' " "!""""^""""""""""""^""""!" ".` '." "!""""^""""""""""""^""""!" " `
`1 .! U U ! 1 1 ! U U !. 1
`===============================-. .-==============================='
:... !5555555555555555555555! ^ = = ^ !5555555555555555555555! ...:
''. `-------O---------O-------- ! ! --------O---------O-------' .``
: ^ $ ^ . ^ ^ . ^ ^ +== ==+ ^ ^ . ^ ^ . ^ $ ^ :
/.:"/ \ ^ .' `. ^ ^ .' `. ^ / \"$ $"/ \ ^ .' `. ^ ^ .' `. ^ / \":.\
:/ 1^1 ^ . X . ^ . X . ^ 1^1"""$ $"""1^1 ^ . X . ^ . X . ^ 1^1 \:
<$ : : . XXX . . XXX . : :`^"P 9"^': : . XXX . . XXX . : : $>
! : : . XXXXX . . XXXXX . : : . > < . : : . XXXXX . . XXXXX . : : !
! : : . XXXXX . . XXXXX . : : . ! ! . : : . XXXXX . . XXXXX . : : !
! : : . XXXXX . . XXXXX . : : . ! ! . : : . XXXXX . . XXXXX . : : !
! : : . XXXXX . . XXXXX . : : . ! ! . : : . XXXXX . . XXXXX . : : !
! : : . XXXXX . . XXXXX . : : . ! 1 ! . : : . XXXXX . . XXXXX . : : !
! : : . XXXXX . . XXXXX . : : . !$ -+- $! . : : . XXXXX . . XXXXX . : : !
! : : . XXXXX . . XXXXX . : : . !1 1 1! . : : . XXXXX . . XXXXX . : : !
! : : . XXXXX . . XXXXX . : : . !1 1 1! . : : . XXXXX . . XXXXX . : : !
! : : . XXXXX . . XXXXX . : : . !+> O <+! . : : . XXXXX . . XXXXX . : : !
! : : . XXXXX . . XXXXX . : : . !: 1 :! . : : . XXXXX . . XXXXX . : : !
! : : . XXXXX . . XXXXX . : : . !: 1 :! . : : . XXXXX . . XXXXX . : : !
! : : . XXXXX . . XXXXX . : : . !: ' ` :! . : : . XXXXX . . XXXXX . : : !
! : : . XXXXX . . XXXXX . : : . !: 1 1 :! . : : . XXXXX . . XXXXX . : : !
! : : . XXXXX . . XXXXX . : : . !: 1 1 :! . : : . XXXXX . . XXXXX . : : !
\` : : . XXXXX . . XXXXX .- : : . !: 1 1 :! . : : -. xxxxx . . XXXXX . : : '/
.\\ : : . XXXXX . . XXXXX .\\: : > !: 1 1 :! . : ://. XXXXX . . XXXXX . : : //.
1\====== . XXXXX . . XXXXX . ====== !: 1 1 :! ====== . XXXXX . . XXXXX . ======/1
`1---`` V 1--------------------`` 1------------------------------1 ''--------------------1 V ''---1'
`1 V /======\ V V V V V V V V V /======\ V V V V V V V V V V V V V /======\ V V V V V V V V V /======\ V 1'
<1== \ /===================\ /============================\ /===================\ / ==1>
1 1 /\ 1\/ \/ \/ \/ \/ \/ \/-1 /\ 1 1\/ \/ \/ \/ \/ \/ \/ \/-1 1 /\ 1\/ \/ \/ \/ \/ \/ \/-1 /\ 1 1
1 1/ \1/\ /\ /\ /\ /\ /\ /\\1/ \1-\1/\ /\ /\ /\ /\ /\ /\ /\\1/-1/ \1/\ /\ /\ /\ /\ /\ /\\1/ \1 1
1 W-++-W V V V V V V W-++-W-\W V V V VA V V V W/-W-++-W V V V V V V W-++-W 1
<1 I 11 I 1 1 1- 1 1 1 I 11 I I 1 1 1 A XA1 1 1 I I 11 I 1 1 1 1 -1 1 I 11 I 1>
1` I 11 I- 1 1 -1 1 1 -1 I 11 I- I 1 1 1AX XX 1 1 I- I 11 I- 1 1- 1 1 1 1- I 11 I '1
1 I 11 I 1 1 1 -1 -1 1 - I 11 I I 1 1 XX XX A 1 1 I -I 11 I 1- 1 1 1 1 1 I 11 I 1
1 I 11 I 1- 1 1 1 1- 1 I 11 I I 1 1 A XX XX XA1 1 I I 11 I 1 1 1 -1 1 -1 I 11 I 1
1 I 11 I 1 1- 1 1. 1. 1 I 11 I- I 1 1AX XX XX XX 1 I- I 11 I -1 .1 .1 1 1 1 I 11 I 1
1 I 11 I 1 1 1 1. 1. 1- I 11 I I 1 XX XX XX XX A 1 I I 11 I 1 .1 .1 1 1 1 - I 11 I 1
1 I 11 I -1 1 1- 1. 1. 1 I 11 I I 1 A XX XX XX XX XA1 I I 11 I 1 .1 .1 1- 1- 1 I 11 I 1
' / 11 \ 1 1 1 1 1 1 / 11 \ I 1AX XX XX XX XX XX1. I / 11 \ 1 1 1 1 1 1 / 11 \ `
<====\ ^^^^ /===================\ ^^^^ /============================\ ^^^^ /===================\ ^^^^ /====>
`^^^ 1 1 ^^^^^^^^^^^^^^^^^^^ 1 1 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1 1 ^^^^^^^^^^^^^^^^^^^ 1 1 ^^^'
1 1 1 1 1/`*'\ ..--------.. /`*'\1 1 1 1 1
1 1 1/`*'\ /`*'\1 1`-^-' .-' ........ `-. `-^-'1 1/`*'\ /`*'\1 1 - 1
1 - 1 1`-^-' .---. `-^-'1 1 \-/.' .'' ``. `.\-/ 1 1`-^-' .---. `-^-'1 1 1
1 1 1 \-/ .-' `-. \-/ 1 1 .' .'.--PXXXXXX9--.`. `. 1 1 \-/ .-' `-. \-/ 1 1 1
/ 1----1 .' --- `. 1----1 . .'./ \ 1 1 / 1.`. . 1----1 .' --- `. 1----1 - \
1 - 1 1 / .: 1 :. \ 1 1' . / \ \ 1 1 / / \ . `1 1 / .: 1 :. \ 1 1 1
1 - 1 1 / 1 :O: 1 \ 1 1 . A`. \ ---`'--- / .'A . 1 1 / 1 :O: 1 \ 1 1 1
1 1 1/ `: 1 :' \1 1 . A `../. \ / .\..' A . 1 1/ `: 1 :' \1 1 - 1
1 1 () : .-'`-. --- .-'`-. : () 1 ./---...1 \ \/ / 1...---\. 1 () : .-'`-. --- .-'`-. 1 () 1 1
$ 1 - 1 /\ 1 / .'`. \ / .'`. \ 1 /\ 1 .X /`--..--..--'\ X. 1 /\ 1 / .'`. \ / .'`. \ 1 /\ 1 1 $
1-1 1/ \1/ .' `. \ / .' `. \1/ \1--X----< 1 1 >----X--1/ \1/ .' `. \ / .' `. \1/ \1 - 1-1
1 1 - /----\1 1 1-+-+-1 1 1/----\11X ..\.--'`--'`--./.. X11/----\1 1 1-+-+-1 1 1/----\ 1 1
--------1 11 1 1 1P1 1 1 11 111\--- 1 / /\ \ 1 ---/111 11 1 1 191 1 1 11 1--------
1 1 11 1 1 1 1 1 1 11 111 V .-' \' / \ `/ `-. V 111 11 1 1 1 1 1 1 11 1 1
1 1 11 1 1 1!1 1 1 11 1 V' .- ---..--- -. `V 1 11 1 1 1!1 1 1 11 1 1
1 - 1 11 1 1 1A1 1 1 11 1 \' / / \ \ `/ 1 11 1 1 1A1 1 1 11 1 - 1
1 ------------------------------------------------------------------------------------------------ 1
1 1! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !1 1
1 - 1! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !1 - 1
1 / \ 1
1 ---------------------------------------------------------------------------------------------------- 1
1 1/'`\1/'`\1/'`\1X1/'`\1/'`\1/'`\1/'`\1/'`\1/'`\11/'`\1/'`\1/'`\1/'`\1/'`\1/'`\1X1/'`\1/'`\1/'`\1 1
1 -X()X-X()X1X()X1X1X()X1X()X-X()X-X()X1X()X1X()X11X()X1X()X1X()X-X()X-X()X1X()X1X1X()X1X()X-X()X- 1
1 - 1X'`X1X'`X1X'`X1X1X'`X1X'`X1X'`X1X'`X1X'`X1X'`X11X'`X1X'`X1X'`X1X'`X1X'`X1X'`X1X1X'`X1X'`X1X'`X1 - 1
1 1X X1X X1X X1X1X X1X X1X X1X X1X X1X X11X X1X X1X X1X X1X X1X X1X1X X1X X1X X1 1
1 AX XAX X1X X1X1X X1X XAX XAX X1X X1X X11X X1X X1X XAX XAX X1X X1X1X X1X XAX XA 1
1 ------------------------------------------------------------------------------------------------ - 1
1 - 1 1 .---. 1 1 .----. 1 1 .---. 1 1 1
1 1 1 .-.:::.-. 1 1 .-'.::::.`-. 1 1 .-.:::.-. 1 1 1
1 - 1 1 .''':::::```. 1 1 -''::::::::::``- 1 1 .''':::::```. 1 1 - 1
1 1 1 /'''':' `:````\ 1 1 .'''''''::::```````. 1 1 /'''':' `:````\ 1 1 1
1 1 1 /''''' `````\ 1 1 /''''''' ```````\ 1 1 /''''' `````\ 1 1 1
1 1 `' 1 :''''' `````: 1 `' 1 /'''''' ``````\ 1 `' 1 :''''' `````: 1 `' 1 1
1 - 1----1 1'''' ````1 1----1 /'''''' ``````\ 1----1 1'''' ````1 1----1 - 1
1 1'()`1::::: . . :::::1'()`1 /'''''' . . ``````\ 1'()`1::::: . . :::::1'()`1 1
1 1X'`X11::: :::11X'`X1:'''''' ``````:1X'`X11::: :::11X'`X1 1
1 - 1X X11::: :::11X X11:'''' ````:11X X11::: :::11X X1 - 1
1 1X X11::: . . . . :::11X X11::::: . .. . :::::11X X11::: . . . . :::11X X1 1
1 - 1+--+11::: : :::11+--+11::::: :::::11+--+11::: : :::11+--+1 1
1 1 1---- ##### ##### ----1 1------ ##### ##### ------1 1---- ##### ##### ----1 1 1
1 - 1 1:::: ##### ##### ::::1 1::::: ##### ##### :::::1 1:::: ##### ##### ::::1 1 - 1
1 1 1:::: ##### ##### ::::1 1::::: ##### ##### :::::1 1:::: ##### ##### ::::1 1 1
1 1 1:::: ##### ##### ::::1 1::::: ##### ##### :::::1 1:::: ##### ##### ::::1 1 1
1 1 1:::: ##### ##### ::::1 1::::: ##### ##### :::::1 1:::: ##### ##### ::::1 1 1
1 /\ 1---- ##### ##### ----1 1----- ##### ##### -----1 1---- ##### ##### ----1 /\ 1
1 - 11 1 1 ##### ##### 1 1 1 1 ##### ##### 1 1 1 1 ##### ##### 1 1 11 - 1
1 11 1 1 ##### ##### 1 1 1 1 ##### ##### 1 1 1 1 ##### ##### 1 1 11 1
1 11 1 1 ##### ##### 1 1 1 1 ##### ##### 1 1 1 1 ##### ##### 1 1 11 1
--------------------------------------------------------------------------------------------------------------------
..........,'RRRRRRRRRRRRRRRRRRRRRRRRR`,..........
1^?##-------##-------##-------##-------##-------##-------##-------##-------##-------##-------##-------##1
1 1
-------------------------------------------------------------------------------------------------------------
===========================================================================================================
1!!1 ' ` 1!!1 ' ` 1!!1 ' ` 1!!1 ' ` 1!!1 ' ` 1!!1 ' ` 1!!1 ' ` 1!!1 ' ` 1!!1 ' ` 1!!1 ' ` 1!!1 ' ` 1!!1
1!!1 ` ' 1!!1 ` ' 1!!1 ` ' 1!!1 ` ' 1!!1 ` ' 1!!1 ` ' 1!!1 ` ' 1!!1 ` ' 1!!1 ` ' 1!!1 ` ' 1!!1 ` ' 1!!1
1!!1 1!!1 1!!1 1!!1 1!!1 1!!1 1!!1 1!!1 1!!1 1!!1 1!!1 1!!1
:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1:
:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1:
+-------------------------------------------------------------------------------------------------------+
1 1
=================================================================================================================
\ U U U U U U U U U U U U U U /
---------------------------------------------------------------------------------------------------------------
1U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U1
1 .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1
1 . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . .. . . . . .. . 1
1 .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
---------------------------------------------------------------------------------------------------------
------------------------------------------------- - -------------------------------------------------
1 1 .^..... `: :' .....^. 1 1
1 1 : .-' ..---! - !---.. `-. : 1 1
1 +-------------------------+ 1 . : .-' ! ! `-. : . 1 +-------------------------+ 1
1 1 ----------------------- 1 1 . . .' .----`-'----. `. . . 1 1 ----------------------- 1 1
1 1 .. . . . . . . 1 1 .. .' .-' `-. `. .. 1 1 . . . . . . . .. 1 1
1 1 . . . . . . . . . 1 1 : .' `. : 1 1 . . .. . . . . . 1 1
1 1 . . .. . . . . 1 1 : ' ` : 1 1 . . . . . . . . 1 1
1 1 . . . . . . ... 1 1 : ' ` : 1 1 .. . . . . . . 1 1
1 1 . . . . . . . .. 1 1.' .' `. `.1 1 .. . . . . . 1 1
1 1 ======================= 1 : ' ` : 1 ======================= 1 1
1 +-------------------------+ ' : : ` +-------------------------+ 1
1 ! ! ! ! 1
1 1 1 1 1 1
========================================= =========================================
1 1 1 1 1 1
1-----------------------------------1 1-----------------------------------1
1 1 1 1 1 1
1 1 1 1 1 -. .' ` 1
1 ^ 1 1 1 1 ` . . -' : : 1
1 ' 1 1 1 1 : ```-.. 1
1 . . . ^ .```` 1 1 1 1 ---: O ```````. 1
1 . .. ````` 1 1 1 1 `` `` '`````' 1
1 . `` . ' . 1 1 1 1 `` : 1
1 . . . . 1 1 1 1 : ` ` > 1
1 `' . `. : 1 1 1 1 . ' ' :`. : 1
1 . ' .. ' 1 1 1 1 ---` 1
1 ' . ' ` .. 1 1 1 1 `. . `. , .. 1
1 ' `` - . 1 1 1 1 ` ` .. 1
1 ` ' ^ :' 1 1 1 1 ` .' .` ` 1
1 .. . ` . : 1 1 1 1 ` ' :. . 1
1 . ``. . `` O 1 1 1 1 ` -. . `. 1
1 ` :: ! : 1 1 1 1 . ' `. `` 1
1 : !! ! .' 1 1 1 1 .`. : : .' 1
1 ------------ 1 1 1 1 ------------ 1
1 / \ 1 1 1 1 / \ 1
1 ================ 1 1 1 1 ================ 1
===========1 1========== 1 1 ==========1 1===========
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
/---------/--------------\--------\---\ /---/--------/--------------\---------\
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
-----------------------------------------------------------------------------------------------------------
M
' `
.O.
.: :.
`.- -.'
. ! .
: ! :
/ \
=-.$.-=
1< >1
.1 > < 1.
.-' ' ` `-.
.-' \-----------/ `-.
.-' 11 # # # 11 `-.
\. ./ .-' 11 # # # 11 `-. \. ./
: \.O./ .-' ...---------------... `-. \.O./ :
`: : .-' .-'' ``-. `-. : :'
: : ') .-' .--' `--. `-. (` : :
<': :'> : . .-' .-' `-. `-. . : <`: :`>
..' ' . ` ` .. .-' . . `-. .. ' ' . ` `..
`- .. ` .'---+.-' .^ ^ ^ ^ ^ ^ ^ ^. `-.+---`. ' .. -'
========= 1 : `..' `. .' `. .' `. .' `. .' `. .' `..' : 1 =========
/ \-----------------------------------------------------------------------------/ \
1 1 1 1
'^--^--^--^--^--^--^--^1^--^--^--^--^--^--^--^--^--^--^--^--^--^--^--^--^--^--^--^--^--^--^1^--^--^--^--^--^--^--^`
===================================================================================================================
\ NN NN NN M M NN NN NN1 NN M NN NN NN NN M NN NN NN NN M NN NN NN NN M NN NN NN NN M NN 1NN NN NN M M NN NN NN /
=================================================================================================================
1 ^ 1 . . . . . . . . 1 ^ 1
1 /X\ 1 ` .-. ' : M : ` .-. ' : M : ` .-. ' : M : ` .-. ' : M : ` .-. ' 1 /X\ 1
1 .---------. 1 . `-' . ` ' . `-' . ` ' . `-' . ` ' . `-' . ` ' . `-' . 1 .---------. 1
1 .-'..-------..`-. 1 !:!:! !:!:! !:!:! !:!:! 1 .-'..-------..`-. 1
.-'.-' ^.! - !.^ `-.`-1=========/-----\=======/-----\=======/-----\=======/-----\=========1-'.-' ^.! - !.^ `-.`-.
/ -' .-' 1`-.-'1 `-. `-1 1 `W' 1 1 `W' 1 1 `W' 1 1 `W' 1 1-' .-' 1`-.-'1 `-. `- \
-------------------------------------------------------------------------------------------------------------------
1MMM1 CHOREGRAPHIE 1MM1 : : M`-'M1 * ACADEMIE NATIONALE DE MUSIQUE * 1M`-'M : : 1MM1 POESIE LYRIQUE 1M1
1---------------------1-------------------------------------------------------------------1---------------------1
1---------------------1-------------------------------------------------------------------1---------------------1
11 1 1 '1` 1 1 111 '1` 1 1 1 '1` 1 1 1 '1` 1 1 1 '1` 1 1 1 '1` 111 1 1 '1` 1 1 11
11 X 1 : - : 1 X 111 : - : 1 X 1 : _ : 1 X 1 : _ : 1 X 1 : _ : 1 X 1 : _ : 111 X 1 : _ : 1 X 11
11 X 1 1`#'1 1 X 111 1`#'1 1 X 1 1`#'1 1 X 1 1`#'1 1 X 1 1`#'1 1 X 1 1`#'1 111 X 1 1`#'1 1 X 11
11 - --------- - 111--------- - --------- - --------- - --------- - ---------111 - --------- - 11
11 U 1 XXXXX 1 U 1111 XXXXX 1 U 1 XXXXX 1 U 1 XXXXX 1 U 1 XXXXX 1 U 1 XXXXX 1111 U 1 XXXXX 1 U 11
11 X #-#####-# X 111#-#####-# X #-#####-# X #-#####-# X #-#####-# X #-#####-#111 X #-#####-# X 11
11 X # ##### # X 111# ##### # X # ##### # X # ##### # X # ##### # X # ##### #111 X # ##### # X 11
11 X # ##### # X 111# ##### # X # ##### # X # ##### # X # ##### # X # ##### #111 X # ##### # X 11
11 X # ##### # X 111# ##### # X # ##### # X # ##### # X # ##### # X # ##### #111 X # ##### # X 11
11 X # ##### # X 111# ##### # X # ##### # X # ##### # X # ##### # X # ##### #111 X # ##### # X 11
11 X # ##### # X 111# ##### # X # ##### # X # ##### # X # ##### # X # ##### #111 X # ##### # X 11
1 V 1N-----N1 V 1 1N-----N1 V 1N-----N1 V 1N-----N1 V 1N-----N1 V 1N-----N1 1 V 1N-----N1 V 1
1 1 1N N1 1 1 1N N1 1 1N N1 1 1N N1 1 1N N1 1 1N N1 1 1 1N N1 1 1
.-----------------------------------------------------------------------------------------------------------------.
1 W 1 W 1.-.1 W 1.-.1 W 1.-.1 W 1.-.1 W 1 W 1
1...... .---. .. ..1 .---. $1 1$ .---. $1 1$ .---. $1 1$ .---. $1 1$ .---. 1...... .---. ......1
1.` ' .'#####`. \'`/ 1 .'#####`. `-' .'#####`. `-' .'#####`. `-' .'#####`. `-' .'#####`. 1 . `.'.'#####`. ` '.1
1 .: ' ######### : ' 1 ######### ######### ######### ######### ######### 1..: . ######### ` :. 1
1 `/:. ######### .: . 1 ######### P ######### P ######### 9 ######### 9 ######### 1:` . .######### .:\' 1
1 :' . ######### . 1 ######### H ######### H ######### H ######### H ######### 1 `\' ######### . `: 1
1 1 /: ######### ` / 1 ######### M ######### M ######### M ######### M ######### 1 ^ U/ ######### :\ 1 1
1-+--+-#########-+--+-1-#########-+-+-#########-+-+-#########-+-+-#########-+-+-#########-1-+--+-#########-+--+-1
1 1 1 ######### 1 1 1 ######### 1 1 ######### 1 1 ######### 1 1 ######### 1 1 ######### 1 1 1 ######### 1 1 1
1 1 1 ######### 1 1 1 ######### 1 1 ######### 1 1 ######### 1 1 ######### 1 1 ######### 1 1 1 ######### 1 1 1
1---------------------1-------------------------------------------------------------------1---------------------1
___---___
___---___---___---___
___---___--- * ---___---___
___---___--- o/ 0_/ @ o ^ ---___---___
___---___--- @ i_e J-U /| -+D O|-| (o) / ---___---___
___---___--- __/| //\ /| |\ /\ |\| |_ __--oj ---___---___
__---___---_________________________________________________________---___---__
===============================================================================
|||| ||||
|---------------------------------------------------------------------------|
|___-----___-----___-----___-----___-----___-----___-----___-----___-----___|
/ _ \===/ _ \ / _ \===/ _ \ / _ \===/ _ \ / _ \===/ _ \ / _ \===/ _ \
( (.\ oOo /.) ) ( (.\ oOo /.) ) ( (.\ oOo /.) ) ( (.\ oOo /.) ) ( (.\ oOo /.) )
\__/=====\__/ \__/=====\__/ \__/=====\__/ \__/=====\__/ \__/=====\__/
||||||| ||||||| ||||||| ||||||| |||||||
||||||| ||||||| ||||||| ||||||| |||||||
||||||| ||||||| ||||||| ||||||| |||||||
||||||| ||||||| ||||||| ||||||| |||||||
||||||| ||||||| ||||||| ||||||| |||||||
||||||| ||||||| ||||||| ||||||| |||||||
||||||| ||||||| ||||||| ||||||| |||||||
||||||| ||||||| ||||||| ||||||| |||||||
(oOoOo) (oOoOo) (oOoOo) (oOoOo) (oOoOo)
J%%%%%L J%%%%%L J%%%%%L J%%%%%L J%%%%%L
ZZZZZZZZZ ZZZZZZZZZ ZZZZZZZZZ ZZZZZZZZZ ZZZZZZZZZ
===========================================================================
__|_________________________________________________________________________|__
_|___________________________________________________________________________|_
|_____________________________________________________________________________|
**_______________________________________________________________________________**
