From 5e38dfbb01b8401f8677135da2a9267c2fcb7fd0 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 2 Jun 2010 04:58:23 +0200 Subject: [PATCH 01/10] First draft for the 'from outer space document Some rough Text and a lot of comments/notes. Nothing if final yet. --- .../lumiera_big_graph.svg | 1219 +++++++++++++++++ .../lumiera_from_outer_space.txt | 506 +++++++ .../lumiera_screenshot.png | Bin 0 -> 55705 bytes 3 files changed, 1725 insertions(+) create mode 100644 doc/user/lumiera_from_outer_space/lumiera_big_graph.svg create mode 100644 doc/user/lumiera_from_outer_space/lumiera_from_outer_space.txt create mode 100644 doc/user/lumiera_from_outer_space/lumiera_screenshot.png diff --git a/doc/user/lumiera_from_outer_space/lumiera_big_graph.svg b/doc/user/lumiera_from_outer_space/lumiera_big_graph.svg new file mode 100644 index 000000000..67cf01f66 --- /dev/null +++ b/doc/user/lumiera_from_outer_space/lumiera_big_graph.svg @@ -0,0 +1,1219 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inputs + Timeline + Viewer + Busses + Outputs + Viewer + Busses + Data on Disk + Viewer + Node/Plugin + Build Connection between Nodes + Temporary Connection between node + + Preprocessing + + diff --git a/doc/user/lumiera_from_outer_space/lumiera_from_outer_space.txt b/doc/user/lumiera_from_outer_space/lumiera_from_outer_space.txt new file mode 100644 index 000000000..256b86b3d --- /dev/null +++ b/doc/user/lumiera_from_outer_space/lumiera_from_outer_space.txt @@ -0,0 +1,506 @@ +Lumiera (as seen) from Outer Space +================================== +Christian Thäter + + +[abstract] +****************************************************************************** +The Lumiera Community creates, a non linear video editing and compositing FOSS +application for Linux/Unix/Posix Operating Systems, suitable for professional +and quality oriented work, building on common open source video, sound and GUI +toolkits and libraries, providing flexibility and a high degree of +configurability and full control of all parameters, but at the same time a +smooth workflow which scales well to larger and more complicated editing +projects. This Document outlines the Design from some distance, +helping people to understand the Ideas behind Lumiera and understand the tools +they get to work with. It is aimed for workflow designers any anyone who wants +to know how the programm works. +****************************************************************************** + + +About this Document +------------------- + +// all things starting with '//' are asciidoc comments and drafts/notes while +// working on this document + +This document is meant to be read electronically, it contains a lot +hyper-links between explanations denoted by an arrow ->. Lumiera is still in +development, we describe here planned feature without explicitly tagging them, +as well some things are not yet worked out. Although this document is heavily +cross-linked we try to start with a broad overview and work out more detailed +things towards the end. + + +Vision +------ + +// objective and goals of the project + +Lumiera claims to be `professional', this is quite a vague term and needs +some explanation what it means to us: + + Reliability:: + Whatever happens, your work must be safe, protected against software + glitches and recoverable. Ideally Lumiera should be very stable and + never crash, in practice even crashes or power outages should not + yield in lost work. + + Productivity:: + One wants to get thing done, in time, with control over every aspect. + Getting this together is a important goal for workflow design and + usability. + + Quality:: + If you work with high quality, cinema grade digital video material you + want to be sure that you can deliver this crisp quality without + compromise throughout you workflow to your final product. All rendering + must be reproduceable to the bit. + + Scalability:: + Projects and budgets differ, hardware advances, Lumiera must scale + in different dimensions and use the available resources as best as it + can. From small Laptops to multicore Computers and Renderfarms. + + Future Proofness:: + Soft and Hardware advances at a fast pace. We must not lock into the + current state of technology but being flexible to extend the System + without breaking compatibility. Projects you create nowadays with + Lumiera should be useabele in foreseeable future, at least there needs + to be a guranteed upgrade path. + + +Fundamental Forces +------------------ + +// the basic ideas which drive the lumiera design + +The Lumiera design is founded on only a few basic principles. Keeping these in +mind will help one understand how that actual more interesting things are +build up on that. + + +[[graphs]] +Rendering is Graph Processing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Processing of Video (and audio) data can be generalized as normal graph +processing (more precisely ``directed acyclic graphs''). Data flows on the +edges of this graphs and is processed in the nodes. + +image:graph.svg[Example for a graph] + +When we look at this model we discover that we only need to build +xref:builder[->] such graphs, the nodes themself can be seen as black boxes +and will be implemented by plugins xref:plugins[->]. Moreover one can +preconfigure subgraphs and handle them as single entity xref:pluginstack[->]. + +In Lumiera everything is a graph, the footage you put in will be demultiplexed +xref:demultiplexer[->] at a first node, down to the encoding xref:encoder[->] +and multiplexer xref:multiplexer[->] which assembles the final video. + + +Pulling not Pushing +~~~~~~~~~~~~~~~~~~~ + +On a first glance, it looks natural that one sets up the graphs +xref:graphs[->] as described above and then pushes data into the input nodes +whereas the final result can then be seen soon on the output node. Serveral +multimedia frameworks use this approach. But it has a lot of shortcomings +which make it inapprobiate for non-linear video editing. + +Lumiera instead pulls data though the pipe, that is a request starts at the +output node and makes it way up to the inputs. This has certain advantages +xref:pull[->], explained later. + + +Don't waste Work +~~~~~~~~~~~~~~~~ + +Rendering A/V Data can be quite CPU intensive, to ensure that we do not waste +cpu power by rendering things twice, or the worse, have to throw results away +because they couldn't be rendered in time, we use sophisticated caching +xref:caching[->] and profiling xref:profiling[->]. + + +The visible Universe +-------------------- + +// coarse overview whats seen on the gui, details later + +Now its time to take a look at the prelimary Lumiera GUI: + +image:lumiera_screenshot.png[Screenshot of Lumiera] + +Just for the record, the GUI itself is a plugin by itself and only one way to +work Lumiera, it will become possible to create special-purpose GUIs or +control Lumiera in different ways, like a headless rendernode +xref:rendernode[->] or frameserver xref:frameserver[->]. Completely script +driven interfaces for automated processing are also planned. + +The GUI screenshot you see above is faily default as when you start Lumiera up +for the first time (only a 2nd Viewer added). While we support a much more +sophisticated screen concept xref:screenconcept[->] to adapt to different +workplaces and workflows. + + +Viewer +~~~~~~ + +// only one viewer type used for everything +// how is audio integrated in the viewer +// effects may add overlays (masking/rotoscoping, information for example) +// these may be manipulateable in the viewer, but not part of the rendered +// video. Maybe effects can add widgets to the viewer too (how, where?) +// one can open as many viewers he needs +// these can be attached everyhere in the processing graph (pre/post effect) +// have bus in front to adapt output format +// detachable window, fullscreen, external screen + + + +Transport Controls +~~~~~~~~~~~~~~~~~~ + +// current gui is not final (transport controls attached to the timeline) +// It is not finally decided where transport controls will be integrated +// possibly as its own gui element + +// This are devices either controlled by widgets or by some input device (midi +// etc) so their gui may loog differently. +// Either way they connect to a Play Controler xref.. in the core which +// manages playing and cursor positioning. + +// thus there will be some gui facility to attach Transport controls to Play +// Controllers. Transport controlls are ganged when they attach to the same +// Play Controler. + +// just playing some footage for preview creates a simple internal timelline, +// no magic here. + +// TODO: bit unrelated, think about how ganging controls in general should +// work, also for faders, masks and so on + + +Timeline View +~~~~~~~~~~~~~ + +// hierarchical tracks, not just a stack + +// Format Independent Timeline, one can put anything on the timeline. +// the busses constrain what kind of data is pulled out and in turn the +// builder creates a processing graph which does the necessary conversions and +// stuff. +// Q: how to handle interaction, for example when some conversion can only be +// done in a lossy way and some conversion node may or may not be inserted +// (i mean gui wise)? + +// TBD: Cursors .. discussion, handling, gui representation + + +// Busses +// ~~~~~~ +// How will the gui define busses? + + +Asset View +~~~~~~~~~~ + +// currently named 'resources' should be renamed to 'assets' + +// Manages all assets available in one project. +// * source media/footage/soundfiles +// * prepared clips, known subprojects +// * All available effects + +// First this will be simply implemented showing data loaded into the session +// and all available plugins/effects + +// (much) Later it is planed to make this a database driven interface, where +// the tabs showing things are basically just database queries. Then it +// becomes possible to create/extend this by customized queries and augment +// assets with all kinds of metadata which can be queried + +// this is a sequence, ichthyo may explain this better + + +Dark Matter +----------- + +// coarse overview about things the user does not see but have some contact +// with, details later... + +Now lets take a look under the hood. Lumiera + + +Session storage +~~~~~~~~~~~~~~~ + +// not generateable data + +// its the timeline mostly +// session storage +// benefits, unlimited undo, selective undo +// export/import plugins +// everything is stored in the session + + +Rendering Engine +~~~~~~~~~~~~~~~~ +// rendering + +[[builder]] + +// rules system + + +I/O Subsystem +~~~~~~~~~~~~~ +// file handling +// vault, work, cache +// repositories +// explain details later + + +Configuration +~~~~~~~~~~~~~ +// configuration system +// serves defaults, actual data are stored in the session + + +Plugins/Interfaces +~~~~~~~~~~~~~~~~~~ +// explain whats it is +// portability +// versioning + + + +Rendering Video +--------------- + +// describe the flow of data to render a frame + +// viewer +// final + + +Pulling a Frame +~~~~~~~~~~~~~~~ + +// special cases, +// case studies, +// constrain viewer + +// proxy +// viewer circruit +// render circruit + + + + + +//Example Plugins +//--------------- + +// show some case-studies that someone gets a feel how plugins work + +[[pluginstack]] + +//Audio + + + + +// TODO Following things need to be integrated nto the document above + + +* [[plugins]] +* [[timeline]] +* [[demultiplexer]] +* [[multiplexer]] +* [[encoder]] +* [[pull]] +bus defines rendering format +* [[caching]] +* [[profiling]] +* [[rendernode]] +* [[frameserver]] +* [[screenconcept]] +* [[busses]] + +// gui/screen concepts +// perspectives + +// Automation + + + + +// 3 layered model + + +such as that we only need to pull exactly what we need, +posibly down to the pixel, this also allows efficient caching xref:caching[->] +for intermediate data, to be reused later. + + + + + +Glossary +-------- + +// NOTE Draft, plese help rephrase/review and sort this terms, shorten +// explanations, the long explanation is the topic of the document above + + + Viewer:: + the display showing video frame and maybe + some effect overlays (as masking etc.). + + Project:: + the top-level context in which all edit work is done over an extended + period of time. The Project can be saved and re-opened. It is + comprised of the collection of all things the user is working on, it + contains all informations, assets, state and objects to be edited. + + Session:: + the current in-memory representation of the Project when opened within + an instance of Lumiera. This is an implementation-internal term. For + the GUI and the users POV we should always prefer the term "Project" + for the general concept. + + Timeline View:: + A view in the GUI featuring a given Timeline. There might be multiple + views of the same timeline, all sharing the same PlayController. A + proposed extension is the ability to 'focus' a timeline view to a + sub-Sequence contained within the top-level sequence of the underlying + Timeline. (Intended for editing meta-clips) + + Track-head/patchbay:: + TODO: better term for this + the box in front of a track allowing to control things on the track, + unfold nested tracks and so on. + + + + Timeline:: + the top level element within the Project. It is visible within a + 'timeline view' in the GUI and represents the effective (resulting) + arrangement of media objects, resolved to a finite time axis, to be + rendered for output or viewed in a Monitor (viewer window). + Timeline(s) are top-level and may not be further combined. A timeline + is comprised of: + * Time axis (doesnt this belong to the Timeline view only?) + * Play Controller (WIP: discussion if thats belongs to the timeline + and if we want a 1:N relation here) + * Busses + * exactly one top level Sequence + + Time Axis:: + A bar showing the absolute time (in configureable units) within the project + (WIP: not clear if this is an entity or just a conceptual definition) + + + Busses:: + A list of global 'Pipes' representing the possible outputs (master + busses) similar to audio mixing desk. A bus defines the properties of + the rendered output (Framerate, Resolution, Colorformat and so on). + Busses are part of a Timeline. + + Sequence:: + A collection of MObjects (TODO: need user-compatible term here) placed + onto a tree of tracks. (this entity was former named 'EDL' an + alternative name would be 'Arrangement' ). By means of this placement, + the objects could be anchored relative to each other, relative to + external objects, absolute in time. Placement and routing information + can be inherited down the track tree, and missing information is + filled in by configuration rules. This way, a sequence can connect to + the global pipes when used as top-level sequence within a timeline, or + alternatively it can act as a virtual-media when used within a + meta-clip (nested sequence). In the default configuration, a Sequence + contains just a single root track and sends directly to the master + busses of the timeline. Pipe the conceptual building block of the + high-level model. It can be thought of as simple linear processing + chain. A stream can be 'sent to' a pipe, in which case it will be + mixed in at the input, and you can 'plug' the output of a pipe to + another destination. Further, effects or processors can be attached to + the pipe. Besides the global pipes (busses) in each Timeline, each + clip automatically creates N pipes (one for each distinct content + stream, i.e. normally N=2, namely video and audio) PlayController + coordinating playback, cueing and rewinding of a '!PlayheadCursor' (or + multiple in case there are multiple views and or monitors), and at the + same time directing a render process to deliver the media data needed + for playback. Actually, the implementation of the !PlayController(s) + is assumed to live in the backend. RenderTask basically a + !PlayController, but collecting output directly, without moving a + !PlayheadCursor (maybe a progress indicator) and not operating in a + timed fashion, but freewheeling or in background mode Monitor a viewer + window to be attached to a timeline. When attached, a monitor reflects + the state of the timeline's !PlayController, and it attaches to the + timeline's global pipes by stream-type match, showing video as monitor + image and sending audio to the system audio port (Alsa or Jack). + Possible extensions are for a monitor to be able to attach to probe + points within the render network, to show a second stream as (partial) + overlay for comparison, or to be collapsed to a mere control for + sending video to a dedicated monitor (separate X display or firewire) + + High Level Model:: + will be translated by the Builder to the Low Level Model. + + Builder:: + A kind of compiler which creates Low Level/Processing Graphs, by + taking Extents from the Timeline/High Level Model/Sequence and using + the Rules System. + + Extent:: + (TODO: not sure about this term) + A range in the timeline which yields in one Processing graph, commonly + the range between cut points (which require a reconfiguration of the graph). + + Low Level Model:: + The generated Processing Graph. + + Assets View:: + The windows showing and managing the available things to work with. + This are the ingested footage, already composed Clips, available + Sub-Projects, Effects and so on. + + Rules System:: + Translating the Timeline to the underlying Processing Graphs involves + some logic and knowledge about handling/converting data. This may be + configued with this Rules System. Typically Lumiera will provide sane + defaults for most purposes but may extended/refined for site specific + things. + + Processing Graph:: + Rendering is expressed as detailed network of Nodes, each defining a + processing step. + + Config System/Preferences:: + TODO: agree on one term here + Provides defaults for all kinds of application configurations. These + include machine specific configurations for performance + characteristics, File and Plugins Paths and configuration data and so + on. Note that this only provides defaults for otherwise not yet set + data. Many settings will then be stored within the project and the + Config/Preferences becomes overridden by that. + + Input Device:: + some hardware controler, like a extra Keyboard, Midi Mixer, Jog, .. + TODO: decide if the main keyboard as special (global) state. + + Controler Gui:: + This can be either a full Software implementation for a Transport + control (Widgets for Start/Stop/Rev/Ffw etc) or some Gui managing an + Input Device. They share some feature to attach them to controllable + gui-entities (Viewers, Timeline Views) + + Play Controller:: + An internal component which manages playing and positioning a Cursor. + This is controlled by a Controller Gui. + + Cursor:: + TBD + diff --git a/doc/user/lumiera_from_outer_space/lumiera_screenshot.png b/doc/user/lumiera_from_outer_space/lumiera_screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..f513509c32d62c5cb3a7492415de832488cb6950 GIT binary patch literal 55705 zcmd43cQ~8v|392Av{scGwOTD&d(@6-ORI{~+Iz$%_7+qXRU<`FyQ=oydygQ9t;7ye zI}$s_FZbuZ@6Y%9dyeDz@A>1oj>9!_=DKp8@ALJZ=j#%#{#KFl*1cN*0Dw~IwZeM< z;07B2aE*_Qg!qYwYzvBbxbF5sNt2AYLCGvW6R&SNzt(djet+t(zbh{ur+5=TWO9G0 z>#pHs-ixmu^}0Pg_+_W?=@&o#YMx8{_bSy1T5kCYnV`N#XhNcqgQCwT97k8cB>{{+xoiQPR4H@GreG~o6&y}!%s zVv|Dq>Amx*nAa<}IsUs@s_W=TY(yw}?vV>Dmt0g>SqWO25R`l=?8=si?##vl(oo%66WAWX;!(OrX+PCqWz6!f%$N%3^ z{eLmuQefYA+@t@Qi-k{uHE{G`icXymzCQug;%vO<-2Z;V=No=D+N8cW=tJi~B{xMkp1oWP6$?t{=^~lx9hk1Bt3fbq;r9JiTv^VNK8v8 z2vhBQ+NeBEY~GPG=fe17jeoy!If5r{)}St|N=#%U6HV53n%j~3L#5lGb4?#FKLHa1 zqrZ`GCe5R~IO5>;%VRHSFN_@oHRa3Ef;v@J)ut>sLJNvePY^Tb;xe_xxanwh{1eB+ zN#UI+{Myhy>27VR6ml?SoA241PNO~c=*i;2(&^@gP>>?1dJa=JedninUB-I&%7!OO2SF4pnZc8JAd9KM z5eWa+56%PS?G8a+0nm&|OjB-4D1i=i?p16Uh;K<~xcwhwoaleUOWB+F0_pt=a{Ch} zBeGLhPi8UV`+4j~`;_`a=?{+4Pm`)yYqtOlNO7}B#F*kkKkXdXjq@E5hPPsS$E6ps zgi@~0*{;Vgw5nL8yQax8hmGC~MNw0)g|WwCMluFWTPDle%FJO6o2IIZ!oPpNEWRcX zpK5z^Pl7go;^>~QG(h(cyK&-Vt)}2V=#wcg4T7sZ@nKB6`{P`lbTG<{=OZXGg_|Zy z=)y7bbq`^`+>+kTCVR8@O2J2}{68GQ*B++q)b7nrQkfYM2yd@3tWWDu2$(EsZqxW~ z1OxTF<@P0iJIB(R$xW|5FdoQ})93oJ(y)ELbEg`VB5}kn+$aL9#*f~ZDQ4P{O}*N7 zDB*g(@lFNQpXOKUjRoB;0vSBJy1s>CNvQ-Cq`w#Kb#X8v1s$(@QbHhG0yi@FvXH*?_dr0;4DyhvoG zH=EaP>+<+|*0|0|y+7drAiDMAq&#btM93cM>)fxucOEbGg0nSOvYK}S^>^k1?%Z=7Di(FdW{FCER zzFw`-fic`zphcN2~zX^ z-`1SJLbJx(Z=<>5c((XVsCi%bcyXG#BAyv{2%Ki9C{lAVfjWEAY|%oWv5fZ-V?6EpE0 zw$Oy`@iEM=DPX4)-(XDUD*e+aJu2!C{3rMIrYdGxw$p!7F2@%dvF9{M^%>-MF|`BT>*5zh*hZ;~D7xw*~4w+_Hzk zqaw5%YQs#n!$oJCT5Vz0>jXA?fUas$*SwFFVS3XdTLAvEP z#`XCvxDj@kN3Toy?5HT&F0`Eg*y_}_CZy96lt>R`t@BR;zJ0eZOXU&pnp&=RVcX}2 z;*Ph+w-=v%O5rbN*(nLhr@QFybf2kI8S4+{kvrd;-Ebc74)SUQ)%qQg<~6v-&KD;B z(beU;rxvU7=riBT?<}mV+ZGlmOnC}&7wqZk&sHe1PuawkEbjh__c-_RM@r!WE2i(a z8{nQ=2Kscu@qH;9Zt95SyTMyi(gK@pU>zDL7napdN1fjEkU3dzZp}(Vg(9lrHo}x3 zU&W?`Gdb_v)U4=@TOx3#E$9=)S~(@)b^w*>RLgM24B?FqJg*BGf5D8|1{|s1&E33u zCX~^Bv&Q9TKYXP$=X<~4BH_f0iiGu*h(PSS)dhc`?@_0e)64(3-4*;34VYr(pw1IGqy~8kY1Z+}r|Hf{>7aWYF@tC;+9rS2lis~-N7M;#2IK0w!Yz}$;L73$ zZR*oAota*PF#Cvo7S0g@-jzRAkXR4bY5LylTvJFQ`gICh|`Nq1iSvA z{*WA;t9>NnwfZPNdT`87@VoIBv~Q@P^w95=M44W^+br`9w`-kUl|B_CH`^BLUFHXK zY-HxUy`}_Rwl|ofS@Hls8k+a<1}Tcj_z0-i`fXa|t>^H1%@#h481Coo-_ij*6pRH_ zp0rgI=bbLgS*5}W8I@r?SL7j64**sskxqpHHK(b{&1^_Rf$N}*xlOP@a)&5e{vV*) z&H-2^e&5(9W6gLWH={*IJkW{zXu!%=py{4oaqSfBw45&`3**=C{?>OrJJI-mcCA#U zxMQMqd-76EnM`+`({0~BTQ`CI!?WYZScK8)yDBX`nAY6_oDuHa8DR*m;`7;!TO73wXulV1+lJwNe2&F?|G$NYPFwBe~E6 zK4ktqIb+8losn5mA4p=Nn$YpGRHsuxUU6|wLBU672y58e)V2K>+S%U0(aYU*$4wvz zj;W2?bh8aG`!L;dIsq~AxB?)d7tbhl6x(4?Gu%U5NgcC2U7=(FW3NJZ*;oq#UZ(@?v{a}&4{S@4`-LdBf%_ym! zUO*bumIRa)8&2&u_$o(USuB*UDi(?O+imRlmq#GJ{gedjcy>xJ^sF2&g%SKreh8{S zf5Gks9!c3x9s-BFl#JX4G;h>k1Tq=)+L z)Q2dg`6Q1<`ko#A$>jR=n!Fal)%4d8Mo;KT4`;&+&q?DYMqEu1qhx8smm6vzAqdv9 zU)x6YtnRHHTt8^uPL&Ldp6&v3B}nM$+K}S%-@OtQ2-|%7e%r67e(24pC`?B?47q2{ zHMr}3cpIlWtijMW7>O6CZf?UQWZtCtU@@DNzNa#;z6hAko%unH#&XRK|P`*sEV@33*d@AK|FT#4ymA++cu7q>N<-R zn=JTAs|OXT80B>yG5k*HsGIx~o;EVa$dHS%Ps?>1=K@$GAjYm$9of(dE(}(>ylGxd z>VSUi@s$gHmX9eo77jdtr0 zStaXXv#LPzgYEK*m#M+5sgANQn~_{N&ku%4V1sO9Sm{H(lBXe(TI`EUXUP+ro3JZi z^?Vy0FPodxynYgKG~S1aJ%071(gg^X3|wc_3Sj0|?;FuLFkr7Umo^|X^$3;QlB#9Sf|-2X zqu>@`YxmY;lTH79dcVe`wmehEyGMP>Kk^t`7@z(@K=9Qa7FoSuVK#qx6m#^cFfkxm zZ6xQG99EB7C@*tJ=}(q!(57F|^(MFyomv`lw_7(8{wG9(6g$0GO6Im~u}wTveCWo z3Ye3Xtlb#FOVpt@HnuCOm*l5x6b=Mn4gQ33)~{paiyKQbG$y6GxNDh7WRGUCzhuK1 z3`&7y?E3Ym>4&9fDc0ePZp3)U8qS;Q(Pstw`Kdt*2AFH-8c~Xa@o|QAo=N?OH{LTb zR0@%$PEVdd1|Bv7J7Kl#0G;}ZQT(3TMJKEglzV)vEMm-14YzlxbZb&-YV~vrH(PUM z8-&{n87E-SeX%?F#Wlrq#v2Ec3zv~H)u4uGwl&WohNN80~|5BccvSuV@|~6pDF|Yiob~=S~y7_tjH9;wm2qgb)WiBNPqsYD20)j$VyE{`3_%rdo z&cR3D(<5S$kHT~Dkx{Ctai#~wC%*yD|Z?c=i&O{BiPpZqD9J@C@RZMwE%3UerU(H%(I)_SUQi7y#Do$)W& zX|36`5k=M4fL0CiBIah4j5Y%9{+*_au*gidk7ThnzR9YoNl1}!x=>1@Pke$ot}b=q zo1M~K`&nAQWpLurDsU9Lfsvi)9{Tg|t&>~p1(R}T&VhoJsQA+SB4+w&jaF60YRY?afDw)nRUrC^c4 zh&Iz(Wxj8e&<1|2`R@O20%K3kER{?7g5Xe)&i`&=X9D*pB+w`R+kyXQ58ehT{Cd(%0%x@JTenXA7=O(4sbiEAazDJ+ zo)EixJs8C2u!c#LYcSE!;LrR5K!e>Hhbo)1Zh~hi4fy#s$7nmOM5O2$mK%pIHTZa` z9r%Jng#B>2ivP&va3mdgE+MXkk29#Xv9~7$3-uIz;uv`2)OI9Ce#vxaPcpy+fIMLI z6@A5*Fdy+VVNRhYT_e{Id%|*2X>uXh_{RPZyT77126t*1*cSwMmsXOTeI{-&e`;Tv zVIeT7B4E} ze%hQ6^US=Db=KcV|*A@K6#Dy*m56L??E&+ppg8yzDsMO<8j zZbG{oq%0K~*ZPlaw;E+{0;Qv0T4SD9O!GN{VAep25WtGveOIyjddEqxxz=}f9_%(S zqJ^J6Rf2}evipPNwJ6)Tp5I4svE7ik^yv}eZoZ$0WV04X&bCdo^$7-&{c2_f37ZTvcb)4NP2kD?ZVWi^8qD#WF2{%NvNx&XI=h#FNe$(KQS%#)bc+Ci zp3(PP!TtsIJjD2Wc_lnw%Dq29n(ihkV9xqf>k zlG6Lz2g*GkTgwOSY_{AysWZ?iFwm0{>{)w49&xNHRo^ar0qBu`ZoCEQI}0oDvko9u*apy0hMmzxBMYRzB`g zToPo}Knq;wa!#MFWHvxBh9y{nRX$iF(<_9IPCnYC3+pDlB($C-Hok$MP6ZPBqzIte zp`M$Lscg$<-C&g#-!RN};35q&GrK;%AmO&t9|FfmScG!KxaQRG$bA2(d8*C+dD-zs z@+~ShJIrx8S~6PxKK8^nvV{%$5_qwszOlAu^|Ad0YjyQhAok+zS^$L=T+(lg?70kb zZrEug{*We0Ko|sSY)})%l6`$+Y2yHTb{-UL*oTbWgYGx`)fNN)3FTK1HMv2Gh#HWg z^;K>9_Q!{Qe4p58!>_|KfIWkl&)j!@jVTorT&t>?*z>fpN|9>R)YcZ2!aEu*4plhJ z==+vK@`@MgB;lmlkK$^kdu%4PdcJ!UzN2nto}Ju-!_xV_wN>;tyg2lv3yx+ebsvLb zpK6p|CPye{#14`wVP2>xCWk-T0QpHp#&s5^1@|+i6OS3051?Q1X{{kk3>4dL*b)5V zbS1;tmP9~*wY^SKYO)@K_tuuf+IXJ;adN<5w0DZy6+QZgS)HkJUNHv}bA$&-38&f9 zMcO4>fUeXpEwf zt51qINB80|8EqxHDM|VT(CA#Re@Q$FETLc{?Jzd1A0($6v`s!X?|qy1D|)}rjWHeT z$sPUnwFtEb|sYRGVYSZRsf(hjWks^=YV!wj!- zQuNy`k3|=;Ki(%~l>AgD<4256p*iB@KvJZxx1(5bF+C!JW(Vlq11lAb?brTR&Eklb z)M`ev?5_XfVY#oqZaPikAfMo43@2bw4;s``+rML)P`Qg>U;@XT@Vzr1_Ovus!+L1A zMDVT<8w>Ea%2c1g$M*a3^74^UyADI6YSUY|-x2lf5z`GNr0jZm4c^rB^s&CJa|d+p z|M>e8`fURkyqdhP=&rt;2nq6Xm9}tJ>xy@N%paRl;_s=e@jQ zxo4{9?*h!JV}@E5cQy+xdBbjY?|C(&2fEn`lA#K&S$r!Dy}n9@Q{4!^5TB>zy*l2h zvH|h0w*>XxP%p8|8P&Lcv-6Sa!}gM`yC+XxD^8Uf>umJubWf9R4@Ywg^$brfAjel; z=;055rDY#zb5x9p%O|GxZ4Z{Aha51GQHc~d7P-Z9H*F6BM z%6S+sLEkF(LF-YZ@QSNUhPp7gt*;sit~E? z%iLQkc(2Xd)TgBbnEZ@NepKn>rl}8sc97@L7b^O+iwNX;-&GM%Mt6NB273afplGr( zH?JvbW+k8MIpm5w(-d;fHJobWo<#$Goil8oo3|N+oD2nyS0KxG z;9B)n`wmYQK8I0bx>nXlE8=@++t)Y*H?XSgg31>%z-nF2trN&rj6oA*asjl7k?}AJ-o^9p{JXMA zus~jeP4-uaY%;|8$kF+TogJ66eU-85weVu|o>esimfpU7TFI`+lomyM>$q&IBQ=qp zxBa(R1oC@4XA30>l2L>y5!0#62<{CWvivGhe%pR!e$(+s204RWo;@gv)`n9=HaZ1~ zzHXOaRKk&w!jZ!I;9JH+^>;5-ZTt#30>9*crn#l{RYkGP^|?N8^x_JyQnwM#IJ763 zK6yi0H(F3w5*Hi7ZI(L1hCSTJ8FRBK3rk5wATeOhLpF%@P&H~t@(WtV8hD($MYKKAYYH#EG#)~)InF~FPEV;wkZ$&lZC|K$Qa+!_o@oE5>^+$hk^xe3;xxpm^=z&v%}DaEjGI0#R! zlk>iZ@NLhIkV>9O2}ee`)RxBdoLUa0dD`v(l|W+D-YcR^6^=g~P7Hb!xiZ>%GRtv* z=Mn?GUDqQ@U;OgNv&d!iP>Cq=pwhSlB-jh&*1Dfc(EX`1d8!tAQgM%8=v={xS=SllgQc`@d*nlMj zDfz2cVMKS>h95}2yIS2F`FDugTWewRQ?$G7v!xz$==(s6k)(LDsm3Lr(EL8zjZJ1L z=O3(7gOE*cR874HzP5Lj!fSWl%=>Y$aCV3w-thspvWz9m{6s2@>eRNR)R^Huj&NQm zn1Ku$*)mgc8uUFv+~v|kFySB-v38dcMk>#cUu>AubE$lf zdYq=n=6YeQ<{4{DS5n0)qnD;Qe#>Wz39joNfPEI#J1E7^^e zYX8?JIw4v-$O*c;aBBKAy-I&C3OqUfY@fST+0TzO-`yScZ_}`?gGBXrHEsdtqeG zn*#3g`4w8S5>r+YZ|cMMioQHdZHali+x5u0qD}hM`XWuDU^-`pF;^mAk#1Vl!QPq< zspMYVWwKZ6sfpCa-0Jv}HsCBi3IOy!Av0BMS431KrRpv&oHxoDQ0^Bub!K+*v!@Y8 zYPMf2y2P29T0AL7`#wJOHk8?yp}SQ)uxsbCe5~}d{BdWe)6HCy(bO{+H4OjXi9JnB zbLB4joy6w(@gC6(B@SAZ@u!5ITE*s*tq&Xq^G4I&zY`w!`j>FdzNI(*WZBT`8R(^f zJu}gfnao|>opz>f|1BSILE5TjX?d5Z3Q&;RqdS>7IV5q)%fIPOmwegk&n|ATU9n0u zsFUy}L0gtV7^d9vsIsx7`ej?UMbThlz@*X=*-W*a?MZKy9s^2vsEdAQ^bYY}D1GGNrwdKHSif0D$Uw^SKZb!&vACB)<9xpEpPcr=|dC)skfM6|gH?c3YP=D>K`oXkKU zZt*cQ^LZ?|^(Ut%b4FtqAxQ@ziv0CYx(H=Dl*N*0PdI(kQ0S$V}Z zL`2`yrP~zNwCUJ5yDDBi-q9?Phy~gd8UJV*dZH2)2_gyGe zQ+DmqQ&Os@!V9NV)-Bg~MXIIqBS>!#?ck#@4E3;i5=Q48D5 z-EL+U4fyynM|>vJt5*q0KVqoZT-Fu%H6mmTRvUy&vVtL%GnM6797y^I>=F%+r_&A& zDmA7Smc9F+vf`AWxQiGpn*HH}yzR^&L2*ukDi`hnuN=tVc}Q*Zd7-;caQU96Y}Chp zWt0T+TXc~j*D9iP*VWF<0=wkEt25z)^ux!DUYzQfBf|RnPPeF($nD@HT(z7bQ*uE9JVHaE5o2?72BA4mat^x!Ux?I<~ zhcPE1S*XW(?~kbdj6D`7oD&B3e)_x9yom(i%WlK3m_F2XlYU-BR9oha{pOXAtja5) zx#bV}84*_z*S0EF>a#@jzbXrS{j4IqadAyLwFA3ezsfh36PBI0nVC{llP3k>bJ}b$wm%mpL5lLa$yrJKrD*(o2!VZmaW=tIW9)t(IY-Q+>Bz=Ay;aHr zh#9{=4@wV2t2vh8yePo3?2chkCrAD5Yyp{Y!PYh_`vHcrnN6hnKgE@PCu(1yqhQ++ zXtB&J2kznW`6$BLfin?t6%@IbSL)P;2cEU`L*j3??G`@DK#Gcqy%kBy{Z=5_v$$A6 z7rsQTX^ILF(b3Yna+^Z?Yg#>Qf&IFvqobqPpYN|9+1S|V8XaHLpa3=$+V1*0_Y?_e zn@1}5W-R{+dS_<`6Oxr4oU@MFk7Db=8}bzj<(j(OT{Xfa9fB#-%!?|hTjieBWyU5= z*8awO=+;C*WI}-ajm{ohW^;__pc~;ypdUh84aE;$i)>e?_9frLx5$l8iiF*=Kv%mbW^^i^6zv+)@#x27G76dTbmf=on!@`DR!B^yBY-k@RBE< zBd(8Fxxah&u4HtuaOl?sQbraySKQzgk|_@zKh>QZm80iXj9s`UpbsznMb($?^&1yE z&-rUf-^L7mfMCiYq~IXSco4%{j!y*_a{3j{KaA-h3T^*-xn~1A%Mx9FB^Yud6dh6> z1}=#R`kj{#wy^kA6M7#)L8Ol42F@T0k8iqOP(-6UJ@8F$GJg2leV!Mub20sz6IvM= z*~Aq~9@qCv=jz~v(E-$*g&Bb>ulh#B&ulzf?e1V3GY_8_k}0NFWZJ=V?yD8@H{ZZu(2bfKj`N&fO*%aAe)qgT#kb_< z95X)>y%GTR|8nx@X)U4gGZ!zp8)bs1TIXrHZyf6*KI*Zj*T89}0|fs=my))nS-pWR zw+4gv02Th6dbz3YkEk~x3;KHRX3PX8dYY4flzP!If?&sl(Y0 zC2+mOzvXCZjKBtC-t5J?ygW_Q3OAITAEK)%&;B z6e8=>kdYFFL$sb7NXy800->Xfu=4VoYimDI(nGt{Uk4j3=qbtwA$oj>_FX~Q59_+2 z&YqDgMIm9Z*N;0d4_hxyI49(Vv2{S5@3}~QAF-L6U+_$hoQy^H8|NmR#orlv%vRj$ zOxCHvIUWkRAqKldwIo4)2mXi}WwwgOG+>nVk}7MDzT@@UdkAZ=9$}9u@h7&#=6TZbAEAG;U~$kn7onaP z`|N&iU44~^S8m95Em`sOt{ac_X~=v`h}07!6B*mxwl_b@z1c!S9KRGg$h#Q7)@ESm z*)gb7BYzIxrZ}Sid#+;yr`YzrtFVThXX1W50Z+vWfA8)hto6j(O>YD}b4C@~1aeGF zXoVlm5KO-|a~%_wzRpn}T{hrm!;hYK!U6@l0jQpCaLeR<)XawhG~L<*f4R$oZUS3$ z%0ZQ(9NfZeDSOb*_TSpglr7OST%3~7zPb6zKWZ{C!4F@*qnMt7sPz;qG71kk&xf1^ z{)5634;2hzDNcQmimt z0iUACe?O~$IiQ}H=vylP4}aMrn>K1WSKxi*Tq47vk)U zqoncRQUB^&H3fwhkez{o!mm_5#LtF?FV1!MGLToqYi@)>=Q;01(ZYx&ku6)_#!NOM z$r-0=Z)^Ljrp9-SRO<25{_1M6s;Z|u%D%*wgLf!m-&QrXw3OuKS=&uNPzQek&=W(g z&`{}uf*ND%?Ai70P+uaWx>uq&D=WUe-Af^BkGiF=5<(8X&r-6q()UnBbub~-SS0CZ zW@dUw$V;3LLk2RlygaD8o0Er^SNVT;wquF7Vq@j%8tN`xxzpU?^`7`s9}W+%ed?U( zLWjqWrlhBLV%&sC?u2&;YiVie(y!nJii-z1vum0EB4`u)P*JfQOe&A6Aq%t5E2b0` z5qbOcURFhgxxspME&Gqk$|&{6y#oU*#3*lUW+oDe5t5S9aQ$B+T{$8+8#x&bk5t^J zyLE>uOet5CPf*dth`Kd!Q{7ltme}>Ith+>G_TY-XLCPKw79PGHJBEs?$Yp~G(o#*K zedZe$ByNTA=H*drJ%(wDC_hb}fxLUEurl?*Qm>FY)Sms;=0*o`K#`G=;K-9d*c!EL z3|`9Jv*ymN8@6@@CUe#@>kv&l86FM}0>%Jhupi0AQDHKF>2Jd9TvSM|VPMd?zt4g| zj8GrW@yLSPY9JdM9oMf0{J>i3Ji4=b?qw}wZ}3KoXeA&rziWaqKAQmxf1VkzVusS@ z-?1Un4-$*tHM*ch0A4#lzW+?JCGLb}W`=5bSY1)lFbcBkn2b(Jk|KuGX=#wE8u4pF zAW-+fz--AVe>Lk3Y}~JqAV{{HvV;_97bw8N(JIhVUGoxYL+ozhv8A@MGOdS)8S&-> z%kATcTp}Nz*xR5F8P0ViA8elX5HG?NK8A)ixY7q|SW*MEb;9<5N5Kmc1w|Cj%PTi` z7MLv@s;WZw7c;F&0=!}+oaP-)FZK`&Ha8^)K!N@0z{_^R#YU&06zWq-8fLze2H-fa znZ?DyVG{iwHNs`AG04|?iC^HZm;7Q$274=-C(U%nLU zp$ny^YY1|r?-QGCmFS(=eH-w!SY4SxLTyUek&CfG=DeN2Z$0FKw_=VsUvP7>L~Wz& z1{4$mScyobrPb&%-}C5P@+^?t)dmq`qk!<79A6@ih$vH0f&M0mFBtc%3V$Ae_PTT% zx*Q7ZoD0OuEgmt1zO73qmWMj8vcTKjDBfz3%Sv1-p9UVw3GE1ai;1ZWoO>^pAGhf^ zJY)_0Jk$wam!5C0Z1nPx%FcA>;J|KI^S|_cMN2cyo^Gvc939(dLEINpRnOOb)ypUP z2^$E+I7wNOgf3LSwnjW|aIIf&A2w5)Ir$Py3?$Dm*5Z(HktATrCb2YPA%a|7JXc#g zKO9k>P2a3a-RAUmN*n9|zqG(vrO3 zwJs=UOCS-KM<>xks`DBK{5TJSHY$NbHY+~kVke?EmuYec@%@eE>s-v|S6PJ-h@yqs zs(n6kAoAgz@PM+q0m2CCFI}p3k}sa(smZ8MRTi-BT?HCWJxn1|gDKT*#%p5J{RU0< zMRGgB)=Q{y?n~#Sv_*35d-vF<{}`OEjTWLL(&V~s4SVLLC4>rP{-8#$DJeWup@7lq zjlEBA@r}{X7)&9BB_ZzCco_oK!o)h86+@ix4uKD+N?6)gvSyp*>b8MjRtbCU_6@$# z>L#m1HCD_h3ftL16W{c3J=)1qWiD=L5Sl7A;kcu>wlfDe&?@}gtHYn9LPIrmJE}*U z{r4p3k$%EU2!yiF!nXPN%lhEZP#m(6kB_h9(EBg@CLjReZH{^aQM~rZ1^;BN$Jq6P z`_iUb*yAkZ<&}?j#lFV}HjR(h#u~73B_iIx8++Y0V?5nt7`hk4fIafdmzkw3x(Q4e zPS^AN8vT&<>4Xlksw$MOEJ6?VwEL2j{X)+n@GdEJ?Wnqr>aY`ft)h#ArYGz#Li#26 z4;UW+sX5nxR` z*N^E8DMd;spM8A!n6ArZi}HD|TCR?bat@ISyYTRtcnYsd-#0Jiw@wm={&^nnq_-=Y zQXggrKDA5NIh#cGRPcR#ewkoPf@aAuAm$BNkMR6`}G*ic-Jzk+9l~@^8FV9UijQ^&>1ClC$t54cjuP zVPilHm3=5T>@u||NPX<@cQkfrymVS9X5X@P<5ams{zE(WTpWvTVs?JMp?F`M zr<&EHckgh|g<6WK#;u0RLHccW4FiPWUkwY#ztv>r-;X)}xubsyqFrM?AD3Q5XGp)o z1W5-pq0|P976cqAfQ~iiU`QU3THoQt@JD)7!QC@q)%#Xp-j^ZTIh6r99+Z#&ml-?a z5=!k%jl(bNr?Oe$z4OHS-0^w942pWOA?4Cw&V|KLqE*_W;oCmZ{^^XN>b?$mj-sOc z+3hI5s`x&NW1B9DvV8YFrQh6RHT?xzd*&9%%^w*)=aAddn3%k)816%Y$X_=1;!kJB zyj$qthLy?&gfdSd+j=#2fE(6av0XPOh6jf<|e?aX+h zN^!SY4_U^lTz~ef1p*c2y+{Gd*LFR>DUQULehE_x>kGB2DGCk>dccQRo2e!zPEa@; zW4fj%oLwq#XFbqeW|4}P` z;2PY-1?P2>Zk?Nj`DF$f0lRASzatD{14inV7)ia{H~_b_UdGn1KJxq#do7I=;cJ}nvqpbq^RT#v-+rA* zmFT)FyzYcQO1L2=HgS9o0-X`;UgwT=nY-KxFTUhA+1d95FNEo{1AlidE((<(lJ{13 zbB@!Gzi@!1cohT5*ZM)B#tENr%2d9!vL zT*WTe@%tG&Y?4BWw^|l26H?Q(*X!b&`o@YOQBPmj>i9qzFk}c)iU+&xK9_SF=}?Dh zx(DS_lN|T0Gw&Nqbqf-9zImpn{Qe!9-VFWt2EGO-5GnIKE0~@`iO#s6BGDz_nj{Da6ysgx!*^blb79c=ajGDYi(sBz@lO7y|(i0c+9Vk zLonx4JJUaYPrC+#t)=|eZ+mf(N_v);_0Mc7me!_mvsud(K84b8rvtT@kS*FKM|KFpkRT~S~f69LsZz!oB zl9Il>-a8pHA20U24|1I4q>_%RWv}q8W=CiLNkL*$wkP(VJ{_J|!6HT;-85c0yWpQm zVJ%=y=^C()O`m?p_A-B44PIShCgYY9!60Z{_?(vJq$7SNy65r0rN_pZ(`{A(NS?t& zrUAvlf}X4=FEOgVj>u`q3^81kkXo2SOoVV=tc~bq7V#1w6Y0(V`=4f)`BW*Z$0sL; zXD9oz!C^KxnO|L=*(zB+agAy(=X01G(6qfld|`tW@`rwK(KtPE#*Sv1-1pU(X!7UY zfN5e_CaOVmA>c|qb&%(jw_=KUV7_NbTp9NuhcjNgd-p-|y%Z*Iv9=BFuS(ZmtrehG)ucW`}#^2{?mG;XtvBB|G~Y2q%J%Wc7jMk=MEMnUx=Bu0Sex zYK8?LdRe61rX+S(fbE)TOQ3^}PumcKgrK-Xxo+g%o~;-$;y0<=rV1m!&YO2jBH>$& z-0hiwph!iiS+buOyW27Q<)_L8BMVoD1Rb}eSd=I_hmrN3xjWg%_=&12K`cDbJ1$zI z8H-V4GVCWZ(G_(3KPckub!233J+rd)_CT4>XHD-8Z`CI0=@pNgxcwQ+EnB)YQLHeu zyX8_K+=i~F*4g8o@`--~ss0Rg{8v8ZweyyKKS#1v123Ih>EdW3B4L9f5{<7R5Pl;g zBX>`>U-j7`p*+Rx4uUx#SfW89h)|Rd?`31`H$gdWWJJsK8BpFm|;B z%?s-zg6`|pdhFbd=$Z*yoD4wn0#F^Ln!2@ZR2#UpeLr1zJWcuybVV#=Z4%x6`r||H zLgAjQO9)iQXDdNCw7mSue}ol8Oi(xi^I{8}<&^{j7sq6;$#Dux^`2X692e@>2b}Xw z)M&Z-d1hj6t5(M!J4C4PyyP?X{(<05yyCs*{PmZ;B+-@*E_HO=y1PU&WU}7lrm-&v zt=5lb0EeUtGc@S`#YxXw>I$EMq#+^{onAMvVM-5Of0W!oT{S6-9iq+sFp63)9>c$2|NOq%M9>X%$C3Y5F-rN6ZdKCj3)B$USp&6Aj3Kc>{-*m+xd{p}T(eO`I#o zgi{EYd8gr3pO4~8eeO>CmT-RPHD&iI;CstzpLJv?NJ?w#x^sz~_rC#mSvwE7^f-F7 zLUHxF+gsBi{bHP*j&0n2I4RHN%WH9JMr#*xaQf9 zR}mHNmID__U8-}ca>bTrie5u(YI(@1hfAl$I3PAvXT67Y~=c%SKH_}8# zwXo%pa?-O^J|4XLdSl#7S;@P?DWaD0Lr!tf0JPq(3T=BHJIm<=2bnzF2FZbE)#gTh zTjoI z)+C&W(I7-Mo6X4XTWN{}JFuIVCA#;>|D;83=Ro0Adgxkx`p(>@=F^$dmX<5sXqWDv z!3_cDIRYm2IVlp3yfkXc6?boi(2-rYM2)FV?vKlD@l20pr|1aeHCyA*_V$grGG4Eu z+qImm6HiI*^w*_3pb{WT(<=JG*Zl1oT{Qakzgu2!Dg3l)zbHSw5B!%4;20)g;;1n@ z$Xb}9((guV*XW^DyVJwA;bP?B|(QQ7)f zs9^DsU-P|4?p1>t2h@8mrm1aviT%!#&3i1B6oRaqW6wD96-0RZbVMdg3w5MdPHCrr zBjO9ng_T)4d*1I$EclVw8UR~kxyNG&}* z-Sk~VtRSLd^(6g~@^oaOyEHG{WkoVbiL^>S>~O^hKa$0rvv3pe!ACsKrE11bCuu<{ z>yWfrzk5rIHXz!C4nWU6pLGRbWj;}mtzXU4O8WjS@#U~LVbtsajX#u&-3X{7()=G4 zdP?^Q7H_THGl)x04VnPJmm!s&kt?k)uh}J;k&=A54&ZxC91Vc(O?$eXEWKAI4-xHnthEu6>dyK%|qe)H9@u_u%isqf^`%XI=HdE;Z&o3s6w&BNK>V_v_` z-+VvV(F$sX60D`29j!AFLVp5d+>8I}htmP`%j$+(M1@ME+qS7||eP={K z&3E*5Ix59Sw$Isj&84VlU9TjT5+9YE?0e(t13mh7G!*Y|GVP#$elGhaJ5*C&U++&W zQNDjo!s99j@hop(fvHf@v-_HVT-Ux~>c7CVaQ-Hl>K5&6|9Kn{dpz;#U~q(k%wr^; z^CU!IGu%S&xt8X5LG$^&_J;t#<6GBZ005mX2ThzsepS_rcGJ4y)q#8!u56nso&52y z1%=G?TYCZtXrTvjO8JeAM$xq2Hhpn@EaU_4iS}ehU-Zb5IOE?b|AN3R2OAspg9H9p z*9Sx9I@;RV7Ov`}9iaJcR~D`=bTH1JMwY0Qg}3j0m4+LH~!n_l#<4>-tBr zaxBO>Di#n>>0Rj^6_DP0SLr3xgkCI1umRGgi}V(xBtU>5B1C!(0YZpK2}yv^LP-eR zjqmf0@&9tMnqx*jG)Ahc9{saoW zA1-pz{uFRu{|}K)8a=c8YMl^Pdkf{G{OKvGM^HKcCh*0dJ^nuC)F2}nQ**R~{r%S}FL0pRQfG8yz7*xt$BEK_ z7&gS**+&jBw1Bsa{CUgI_E$No0ohm-BNH6Ee(SiZ zl(&|c^iBAo4^^sZgroV8ElUEJpX|JVFbFp2j>Z|yhB|WC=~CMd{bEMsLcVMsls9He zJLK+%-s|*@e8D<&GV|2gm=LgpZ1GAj^tdS$O(`b?P}kcaDqHnv z*yA{JN$fYc@Dq&84?Ho^d(_T+ZY7S-Yjw}E1NvMyX z%+;ZC%yIYc{NXtLeBr2QXX6@`t>pB!D9eyh=*ePl>gHN_mv3YdiKWJ1GQl;&i!otf zTU+&zjqmBcuPy_}i3p{&DqfiyVf5Nfc*l_0(Wz%-CUMYtt?t3!;llt2AKE8x)A8*} z2(iD*ho{Bt8lp8{eNT|ixiOBj!$4?{u&;jc4mtbI9JM+!HY`~px0o6GojmWFS#58u zkjFC%kH0Ew-Mh3h$OX%NbWpr=YqofiWl>k)3nFkQ!oe$%FqmOhVxR=~&bVFs%e(?c~Oy0AaiD=vhqgl>&L*;28)imt_lnR))@0b5g3MG#igN1Cszg0WghN3S`Ll=S zyQa{WY?ahXIVa34j88G@pf#D#VtQ*Fan3uGT%ANevGiR+$+`yPG+W(KP~`&vv`kCV zvUiuuqp;)aYm{w_RFsrrx4N3r=gZhpt(g6A`(=4c)NAK4_?CaJb7L-L%?!f(`GHQ_ zj`CJ&u#e9~%)u%*1ahxXOya=2Jvz8_Jj%d|qA9b|Qc(sP-cdI|?4Wkt!J_*d99LDY z-ZFx#3<1ZF$ka^boKkx1WE7$= zLzeTTK&iTps>Ne?CrkVj+qrjMAf@ewODnz>veN}I2g7Rakos|;dezk{$4cwkn>@-P zbZ7e^XDC&H(N`Nn-R!eVGr*w*1j4EPr|EKQVGsQdNt*laY7|k5$-S3YNxuQ&HTr2AHtBoA zwWw+gR=*0{RT?={ZD{!htAs=fFDIu|_CN!tt4`FxzDbuwiJ@QSVT+vO@bKyt8bQqg zEfKx{5lT5>;%MYofqsVcXISnMS$?i@W86sgAy8%B#A>OFGE}esE=kwVq}5 z2ua&G0i`i(XAc@PGVEXB6c6g3)xcQQ2+<W5$=H+Qr!RtPP$otnDduv6bXdCCKtgfjy*@t(vCDo!A-u zd_&x=aT<=9+AZOT9&(Cs#9CSCCRfO*$}HYDXlT2?pq-2uTT3OlRAiN4g9+L7g{ZKV z6bTobgy7b_hDf}X{HF^(=^%V5_bR>wCc?hR8cg0Ek#Gaw+V4NehR&A52@xQtQ0hnF zQ*hM?iXS4p(di~;%)ix%(9ZChK9*sDQc?_M)yEMLF4zH$;F+BYbT;_cH$xZ{YPE2< z`}$yJ7vY*=IP+Lp3Ng^P;D()kQ85C-=QdTf;7r8u4K~b|R)zr&Fyw(rsk|!q=c1G?q2rV%sn3(;#yYTHE zEdhSqu2yAWJu}CyYK>fovNhais+l=GReB|P`^du`Vx0{3x-Ekk@;{ntC3#LWa%O2$ zC(!OKkb-KhPERXjhBxZcc>nSwZ@I{-mnQFL+UIJlP)N5^e&Ply%n+ExpvuDh5GA@? zF3$_SQ|dHcB9;xVZ!-(Q`jUTG<&$S{3(nNtK_!Y|``E?B2oS6E;$dVFXh}-jJzU(a zWn7UMHosQT6y#JnA(OWJla2zf8Ro}IK}B2a0UF$BD_!V}ZL96u3c{~E z-ad65IbK|l(ctL-8{O!mVY_;`Lhqhg6S!R-#~rs)x(!T{{hXlVKDtuzD^jTZV>bO| zG7W78zi)HIgT?8aHr6-*&a7!ugMIu!8;we4hJhJw#QFMpf<(gpD+0YvOfOxUIM$`L z)2{e&1d8}NVG#$eBRu?>n@tofrunIumQEouH;zp`=3`Uu!kY}@gcb?`BkmWI6nEqx zZu~L6+ez4SZMASy2LUwUjvoN{&RqROVT8l zzV>M_N+8V=<4ujVqctAQw@;LGN@#0dRbGk!wG*{T?tOg_51VpTgv>^j7G`(RI^D-} z#_T7+8-aIhkUE5MBfgBHmbV`!tYRD7Jc|cs-wGRBRvVD}+{U{*u^~RTP^H~)Hcoxv zv|FQ3l;wh?vOo03EO>JtG)t|PE39~UYHEi(6EYBOJZh%Yc+GFwHGp;>!#LZDW$DED*NuSRrXi^0#~fN>VdIeJHwqplpvJ08sXh3hYlgn zZZa0G*LV<`GCh2ww8erg;OZN5PeRAiIc#Jo zc9DK!cGkckP*krNrbjJ&1smhSxa5-+cQR*>Hgkk`ke{7e!>zs3CxmW+U8WLxz1d;& z>-FK}>ii)RSE3kmBTj8lcQs<)W*=E9mA|+awwJ=aI$YN+e1=m`z4iokd+||Q|C7?~ zPrIR!Gjwx9mnFb(6PI(bV-!rlid35!h`7GS628+#fWcyni62BTyFoW! zyAnSYRpv(*C0eC=Pzngtk~WRq@GtBM`6=7e4NF18N;rKXy)y;aDs%1* z6%s;RqLPz~^jESD*9Tj?u*kvLvd5nv0PFVS!BvldW z)!3V2!b$IoLj*4UD~^&(E;2d{u;swim53ake4_) zd``c2Ht+u0S6_QX6-T|t{M>41ZL~uob*QP^C-6Z=%#EKBF%l`mtCbjO9EDkbLgoAJ zRy$Brl_@Cx*FQ|pzuen5uML^aRQ;9(=2ok=%NQh16bG3_Gk)dj(XhFCWAOcTS$sTk zA*p8DKQh^9z>KqAN%`~pQp4qET-6I^1Z&3(gm*_FC)_@w!UzG zZr!Wtl!#*sfJyV!@f`22^DfD}R&*O_AQnzO&^=vyw+bNtIo$G`mb_FhVa z__LC3RW$qSE>mwnO)CG1pqw{)_C%^3b+Cht$tq0G|KTmib!Fw<1`zY#vhx{)s|HDL2xVq*|rr?a9z~1D#?tB5*Q1^jg@;v|woCH!z zY(2~LE8spH;CHrTKHDm5Z8gm!sBW?|Jx6sNNB1p{d9uIIx+>;7Q0Q4%y!#puM7;}e z=M%2lTbG!gu>TqIn4|9{T3=#jx))!2hRL|j%8Fz&l!85H&-Q2sypglC$^aT4Wc3b&ZPN&j~m z|E0$N-@H-zpx^?a;>8&Hh_+f+^JgIIH!n>jS{Jf3E){ZS`M)`(J_kU#$)7ivREC zN>-h@{QqJB{UE~BL;&Dp)j> zdt<1tH{j&|*t++1PcRujDK2Jv*A)(HDA$B@espC++y(MhTMQt-AT3=sI{NNW#wn(6 zMSmQJuXT00ESGjFk??}yVqmOKb#=XuGMIpWe>k0pg|FTp(eL17&@>A4?tOG-V0%~FC$rQt0i197QAY5`|q6ft@n#6 z>`YG%Wn^VJy!*7*C#MneXJLg}ND1({Sg{1MorDB7LQQ2*Ui?ON`}we z0Lo(U;)KCB&x#$iOPQTJ{pkGZM*vxXL(+eny1K^KP4xpW`u5>JseX2j40iALaecr_ ziQZjYOxsir=|BPvIKKTp&JZzuee>fP;{xqC#eI$S*m`=d`2)^51+RbN1b9_XHjaG{ zCTop%Pn)Ins(}Rf?VI6E7w_H8H55we`MJy2Ck&PmJPTj_Sr>Wc)g6UPM+;2f>^bNz z%bBfQTwJ5So|tFqhYxx;RL!XS3kz3VeVe)|4cLs&HQ!xj>Mk1dfIgW)FY+rU~5lAdXrD&2R&woPY7_pW_*&rKk77IrotgJrZD@pRWk6<|ZbE8h2F% zR+S8mWn|(J0rM}@C7hH5qL`T6N*f!^`ZBmJ1TZvR>yd25fXv$3kRw%-W-9lazOvpR4*^E!~->4XdK$t4z+mQamn{)06C zoX?V(<2f)^rcb$GMLsO_BZ%1ryR|$2^xouWaMlK}49Zizy}A~5c4Da7MZ^^xecDw1 zmL&-E07((yGV1q^s0S9ea7mI6HS>G=#J3b*Xoi(qZ{5Ja5`Yfh{*^(H+RRv zazZ$lD|$s%IYvAEdtFr*x2?+BK7bGD8UJ|p%6&8j?V;(MLLzzd>1>4BkGyE|#R14W zolM>D#ogSoR?CMcn7)0#a`Ef}Vzvo5=T@Z6TLpYS3v21s`0fQn-pdYRVQbRP$rD;) zVg_}q_J0ZK0F&8NHd+J9YYH0)S^iV>t2~(j#|zwA9s$W6f@MF~{YXIn9itEd-NpOsxC6 zSR%HK^0P2AD@+$H&mhoAt7HqKkbJ{@mC~`&LGLGD zozQGD-QU|E?Xm)!w1Qdf!UvXHm6amEX~F_vAv6nXwRUo$D)=GXC*MYoJqgvbzR<8N~l|fCIP)TJSzntsYkx(27-3N0~!nIm-Dq418stHGis% zg`CIrT7CCBl*sRevGJ zolNjMcmxoZJ7!aE-?!|E6t`I4L@Wyj+h3;}+y-oMO#y|UMYsVJ+3XAPw!QB`v{Jbk zJ}i8Zj=a@3LL4jQ)2YVVElxJOl8jU!50Da!wIfE#qk^ARlxBI0qhwyKz=Ll&RDes3 zKYUEZbo6#Hz0=*WgXJI!ekU-k$3ETUq%>K;Y9J04$ki z$Vvvd?gmcwJ6z1dBEu6+a^swAw<2R|FwI*87c9Ki$;&3ac=O$5Si?AZeJ*Oc)wSMt zwpC^=LKaw^UU(1+5x6L9ff+A@LmhY5X3;$<1nGN!TZt+b`AlTjXD;w`P}XqGwE`hS zr28mQ@9lgD`7oxPv9?z<=Z}1x5P^Z>fMbjkjVPmKT6_!pve5^}u|JDP_rIl;?&`U< zG$1S{G&WW5zIavswy@CKWh!R&BN;*49+Oz0Zz*k!Y}sz_wmYRQc+Pi=&<5J~i~U%> zSc^7#RW&qd0FqX>l(3fm*csR;&b85itXJNoJw;M_x1<8we0=xcQu=lSk9Hp)t|T7V z6xN)2@maUi_54}&u?fk`3!Dm@9v|gK;EzPQv-AZ)jx_`zS39cfv>HN}PSq8$w=I{^ zv+^A4Mu!t{Ll+!=e|I|r*~{#l#@;ZgtJD`5jG;|F9M*XJNDH5#dUWuHMxy~*v5-Lz z8IX_6`BaRqR%!_93uFli@wlC7QWXAHw#uoXyJAZ*yu{$pd6mw)BWD$rDbJe7e$LN_ z+|fqrKCAfRdExYQU^V`$Y0K`)Xm47dg{f&Won5`7a9+NmLVV;M+km3Kf6YX-UFB%9 zslo{@IH<2qbPBGrs+zd<>YMgDuwNvn8Z4`V>qm?qq^)XZvyQFs3}6Gn)FB5ZS+geTteO*R(->CeV1bqqv1Q zX(yxNL0o(7qvTS(j705ZaR;Q}ew=I1g!18FSWbtAzC_!)Ga7@LX~!?T8m_4Z9munt zj}2rEPTJm1yhKtv*a@k>bXY<)*+#c!9(Cq$)Z zbFtFpJCZw3NFIIh`?DMi>*Xv!Ec1ExGRG~{4|N8sL>bfJ;v*ZZcy!WMBO9l#h_z`! zI=T`Tfp^q7oml@*Iks$q_I0MHQk%gKs-)`*MD+LHt%gExv2eEU{eJju5|HWz1x0yL zJ74o6*1jHYmnLrR<$c;?v2JpMUE-X9_D;ICMf`41EbJ66_xiXsmI2%S#YKffmQ7>a zy6J{)_jmt?J+9n5cN2A1k*B^7ura9Av}pt=H+XfrfX`rnUH4K2ucpvt(`+c4%Ud6K_p)vVt~akZUAQm!vVr#SPOsZZBO#M#SA1fW7 zofRL7_}jc4IK>Xws$ybd({NC>WM+e9wSB>Yf1n|q+Z*~vyIS$5Snyu9ZnqfkteM~NRq^?KcKt=R1NmtwF>agPFh>IHg(~ezXTOOnil;qy_;uoZ^2WZ*cUviTY781_vda&{;GVg5T$l+z*Eer#a7R& z&o$yEb;f&)x>F{q^o7mas;rriZq+E7z94jUN#Hhr^gY zpv10ipkn7r${O_8M_71ORDWD`XImu>FOnVDF~3D==|u+F6BP)AEyqpmTtW4{JSSLKwwJ#*dr#B1@8~pt^!ZUg#1-v=Ey8ZC zL~MJvA6Qn(fsFOki+v;t51}ozxlM<72DDL~&9*+cncYj|>UnEj)-E7-TH+hh5uHc{q$PO4$yY!?+Ps%wVR#k^q=1Vfod zQM9pSf&NlQyUv`ywuMabbZgi^5&e_3m)K%7YIz?yN=#M8Sa^n&+ctvCg3RhIt8EMF z-6bjt3-uU`bH!#hJSP@B)#TEF=47Zz%@r%~eE z1BSF>`cd=IQFAW!HZn3|No2(NGh%>cY>P_Z<_PhA&Z>IwAYp#_+u^BcWK;_aVyKo#K>uHFRvRQ${ce~e^J|% z;H0THD#%>Y{>x~Gq~;f!Gp)~y?#S2~oTqo5Z_ax}`~WQYQ>wSY6gvwx{deXGO)1Y} z#uP3zrXoVrkrH3de>vHedAuRGP`1h|Rh4c#(JNE&F)D`64|2qQc|yC8+oB|@Q@8R} zc6GLVz?)rW99unU{5aV2wWW`B^`e1{V(`KTTB-FZB?|+&@WP6Br(Km!z^ZUXVr09k zgOTN9Aoa%p_j`biv*l_q9j{ur&v9!#LM<&l#vvdAlr2%6sLnjn%YA4sO!tu(R8q2}+E8dj*v35rK?KWK8!tFe-#tdIMkD*1EO?hgM$Ii7E2) zTZ&ErI&L)_p_m&W4uxMrDCK_s+8xP()zjk@SO+a&6KJeFh`$7z0M1U4DxFd0LH@by zw!39(HJI`2Tn5KCz$HTN{r*{0e-kLtG4|~N__5RzZunF6HSTu3#w+u16c(yyTRF|* zT|_UK(BDbpKU9K!qD4&FQ)RFSeyNcUsO03Yy&|Wk+ha0p?d*Us54515DRO9FKsI~v zgA}S3IJ#u+qdVwQ&(p&5+CDQLaYRkYL$n`PhUp*Og0& z(Kw$(y9q{|U#KpBoVl4@byUQz;H`7ye&U7X1EF1o=!2qg#Ir)FhlDQ)^C%}dZQ zWYPmaIN=HWvD*p)3Y__=_Lr~9Kiqcjb*Wbbo|mp%512cD`Xq__hOt9bwerwd0;dx2 zDH20l+Z}P-+R1>%fQ{UY+vG!?E30hLIw2rm%1D&4`eP=FB;81M)nQ{>Jb(67IJoO` z&D`8mmP_4f+WPIL-@y^}CV(xFKrXv)S~&bbJ3hVG#Yoq}yVJ{`!@?xlG*G_yO`54> zlId53l?acBOjW94>+@Ji2VL*AyuIcUdxZZ+-Ivb1Ea!h1?rPX7b>`os51LdQQDh!Y z!ME5FX8T^dTX;7ThdV%{)nke@1}o{-jpQrk!~80R8Nn2D*=gvIAywJZpi-}xTin4? zluzt^+H$_*Y*|zUW*LlCaE@|n4K+x2C4YO73;5!@4CY%u%pDxc9a`Y!&CMpqfZne6 z7=F*EzvX^8#Y9=MG0SPtO+5cBX5e{(NODS)^mPuG?on9`1cqZx3wK}lnFEa5ik0=6Q=@64XUcG4yOn)l{M`| z3*CP>mBYT25rV5hLya{L5$LhPw++(wZlYrtR$AM{QaYsg2*F!EzpN7#yz@0#1y61y z_>rlhkKCFZ?HVbfh=G0f5bm*^vf_=r?C{(hql;Q*v`Tdc#kQ7*?NPsmj%=&038!CH z)E$L;9G*IO68zNvm)jNrq}h1Q!qPSxH%=X&ZSkrckFIu!UYEU+EG_%G;pm%qR3we( z%*zwSqdH+yt||kD5HYtOg->sskL&dEtR7>I+gVOYR2yW@F8^0~D9!UzGI8K+V#JP5 zwzye)WaeFZ?aaPi318<=BZ7>+S?tATXeEHDcyg~SS1GuxrNwS_l>^M6K~y3Rb$Qh9 z>nKbG2eh-gm*^9QoK2QJ#BRTObfw6}I4fhw&9;w@XpU5pz$y5lQzvq-6sR_K1f@%uZ=ciH~e$wp;}7 zYm72A?2tD7I>cpeUPOo;I#!4>f&~#|T?0Ki)q?F&iJTd{jCsG!?7oAQQnhR`KP9+m z-zd;Ni!ENX{X?SDssxI%102g(1!7vY){knfpHaWFmDOBDwg-uWD`4cX-l>GTsT|2M zr)0OIw$Tmy!E|!^Zv5(x`Dg>)piO(N8tz5)u6Slvvg^TFyk(h@gdHl zx!Tx`dZ|VB!X>lbA+DdEuBrum-BVQwE9prU8-mH~{mSDlFTmmfr2QC!o(Lw68h~bJ z%B9>5N&T5AiV-^tKFgs;hlLiZ)}eaHJcs70AcFYv_cX`0Ol_gRt1<94X6mb1y zgCq|tFnndhD6vw-hd8m%5q_UNWxlzWpC3&BEpyXNBTh{LXk_x%Ov#l!7U~#Y7TTSj z@|J8ew0xdnUG8@w@%r@60V+Wyv}!}cGA{-F4VRr{I&rEByv|*yHb$5r2BUkblhl78C;47n zWN5$$COzO`;#z$0v$M;)6k57-O~lHsc*mPBD7&xUNogo+)*(#%qcn?IiKk&)kQC2g za2M5e>DI;0R9BlieedvvLIry1eUEL72tb%?qDlV!Ad=7h=}d&k8Iy29Ib*x+pl@LzC!Jv znCqu3*o&8Tcb{eK8AVs|XkF^vl1!es);)+OUORxTZ@gCXEmqVWvBno&xGo`*sVkDJ zBc$YK^Y7Z4FC-*HLf%S!bZ@c<*$&oZff%@gVrl~$j>9zZ!i|+Mat|EjT9;Qh_R#r3 z7K5(8_bK-}&>Tl$afJw});;QneJQPNh6K;deB$l-da{p84yX@{x&)5p(-~-CCH5yY z%Z34ib81x+Ir5fjGJLiY7|8Z9K}aOfKTdzMEV$af+L?rLr~H*`Ke~ z6joD&_jXc09F0<@g!OdiL7V-y*rs!tO;{>H9RU=kj!4JrRA@Zws*-|H2 zl)!;@(e-glZNNAVP<@f3j^d|SlU2{AFIpR;T4&|tGJvu{c_ z>iOK~VcE)Va*?^8H~eZ=^>wESu)EDU6lDc-4fUX6ev10r%EYNHtMiV?FNIo{BmlK3DwMi4JN~EauP_$&D@9fyJ_M=RFco~H20ufc6 zz3Y$EYJCu|eFC2R;$e zd!c*ls<<}#*U!TNu!jOu=JtN38&ffA5h)|JI5iV&USaZPN1=>^PVh*X<P02{&y_p`YMm7sOX1SGSxp(0NqT!H}_y6t7F4-l;T~_Yk|DIk@X$ z^7z5wAt|Z~v*lWN7U<}!MxgNEC?P+lB3q6kK4t$nIe2Ax0w_NMS)19nD7CKvM=2XA zczH_0_*{q^tpnix;m113Dd9HeQ)yL%onCZ0_fTixl59q1wigHs96@$Q1n$Eni60WU zl}dJ4I8uAu77&Iy9fhg*bMk4r-l3CY)pomSx~1UXo%7QOnBJ7VTQG}O&)9;7X`?UB z>TafWLH|tI&u5~4A(!Hwmy|!b$2-;_t*l)2;st?34EtOlSIEwhD3aTo+FDpIt+t1* zC@55*C^OD;xjznPk1g;Q{8C$cAF%E1fVy=V^EbRe7m%?2<)5j^J>Zc!?>meeoSCLt zS{{g;`xIKG&-$`_f;}ef=?z_evtF0YT@(hNGq&KOPXq_k7(LT@+0ROBhuRNBRM69P zC%rs!!ZX-G8{Tr<>D7))MU(0S##o3l_#L0m-Gy}WRxw=4{ewRFr)E_jKZWeOA zVo}NvQ_2Z~3AuPW|IBhI6d!N!)@go(b$lP;d^2kFCVDR6D>9}HJnmczVt3QX&zZhE z6a-;l-z#F|t}n~3NrMA1HzE0o1oEsD0&7~q%v7$Q>6tU>lmq>W3u+JnC!|2Z!&(<%J z{;kvKr(&#_HW4Ra=;3XZ5!l?{`mJUUeY+1B< zb`rOz+Wn;T`6~O8)B)F}{P(VBT(s*>K0G6;my%*eqEN=hN{2SH<>OIl`fl&JaE&e)k7Q&kuB!l}YSr~oQ0o(C0>rmYxgZ)LV|(9S7$ zR7zerlCJ*z<&Iv#uhDv5R6)z~UQuibKg4&sOiM*Y zW(-aUW4{q<5r|hk`d!6tMuJ5>bvd)l?&b6()f_j6eKz z80hrgkbAlcKNBv*Gg@?tIo&biHN5Q_Mq+j>DL=Z*EI)5}s|GM3t>?l)xLPwtTgW?K zDFpHBCHTLo@72)gE+rPV_G;9|*fh4z3MHor2CTf>;ciysAvLv13FMx6hPVS}a`IoG zOxQM1CJX>9*oCx-{~%{KQp54?B-H?o>^LZy>S7BS;8YBI_C9dqjzgP*y}6B!VvrkA ze2m=O76^k)M6(HVKUvgr8K}<9z?aKq>U+9q1mdFk#%zFSifK#8s<3BJ=Ds}!Crr~?*FB~sktZ3X# zDk(92XHcBlk*_M;}YvkTV03$GDxRrPA)>ihL>@jcqtP75Xru}LZK(>`eMFHvf zEE=6zM)9(lWF`=uw1Mg0SF)*r0i8)iL-X9s!z-xk>u-R5b4A`5KhjkF2{a~ddv1dj zviSq3%W&Woz7SPg5V~pzOW&+<*K@8kB^Du7Lv$q0I#$+}KZHR3=}GBE3CJibS72(i z#wUlXJb1sjOK^$&-HYZNgeN9jn^ zI8GD~e!X<-&{$2iK~AnyDYU(DPj)vdQ2#{d@D>L~dQmj1Wc9~3BmT}R-KWwp zs!s3vk+bL1keH)yFV_RWVEfh8YF*xB#gMh{b!J~P>PNqQ?cXzVI6zvUSc8dsJ@Z-m zu59mQJyRZosdO%tTSI`Sm^_&0zz3>$Ql0vNCW zNS;)5bo>*axTtkQF~QC_)0A!cF>>bnuiEinE#^o2m?IlGDBeUkH^ozfEm2^6EXW9z zz&R3vhk5!)%d~WF*;YX+U{Cv1B=*%f!yFg!g*Rgh5ZZ0uJH9#s>2yMC4$Imp0Fhy7 zyjq=GKbFnH^ZCIy<8RW^s%b}wsivJMUHGxlZXhg+p1vn)6I&cOXxUo>vfkUZ6n0t< zkSJu9^YdC6;DEs8%2nCZU3G)SEBD5WV(}Mi4kk_M4Y6=MtY$D5vlP!UKB0({=rnm2 zsIM+Tqq?mZpVcB5+z%c@MC{kaGBd-P>n&IyPtWN047y6o+%Leq+W+TM@b5IFLde6; z7TL->UOheh+v{t3#Or$4L@Iv5iZD72ueEsCX(oHWV3uB!4lS^Lf=#xxj|tcaz~qgm z`AK+zzuIwv;?JJ}98G8kf#K~Ngd8Wg(7gIb$sBz(bMpSwI%J^YqDuyT+^u>kE|Hma z&B6)4CG$EVOyspxUfwLSczmHu7A_}rxi0n7jnOoL&hQ-{kCDAhSgHf@&}L{gt+EvyuK*AOQA;iI^Hld$@o%*P(#AqyXY z+J9fhN{xtzsbAJ2+0`H*=_&lH=Ttm9@2YTC(%K;k%GcskMccNiS* zi>vPFaIZ|yozizJ9&nponyPmM60`xexF3q(?PX@k{+XA~c^u=b*xhTlq%NvcsSp72 zVCHP5(ebfhVhA%X64_Oub?)lVR8q3B)P+v6f zwy+B#DA@(oj;;c@x&B6H)V0;g+U6p~tn6$c_dC^IGimN!r55|tyzBd>DMZxY$@_fR zAdQyi9T{nQ>JgK5w6?#Ilj+6$*p`rSucwmL#{PlbTo8gT#e+lJp8egm$vnrcM{ z5QO~`t6IENUM5~BEZp6DC}-mzDPjg*o1CfB4bUAaPV0&#oGt zr$mQsMxtRsUE z_6~JrY^+8~x0GS?_(`pcBp-&F+Ov>q=$_7!abC#mO?i1!pn@G7lo4eMk$KzoyKeO$ zOdzGtFWN#oGh~ESC)})~Sl9A*SP=O>0xE*)iF<8Cr)>|#?7iX_xEy%PC|P7ox}*=< zIW+tkGD#ZiD>5+NzdLrH|2e&sc^{(oaqYX1ov zQ$n^I9j|HXD@w=w0jnXUFHW$(eEUJCMEe0$m}a8qruruRNMZieRb4CS-(E|XNAx2U9=V6qJc4OIg9Z%pmQ*NQ@r|i zeE)LM&Di@bJ&6Pxz0OB^XR66f<6bSc9Qy+&#PmvtgX#J7+5Y?>vr4_p4f5iFayfA+TRW# zrUk=+Egr|{QY zv=YqJ{|OH|o%rbz*Q=R6IkNUMCcL=gh08GSWVayTHc) zExp$Na(eyfpVyBLBcIC$EftA7wl3*8d<*YnoT&OhFO*Nx&b^z2&<#1|+WqIwDeIfN z%u*4Ayyn6s}GY~le#KW^?A!TiC7Rl0zicm~VT$*k% z#=PVcq6Hya*%Hy0i~?Rn>UwYGN(rhZSX5Uz9d2eEg+F=n%a}h!2$6hvn3f;<+1h@)d%u@y^VZS~t zIm1n9+$A2$hi$$gk?tN#El;n$bVC5;H8QeMx0^{Xlx;KGMU?}su_mo+9^6)&0NTDo zzzrho@qngpsES%TEHj{tG46LtvqbI9Jw>B6sXYP$vozKB^m)dPI3*DP5aL=Iz3DsE z!013Cn3EH9{jXk|(Xqe4d-T@6a6h|FrksQB7{!qbO&))vbbTw*~2LMS4-HlmLo=bOodrmEMsS zYOoyPSRm4+Mx+J^k={W?2tBlb5Fj8WgwPW@A#Vjd=XdY#-9PRaZ;UtI81JqTP5AO< ztvT1X*6eFe9n<2m{?*kF3W{=F(Z7ji>z4TI^ndvxVqG8T@pTxlp}319KEW2IoKyPb zxHwX#2GY&;e*YfNg~5UUmnXtLLP7$HkniFNF@=}N;+hRDs3leCJP)G)3Zl==;l_oxk5lGLW3{9y*@EQ`3mM`d&dIm?_pv( zJU0?vRZ-Da=>ZAZG(;L(fEO0g6z_p|b#oJ{KEy9kjB}$;6XU;2y~!=_qYBbI8Vi=M zV_BMZt(@tur@mfu)c`|8L`1N0g-{&tf{Gt*!q>#cV+u_c{wEaKUhW;ER8-2kJ$iHp zlq)F%@msVKU@C72-3e}4*&AW(yUhOK)w*hxo-}!6nG?k}l67Uc!VQ`jzgCAG8 zThUizyuX4~8R97P%~|@B>K8*07Q4ATo(a~lM1F`ez+^rM_m^za?e0Hbz0etY-sb3g z`qdqPh8CN+s8wC|{|Xa5y&8_o&b{C7zOAi2aUF%-%PK3g##ega5=5#JX^jN1i4Iq2 zQyqafLbTIRngcu{k@%^DK!mPtdD{&of4_Hv7c5|?8g1L=*&?uG!oXABT2V2{tX8>! zK%h6ie3^U^ZfOF0H@3gQ%#G>m!mi)xykNQY<;%y22n`uPU4Wwm;Io9UD-WV*9IH!(TpV7~cclBDV8@Ffx!_MVV>bdKQiDA zw)EZE#ino?nJsvuz?$UexViSWQ#9{ACZTMZJ)-aLVHtn=LADiiR)Mw%Nb;+WT^u?? zA}|c>pQg8ac8y6A0@5-UZA+N9Fnc-0;z;{a{pM!Q!M>ZNGkXazR^y)9m5H$JA%%_+ zrwLmW>ue~>2w8qL#t{TXxIMXQTbY@upXeZz9?fQz`=d5#I!FYbxK)O2*+d`G2_@JV z`kLk@5RQSf(+V&th0wqz9+hQVBX%LWN)Uza^!XBbvvA@LUc2d}0^|CtWsUC4cTvJHsg>p)+u*}k=c{`?o% zkjdS)jvD;YQF{4VS=RU}uXJm#r}#<~V5uCOse%j&1NAEx`s=l`pI>Oe;N0et<;Am+ z(zmu9M{0kqfIoO1Nbx{|3!k8osdFSB$CH=kRoxPvKk$cnQ$jt-!=)BC#v)AJu$Vh*` z2zMGBGC^C{EzI6J2e_o_mj{x`_piLSg$iEiaA}TktSB!6?vJxv&O<+bj0Ky$Qu2HX z(%OUY*1TowI@$b+3iG9|&*jUvq~o$LWi>U`!h#-!neCsEPVII9DjfK2qJuDx!TbRYlalrhh3tB_Lsq(A zwDtPDCKXQKb}(NM&n6T?=Dg^ePQU~fVvFA#ARH`V3wGJuDz;X_YE`mpY!@ghMO|p8 zwVTWE^@7R+e}9i5KysX*Vv7sF@Jm04@u~TEC$mTi3l!4_S01%XvpAH=v#`R2;*u?G z+n$a+?CkoG@&-+M`nJ=3r1Sw;3_FHEqJJ_b8B_zWad7+RCvrG3pH_uGTjX+KwHq7)o!qcfd!3AVcP6 zAOQ9intDm!Sk-Q~4<4yCE!+ZfQ~?@o|?D3tXY z&jX{@R(=z18>@TCv#^ioie&>8NP~Nj%7RV%PlojLUNRpBHh|!a-eo|*Jm%DXzU%3E z3`qBVN%Oqg+H6B)xrWBv3erj2;@0@hnD-hQe|d=w;1$gWr{|Ki_&Ia;41>p6dG%dF zmGV^|ty$LAbo;sEO~UE8*19!&E~=wgOR}p*a5|3^z+|M_AP*=0Zu-=u~&F!VTyKfq7^+H zT=PXSLAwy`r5YBd1AT8(tb5~f8pOnPJXtrOJy-e_H3StVo}(-Fci{JstkKBgfu{c6 zf4|~Ko4|CFzP)l&2nq1?a~F&^(!{jASiPBCWa>m*RRr4y)EILM-CtWce#Q@YSFM|1 znvrLhjBasdKr-6x2Z7WDC``<35-e1JR=7!oA0$K^zH;LaSXlf8|I!jkE;5o%F=2Gu zy9Nd-j5s^HNT^e#Ypc<Ke9F@r-x}b6>D&GuJjViwXnv5d?NkQ!M5Qug>5&)5L5zOGg2{nUgY=0BLvc z(;UBHcECSp>4tAvLy@}th2-It`Q42=u#HLJ4WuXUQM5ku2a{{}&)x^IUYXaJu3)Rq z!7I}r^2a4k|A2wwe(zl@-rW5J&S3_x<{Nl$do<$o4x!NuBR4hL^Jm%87HX`}VVh=G z1S`B&?T?Qg$DG+1-#PfivsFyi$;l}kwsCnPSp=%J2*n9`-d?qkw_V6mUdU=RT)_8E z738!SUHQQ$*Yvsqwoypbc9d+S=@-lqk^sWE`?iux1X`jlQBF6vvEKMZa?FDxv7W&^w68 z;k<*-S<`?H%5>i@c*T6Tg)n0x@dwjGPrpE8yJkBO|4s4(VFeb&;K?||fP~r!E7d@Sg4ZYL9zqlHB_o>oIfd2XO z&Dwmq!sG0Rdh4?kP@@!>1qyWeQD*LUUfw?fBw<&)LmZRQz4M*l~O4I4t4whaFs6ojLdN=W1sbr56YNh+4~;sl#@|nk8WgxoNy*#VFqjo8{s?O3;y6K8z}-aW1liaJzu)NYEYz-c+uF+4bYio zpmsxZ>VRbew9m_a{{AF`gBgs%)1TRQGCzYEry9_y@C9;6?N4cU6=U^PL9JYuH(%Ch z_U2!Y*NGg>@)usqDo-4nZ77HySpqUvZfyI9fR%|H#Qux~wT?g=co74K6~<2X3A)vu zKEk{nJ~}#j;WUoCyMYIuxsaA8=M}ssKk8@f-y0uSr2cGqTgvhW_{oERr!9Jh1)h84 z-Jd#9a5#_$%`%9j<#9Z)JH#1J=oSmV&}_bMe(CewrAGq3M?5{?9ZS@aYPZ*4^92_$~r2IA;ts7G#C{9S*zM z^;tH+!-N>&C^M*jf%$_Ew`Q`jc1gPyO9L#c&n&lp+$s)uPA%`(_!2uf|LCD+fuu^u zK!zGd+c)014SV>P(r%o>aZW}5{bttk!a{RoJBU~;;u=n1KaFfG(ZX*n#j)`Ygl}VQ zclvE|im)+}eDEV2V5d%~6%<;2sG2zmV;=~&-EQ!{^)rOGfG^(b<8}3c1h6w22^I?NgCo9_u11?2krac&D&T$slkujb#;S%quKY`;^VrVecX*{1}83b2I(xA zas4h14W0WjOql3DXb!=R{1ua~Ki?9k8LS*DzPnEd;4#V9w}iSI4Yyu;r7IMt?@HYe zfxu*ob}V;4WNIvpj-#S0HD3J|QQBT@qf8#AWNw#woLEq#_8}psgV{H18gk^c^5zf9 zYM2k_?O8bRc~k^Z0_3B`+KpiHnqC1*nB;IQmoHaH*aQY-|zHXM%!h z)lOeylKWm_r(I-TiM>j#yKWuN?%Yq}g%z;|c=i5xds{EZ=X8~yD;*pFY|POkzL$RDA_h;ul=T+DmG{gdH~n0FRufvEXdTaD8GSnWuMAdetNx6Oo;XcJ zdLLZhV<4_D31?{x^29LOeeq(lU{a^^>OSZ%K2AoJ z<(`O|?}(%9P$0pEh;&GiJ$7q%X$Kz+$#~CRJPbn7lFA>S;PC%>(uqoH_k=VAn}g`- zhU~uRLtL25!ogyW*B*DtlX;{a%kK`oZH)*&AjOt~YJs*s?(;q8TO=#vgT%FVSG!KS z{_$aV^P65na$96_d;8zk^5Hrv%DVyzu({7LsNI@Hj7WNO|MWG8!A0zk*q^mfQX*{a zrTCJvzwz$eYyok%GMEh!>1IG`C!6>$(N*`d{x;7QYG&4o<)~xT+0~ErTkpD!v&?Oj z54V=kq%^yx8|%^a|G*L9RXeS~iOh+^4+zUoJh?GQ{3<{JKV6Rns!e4)fBYg>fO=B-mEs z_+D`YfHG|5RHe~P-eDpFfkTF+8nc}RHjp5j#&?fpx)S$3iiI~qBTad42G1=%mN{;< zG2WOZ_qtyVqZE6@1DP)-cr)N-FKUg2mO5sfl0;(C^tTtv}`U1n|-+-7Xx zM$*m+&ULcj+)snyA(DfrGW=y~R&2H++(sn19j^Z_fX8gTI++3)J7=@r(9#ngcAL$s zv9~fyU}FcaJXC3-B7XnhbK-MDPv`5SyP5aF%XrEgywZPr{wN49=C-ubyG!$+psy zu!LP<4%_W@Jg%pfS?kDst9N&3S5f%~GUEMp5o7dAUfwujO|Z{WPYO0f=2%JSkHAME zsiMvIvt3?B^SD|WF7LL4Xx}Q<4-39yIm%(r5%D5szj)}agMbaG4lObNO{}T;7jNGd zI=3-?g)P;vPaigro5abzK+xz^R&jS{JagvuB6n;?DOhq|JZrA4&rJ3qgl(v>_YP7WWn(Xpn^5SU zoC*)S!WR*F?oaMCY}umBs`wyHd&d5eTY@Qi^AjyA8|$QN4T9cTiL(pVNK}$s@q8im zgKVWt+qzOtp2i@4&oCzO)vR@hp=o17e&1J5|8g1O3-5i9)h7^J=pPyZS9z5kTdPE_ zG|46(QR!z0$6N~uh|NTMFAxAY*6S#{2Fv3E3lHTv z0=;dIv7ScbyIcHLTBE)x)U;W=(8TJ`Po?97%~XRFA;?HboK8pM(oIqc+wSJrTU@Ob z(|`7%+AXe!(iRe0W$bChpwgu@_d2THOH;#(U+rLtD3z~vOM!$Qwxd~2Se-Da*mU_~ z*Zn_STgx!0NSsJI_skZyGfpK;z$s!}MvOc!pmj_&fXY10Xn&rtET<@?18(_%+MHd|fG(gjo@4UcJD4LS!7Iw`R2MeAgEkB=VH{ z)r}5=n(NO)Rc36-Al^7PcSsw0L`RvF3*JoL+-A1@a2o=+Bdcej6~yo`5s zb+w9~Zu3tkUGw6cCo%+|iO2$wAm->d@#23W<3Lzz-uc+|GJU5m+Ia8SW3|ltW{D0v zqlcMs823Hmetq}T8x2nT%X2S!pUSk`cMZcnG!FejgNc#C@UY!KAp>@4oJdf>0e0lo z4L$Z!`^$;h-y+|M=MVeN2+5)K)gsQlf52(La4mv%zoJ0-F{M6DY4*bD;}@7;f%6Ys zn1|v{oh2SY8P|jao6Yc(dRX7V29%n$b?Qab+ctmhs3?Q^+bebshCO~CPaSph@$y4% zrQnYC&pxi61*W$yJOug+ksVmjlXW#}+)XOujARwd!~&AY za9R;hPV}Q`!$q?il>~q{m(l7^7RUxtXWDL*xq5hjGn26%irW0sKI1hmeb4XT|Az!0 zySco)Wih#+ceU@K38+igPd^CXM+dKO=kOUQ26zl58>sYEh{*B%rxa65!Ow07NmuuR zxEUd?v&f1pooh8F5DxS}s(ayrMHO&~&n}k#W}<3xMR35X(*j=n+ijhO238Ov-r*ny z38tFuZ7wFwB$CpO0DQKkmJl82cY#?e_pviEntNfi#FifFX1ErC;?QZi&?#>?*2{X< zzr8D(G}o;d`vT~p8N?2XiHB+|HI=Zh0hGB%DXz?$ofRjklO1%VBRNAi%Tp_8*xBUU z$n*;Gh}$ud@B5#CYv=aWl8(xU(d*C-91pY%v;6f`c1Ez*(YEv!TkiMd?3o&&8hyj) zxcjnk{aXYT{(rBa)Ati6OOVLhzyM=gVP$|lrl;4E#8p+aA5Xd#2?xlg?@rTw)E%$n zyZ6KpwVvNMi=|@Oco)L=SLlXK+dH9hy58QX&@!(Dou z2V5vAJw81(KAjTZot;p!MOtqmT=d>NnpUO`*`FmfHMc{ymItc{>BGINtBY$r(PwF^ zClL#MS&bKY$w9YgOWFOQ{vv<2L7%$Y>jJ}2^fd=5Bq?_1S!qSZLzUe=Vr|e~q9N%V z`|;o5osyzLP%WDPD^FQ*0nViKx1Bw$4!>7kG!-}+ag|3{XZ4oM#o6tu*(Kw+4F%JP(pF^L97+VcqoBKIXEA#a&R~NX#m0#qLe43DA0Vv z!Ko}Z8<93r_{_l-ggVK2TA7Nc#?@a{)6`o3Vf<^GuBwe_C;|Vg|Hgtxx`MwkeE}Vw z>D8o&<~^7+@>m#KAL@M?L5%R5ZuO9np$T{pN{zw;3M{KK-nsZm=4{U8M=vc6+J=@t zOcD=6D?(T17jT?!TKXj~2xkuKpMw9|JU6n6z^NftUV32@jdMgE{Sg?Cn41kHUC32U zdms+hW4JOxHVPLdnDV+%9+)lDsjEHJ8Olq;lanGro~o~kmbPUxk`m5st47H252U^) z>9tA5p1yp_!M!fK_7|(!(i(wQfbe!W49(Vy$O|e+#Y2(^o3rO&}1WDi8Ix9C< zS5yta^zk4GZ>uX>=EKY+y`ZnN?iv37$`S39nN1{dknIg;9mU7++BoIWZ~h)m|XcY-h=q2 z_!_V?G8~TUZohr1Oa_Nsfshs92)!%U{frBf=C6q@g@hS*uqGW?4W)Owwe-=~%QL>0n zZF;)7?CZ6o9qMYUcN`8*w)*?C95PX@b>Z>r@ol9qTs@YIZ3$ui(3N68=+V8CaVe*H zt^;B2+^u2>U~d#pLix%4`YMa#3{Mm(=9dwGslYtyIQ&0SldCEiB;xO&3`>&dN9G@y zT!%k;6oy1jK6vu|7bN%30HvGh{d$)95dxoKgJ!Gu6e?hAqetwzNI>S&FFlnh|G3OW zB}r~5?TPO%Q}aen?tf@aMP};@O^udcw5j6CebU*YbW_sVkIWxjj-=Pmje|e_rCDVA zZ@U~>3qbhpjb&4y$FJ#20=TkYtjhRbkN!J6|MUspUzBm^;(tbNJY!sY%+0QiQm+mD z&Ef06{-e(4zQF9eTmAdKkE1waV0dNzH=Qi7?FPdKTA@F<{(>)K@X@N^P>_`qbMqrp zkXaG5Xa2bW#m>^1AlU)bF#CU(#^?S^8t=aTyvSo`_{LEzU4Qx!O3&b~!hy_@Y9NRS zR7S7#keaP+1%c|SSFQ|5coCcpO}{=wsBr5wmC%z-k!#fALO zYRF=&2B8aY1TS38{v}WqB%71Y9s&!DDB+A0ori7vzcL=L{MW@|a9S>i)1Y`}WJg7& zY`Q{74Or%5?Jt<3iET!nHtE0(e8nyd0%D;V?U~n*p3hv6d{Bqbh0}tUPj^Z)%SRW2 z1JQQ)btO&1`w=CTw=*(``5~5(!1pU+!4^YS;NV1n^O~5B>@n&Xqr}{PWM3Ut6Dfc-Ou49h)+8s4FO}MeltoE>PA~r^@9EeezVS zy;`83?)_sH)V^Yp`r{wJWu7`)mK*QWGd8gBcJP^oVSl0|bY1Bj`)Eyh1oZhoD`E93 zHcW)dtKaOBHQu;hE7XkWA69%1!rkK?VjRm7c6N587dE6VqXx;S0Zmb5<-}Pl*iNTY z+^4RXYnlVDGQKNeTiJ$s6G6US1ueZ%H9`yo=AT&e@^qFP8ZWSOTgNpvPDrPsy1I08 z#+9o?YlrZ079*(_Hp)4=%kfL1vdWc4SdbKrf;garw`IPx!}7S0-PY9pL0jWnaa7=y%@xH9b*|K_#?EXt(ZeiICawwE z5h2QYbvr@IFiMlX|3v4XY^x%8IA^O3L%69D3u`mU zhUrZ1nh?tP4y7qvD#5~FA&HPb?u&hbbf^ZBFX z42KMItr6OV$_b8k!ri;ZZ${I(tECv-&U;$Zypsb8V}l_h;g7;|^YSQF1_VUwm@dD5 zMpxHN;9PEQEFV_I-_{kU4Pp$F$Lk1MSrhj<+}=fN83yMc8s@FEOtFEwv8Cgw;M>l& zws5R9bSyo5{d?}BymaFE=`!=G;4AR4s=vecrg>+gW%hUmgd z1z8va9JAN8%1W2iWu&CK_ov|D?TI1F9qENbj-XiRiMhPe+9s9M6LGW^MAuX^Vy+O~ zs6SHda1*f|4ztT=tq;k0?ZBH;aJf$VFyGj2(~0&nCkABO8RP{0kCQR=l%cD zJdEkF!X3;f7Ipd^_WxoqpLtkCYEX%5MWSQbQz;28HrJ|Dq=}o>!VY!7ASoE64rgMr zdYQ_>bMj=Q)Xk??X*9LG=D*U=I9EqUN6D8jo0F5}|32LEe#le{ItWCRln;^|7&tFS zDfLVKlyC3s%y$u?TDzEbE8qz-lIimwRSu590mzg8P#rd(rHOyO+9jT~^-WGjX~-4A ze))38_wVh4WM4T-zu)su_gpI)-@Pl+Lk-2%E!TJ41S0SvGkhPyVi&#KFa3w(vJo@2h?8-_1_(^S4UE7G?}t zueIx)g##dw#s%yg99pQM^HVXD1Q%IOdH;nEv)c@$t(S8nFv-d7W3atBKCQa(#^j`2 z9b;h}^Vze+nRYuJ$e~-jxLJ<{jxv#|urNsJZk0h~*&qzE`tF&Fhw@(;M**TO*g>UI zGs60Vatw6}aaKQL7<29o@pJ`5;irP@;|3cnm1^AK^S8b=w#MviM>&2&S3jd|w4%xp zR}jPZLXv^8w)a5u^u~weWPNk~h6Y-m6Gq5*9Hm=kZeTbAU~y_b6cESJh2QKzf0L61 z0M2-ajzn`WT;4>G9|pajpg&QM-n$ zjGgxE>_X|PSy~3^aJz{*SzqG0cKCQz+2#vY%`Rw}S0)8t9%IV5&yZq1m-;;n)a?qa zAAzmC&5PrcsQ>KtT9d)zROLvutARr5ITBT#^$<=^^Yn)=X(Z&se$NU?6~)x{wKXo< z+&z8W9*K<`=nh{jq#>Ucuv}kqd$sFUv8>W2D|{{*KkPIiwB5+W?| zTAug;^zk}it#pWYAA1SmvM2Yc3CwfYa19u48NN@2^~*} zagxjclq@*HE>G!mW1`%|!IhI|!;?$ecc{$KGZUH_9rT0!X?ABs+f-9{I5Ltk&0kms zA5N`(o2_=MR8B-FKlO4{36_y)T({v*CGsc@6c78Z&&Q-G1xsTL^bydpAcvJZ&eiPRhhejR;C8U|#*bYKX_Whpf#) zMs|C{Mn31Nbk~qVpU$f)D=I^~>C<9RT_&c>J&afYrD8u`+{D-YN0juDKynJzBzC7J zIc5( zdlc(9qHftNHOV$uVmc4)Tf_dZq*0h7ULcQOYRpm(<@K;qdH4SExS!6!{$A4hti#W7 zXw80DQO|%%qeK}6Wo(!|ghyD)5fI$?<(`EkdaN9)9>11w1#V{zi|E=6k+a_~L`%ua z$7MW!II{mGIy8V<@wV7>iL)CXeqfvt_Opj8n2a8QzA6b*RLFS1$<>g%$5=ui_x#KQ zmBLNNnya=1w3N5!Mjcru@G5b`6H4!c>BCyF8;U$wEMg)inboFy1=^5gH|*X-TzkJ{O$R z`Uob{*Zqk&ZsPe^iGu=tn7&3S>R77}n#aA`3)^1X-zP;%mThh9PvN%KyW2^|yAkUz z>y{hmITA*_VcP?F>s`~SKHI3KxfV7;&7wO-r+`ZAbIQ19p18A+1sV2l0yr^=h6Ab) zH#6o#?6bJ8!K-9Ur1%lb{W$*YYks znd{o_tKV73*k7NbUxzDi+&`$^`-XiZ>g&ShrP8?NojaGRmAgL08M2N?cy=WU@aWs@ zuCG_s{flA~$h$Om_iUI{N|YsU*U<9`W08al2@`zntGSV}^|5?G`$!M=0+aRr!j+lM z^JQAGLyPvx<69Hz!-3l*0m^{DN{`b@eR8@)L;5wT?!wEyGFu0$nnAmLmOk4w==!e6 zo_H;*$f3S!lGtI$IvJd%)UX(o9q_n97z?T(vl$?)V?#5K#YIsX36;eXTBTdt`$2eO z^pZg=6C8 zSfP&a(v59->!lq5Vn;>h@pjxpr5j9ysA%S*`4vojhNCf*F)VL8GHk`3*ke5sPBk1h zI#d=-Vgco5>v^*`*>>kk@M>ZsrE+DghP*hO&{Zz+!5@0j&L!at#-ypCq(A(k(|p>Q zm1!h`&d2ImbB(uwrf&lyRn)J3E3V(}|JH2PNc%IXvl~|*AI2M&=on1-avl^A@0(EP z-FoQ(pRI8UkKZJ&I1zi~)<<6JXzDWxLozX$Br+h#{n~&IkKYMM=2jU=Y;>!RJJXDh zv^yikU1j^H+Y#VqQy-B%Tn>Vx^F^iHAg!%B>=cZLXHq!Kp${ z>UFC?Uc4trv{xTKncCGQ(WTGzWA%$VCcTCbIkaU>^#x)2E!IIx;}Sl^W;n6N31MX% zTEBFlxjyErqD3fym--UPJJj#{7dK6Q&5-yRI8kw@PjRGz7{~0n_ZYT0ebRTYHikMV z+)fgZC;05;7Ag>yhn2hh3cIEaR8lNWS+fP-Fc;e(1TtW^mOuu?`pvI3VJg;vl2mvl zAtOUOX5uR@X!5y;N<|RuCDiGmmke$q(>-K8Cf-3Yasoy#SlO!!Rj&DylegN?}xRfi1a45M2nxOoWI?L=UY`CWfpJN`=YG;B{BNcrRP2BtdP)0ohS`8bD}3Hzw~z z@L(GZ4sKzK4C7NZf8_tzVx6%wY8{JX7w)_$NAm&X&NguOnp^OJLD(Vq4x3=y(SQu4+Wa6vwdl`NHjfBT4VT8?$H8)C2V z^AMxX-y?O>!s-XUjW}CkR8lKtCl_A^TUuadq2`*1^?yKg4#Q_ix-ez(FJa9wE%iA}Ke2g(p?5Pu3$dt@eWW%gCNZw+Ork9xsj zVIZ$`B?~PPvdp)$__CQjbbf+)Fpo0jh9-74pImRb$~)+Tq}VK5*e=7QB)XzzhbjsU z#X7t6xUh|3wz=WmJ9|~B(?OKkVV|Fcdge_5w;C$4Zz?9BmG`Kn!}$n{f59mNE81d7 zynAcSyfd%Jw(1PoNi~TfX=RH_!1#dnnT}=U?jlBBf+mWzd>z^cgl_wBjA8JY@*4KL^ii7J- z9U1i~f#}%(aO&w}nPr^P+n^fKTnR(Q`|{HtNNuq?x`B%v<4OVG3R5+QH5*Ue)1gUl z`mlp!Ixe@FieZ$WWO|m6eWuw?d`BMMIRd_0H)MTmF7oEvk*D0`1E2&rR~d(qa{HiH zLT@A?5Qq-sQ14a9Cx4s%{vAo(Vs&`zQvBP<_@x8xo-SP{dwW0RNd^?ECjk_TWU^k4 zVf+5RZc4Y~uvpDpsQQC!lfoQBq5902Z1@hC~JZ|Mp%?<`MV3?l7t~ zVzqtKDI?HYE5`NBrm(dIX2i$pnv2JU%zi9s5| zkQdY~PyrlKjuzdH9i<7`0_sowCtDEr2r8-0fX7;u#-|Mcm-~0 z1`U1YWqEF@ME9C{MGWqm8i~w(&%nT|qx4?cNXPzuD91){3QA*PV~BL^5-)G3k2pAi zQKt1^t}Q0Zr6Q$ft1$!|;a;h)k;6TiZyh^SL=Lrh2MZzLjd#(-TEN_s(rx1CnA`7( zu)JhVUeZD>>b(iJh;kfV3b@3{i$^-`Z7%H?(05d3dcR7<#gBwymx30O5i?72P=RxY zWOVY5$mEnHg`J08*Dx22mdhf`%>~*?pVU7)cP~u(WfnBsP-wupC&vVpV?ox+@sUAn z{Ln|`rG)J%>u1?$W!ZE;KX%fW-e4J5?$rxnAgu}|ud~BZR4RYMr?&A_Ij8A4)XqT0 znl5VhcB`X+)QIzSBXwA9n4R!ON&VjPo>nkWP>d3n;%A{YSG3mm2y|tXiAaU^^=1en zcYI%ow`s?=w08HgaLc6nUe#M%vgbH{#FF7{cqZOIK2_qJ4Zx<+j_quq>EhwAt-G5r zNaEfyA>MJrI6BlD)orGgXoSp`sMZM!AJn7;KZ8apt*?pPw{VdCzJh%*()$7@cQ!H?ThYQ;PJ&J#&@h zfG}ayu5n5fQkrZevy7g6cbsvaMB zw6^8(mFx#ze6und7(OA$ksrI*zTHVlUsrb)RW;Fh-asiW{Gg67H*0FsjfL&%dg8q? z7qh0>9qQ!jpiN0JG4zbOR_A}OeF6_;?~5T^Mk&%qW?XE+(VP$Sp)jC3jdOk5MIiq zNHpu}D{>e$sDTMu-q*J*8G+DwAlfA_`sU{%Ha*08W^C@&Fv_GX zYx>Va>hS1za%!rUE#Z-dhK9bEx!^m(0^F(Ux>g~sjY_?n(ygJ1IWnbvIV~kAnS%Es zq?r^Zmx>yAi5Vr%j;yf3obyK9vw`W&)wMp$?%$mPi=B(~oIzx(Z{M0#pc17vOs#lj zieWfn`h16lnd;>1d?TTwhS>~hEGaGh;p^AuoWUMbheeW2@+;g-o$!@nHMC6@Bq-)& zEL<}kZCU1l4+GwlFg3IXl2IRxspx)LnJ;N+srwkKd;0>eS*TO8YP|Aqa4|VOy)JWD zcKTO$B_(T%c&H#CC`#1cp~W9-s&hmlrBCyuq-?-Kgbn_v*r(ao)>i%5W>!{!OO9wK z_{DsLCg$!TYkqdo%YD&!b8$z|!5rYZn`=eMjl@X7$q}7vI)^GXB{$E>(>1jYiC8m3 z4fVUrdd^)Z-B}8d!WFbvGoT$`%pFSq`gKZIH|<_H{r%_f*DEZ#fe*;h+dB{$$*@lK zRsjEr1!^cZdMbCQDKj$$*xb6P)bHK(qSm>B!oVij{@P9;F<6kvF9$Cv1*sc+$@Gz2 zv=06Ak-D=S@G3pm)qR&U?wK)R!B^A&7g-WKeG-}To-IKY)9Pc?YzHisQ&TdG1yP8r z|Jm5>81`VV#OH##Vc~{@y}gHPMaKU0)G-|hpSbrhWJ_%0PXN?2k$EyFu>5fXF$&n! zbszAZ=_|QKQ%DMh+^QBncC4^gPKh7bDpM^`TZ&ufd72Qy39iAx!994{n>Q=(W=-8W zux1+n*c7g`6cB=p{D*21X$5Wn&+$Wg>y_+ zby8DLot*>C?_%uPBQ@{E28Ss}X-K&ZF-*0oKgX0N-%4{(v|_JmHnx5FQjjWhmuWI& zzAZ+g?CEr34$ld&F7m@$?#)$G=6EKi z;X=Vn6O+SaUxsb>(Q(%*ODBRCFr&uA#JG=^3!Oh7x3f>d76*>`1lzn>Z7UsemzBKn zSy)Oc&Z+96dQ8Z2jfi5v7y|IXn*9B@(M(^W0+wm5P^>CbwK+e(zTWLUMzED-*5uAy~%I}rFalK|^Y z-R~ys3x{tvuTVh$5oLix*ZcS2Z4B2@c}X#k%JxJCWhrd!e)qQ>QKSXvp0_dvir8 z{8|_9`!gyTAz?_BTVfR_m^{nR5VDv=1-@M?VrH9*0<H2wmrXVUx5fAi^H)&qLSxF{Sv0t2Nn(P7CIZeC!gmE|M9bvh{AWcuu5 z4x%E)%x2Z;ab+X!qU+V1as`Fg!BdWU_s-GBM>H-j4~WvGA4cBQG9Klw_%6ABMWI;pFKlOQA@yb8$63KiZ58$Z@V>6bkV5TD~pV1ReuN zM}DvUNv3BjDAx)B0sYXj!De6@`ka|L#mpk6d}VWkB^&K^Mg2j|^Q>A0?o)68g2Gdd z>TK89IT-Biy>qY;2LGCi=*+ zNw`L^vH8Vyd(ZvXXYX$Ds`}AGm7HlZ#o9BdBIoc7!55jjv31wO0;NpP3QIrC;u4QM zrlt-zI}7WcApL=23HU^w{-LO575V&mW?5%`6L}-5w`BE}loSqWbU0~pBV%K_n%Lo( z)oMG;%k*1^ZrRWOly$Gpu_G?r3k;pl^!WGHJAu`QO8)=*@?HfW;LR2bPZ@K{B=RMB y$V^vPcb@=?{M7os#xPWLrlLOqAKF=@pTw2DFL(y+0n3t!NlRV-Zt Date: Wed, 2 Jun 2010 19:33:28 +0200 Subject: [PATCH 02/10] Some corrections by torwil on irc --- .../lumiera_from_outer_space.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/user/lumiera_from_outer_space/lumiera_from_outer_space.txt b/doc/user/lumiera_from_outer_space/lumiera_from_outer_space.txt index 256b86b3d..c81e9115e 100644 --- a/doc/user/lumiera_from_outer_space/lumiera_from_outer_space.txt +++ b/doc/user/lumiera_from_outer_space/lumiera_from_outer_space.txt @@ -5,7 +5,7 @@ Christian Thäter [abstract] ****************************************************************************** -The Lumiera Community creates, a non linear video editing and compositing FOSS +The Lumiera Community creates a non linear video editing and compositing FOSS application for Linux/Unix/Posix Operating Systems, suitable for professional and quality oriented work, building on common open source video, sound and GUI toolkits and libraries, providing flexibility and a high degree of @@ -27,7 +27,7 @@ About this Document This document is meant to be read electronically, it contains a lot hyper-links between explanations denoted by an arrow ->. Lumiera is still in development, we describe here planned feature without explicitly tagging them, -as well some things are not yet worked out. Although this document is heavily +as well some things are not worked out, yet. Although this document is heavily cross-linked we try to start with a broad overview and work out more detailed things towards the end. @@ -44,10 +44,10 @@ some explanation what it means to us: Whatever happens, your work must be safe, protected against software glitches and recoverable. Ideally Lumiera should be very stable and never crash, in practice even crashes or power outages should not - yield in lost work. + result in lost work. Productivity:: - One wants to get thing done, in time, with control over every aspect. + One wants to get things done, in time, with control over every aspect. Getting this together is a important goal for workflow design and usability. @@ -132,11 +132,11 @@ Now its time to take a look at the prelimary Lumiera GUI: image:lumiera_screenshot.png[Screenshot of Lumiera] -Just for the record, the GUI itself is a plugin by itself and only one way to -work Lumiera, it will become possible to create special-purpose GUIs or -control Lumiera in different ways, like a headless rendernode -xref:rendernode[->] or frameserver xref:frameserver[->]. Completely script -driven interfaces for automated processing are also planned. +The GUI is a plugin by itself and only one way to work Lumiera, it will become +possible to create special-purpose GUIs or control Lumiera in different ways, +like a headless rendernode xref:rendernode[->] or frameserver +xref:frameserver[->]. Completely script driven interfaces for automated +processing are also planned. The GUI screenshot you see above is faily default as when you start Lumiera up for the first time (only a 2nd Viewer added). While we support a much more From ec4eabb95f6032d24714fd6e3cdf765bce128604 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 3 Jun 2010 22:31:20 +0200 Subject: [PATCH 03/10] went over the "outer space" draft, expanded on some points also answered some questions inline. Please see all of this as a proposal and feel free to merge in parts.... --- .gitignore | 1 + .../lumiera_from_outer_space.txt | 285 +++++++++++------- 2 files changed, 179 insertions(+), 107 deletions(-) diff --git a/.gitignore b/.gitignore index f66bd5b09..8974116cb 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,5 @@ autom4te.cache semantic.cache wiki/backups/* doc/devel/draw/*.png +doc/user/lumiera_from_outer_space/*.html m4/* diff --git a/doc/user/lumiera_from_outer_space/lumiera_from_outer_space.txt b/doc/user/lumiera_from_outer_space/lumiera_from_outer_space.txt index c81e9115e..40ee454b1 100644 --- a/doc/user/lumiera_from_outer_space/lumiera_from_outer_space.txt +++ b/doc/user/lumiera_from_outer_space/lumiera_from_outer_space.txt @@ -14,7 +14,7 @@ smooth workflow which scales well to larger and more complicated editing projects. This Document outlines the Design from some distance, helping people to understand the Ideas behind Lumiera and understand the tools they get to work with. It is aimed for workflow designers any anyone who wants -to know how the programm works. +to know how the program works in general. ****************************************************************************** @@ -26,8 +26,8 @@ About this Document This document is meant to be read electronically, it contains a lot hyper-links between explanations denoted by an arrow ->. Lumiera is still in -development, we describe here planned feature without explicitly tagging them, -as well some things are not worked out, yet. Although this document is heavily +development, we describe here planned features without explicitly tagging them; +some things are not worked out in detail yet. Although this document is heavily cross-linked we try to start with a broad overview and work out more detailed things towards the end. @@ -42,20 +42,20 @@ some explanation what it means to us: Reliability:: Whatever happens, your work must be safe, protected against software - glitches and recoverable. Ideally Lumiera should be very stable and + glitches and incompatibilities. Ideally Lumiera should be very stable and never crash, in practice even crashes or power outages should not result in lost work. Productivity:: - One wants to get things done, in time, with control over every aspect. - Getting this together is a important goal for workflow design and - usability. + Professionals want to get things done, in time, but optionally with control + over every aspect. Balancing these goals should be the central concern for + workflow design and usability. Quality:: If you work with high quality, cinema grade digital video material you want to be sure that you can deliver this crisp quality without compromise throughout you workflow to your final product. All rendering - must be reproduceable to the bit. + must be reproducible to the bit. Scalability:: Projects and budgets differ, hardware advances, Lumiera must scale @@ -66,8 +66,8 @@ some explanation what it means to us: Soft and Hardware advances at a fast pace. We must not lock into the current state of technology but being flexible to extend the System without breaking compatibility. Projects you create nowadays with - Lumiera should be useabele in foreseeable future, at least there needs - to be a guranteed upgrade path. + Lumiera should be usable in foreseeable future, at least there needs + to be a guaranteed upgrade path. Fundamental Forces @@ -75,50 +75,75 @@ Fundamental Forces // the basic ideas which drive the lumiera design -The Lumiera design is founded on only a few basic principles. Keeping these in -mind will help one understand how that actual more interesting things are -build up on that. +The Lumiera design is guided by a small number of basic principles. Keeping these in +mind will help to understand how actually more interesting things can be built up +on that foundation. + + +Open ended combining of Building Blocks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Lumiera is not so much defined in terms of _features_ -- rather it allows to combine +basic _building blocks._ These basic modules, entities or objects each have a distinct +_type_ explicitly limiting the connections. Within these limits, any conceivable +combination shall be supported without further hidden limitations. + +Lumiera is neither a set of Lego bricks, nor is it the business application +driven by finite usage stories. + + +Medium level Abstraction and Project specific Conventions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +These building blocks within Lumiera create a moderate level of abstraction; a user +may, if desired, directly manipulate through the GUI clips, individual effects, masks, +and even the placements xref:placement[->] used to stitch the objects together, which is +comparatively low-level. On the other hand, these abstractions shield the user from the +actual technical details like format conversions and the accessing of individual channels. + +To complement this approach, Lumiera does _not_ rely on hard wired, global conventions -- +rather we allow to build up project specific conventions and rules xref:rules[->] +to fit the given requirements and preferred working style. To help getting started, +Lumiera will ship with a fairly conventional project template and default configuration. [[graphs]] Rendering is Graph Processing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Processing of Video (and audio) data can be generalized as normal graph -processing (more precisely ``directed acyclic graphs''). Data flows on the -edges of this graphs and is processed in the nodes. +Processing of Video (and audio) data can be generalized as graph processing +(more precisely ``directed acyclic graphs''). Data flows on the +edges of these graphs and is processed in the nodes. image:graph.svg[Example for a graph] When we look at this model we discover that we only need to build -xref:builder[->] such graphs, the nodes themself can be seen as black boxes +xref:builder[->] such graphs, the nodes themselves can be seen as black boxes and will be implemented by plugins xref:plugins[->]. Moreover one can preconfigure subgraphs and handle them as single entity xref:pluginstack[->]. -In Lumiera everything is a graph, the footage you put in will be demultiplexed -xref:demultiplexer[->] at a first node, down to the encoding xref:encoder[->] +In Lumiera everything will be translated into such a graph. Your footage will +be demultiplexed xref:demultiplexer[->] at a first node, down to the encoding xref:encoder[->] and multiplexer xref:multiplexer[->] which assembles the final video. Pulling not Pushing ~~~~~~~~~~~~~~~~~~~ -On a first glance, it looks natural that one sets up the graphs -xref:graphs[->] as described above and then pushes data into the input nodes -whereas the final result can then be seen soon on the output node. Serveral +On a first glance, it looks fairly natural to set up the graphs xref:graphs[->] +as described above and then push data into the system through the input nodes +whereas the final result can then be seen soon on the output node. Several multimedia frameworks use this approach. But it has a lot of shortcomings -which make it inapprobiate for non-linear video editing. +which make it inappropriate for non-linear video editing. Lumiera instead pulls data though the pipe, that is a request starts at the output node and makes it way up to the inputs. This has certain advantages xref:pull[->], explained later. -Don't waste Work +Don't waste work ~~~~~~~~~~~~~~~~ Rendering A/V Data can be quite CPU intensive, to ensure that we do not waste -cpu power by rendering things twice, or the worse, have to throw results away +CPU power by rendering things twice, or the worse, have to throw results away because they couldn't be rendered in time, we use sophisticated caching xref:caching[->] and profiling xref:profiling[->]. @@ -139,9 +164,9 @@ xref:frameserver[->]. Completely script driven interfaces for automated processing are also planned. The GUI screenshot you see above is faily default as when you start Lumiera up -for the first time (only a 2nd Viewer added). While we support a much more -sophisticated screen concept xref:screenconcept[->] to adapt to different -workplaces and workflows. +for the first time (the plan is to add a 2nd Viewer to the default configuration). +While we support a much more sophisticated screen concept xref:screenconcept[->] +to adapt to different workplaces and workflows. Viewer @@ -167,19 +192,22 @@ Transport Controls // possibly as its own gui element // This are devices either controlled by widgets or by some input device (midi -// etc) so their gui may loog differently. +// etc) so their gui may look differently. // Either way they connect to a Play Controler xref.. in the core which // manages playing and cursor positioning. // thus there will be some gui facility to attach Transport controls to Play -// Controllers. Transport controlls are ganged when they attach to the same +// Controllers. Transport controls are ganged when they attach to the same // Play Controler. -// just playing some footage for preview creates a simple internal timelline, +// just playing some footage for preview creates a simple internal timeline, // no magic here. // TODO: bit unrelated, think about how ganging controls in general should // work, also for faders, masks and so on +// Note by Ichthyo: the connection to a fader is handled through the placements, +// which allows to inherit such a control connection. IMHO together with the +// tree-like tracks this removes 80% of the need to gang faders. Timeline View @@ -194,8 +222,16 @@ Timeline View // Q: how to handle interaction, for example when some conversion can only be // done in a lossy way and some conversion node may or may not be inserted // (i mean gui wise)? +// A: this usually is detected at build time, which means the incriminating +// object and exit node is just in scope when the problem is detected. +// My intention was to have a problem flag with accompanying information +// attached to this object, so the GUI can highlight the problem location +// and give a general alert. // TBD: Cursors .. discussion, handling, gui representation +// Note by Ichthyo: we shouldn't focus on cursors, but rather on selections. +// IMHO a playhead or edit marker or similar cursor is just +// a special case of a selection. // Busses @@ -211,17 +247,25 @@ Asset View // Manages all assets available in one project. // * source media/footage/soundfiles // * prepared clips, known subprojects -// * All available effects +// * all available effects and transitions +// * internal artefacts like sequences and automation data sets // First this will be simply implemented showing data loaded into the session // and all available plugins/effects +// The user may build custom effect collections ("effect palette") // (much) Later it is planed to make this a database driven interface, where // the tabs showing things are basically just database queries. Then it // becomes possible to create/extend this by customized queries and augment // assets with all kinds of metadata which can be queried -// this is a sequence, ichthyo may explain this better +// Actually, the same underlying data structure is used to implement the +// asset view with folders, clip bins and effect palettes, and the timeline +// view with tracks, clips and attached effects. Technically, there is no +// difference between a track or a clip bin -- just the presentation varies. +// Timeline contents can be viewed like assets for bookkeeping purposes, and +// the contents of a clip bin can be played like a storyboard + Dark Matter @@ -245,6 +289,20 @@ Session storage // everything is stored in the session +Placements +~~~~~~~~~~ +[[placement]] +Generic mechanism to stitch together media objects. Any placement may contain a list of conditions +how to locate the placed object, examples being time-absolute/relative, relative to another object, +or relative to some specific source media frame. + +All of the session model contents are attached by placement, forming a large tree. Placements are +to be _resolved_ to find out the actual position, output and further locational properties of an object. +Missing placement information is _inherited_ from parent placements in the session tree. This causes +a lot of relational and locational properties to be inherited from more global settings, unless defined +locally at a given object: time reference point, output destination, layering, fade control, audio pan,... + + Rendering Engine ~~~~~~~~~~~~~~~~ // rendering @@ -293,8 +351,8 @@ Pulling a Frame // constrain viewer // proxy -// viewer circruit -// render circruit +// viewer circuit +// render circuit @@ -312,7 +370,7 @@ Pulling a Frame -// TODO Following things need to be integrated nto the document above +// TODO Following things need to be integrated into the document above * [[plugins]] @@ -351,14 +409,10 @@ for intermediate data, to be reused later. Glossary -------- -// NOTE Draft, plese help rephrase/review and sort this terms, shorten +// NOTE Draft, please help rephrase/review and sort this terms, shorten // explanations, the long explanation is the topic of the document above - Viewer:: - the display showing video frame and maybe - some effect overlays (as masking etc.). - Project:: the top-level context in which all edit work is done over an extended period of time. The Project can be saved and re-opened. It is @@ -380,92 +434,119 @@ Glossary Track-head/patchbay:: TODO: better term for this - the box in front of a track allowing to control things on the track, - unfold nested tracks and so on. - +//Note by Ichthyo: while I like the term "patchbay", my concern with this is that +// it has already a very specific meaning in audio applications; and while our track heads +// certainly can serve as a patchbay, that is not the main purpose and they can do things +// beyond that.. + the box in front of a track allowing to control properties of the elements + contained within this track, unfold nested tracks and so on. To a large extent, + it corresponds to the placement of this track and allows to manipulate this placement Timeline:: - the top level element within the Project. It is visible within a + the top level element(s) within the Project. It is visible within a 'timeline view' in the GUI and represents the effective (resulting) arrangement of media objects, resolved to a finite time axis, to be rendered for output or viewed in a Monitor (viewer window). Timeline(s) are top-level and may not be further combined. A timeline is comprised of: - * Time axis (doesnt this belong to the Timeline view only?) + * Time axis, defining the time base * Play Controller (WIP: discussion if thats belongs to the timeline - and if we want a 1:N relation here) - * Busses + and if we want a 1:N relation here). Note by Ichthyo: yes, our current discussion showed us + that a play controller rather gets allocated to a timeline, but isn't contained therein. + * global pipes, i.e. global busses like in a mixing desk * exactly one top level Sequence Time Axis:: - A bar showing the absolute time (in configureable units) within the project - (WIP: not clear if this is an entity or just a conceptual definition) + An entity defining the temporal properties of a timeline. A time axis defines + the time base, kind of timecode and absolute anchor point. Besides, it manages + a set of frame quantisation grids, corresponding to the outputs configured for + this timeline (through the global busses). + The GUI representation is a time ruler with configurable time ticks showed + on top of the timeline view Busses:: - A list of global 'Pipes' representing the possible outputs (master + A list of 'global Pipes' representing the possible outputs (master busses) similar to audio mixing desk. A bus defines the properties of the rendered output (Framerate, Resolution, Colorformat and so on). Busses are part of a Timeline. Sequence:: - A collection of MObjects (TODO: need user-compatible term here) placed - onto a tree of tracks. (this entity was former named 'EDL' an - alternative name would be 'Arrangement' ). By means of this placement, - the objects could be anchored relative to each other, relative to - external objects, absolute in time. Placement and routing information - can be inherited down the track tree, and missing information is - filled in by configuration rules. This way, a sequence can connect to - the global pipes when used as top-level sequence within a timeline, or - alternatively it can act as a virtual-media when used within a + A collection of *Media Objects* (clips, effects, transitions, labels, automation) + placed onto a tree of tracks. By means of this placement, the objects could be + anchored relative to each other, relative to external objects, absolute in time. + A sequence can connect to the global pipes when used as top-level sequence within + a timeline, or alternatively it can act as a virtual-media when used within a meta-clip (nested sequence). In the default configuration, a Sequence contains just a single root track and sends directly to the master - busses of the timeline. Pipe the conceptual building block of the - high-level model. It can be thought of as simple linear processing - chain. A stream can be 'sent to' a pipe, in which case it will be - mixed in at the input, and you can 'plug' the output of a pipe to - another destination. Further, effects or processors can be attached to - the pipe. Besides the global pipes (busses) in each Timeline, each - clip automatically creates N pipes (one for each distinct content - stream, i.e. normally N=2, namely video and audio) PlayController - coordinating playback, cueing and rewinding of a '!PlayheadCursor' (or - multiple in case there are multiple views and or monitors), and at the - same time directing a render process to deliver the media data needed - for playback. Actually, the implementation of the !PlayController(s) - is assumed to live in the backend. RenderTask basically a - !PlayController, but collecting output directly, without moving a - !PlayheadCursor (maybe a progress indicator) and not operating in a - timed fashion, but freewheeling or in background mode Monitor a viewer - window to be attached to a timeline. When attached, a monitor reflects - the state of the timeline's !PlayController, and it attaches to the - timeline's global pipes by stream-type match, showing video as monitor - image and sending audio to the system audio port (Alsa or Jack). - Possible extensions are for a monitor to be able to attach to probe - points within the render network, to show a second stream as (partial) - overlay for comparison, or to be collapsed to a mere control for - sending video to a dedicated monitor (separate X display or firewire) + bus of the timeline. + + Placement:: + A Placement represents a relation: it is always linked to a Subject (this being a Media Object) + and has the meaning to place this Subject in some manner, either relatively to other Media Objects, + by some Constraint or simply absolute at (time, output). Placements are used to stitch together + the objects in the high-level-model. Placements thus are organised hierarchically and need + to be _resolved_ to obtain a specific value (time point, output routing, layering, fade,...) + + Pipe:: + Conceptual building block of the high-level model. It can be thought off as + simple linear processing chain. A stream can be 'sent to' a pipe, in which case + it will be mixed in at the input, and you can 'plug' the output of a pipe to + another destination. Further, effects or processors can be attached to the pipe. + Besides the global pipes (busses) in each Timeline, each clip automatically creates N pipes + (one for each distinct content stream. Typically N=2, for video and audio) + + PlayController:: + coordinating playback, cueing and rewinding of a playback position, visible + as 'Playhead' cursor in the GUI. When in play state, a PlayController requests + and directs a render process to deliver the media data needed for playback. + +//TODO not sure about the term and if it's appropriate to include it here + + RenderTask:: + basically a PlayController, but collecting output directly, without moving a + PlayheadCursor (maybe a progress indicator) and not operating in a + timed fashion, but freewheeling or in background mode + + + Controller Gui:: + This can be either a full Software implementation for a Transport + control (Widgets for Start/Stop/Rev/Ffw etc) or some Gui managing an + Input Device. They share some feature to attach them to controllable + gui-entities (Viewers, Timeline Views) + + Viewer:: + the display destination showing video frame and possibly some effect overlays (masking etc.). + When attached to a timeline, a viewer reflects the state of the timeline's associated + PlayController, and it attaches to the timeline's global pipes (stream-type match or explicitly), + showing video as monitor image and sending audio to the system audio port. Possible extensions are + for a viewer to be able to attach to probe points within the render network, to show a second stream + as (partial) overlay for comparison, or to be collapsed to a mere control for sending video to a + dedicated monitor (separate X display or firewire) High Level Model:: - will be translated by the Builder to the Low Level Model. - - Builder:: - A kind of compiler which creates Low Level/Processing Graphs, by - taking Extents from the Timeline/High Level Model/Sequence and using - the Rules System. - - Extent:: - (TODO: not sure about this term) - A range in the timeline which yields in one Processing graph, commonly - the range between cut points (which require a reconfiguration of the graph). + All the session content to be edited and manipulated by the user through the GUI. + The high-level-model will be translated by the Builder into the Low Level Model for rendering. Low Level Model:: - The generated Processing Graph. + The generated Processing Graph, to be ``performed'' within the engine to yield rendered output + + Builder:: + A kind of compiler which creates Low Level/Processing Graphs, by traversing and evaluating + the relevant parts of the high-level-model and using the Rules System. + + Timeline Segment:: + A range in the timeline which yields in one Processing graph, commonly + the range between cut points (which require a reconfiguration of the graph). + +// Note by Ichthyo: "Extent" sounds somewhat cool, just it didn't occur to me as a term. +// We may well agree on it, if "extent" communicates the meaning better. Up to now, I called it "segment" Assets View:: The windows showing and managing the available things to work with. This are the ingested footage, already composed Clips, available - Sub-Projects, Effects and so on. + Sub-Projects, Effects, Transitions and internal artefacts. Rules System:: Translating the Timeline to the underlying Processing Graphs involves @@ -491,16 +572,6 @@ Glossary some hardware controler, like a extra Keyboard, Midi Mixer, Jog, .. TODO: decide if the main keyboard as special (global) state. - Controler Gui:: - This can be either a full Software implementation for a Transport - control (Widgets for Start/Stop/Rev/Ffw etc) or some Gui managing an - Input Device. They share some feature to attach them to controllable - gui-entities (Viewers, Timeline Views) - - Play Controller:: - An internal component which manages playing and positioning a Cursor. - This is controlled by a Controller Gui. - Cursor:: TBD From 12f6e485146f71811e122668db4ce29a83c744e6 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Fri, 4 Jun 2010 19:30:51 +0200 Subject: [PATCH 04/10] rewrap text to 80 colummns (except for comments) --- .../lumiera_from_outer_space.txt | 211 ++++++++++-------- 1 file changed, 119 insertions(+), 92 deletions(-) diff --git a/doc/user/lumiera_from_outer_space/lumiera_from_outer_space.txt b/doc/user/lumiera_from_outer_space/lumiera_from_outer_space.txt index 40ee454b1..75be10ba3 100644 --- a/doc/user/lumiera_from_outer_space/lumiera_from_outer_space.txt +++ b/doc/user/lumiera_from_outer_space/lumiera_from_outer_space.txt @@ -68,24 +68,26 @@ some explanation what it means to us: without breaking compatibility. Projects you create nowadays with Lumiera should be usable in foreseeable future, at least there needs to be a guaranteed upgrade path. - +< Fundamental Forces ------------------ // the basic ideas which drive the lumiera design -The Lumiera design is guided by a small number of basic principles. Keeping these in -mind will help to understand how actually more interesting things can be built up -on that foundation. +The Lumiera design is guided by a small number of basic principles. Keeping +these in mind will help to understand how actually more interesting things can +be built up on that foundation. Open ended combining of Building Blocks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Lumiera is not so much defined in terms of _features_ -- rather it allows to combine -basic _building blocks._ These basic modules, entities or objects each have a distinct -_type_ explicitly limiting the connections. Within these limits, any conceivable -combination shall be supported without further hidden limitations. + +Lumiera is not so much defined in terms of _features_ -- rather it allows to +combine basic _building blocks._ These basic modules, entities or objects each +have a distinct _type_ explicitly limiting the connections. Within these +limits, any conceivable combination shall be supported without further hidden +limitations. Lumiera is neither a set of Lego bricks, nor is it the business application driven by finite usage stories. @@ -93,16 +95,19 @@ driven by finite usage stories. Medium level Abstraction and Project specific Conventions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -These building blocks within Lumiera create a moderate level of abstraction; a user -may, if desired, directly manipulate through the GUI clips, individual effects, masks, -and even the placements xref:placement[->] used to stitch the objects together, which is -comparatively low-level. On the other hand, these abstractions shield the user from the -actual technical details like format conversions and the accessing of individual channels. -To complement this approach, Lumiera does _not_ rely on hard wired, global conventions -- -rather we allow to build up project specific conventions and rules xref:rules[->] -to fit the given requirements and preferred working style. To help getting started, -Lumiera will ship with a fairly conventional project template and default configuration. +These building blocks within Lumiera create a moderate level of abstraction; a +user may, if desired, directly manipulate through the GUI clips, individual +effects, masks, and even the placements xref:placement[->] used to stitch the +objects together, which is comparatively low-level. On the other hand, these +abstractions shield the user from the actual technical details like format +conversions and the accessing of individual channels. + +To complement this approach, Lumiera does _not_ rely on hard wired, global +conventions -- rather we allow to build up project specific conventions and +rules xref:rules[->] to fit the given requirements and preferred working +style. To help getting started, Lumiera will ship with a fairly conventional +project template and default configuration. [[graphs]] @@ -110,8 +115,8 @@ Rendering is Graph Processing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Processing of Video (and audio) data can be generalized as graph processing -(more precisely ``directed acyclic graphs''). Data flows on the -edges of these graphs and is processed in the nodes. +(more precisely ``directed acyclic graphs''). Data flows on the edges of these +graphs and is processed in the nodes. image:graph.svg[Example for a graph] @@ -121,8 +126,9 @@ and will be implemented by plugins xref:plugins[->]. Moreover one can preconfigure subgraphs and handle them as single entity xref:pluginstack[->]. In Lumiera everything will be translated into such a graph. Your footage will -be demultiplexed xref:demultiplexer[->] at a first node, down to the encoding xref:encoder[->] -and multiplexer xref:multiplexer[->] which assembles the final video. +be demultiplexed xref:demultiplexer[->] at a first node, down to the encoding +xref:encoder[->] and multiplexer xref:multiplexer[->] which assembles the +final video. Pulling not Pushing @@ -164,9 +170,9 @@ xref:frameserver[->]. Completely script driven interfaces for automated processing are also planned. The GUI screenshot you see above is faily default as when you start Lumiera up -for the first time (the plan is to add a 2nd Viewer to the default configuration). -While we support a much more sophisticated screen concept xref:screenconcept[->] -to adapt to different workplaces and workflows. +for the first time (the plan is to add a 2nd Viewer to the default +configuration). While we support a much more sophisticated screen concept +xref:screenconcept[->] to adapt to different workplaces and workflows. Viewer @@ -289,18 +295,22 @@ Session storage // everything is stored in the session +[[placement]] Placements ~~~~~~~~~~ -[[placement]] -Generic mechanism to stitch together media objects. Any placement may contain a list of conditions -how to locate the placed object, examples being time-absolute/relative, relative to another object, -or relative to some specific source media frame. -All of the session model contents are attached by placement, forming a large tree. Placements are -to be _resolved_ to find out the actual position, output and further locational properties of an object. -Missing placement information is _inherited_ from parent placements in the session tree. This causes -a lot of relational and locational properties to be inherited from more global settings, unless defined -locally at a given object: time reference point, output destination, layering, fade control, audio pan,... +Generic mechanism to stitch together media objects. Any placement may contain +a list of conditions how to locate the placed object, examples being +time-absolute/relative, relative to another object, or relative to some +specific source media frame. + +All of the session model contents are attached by placement, forming a large +tree. Placements are to be _resolved_ to find out the actual position, output +and further locational properties of an object. Missing placement information +is _inherited_ from parent placements in the session tree. This causes a lot +of relational and locational properties to be inherited from more global +settings, unless defined locally at a given object: time reference point, +output destination, layering, fade control, audio pan,... Rendering Engine @@ -434,13 +444,16 @@ Glossary Track-head/patchbay:: TODO: better term for this + //Note by Ichthyo: while I like the term "patchbay", my concern with this is that // it has already a very specific meaning in audio applications; and while our track heads // certainly can serve as a patchbay, that is not the main purpose and they can do things -// beyond that.. - the box in front of a track allowing to control properties of the elements - contained within this track, unfold nested tracks and so on. To a large extent, - it corresponds to the placement of this track and allows to manipulate this placement +// beyond that.. + + the box in front of a track allowing to control properties of the + elements contained within this track, unfold nested tracks and so on. + To a large extent, it corresponds to the placement of this track and + allows to manipulate this placement Timeline:: @@ -452,18 +465,20 @@ Glossary is comprised of: * Time axis, defining the time base * Play Controller (WIP: discussion if thats belongs to the timeline - and if we want a 1:N relation here). Note by Ichthyo: yes, our current discussion showed us - that a play controller rather gets allocated to a timeline, but isn't contained therein. + and if we want a 1:N relation here). Note by Ichthyo: yes, our + current discussion showed us that a play controller rather gets + allocated to a timeline, but isn't contained therein. * global pipes, i.e. global busses like in a mixing desk * exactly one top level Sequence Time Axis:: - An entity defining the temporal properties of a timeline. A time axis defines - the time base, kind of timecode and absolute anchor point. Besides, it manages - a set of frame quantisation grids, corresponding to the outputs configured for - this timeline (through the global busses). - The GUI representation is a time ruler with configurable time ticks showed - on top of the timeline view + + An entity defining the temporal properties of a timeline. A time axis + defines the time base, kind of timecode and absolute anchor point. + Besides, it manages a set of frame quantisation grids, corresponding + to the outputs configured for this timeline (through the global + busses). The GUI representation is a time ruler with configurable time + ticks showed on top of the timeline view Busses:: @@ -473,42 +488,47 @@ Glossary Busses are part of a Timeline. Sequence:: - A collection of *Media Objects* (clips, effects, transitions, labels, automation) - placed onto a tree of tracks. By means of this placement, the objects could be - anchored relative to each other, relative to external objects, absolute in time. - A sequence can connect to the global pipes when used as top-level sequence within - a timeline, or alternatively it can act as a virtual-media when used within a + A collection of *Media Objects* (clips, effects, transitions, labels, + automation) placed onto a tree of tracks. By means of this placement, + the objects could be anchored relative to each other, relative to + external objects, absolute in time. A sequence can connect to the + global pipes when used as top-level sequence within a timeline, or + alternatively it can act as a virtual-media when used within a meta-clip (nested sequence). In the default configuration, a Sequence - contains just a single root track and sends directly to the master - bus of the timeline. - - Placement:: - A Placement represents a relation: it is always linked to a Subject (this being a Media Object) - and has the meaning to place this Subject in some manner, either relatively to other Media Objects, - by some Constraint or simply absolute at (time, output). Placements are used to stitch together - the objects in the high-level-model. Placements thus are organised hierarchically and need - to be _resolved_ to obtain a specific value (time point, output routing, layering, fade,...) - - Pipe:: - Conceptual building block of the high-level model. It can be thought off as - simple linear processing chain. A stream can be 'sent to' a pipe, in which case - it will be mixed in at the input, and you can 'plug' the output of a pipe to - another destination. Further, effects or processors can be attached to the pipe. - Besides the global pipes (busses) in each Timeline, each clip automatically creates N pipes - (one for each distinct content stream. Typically N=2, for video and audio) - - PlayController:: - coordinating playback, cueing and rewinding of a playback position, visible - as 'Playhead' cursor in the GUI. When in play state, a PlayController requests - and directs a render process to deliver the media data needed for playback. + contains just a single root track and sends directly to the master bus + of the timeline. + + Placement:: + A Placement represents a relation: it is always linked to a Subject + (this being a Media Object) and has the meaning to place this Subject + in some manner, either relatively to other Media Objects, by some + Constraint or simply absolute at (time, output). Placements are used + to stitch together the objects in the high-level-model. Placements + thus are organised hierarchically and need to be _resolved_ to obtain + a specific value (time point, output routing, layering, fade,...) + + Pipe:: + Conceptual building block of the high-level model. It can be thought + off as simple linear processing chain. A stream can be 'sent to' a + pipe, in which case it will be mixed in at the input, and you can + 'plug' the output of a pipe to another destination. Further, effects + or processors can be attached to the pipe. Besides the global pipes + (busses) in each Timeline, each clip automatically creates N pipes + (one for each distinct content stream. Typically N=2, for video and + audio) + + PlayController:: + coordinating playback, cueing and rewinding of a playback position, + visible as 'Playhead' cursor in the GUI. When in play state, a + PlayController requests and directs a render process to deliver the + media data needed for playback. + +//TODO not sure about the term and if it's appropriate to include it here -//TODO not sure about the term and if it's appropriate to include it here - RenderTask:: - basically a PlayController, but collecting output directly, without moving a - PlayheadCursor (maybe a progress indicator) and not operating in a - timed fashion, but freewheeling or in background mode - + basically a PlayController, but collecting output directly, without + moving a PlayheadCursor (maybe a progress indicator) and not operating + in a timed fashion, but freewheeling or in background mode Controller Gui:: This can be either a full Software implementation for a Transport @@ -517,29 +537,36 @@ Glossary gui-entities (Viewers, Timeline Views) Viewer:: - the display destination showing video frame and possibly some effect overlays (masking etc.). - When attached to a timeline, a viewer reflects the state of the timeline's associated - PlayController, and it attaches to the timeline's global pipes (stream-type match or explicitly), - showing video as monitor image and sending audio to the system audio port. Possible extensions are - for a viewer to be able to attach to probe points within the render network, to show a second stream - as (partial) overlay for comparison, or to be collapsed to a mere control for sending video to a - dedicated monitor (separate X display or firewire) + the display destination showing video frame and possibly some effect + overlays (masking etc.). When attached to a timeline, a viewer + reflects the state of the timeline's associated PlayController, and it + attaches to the timeline's global pipes (stream-type match or + explicitly), showing video as monitor image and sending audio to the + system audio port. Possible extensions are for a viewer to be able to + attach to probe points within the render network, to show a second + stream as (partial) overlay for comparison, or to be collapsed to a + mere control for sending video to a dedicated monitor (separate X + display or firewire) High Level Model:: - All the session content to be edited and manipulated by the user through the GUI. - The high-level-model will be translated by the Builder into the Low Level Model for rendering. + All the session content to be edited and manipulated by the user + through the GUI. The high-level-model will be translated by the + Builder into the Low Level Model for rendering. Low Level Model:: - The generated Processing Graph, to be ``performed'' within the engine to yield rendered output + The generated Processing Graph, to be ``performed'' within the engine + to yield rendered output Builder:: - A kind of compiler which creates Low Level/Processing Graphs, by traversing and evaluating - the relevant parts of the high-level-model and using the Rules System. + A kind of compiler which creates Low Level/Processing Graphs, by + traversing and evaluating the relevant parts of the high-level-model + and using the Rules System. Timeline Segment:: A range in the timeline which yields in one Processing graph, commonly - the range between cut points (which require a reconfiguration of the graph). - + the range between cut points (which require a reconfiguration of the + graph). + // Note by Ichthyo: "Extent" sounds somewhat cool, just it didn't occur to me as a term. // We may well agree on it, if "extent" communicates the meaning better. Up to now, I called it "segment" From 7470b0567e2843a5e636524aeb83c8c783e660ff Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 20 Jul 2010 09:19:33 +0200 Subject: [PATCH 05/10] New 'the inner core' document Describes some of the design decisions and rationales in a rather sketchy way explained. New Developers may find this Document useful to get an idea about how the different components work together. --- doc/devel/the_inner_core/DIR_INFO | 3 + doc/devel/the_inner_core/the_inner_core.txt | 275 ++++++++++++++++++++ 2 files changed, 278 insertions(+) create mode 100644 doc/devel/the_inner_core/DIR_INFO create mode 100644 doc/devel/the_inner_core/the_inner_core.txt diff --git a/doc/devel/the_inner_core/DIR_INFO b/doc/devel/the_inner_core/DIR_INFO new file mode 100644 index 000000000..33f29ceb2 --- /dev/null +++ b/doc/devel/the_inner_core/DIR_INFO @@ -0,0 +1,3 @@ +Internal Design Overview + +Some rather sketchy document about design decisions and rationales diff --git a/doc/devel/the_inner_core/the_inner_core.txt b/doc/devel/the_inner_core/the_inner_core.txt new file mode 100644 index 000000000..36ab1bfb0 --- /dev/null +++ b/doc/devel/the_inner_core/the_inner_core.txt @@ -0,0 +1,275 @@ +Lumiera: The Inner Core +======================= + +[abstract] +****************************************************************************** +The Lumiera Developers have a vision about a modern core for a NLE. Here are +some of the design decisions and rationales in a rather sketchy way explained. +New Developers may find this Document useful to get an idea about how the +different components work together. +****************************************************************************** + + +Overview +-------- + +Lumiera constitutes of a broad range of subsystems. These are roughly grouped +into three layers plus some extra components. This structure is mostly kept in +the source directory structures. + +This three Layers are: + The User Interface:: + User interfaces are implemented as plugins, most commonly one will see + the default GUI. But also scripting interfaces or specialized GUI's are + possible. + + The Processing layer:: + Keeps the Session, generates the rendering graphs for sequences. + + The IO and System interface Backend:: + Manages thread-queues, schedules jobs, does the memory management for the + heavy multimedia data. + +The extra components are: + Lumiera:: + The main program itself, basically acts only as loader to pull the rest up. + + Common:: + Vital components which must be available for pulling the system up, part + of the main program. + + Library:: + A lot of (mostly) stateless helper functinality which is used by all the + rest. + + +Lumiera Main +------------ + + + + +Common +------ + +Config System +^^^^^^^^^^^^^ + +Plugin loader and interfaces +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Lua Scripting +^^^^^^^^^^^^^ + +Library +------- + +Meant to be extended as we go + +Locking +~~~~~~~ + +mutex, condition vars, rwlocks. intentionally no semaphores. + +//sync-classlock.hpp +//sync.hpp + +Time +~~~~ +time handling and conversion at one central point + + +Errors +~~~~~~ + +Error codes + +Memory Pools +~~~~~~~~~~~~ + + +Polymorphic Programming in C +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//vcall.h + + +Unique Identifiers +~~~~~~~~~~~~~~~~~~ + +C++ Exceptions +~~~~~~~~~~~~~~ + + +CLib wrappers +~~~~~~~~~~~~~ + +safeclib.c memory str*() + +tmpbuf + + +Preprocessor Metaprogramming +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +ppmpl.h + + +Algorithms & Datastructures +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Probabilistic Splay Tree +^^^^^^^^^^^^^^^^^^^^^^^^ + + +BTree +^^^^^ + + +Cuckoo Hashing +^^^^^^^^^^^^^^ + +Currently defunct + + + +Hash functions +^^^^^^^^^^^^^^ + +planned + + +Linked Lists +^^^^^^^^^^^^ + +.llist + +.slist + +Cache Lists +^^^^^^^^^^^ + +mrucache.c + +//Undocumented +//access-casted.hpp +//advice.hpp symbol-impl.cpp +//allocationcluster.cpp symbol.hpp +//bool-checkable.hpp +//cmdline.cpp +//cmdline.hpp +//del-stash.hpp +//diagnostic-context.hpp +//element-tracker.hpp +//external +//factory.hpp +//format.hpp +//frameid.hpp +//functor-util.hpp +//handle.hpp +//hash-indexed.hpp +//iter-adapter-stl.hpp +//iter-adapter.hpp +//iter-source.hpp +//itertools.hpp +//lifecycle.cpp +//lifecycleregistry.hpp +//lumitime-fmt.hpp +//lumitime.cpp +//multifact-arg.hpp +//multifact.hpp +//nobug-init.cpp < Date: Tue, 20 Jul 2010 11:31:10 +0200 Subject: [PATCH 06/10] Some more explanations for the library and backend components --- doc/devel/the_inner_core/the_inner_core.txt | 158 +++++++++++++++++--- 1 file changed, 136 insertions(+), 22 deletions(-) diff --git a/doc/devel/the_inner_core/the_inner_core.txt b/doc/devel/the_inner_core/the_inner_core.txt index 36ab1bfb0..29a99c9d1 100644 --- a/doc/devel/the_inner_core/the_inner_core.txt +++ b/doc/devel/the_inner_core/the_inner_core.txt @@ -39,7 +39,7 @@ The extra components are: of the main program. Library:: - A lot of (mostly) stateless helper functinality which is used by all the + A lot of (mostly) stateless helper functionality which is used by all the rest. @@ -53,13 +53,14 @@ Common ------ Config System -^^^^^^^^^^^^^ +~~~~~~~~~~~~~ Plugin loader and interfaces -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Lua Scripting -^^^^^^^^^^^^^ +~~~~~~~~~~~~~ Library ------- @@ -71,6 +72,8 @@ Locking mutex, condition vars, rwlocks. intentionally no semaphores. +macros to put scoped around critical sections + //sync-classlock.hpp //sync.hpp @@ -82,32 +85,61 @@ time handling and conversion at one central point Errors ~~~~~~ -Error codes + * Errors are identified by pointers to static strings. + * Errors are sticky (you cant set a new error unless the pending one got + cleared). + * macros for declaring and defining errors + +.C++ exceptions Memory Pools ~~~~~~~~~~~~ +Fast memory pools for moderately small static sized allocations in highly +dynamic situations. + + * optimized for cache locality + * supporting a destructor callback to free all objects + + Polymorphic Programming in C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //vcall.h +Just a simple macro to call vtable functions with some safety measures + Unique Identifiers ~~~~~~~~~~~~~~~~~~ -C++ Exceptions -~~~~~~~~~~~~~~ +Generating 128 bit non cryptographic strong unique identifiers. + + * having an alternative representation to store a pointer + + * may be extended for a strong (slow) and a fast (weak) variant in future CLib wrappers ~~~~~~~~~~~~~ -safeclib.c memory str*() +Some wrapers for the C memory management functions malloc, calloc, realloc and +free which never fail. In case of an error the resourcecollector in the +backend is invoked to free resources or doing an emergency shutdown. -tmpbuf +Safe wrapers for some string functions from the C-library which also never +fail. NULL strings are propagated to "" empty strings. +Temporary Buffers +^^^^^^^^^^^^^^^^^ + +Provides a small number of round robin buffers which need not to be freed. +Must only be used locally when no deep recursion may use tmpbufs. Using these +wrong (recursively) will crash. + +Very fast and efficient from smallest too hugest allocations. + Preprocessor Metaprogramming ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -120,16 +152,32 @@ Algorithms & Datastructures Probabilistic Splay Tree ^^^^^^^^^^^^^^^^^^^^^^^^ +Self optimizing splay tree + +Advantage: + * can be iterated + * very fast in situations where few common elements are queried most often + +Disadvantages + * provides no own locking, needs to be locked from outside + * (almost) every access is a mutation and needs an exclusive lock, bad for concurrency + BTree ^^^^^ +Generic B+/B* Tree implementation. Details are provided by a vtable at an +actual implementation. + + * Fine grained (block level) locking with different modes + * supports cursors to iterate over the data, in both directions + * exact and inexact searched (whats close before/after something) + Cuckoo Hashing ^^^^^^^^^^^^^^ -Currently defunct - +Currently defunct, to be revieved someday. Hash functions @@ -143,12 +191,21 @@ Linked Lists .llist +Cyclic double linked intrusive list. + .slist -Cache Lists -^^^^^^^^^^^ +Single linked variant. + + +Most Recent used Cachelists +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A list where old entries are recycled from the tail, used things are removed +from the list (ownership acquired) and released back to the head. + +Items not used propagate towards the tail where they will be reused. -mrucache.c //Undocumented //access-casted.hpp @@ -227,13 +284,13 @@ Processing Layer ---------------- High Level Model -^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~ Rules System -^^^^^^^^^^^^ +~~~~~~~~~~~~ Low Level Model -^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~ @@ -241,7 +298,7 @@ Backend ------- I/O Subsystem -^^^^^^^^^^^^^ +~~~~~~~~~~~~~ .OS Filehandles @@ -249,27 +306,84 @@ I/O Subsystem .Files +Lumiera has its own abstract file handles which store the state and name of a +file. The associated filehandle doesn't need to be kept open and will be +reopened on demand. Hardlinked files are recognized and opened only once. + .Memory Mapping +All file access is done by memory mapping to reduce data copies between +userland and kernel. Moreover the kernel becomes responsible to schedule +paging (which will be augmented by lumiera) to make the best use of available +resources. Memory is mapped in biggier possibly overlapping windows of +resonable sized chunks. Requests asking for a contingous set of data from the +file in memory. + + .Indexing .Frameprovider Threadpools -^^^^^^^^^^^ +~~~~~~~~~~~ + +Manages serveral classes of threads in pools. The threadpool is reasonable +dumb. Higher level management will be done by the Schedulers and Jobs. Schedulers -^^^^^^^^^^ +~~~~~~~~~~ -.Realtime +Scheduling Queues for different purposes: .Deadline +Higher priority jobs ordered by a deadline time plus some (negative) hystersis. Jobs are +started when they approach their deadline. Jobs who miss their deadline are +never scheduled here. .Background +Background jobs scheduled by priority and timeout. + + +.Realtime +Timer driven queue which starts jobs at defined absolute times. Timer might be +also an external synchronization entity. + + +Job +^^^ + +a job can be part of multiple queues, the queue which picks them first runs +them. When other queues hit a running job they either just drop it or promote +its priority (to be decided). Profiler -^^^^^^^^ +~~~~~~~~ + +Collects statistic about system load, helps to decide if job constraints can +be fulfilled. + +Things to watch: + * cpu utilization + * memory usage (swapping, paging) + * I/O load, latency + + + +Resourcecollector +~~~~~~~~~~~~~~~~~ + +Handles system errors related to resource shortage. There are serveral classes +of resources defined. Other subsystems can hook in functions to free +resources. Has multiple policies about how aggressive resources should be freed. + +If no one cares it does a final abort(). So all systems should hook better +recovery here in! + + + + + From bc36b12b999d7410d41d0bcb7bc8634ae82b5830 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 22 Jul 2010 07:02:14 +0200 Subject: [PATCH 07/10] Write a bit about resource management --- doc/devel/the_inner_core/the_inner_core.txt | 28 ++++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/doc/devel/the_inner_core/the_inner_core.txt b/doc/devel/the_inner_core/the_inner_core.txt index 29a99c9d1..5c464d9ff 100644 --- a/doc/devel/the_inner_core/the_inner_core.txt +++ b/doc/devel/the_inner_core/the_inner_core.txt @@ -359,10 +359,23 @@ them. When other queues hit a running job they either just drop it or promote its priority (to be decided). -Profiler -~~~~~~~~ +Resource Management +~~~~~~~~~~~~~~~~~~~ -Collects statistic about system load, helps to decide if job constraints can +Running Lumiera requires a lot different resources, such as CPU-Time, Threads, +IO Bandwidth, Memory, Address space and so on. Many of this resources are rather +hard limited and the system will return errors when this limits are hit, but +often one does not even reach this hard limits because performance will +degrade way before coming into the realm of this limits. The goal for Lumiera +is to find a sweet spot for operating with optimal performance. Thus we have +some facilities to monitor and adjust resource usage depending and adapting to +the system and current circumstances. + + +Profiler +^^^^^^^^ + +Collects statistic about resource load, helps to decide if job constraints can be fulfilled. Things to watch: @@ -371,9 +384,16 @@ Things to watch: * I/O load, latency +Budget Manager +^^^^^^^^^^^^^^ + +resources need to be distributed among a lot subsystems and jobs. Each of this +component can become part of a budgeting system which accounts resource usage +and helps to distribute it. Resource usage is only voluntary managed. + Resourcecollector -~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^ Handles system errors related to resource shortage. There are serveral classes of resources defined. Other subsystems can hook in functions to free From e476102467bc98cf8564b198ce93ce19c061bfdb Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 2 Aug 2010 18:21:02 +0200 Subject: [PATCH 08/10] RFC: new doc structure --- .../DeveloperDocumentationStructure.txt | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 doc/devel/rfc_pending/DeveloperDocumentationStructure.txt diff --git a/doc/devel/rfc_pending/DeveloperDocumentationStructure.txt b/doc/devel/rfc_pending/DeveloperDocumentationStructure.txt new file mode 100644 index 000000000..be34174f5 --- /dev/null +++ b/doc/devel/rfc_pending/DeveloperDocumentationStructure.txt @@ -0,0 +1,108 @@ +Developer Documentation Structure +================================= + +// please don't remove the //word: comments + +[grid="all"] +`------------`----------------------- +*State* _Idea_ +*Date* _Mon Aug 2 18:03:25 2010_ +*Proposed by* Christian Thaeter +------------------------------------- + +[abstract] +******************************************************************************** +I describe here how to bring the Lumiera Developer Documentation into an simple +hierarchical structure. Previously we accumulated a lot Documentation which +ended in quite a few different places. This should be tidied up. +******************************************************************************** + +Description +----------- +//description: add a detailed description: + +I propose to reorganize the developer documentation in the following way: + + * make a 3 (or more, see below) level documentation structure: + 1. The entry level becomes the 'Lumiera: The inner Core' document which shall + not go into details but give a hint what everything is made for. This + will be the first introductional doc for new developers. + 2. second level are the RFC's which descibe the design as planned on a + general level, not going (except for some example snippets) into + implementation details. + 3. the third level is the doxygen documentation which describes what + actually got implemented in detail. This can be further split into + an external reference and a internal part. + +We using test-driven-development, our tests are our specifications. This leads +to the idea that ideas, design and intentions for tests should be documented +there too. In a higher level abstract human written form. I propose to use my +pipadoc documentation extractor (that means, writing asciidoc within the code as +special comments) for this. + + +Tasks +~~~~~ +// List what would need to be done to implement this Proposal in a few words: +// * item ... + + * Go over the old content of the asciidoced tiddlywikis, integrate it either in + the "Lumiera: The inner Core" document or write single RFC's for them. + * The 'proc' tiddlywiki is a bit special, we need a plan how to integrate this. + Possibly making a own document-dir for this, or refactor it in plenty RFC's. + This is ichthyos decision. + * Decide how to proceed with the UML model + + + +Pros +^^^^ +// add just a fact list/enumeration which make this suitable: +// * foo +// * bar ... + +Much easier entry to the whole developer documentation. Reading the "Inner Core" +document should be sufficient to get a good idea about the Lumiera design and +layout. All details are linked from there and thus easily findable. + + +Cons +^^^^ +// fact list of the known/considered bad implications: + +There are some open ends yet, doxygen for example doesnt integrate nicely, we +possibly can't link to single doxygen entities since these have no permanent +link (to my understanding, to be investigated). Other parts like the UML model +are not yet decided and moving the other existing content over needs some (not +really much) work. + +Alternatives +------------ +//alternatives: explain alternatives and tell why they are not viable: + +Wait for a miracle that our docs become well organized on its own. + + +Rationale +--------- +//rationale: Describe why it should be done *this* way: + +This approach fits nicely into our overall infrastructure and the way we wanted +to do things. Using git and asciidoc mostly, making the developer documentation +part of the source tree and reasonable easy available/maintainable to +deveoplers. + +//Conclusion +//---------- +//conclusion: When approbate (this proposal becomes a Final) +// write some conclusions about its process: + + + + +Comments +-------- +//comments: append below + + +//endof_comments: From f9e42c53a60880bb2e5c1aa6d7a64bb00762645a Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 16 Oct 2010 01:59:47 +0200 Subject: [PATCH 09/10] comment on the RFC 'new doc structure' --- .../DeveloperDocumentationStructure.txt | 42 +++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/doc/devel/rfc_pending/DeveloperDocumentationStructure.txt b/doc/devel/rfc_pending/DeveloperDocumentationStructure.txt index be34174f5..1f88d130e 100644 --- a/doc/devel/rfc_pending/DeveloperDocumentationStructure.txt +++ b/doc/devel/rfc_pending/DeveloperDocumentationStructure.txt @@ -26,7 +26,7 @@ I propose to reorganize the developer documentation in the following way: * make a 3 (or more, see below) level documentation structure: 1. The entry level becomes the 'Lumiera: The inner Core' document which shall not go into details but give a hint what everything is made for. This - will be the first introductional doc for new developers. + will be the first introductory doc for new developers. 2. second level are the RFC's which descibe the design as planned on a general level, not going (except for some example snippets) into implementation details. @@ -58,8 +58,6 @@ Tasks Pros ^^^^ // add just a fact list/enumeration which make this suitable: -// * foo -// * bar ... Much easier entry to the whole developer documentation. Reading the "Inner Core" document should be sufficient to get a good idea about the Lumiera design and @@ -70,7 +68,7 @@ Cons ^^^^ // fact list of the known/considered bad implications: -There are some open ends yet, doxygen for example doesnt integrate nicely, we +There are some open ends yet, doxygen for example doesn't integrate nicely, we possibly can't link to single doxygen entities since these have no permanent link (to my understanding, to be investigated). Other parts like the UML model are not yet decided and moving the other existing content over needs some (not @@ -80,7 +78,8 @@ Alternatives ------------ //alternatives: explain alternatives and tell why they are not viable: -Wait for a miracle that our docs become well organized on its own. +Spring 2010 we discussed and decided an overall website and documentation structure. +We could just stick to that. Rationale @@ -90,11 +89,11 @@ Rationale This approach fits nicely into our overall infrastructure and the way we wanted to do things. Using git and asciidoc mostly, making the developer documentation part of the source tree and reasonable easy available/maintainable to -deveoplers. +developers. //Conclusion //---------- -//conclusion: When approbate (this proposal becomes a Final) +//conclusion: When approbated (this proposal becomes a Final) // write some conclusions about its process: @@ -104,5 +103,34 @@ Comments -------- //comments: append below +* The general idea of having three levels, with 'The Inner Core' as entry point, + looks OK for me. +* beyond that -- we had a detailed discussion about the overall website structure, + which includes the documentation. Why should we overthrow these results now and + re-start the discussion? Lets just stick to this agreed on structure! +* especially I don't like the way this proposal tries to squeeze everything into + an completely uniform structure. It is simply not true that the RFCs are just the + second level, and doxygen would cover the 3^rd^ level. Look at the existing + documentation to see why. + - RFCs are a 'kind' of document, not a 'hierarchy level.' Indeed, our existing + RFCs span all three hierarchy levels, and this is OK so and should remain this + way. (And yes, I like the RFCs much and want to retain them) + - RFCs are well suited to topics requiring discussion and agreement by the whole + core developer team. I see no point in 'pseudo-RFC-ing' the individual design + decisions only relevant for an isolated part of the application and without + any potential for discussion. + - similarily, in the TiddlyWiki, besides just working notes (``extended brain'') + you'll find finished text pages belonging to all different levels, from very + high-level conceptual down to explanation of technical details, with + cross references and tags for categorisation (and this will be retained + when asciidocing the content). +* so my conclusion is rather having one overview text, and then the split into + *conceptual* and *technical* documentation, each of which has a separate sub + structure not necessarily congruent to the structure on the other half. RFCs, + UML model and doxygen are just separate and consistent bodies of documentation + and can be referred to from the main documentation. (I agree with the observation + regarding permanent links into doxygen. But I can't imagine there isn't some + existing solution to this problem) + -- link:Ichthyostega[] 2010-10-15 //endof_comments: From 56f3d547a7b13b5999db452bbdb6db793800732a Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 16 Oct 2010 02:03:06 +0200 Subject: [PATCH 10/10] ignore asciidoc generated html --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 8974116cb..fcdb5aa83 100644 --- a/.gitignore +++ b/.gitignore @@ -20,5 +20,9 @@ autom4te.cache semantic.cache wiki/backups/* doc/devel/draw/*.png +doc/*.html +doc/devel/rfc_pending/*.html +doc/devel/rfc/*.html +doc/user/*.html doc/user/lumiera_from_outer_space/*.html m4/*