diff options
Diffstat (limited to 'examples')
-rw-r--r-- | examples/.gitignore | 1 | ||||
-rw-r--r-- | examples/cat.c | 2641 | ||||
-rw-r--r-- | examples/cat.h | 13 | ||||
-rw-r--r-- | examples/dmabuf-capture.c | 850 | ||||
-rw-r--r-- | examples/foreign-toplevel.c | 358 | ||||
-rw-r--r-- | examples/gamma-control.c | 195 | ||||
-rw-r--r-- | examples/idle-inhibit.c | 233 | ||||
-rw-r--r-- | examples/idle.c | 197 | ||||
-rw-r--r-- | examples/input-inhibitor.c | 189 | ||||
-rw-r--r-- | examples/input-method.c | 402 | ||||
-rw-r--r-- | examples/layer-shell.c | 653 | ||||
-rw-r--r-- | examples/meson.build | 133 | ||||
-rw-r--r-- | examples/multi-pointer.c | 340 | ||||
-rw-r--r-- | examples/output-layout.c | 295 | ||||
-rw-r--r-- | examples/pointer-constraints.c | 260 | ||||
-rw-r--r-- | examples/pointer.c | 403 | ||||
-rw-r--r-- | examples/rotation.c | 277 | ||||
-rw-r--r-- | examples/screencopy.c | 261 | ||||
-rw-r--r-- | examples/screenshot.c | 237 | ||||
-rw-r--r-- | examples/simple.c | 185 | ||||
-rw-r--r-- | examples/tablet.c | 381 | ||||
-rw-r--r-- | examples/text-input.c | 394 | ||||
-rw-r--r-- | examples/toplevel-decoration.c | 253 | ||||
-rw-r--r-- | examples/touch.c | 286 |
24 files changed, 9437 insertions, 0 deletions
diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 00000000..38582982 --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1 @@ +/compositor/protocols diff --git a/examples/cat.c b/examples/cat.c new file mode 100644 index 00000000..cc1403d8 --- /dev/null +++ b/examples/cat.c @@ -0,0 +1,2641 @@ +/* GIMP RGBA C-Source image dump (cat.c) */ + +#include "cat.h" + +const struct gimp_texture cat_tex = { + 128, 128, 4, + "[\227\017\377L\206\001\377M\212\002\377T\227\011\377V\231\010\377W\224\001\377[\222" + "\001\377T\212\001\377P\211\001\377M\203\001\377P\212\001\377Q\217\001\377K\210\001\377" + "K\210\001\377N\214\001\377Q\217\002\377W\226\001\377X\224\001\377U\214\001\377U\216\001" + "\377[\225\003\377Y\221\002\377W\217\001\377^\230\005\377^\230\006\377`\231\011\377Z" + "\225\003\377X\221\002\377Y\221\003\377X\220\003\377^\227\007\377Z\225\004\377Z\226\002" + "\377W\217\001\377Y\224\002\377X\222\002\377W\220\001\377[\227\001\377c\241\004\377a\237" + "\003\377Z\230\001\377Y\222\001\377Z\220\001\377X\216\001\377[\231\005\377j\246\025\377" + "_\232\010\377U\214\000\377o\242\026\377k\234\013\377g\231\001\377c\222\001\377X\213" + "\005\377_\221\023\377V\214\010\377T\216\002\377U\222\002\377Q\211\001\377J|\001\377W" + "\214\003\377j\235\006\377o\243\004\377g\235\002\377X\217\002\377X\226\002\377U\221\001" + "\377T\210\002\377V\212\001\377V\216\002\377Z\226\002\377Y\221\001\377[\221\002\377g\234" + "\014\377d\232\016\377g\240\032\377[\226\022\377\\\224\020\377g\235\026\377\\\225" + "\005\377V\221\002\377U\212\002\377Y\217\001\377Z\220\001\377Y\221\001\377Y\226\002\377" + "W\227\001\377P\217\001\377O\217\002\377V\231\004\377X\230\003\377[\231\004\377X\217\001" + "\377Z\215\002\377Y\212\002\377[\214\001\377\\\215\002\377]\220\001\377]\227\002\377]" + "\233\001\377X\220\001\377X\217\001\377X\215\001\377^\234\001\377]\237\002\377U\221\001" + "\377R\214\001\377S\217\001\377T\220\001\377P\217\001\377P\224\001\377O\216\001\377M\210" + "\001\377V\225\001\377S\216\001\377S\216\001\377S\224\001\377N\220\001\377Q\226\004\377" + "S\227\013\377Y\235\023\377a\241\025\377`\240\015\377]\234\005\377V\227\002\377Y\233" + "\010\377W\231\011\377P\222\002\377R\217\001\377Y\237\021\377S\232\010\377K\224\002" + "\377L\222\001\377P\214\002\377]\222\001\377]\224\002\377U\217\001\377L\212\001\377K\206" + "\001\377Q\213\001\377T\222\001\377U\220\001\377V\224\001\377V\223\001\377Y\223\001\377" + "[\223\001\377Z\221\001\377Y\222\001\377X\225\001\377V\222\002\377U\210\002\377^\225\001" + "\377i\240\013\377g\236\020\377h\240\023\377T\223\002\377R\216\001\377V\215\001\377" + "[\225\001\377Y\226\001\377[\227\001\377Z\227\001\377Z\226\002\377^\226\005\377e\232\014" + "\377\\\225\004\377a\233\005\377_\231\002\377m\246\013\377a\232\003\377_\226\002\377" + "\\\223\001\377X\224\001\377]\235\012\377c\241\016\377^\231\002\377_\222\002\377f\235" + "\006\377s\252\012\377j\242\001\377b\233\002\377a\235\006\377_\232\011\377V\220\002\377" + "T\210\002\377T\216\001\377S\216\001\377U\220\002\377e\234\005\377k\241\004\377n\244\004" + "\377s\252\014\377a\234\003\377c\235\010\377W\217\001\377U\204\001\377X\212\001\377" + "[\217\001\377]\225\001\377[\224\001\377W\216\002\377V\216\003\377T\214\002\377R\212\002" + "\377T\214\002\377U\213\001\377\\\223\005\377e\235\014\377W\221\002\377W\220\001\377" + "Y\220\001\377W\213\001\377V\214\001\377V\217\001\377W\227\002\377V\227\001\377U\227\001" + "\377V\231\003\377N\211\001\377S\215\001\377W\216\001\377T\210\002\377Q\204\002\377W\213" + "\001\377Z\217\001\377Z\216\000\377[\225\002\377b\243\013\377V\220\001\377T\207\001\377" + "U\214\001\377[\231\002\377\\\236\002\377U\220\001\377M\207\002\377N\207\001\377Q\215" + "\001\377S\216\001\377V\226\002\377U\216\000\377V\212\002\377c\233\001\377]\221\002\377" + "V\215\001\377X\230\001\377S\226\001\377L\215\001\377I\211\001\377L\217\001\377T\225\004" + "\377j\244\014\377l\246\013\377X\226\001\377T\225\004\377\\\235\016\377c\243\025\377" + "^\236\012\377K\223\002\377M\230\007\377S\235\016\377N\227\007\377P\215\001\377^\224" + "\001\377`\226\001\377Z\225\001\377Q\216\001\377M\210\001\377V\216\002\377]\227\001\377" + "_\232\001\377]\226\001\377[\223\001\377Z\222\001\377Y\216\001\377Y\216\001\377X\225\001" + "\377W\226\001\377V\216\001\377T\210\001\377]\225\001\377o\246\014\377e\235\012\377" + "b\236\014\377S\222\001\377T\213\001\377W\220\001\377W\223\001\377W\216\002\377\\\231" + "\002\377c\235\011\377l\242\027\377e\233\022\377d\234\020\377Y\223\003\377b\235\007" + "\377b\233\003\377f\237\004\377b\233\001\377b\232\002\377`\232\001\377]\235\001\377^\237" + "\005\377Y\227\002\377U\211\001\377]\220\002\377_\225\001\377c\240\001\377l\250\005\377" + "b\237\002\377^\233\001\377W\223\002\377W\221\001\377T\214\001\377T\217\001\377Z\225\005" + "\377]\230\002\377a\233\002\377b\234\001\377k\245\011\377l\247\014\377\\\227\003\377" + "g\240\015\377V\213\001\377P\202\001\377T\212\001\377Z\224\001\377Z\226\003\377\\\231" + "\010\377T\220\014\377L\207\004\377L\200\002\377Q\203\001\377^\223\003\377Y\216\001\377" + "^\224\004\377p\247\026\377]\227\005\377Y\222\001\377X\222\001\377V\213\001\377W\213" + "\001\377X\220\001\377[\233\001\377X\231\001\377O\212\002\377S\220\001\377S\211\001\377" + "V\216\001\377W\214\002\377O\204\002\377U\213\001\377Z\217\002\377\\\225\001\377Z\223" + "\001\377U\221\003\377g\247\027\377S\224\002\377O\213\001\377U\223\001\377Y\230\001\377" + "\\\234\001\377Y\226\001\377Q\215\001\377O\207\001\377S\214\001\377V\217\001\377Y\225" + "\001\377X\214\001\377_\223\001\377i\237\001\377_\223\001\377[\222\001\377Y\227\002\377" + "V\226\001\377K\206\001\377H\203\002\377J\211\001\377T\224\003\377j\244\014\377i\244" + "\010\377]\234\003\377T\222\001\377U\226\002\377\\\236\012\377a\242\012\377H\211\001" + "\377E\214\001\377I\225\010\377V\240\021\377Q\232\002\377Y\224\001\377\\\222\002\377" + "X\224\001\377Q\215\001\377P\212\001\377W\216\001\377_\226\001\377a\226\001\377^\224\001" + "\377Z\221\001\377X\217\002\377S\210\001\377U\214\001\377[\227\003\377X\227\001\377U\221" + "\001\377W\216\001\377^\227\001\377h\243\002\377`\231\001\377Z\226\002\377U\214\001\377" + "W\217\001\377Y\222\001\377X\221\001\377X\226\002\377W\227\002\377X\227\004\377U\223\005" + "\377U\220\002\377V\222\001\377V\222\001\377\\\235\004\377]\236\003\377X\226\002\377Z" + "\225\002\377`\237\001\377`\241\002\377]\235\001\377Y\232\002\377X\224\001\377U\212\001" + "\377W\214\002\377Z\221\002\377Y\216\001\377d\240\005\377`\233\003\377Z\226\001\377^\232" + "\003\377Z\227\002\377X\222\001\377c\234\010\377i\242\014\377\\\227\003\377]\235\003\377" + "[\234\002\377d\244\015\377e\244\017\377Z\230\004\377j\246\017\377W\215\001\377S\205" + "\002\377X\223\003\377j\244\037\377l\246/\377~\261P\377\224\301r\377j\236\063\377" + "M\201\001\377S\207\001\377[\222\002\377T\214\000\377`\233\013\377i\243\024\377`\233" + "\014\377h\241\027\377e\240\023\377U\217\002\377V\213\001\377[\230\002\377Z\231\001\377" + "N\210\002\377H\177\002\377W\225\001\377Y\220\001\377Z\217\001\377V\214\001\377R\210\001" + "\377]\234\001\377_\231\002\377Z\222\001\377Y\223\001\377V\223\001\377c\244\020\377Y" + "\233\007\377R\223\001\377U\224\001\377Z\232\001\377^\235\001\377]\234\002\377Y\232\002" + "\377R\222\001\377T\223\001\377W\230\001\377W\230\002\377W\213\001\377h\240\001\377h\236" + "\001\377_\222\002\377\\\221\002\377[\231\002\377X\231\001\377O\220\001\377K\213\001\377" + "O\217\002\377b\236\015\377_\233\007\377Z\227\002\377_\240\004\377U\217\002\377T\221" + "\001\377S\222\001\377U\221\001\377K\203\002\377F\202\001\377D\212\001\377K\225\004\377" + "O\232\003\377R\230\002\377U\225\001\377T\223\001\377P\211\001\377K\204\001\377R\211\001" + "\377X\223\001\377[\231\001\377[\233\001\377X\222\001\377S\212\001\377M\200\002\377U\214" + "\003\377^\226\012\377X\225\005\377Y\232\006\377V\222\001\377\\\225\001\377d\240\001\377" + "_\226\001\377Z\220\001\377X\221\001\377Y\222\001\377[\216\001\377\\\217\002\377^\233" + "\002\377V\225\001\377R\221\001\377T\215\001\377V\220\001\377Z\224\001\377X\222\002\377" + "W\225\001\377^\240\007\377V\224\001\377V\216\001\377^\236\002\377b\243\004\377[\233\003" + "\377X\230\004\377\\\234\011\377V\222\003\377U\216\001\377X\215\001\377[\217\001\377" + "h\240\005\377i\245\005\377]\227\001\377^\230\002\377Z\217\001\377[\221\001\377k\243\011" + "\377e\236\007\377W\223\001\377c\243\014\377[\234\005\377f\244\017\377f\241\015\377" + "b\236\012\377n\251\024\377W\217\001\377V\216\005\377e\237\040\377t\254B\377|\260" + "T\377\230\305y\377\250\317\222\377o\242<\377P\210\002\377^\224\006\377\\\226" + "\006\377Q\221\003\377b\241\024\377a\241\020\377S\224\005\377e\240\030\377l\245\033" + "\377Z\222\001\377]\223\002\377`\232\001\377[\226\002\377P\204\001\377T\211\001\377_\231" + "\001\377^\224\002\377^\224\001\377[\224\002\377Y\217\001\377Z\225\001\377Y\220\001\377" + "Z\221\001\377X\224\001\377R\215\001\377X\231\005\377`\241\012\377S\221\001\377R\214" + "\001\377W\226\001\377[\227\001\377_\237\002\377`\242\002\377W\226\001\377Y\232\002\377" + "g\246\011\377a\237\003\377Z\220\002\377e\236\002\377_\226\001\377X\220\001\377X\223" + "\001\377[\233\001\377Z\233\002\377V\230\002\377Q\220\001\377b\235\015\377m\247\025\377" + "Z\232\004\377U\224\001\377[\234\004\377R\220\001\377R\220\001\377R\225\001\377V\221\001" + "\377M\200\001\377M\205\002\377L\207\001\377N\217\002\377N\217\001\377J\217\002\377P\230" + "\004\377O\227\003\377O\215\001\377E\201\001\377N\205\002\377Q\223\002\377`\242\021\377" + "R\225\002\377T\223\001\377T\215\001\377T\205\001\377^\222\010\377b\226\015\377]\231" + "\014\377]\235\011\377V\223\001\377Z\221\001\377c\233\001\377b\231\002\377`\226\001\377" + "]\225\001\377Y\216\002\377[\213\002\377^\222\001\377b\235\003\377[\223\002\377Y\225\001" + "\377Z\223\002\377]\223\002\377]\222\002\377]\227\002\377[\230\002\377a\243\010\377W" + "\230\002\377R\217\001\377Z\234\003\377h\251\017\377e\245\022\377^\233\017\377`\234" + "\025\377]\230\017\377i\243\032\377d\235\016\377]\224\001\377i\241\002\377i\243\002" + "\377b\233\001\377_\233\002\377X\222\001\377W\223\001\377c\237\017\377h\243\026\377" + "\\\234\014\377`\240\015\377Y\233\003\377^\235\004\377]\231\004\377c\235\007\377f\242" + "\016\377]\232\016\377n\250/\377q\253<\377w\256H\377\177\263Q\377\234\307z\377" + "\244\315\211\377g\241+\377O\216\002\377U\222\003\377S\222\003\377N\217\001\377_\241" + "\020\377Z\235\011\377Q\220\002\377W\226\003\377\\\231\003\377d\236\003\377k\237\001\377" + "f\233\001\377_\225\001\377X\213\002\377]\225\001\377f\236\002\377c\231\001\377`\234\002" + "\377]\234\001\377W\217\001\377V\214\001\377V\223\001\377T\223\001\377T\224\002\377K\203" + "\002\377N\212\001\377_\240\004\377X\222\001\377W\222\001\377Y\225\002\377W\220\001\377" + "Z\227\001\377`\242\003\377^\241\003\377`\241\004\377h\247\007\377c\242\003\377]\231\001" + "\377^\234\001\377S\220\001\377R\216\001\377U\225\001\377Z\231\002\377`\233\002\377[\225" + "\003\377W\213\002\377h\235\016\377e\240\015\377[\233\003\377X\232\003\377\\\235\005\377" + "V\225\002\377S\222\002\377Z\234\001\377b\235\001\377L~\002\377P\205\001\377O\206\002\377" + "Z\223\001\377Y\226\001\377N\210\001\377I\212\001\377R\231\004\377J\213\001\377C}\001\377" + "L\211\001\377V\232\015\377a\242\040\377L\212\001\377N\212\001\377T\217\001\377^\232" + "\003\377a\233\003\377Y\223\001\377T\224\002\377W\232\003\377W\225\001\377\\\225\002\377" + "b\230\001\377e\234\002\377a\226\001\377\\\217\001\377X\214\002\377\\\220\001\377a\232" + "\003\377b\233\002\377[\222\001\377_\233\002\377_\225\001\377`\225\001\377a\225\001\377" + "b\231\001\377\\\227\001\377a\243\005\377`\244\007\377U\224\002\377]\237\003\377b\242" + "\007\377f\246\020\377Z\231\007\377X\225\006\377b\235\022\377w\253.\377\200\263:\377" + "m\244\033\377j\245\002\377g\236\001\377b\232\002\377]\230\001\377X\224\001\377T\220" + "\004\377f\241\034\377b\240\031\377i\250\035\377d\244\021\377Y\230\001\377^\231\001" + "\377]\223\002\377b\231\003\377]\231\005\377^\233\024\377r\253\067\377x\262A\377{" + "\261@\377\202\265I\377\230\305k\377\227\302t\377_\234\026\377P\213\002\377R" + "\213\001\377V\220\002\377W\224\002\377a\241\010\377W\230\003\377N\213\001\377R\221\001" + "\377[\231\001\377c\232\001\377i\240\002\377j\240\001\377[\221\001\377O\202\001\377]\225" + "\001\377c\235\001\377a\230\001\377b\237\003\377_\240\003\377W\216\002\377\\\232\002\377" + "Z\227\001\377U\222\001\377P\216\001\377M\210\002\377Q\207\002\377\\\232\001\377_\233" + "\002\377^\236\001\377Z\224\001\377W\213\002\377[\231\001\377h\246\010\377f\247\014\377" + "W\231\002\377]\237\003\377\\\234\001\377^\233\001\377Z\227\002\377V\225\001\377U\230" + "\001\377Z\233\001\377\\\233\002\377c\240\002\377d\232\004\377^\223\005\377^\226\007\377" + "[\231\004\377]\233\003\377`\237\005\377^\235\003\377^\236\002\377\\\235\002\377_\240" + "\001\377`\230\002\377Ey\002\377H\201\001\377N\210\001\377R\216\001\377Z\231\001\377U\221" + "\001\377N\211\001\377N\221\000\377J\212\001\377G\202\001\377G\212\001\377R\231\012\377" + "X\233\021\377I\202\001\377M\212\001\377O\221\001\377W\227\001\377_\240\001\377]\223" + "\001\377X\223\001\377W\227\001\377X\226\002\377^\231\001\377d\237\001\377i\247\002\377" + "\\\231\001\377W\216\001\377X\220\001\377Z\227\002\377f\246\011\377\\\231\002\377Y\224" + "\002\377]\227\001\377^\222\002\377c\225\001\377e\230\001\377b\227\001\377^\227\001\377" + "b\243\003\377h\252\012\377]\236\001\377^\240\001\377Z\233\001\377]\235\002\377c\244" + "\012\377g\244\020\377b\236\022\377i\243\037\377u\253\060\377}\262\060\377o\251" + "\013\377f\234\002\377`\223\001\377e\235\006\377e\233\021\377q\247\063\377y\261F\377" + "l\245\062\377o\253*\377f\246\024\377Z\231\002\377c\235\001\377a\221\003\377n\243" + "\013\377s\247\034\377g\237\037\377s\253\064\377~\264?\377x\254\065\377\177\263" + ";\377\204\265C\377q\246)\377V\224\000\377W\223\002\377T\216\001\377V\217\001\377" + "\\\227\001\377e\241\005\377W\221\001\377M\200\002\377S\220\002\377]\233\001\377b\226" + "\002\377j\234\002\377i\240\002\377\\\226\001\377R\207\001\377]\230\001\377b\233\002\377" + "_\224\002\377f\240\002\377`\233\002\377[\222\001\377c\232\002\377e\240\001\377V\213\002" + "\377R\212\001\377S\215\001\377[\226\001\377`\237\001\377^\235\001\377Y\233\001\377X\230" + "\001\377U\212\001\377[\227\001\377j\250\007\377b\242\004\377S\215\002\377Y\226\001\377" + "a\242\002\377a\240\001\377X\222\001\377Y\227\001\377^\242\001\377]\234\001\377_\234\002" + "\377c\237\001\377f\237\004\377b\227\005\377a\230\005\377_\232\003\377f\240\004\377m\246" + "\006\377g\242\001\377p\251\005\377l\246\003\377c\232\002\377a\232\001\377<p\001\377J\204" + "\001\377I\206\001\377I\206\002\377Q\222\001\377V\233\001\377Q\223\001\377J\224\002\377" + "L\225\005\377G\220\001\377C\210\001\377P\227\005\377R\223\004\377N\207\002\377O\216\002" + "\377P\221\001\377T\224\001\377^\236\001\377\\\224\001\377X\221\001\377V\223\001\377X" + "\230\001\377_\233\001\377m\250\001\377t\257\004\377b\234\001\377Z\225\001\377X\222\001" + "\377[\230\002\377k\251\014\377Z\227\002\377[\222\001\377[\217\002\377`\225\002\377d" + "\234\001\377c\231\002\377^\223\001\377]\223\001\377^\233\002\377e\246\004\377f\245\002" + "\377i\245\001\377e\237\001\377_\227\002\377_\240\003\377\\\234\005\377d\243\024\377" + "b\237\024\377m\246\035\377i\246\017\377g\243\003\377h\240\001\377d\230\001\377n\245" + "\017\377u\252*\377x\257E\377\201\271V\377t\257;\377a\242\023\377c\244\012\377" + "Z\227\002\377c\236\001\377j\240\004\377x\256\033\377}\262\062\377n\244.\377\201\263" + "D\377~\263?\377l\245$\377|\265/\377k\246\030\377[\226\002\377Y\225\001\377[\227" + "\001\377Y\226\002\377Y\220\001\377d\235\002\377h\241\001\377]\222\001\377Z\222\002\377" + "]\232\002\377^\225\001\377j\240\001\377p\247\003\377f\242\002\377Z\231\001\377Z\231\002" + "\377\\\232\001\377_\227\002\377d\235\001\377l\246\001\377d\231\001\377a\227\002\377]" + "\220\001\377e\234\001\377Z\220\001\377U\214\001\377X\223\001\377]\233\002\377\\\232\002" + "\377b\244\010\377N\214\000\377V\230\001\377[\231\001\377[\231\001\377g\247\004\377a" + "\240\002\377Y\220\001\377b\237\002\377k\250\002\377g\243\002\377^\224\002\377`\236\001" + "\377a\240\001\377d\242\001\377d\235\002\377f\237\001\377h\236\003\377\\\222\001\377h" + "\236\005\377m\243\005\377y\257\021\377s\251\015\377l\243\005\377q\252\010\377g\240" + "\003\377_\223\001\377h\241\002\377>p\001\377M\207\001\377H\204\002\377D}\001\377I\210\001" + "\377S\226\001\377N\224\002\377K\222\002\377\\\241\025\377H\217\003\377D\210\001\377" + "U\233\004\377S\223\001\377X\223\001\377W\216\001\377S\216\001\377X\227\002\377\\\233" + "\002\377Z\222\001\377Y\227\002\377V\227\002\377^\237\010\377]\234\002\377l\245\002\377" + "u\256\003\377d\231\002\377\\\217\002\377Y\216\001\377c\237\004\377{\262\026\377j\240" + "\003\377f\225\001\377e\222\002\377i\234\002\377h\240\001\377a\231\002\377]\226\001\377" + "\\\221\001\377\\\223\001\377_\236\002\377c\237\001\377h\244\001\377d\235\002\377^\226" + "\001\377_\234\001\377Z\230\002\377c\243\016\377a\235\017\377o\251\027\377g\241\005\377" + "g\242\001\377l\246\002\377f\235\000\377j\242\013\377p\246'\377v\253A\377\217\300" + "d\377w\261;\377Y\233\001\377e\250\005\377]\236\001\377_\237\003\377p\254\026\377x" + "\263(\377p\255)\377b\236\036\377|\262<\377s\252-\377\\\233\010\377m\253\023" + "\377d\241\005\377\\\231\002\377[\230\001\377Y\231\001\377\\\227\001\377c\231\001\377" + "k\237\001\377p\247\002\377k\243\002\377e\241\002\377^\231\001\377i\243\001\377p\252\002" + "\377o\246\005\377a\233\002\377_\232\001\377b\236\002\377d\236\002\377b\233\001\377s\255" + "\013\377x\261\013\377j\241\002\377a\225\002\377Z\214\002\377_\225\002\377d\236\001\377" + "b\232\001\377b\240\001\377]\232\001\377X\225\002\377c\245\016\377S\223\002\377[\233" + "\002\377[\226\002\377c\237\004\377n\254\010\377a\242\001\377`\226\001\377h\241\001\377" + "v\256\002\377r\247\001\377j\241\001\377e\236\001\377c\234\002\377f\242\001\377f\236\001" + "\377f\234\002\377d\233\001\377a\225\002\377i\240\003\377k\242\003\377z\261\031\377~" + "\263\037\377h\240\003\377j\244\002\377d\235\002\377`\220\001\377i\243\001\377Cu\002\377" + "I\201\001\377F\201\001\377E{\002\377K\206\001\377U\225\001\377R\226\001\377J\221\001\377" + "R\231\011\377H\220\004\377E\212\002\377R\230\002\377V\226\001\377Z\221\001\377O|\001\377" + "P\203\001\377[\223\001\377`\232\001\377^\226\001\377Z\233\002\377R\226\001\377\\\235" + "\014\377c\243\014\377c\240\001\377l\251\001\377c\235\001\377Z\223\001\377X\223\001\377" + "i\246\010\377x\260\017\377j\235\001\377h\224\002\377h\230\001\377h\236\001\377c\231" + "\001\377Z\223\002\377Z\231\001\377[\226\001\377^\230\001\377a\242\003\377]\237\001\377" + "Y\230\001\377Z\225\001\377_\236\002\377c\240\001\377d\240\002\377d\242\007\377\\\231" + "\006\377d\237\012\377q\255\015\377i\243\002\377k\250\002\377f\243\003\377a\236\010\377" + "f\240\037\377s\254>\377\203\271Q\377s\256\062\377\\\235\003\377h\252\012\377a" + "\242\005\377^\236\003\377n\253\027\377\200\273\060\377j\251\027\377\\\235\006\377" + "]\235\010\377]\235\006\377_\231\002\377e\234\001\377i\240\002\377g\235\001\377a\230" + "\002\377\\\221\001\377d\233\001\377n\246\002\377o\243\001\377p\246\002\377h\241\002\377" + "a\232\002\377k\247\003\377r\255\002\377q\251\001\377j\235\002\377k\243\002\377k\242\001" + "\377j\240\001\377h\234\001\377d\234\002\377x\261\015\377w\261\007\377j\240\002\377_" + "\220\002\377Y\212\002\377V\210\002\377e\236\001\377m\250\002\377l\250\001\377f\242\002" + "\377_\236\005\377b\242\011\377\\\235\003\377]\232\002\377Y\220\001\377n\247\013\377" + "r\254\010\377i\245\001\377k\242\001\377l\241\001\377w\254\001\377x\252\001\377v\256" + "\001\377m\243\002\377d\234\002\377e\236\002\377e\234\002\377c\233\002\377`\227\002\377" + "g\236\002\377p\247\003\377h\234\001\377p\250\015\377z\261\032\377d\240\001\377d\236" + "\001\377e\236\002\377a\224\002\377h\242\001\377G|\002\377K\206\004\377K\211\006\377\071" + "m\001\377N\212\002\377]\237\001\377V\235\001\377M\222\001\377O\226\007\377N\226\007\377" + "I\217\001\377V\233\003\377V\221\001\377N\177\001\377Hu\001\377M}\001\377Y\216\001\377h" + "\241\001\377c\233\001\377[\231\002\377U\227\002\377M\215\002\377Y\230\003\377_\235\001" + "\377g\243\001\377b\235\002\377\\\230\001\377X\224\001\377l\251\012\377n\247\005\377" + "j\233\002\377i\227\002\377k\235\002\377g\236\001\377[\216\001\377U\211\001\377[\230\001" + "\377_\233\001\377`\232\002\377a\243\002\377\\\236\002\377Z\237\001\377Z\232\001\377c" + "\243\002\377o\255\004\377i\245\003\377_\235\001\377\\\233\002\377a\241\002\377i\247\004" + "\377d\241\001\377l\250\010\377e\242\011\377a\237\015\377o\251%\377x\261\066\377" + "v\260\066\377x\262.\377^\236\006\377\\\235\002\377c\245\006\377`\240\003\377q\256" + "\030\377w\263\036\377e\244\007\377b\243\002\377Z\226\001\377]\231\002\377c\236\001\377" + "j\242\002\377m\241\001\377k\241\002\377j\236\002\377f\231\001\377h\235\001\377i\240\001" + "\377h\240\002\377g\244\002\377e\244\002\377j\246\005\377n\251\004\377q\251\001\377o\241" + "\002\377p\241\001\377r\253\002\377p\244\001\377p\243\001\377j\235\002\377h\236\002\377" + "t\257\002\377p\250\001\377j\235\001\377d\223\001\377h\227\003\377]\213\002\377Z\212\001" + "\377i\241\002\377m\247\001\377n\246\003\377o\252\011\377`\241\004\377Z\231\001\377^" + "\231\002\377^\231\001\377p\254\015\377g\245\004\377j\244\001\377p\252\001\377r\245\001" + "\377w\254\001\377{\255\001\377y\262\001\377o\256\001\377a\235\002\377b\234\002\377b\236" + "\001\377`\231\001\377`\227\001\377i\240\002\377m\244\002\377h\236\001\377p\254\016\377" + "r\257\021\377`\237\001\377a\231\002\377c\232\002\377d\227\001\377g\240\001\377J\210" + "\001\377]\233\026\377h\243)\377:j\000\377R\207\002\377b\243\002\377_\242\004\377M\222" + "\001\377N\226\004\377Q\230\005\377Q\227\003\377U\232\003\377R\215\001\377K~\002\377M\200" + "\002\377T\213\001\377a\231\002\377g\236\002\377`\224\002\377]\231\001\377Z\232\001\377" + "Q\215\001\377Q\216\001\377\\\231\001\377f\242\001\377b\231\001\377X\217\002\377Y\225" + "\000\377o\252\012\377f\235\003\377d\227\001\377h\233\002\377h\236\001\377d\240\002\377" + "\\\227\001\377Y\225\001\377^\235\001\377a\234\001\377c\235\002\377c\240\002\377^\234" + "\001\377Z\231\001\377\\\237\001\377a\242\001\377n\252\010\377i\245\010\377\\\235\002" + "\377a\242\001\377d\242\001\377a\233\001\377]\232\001\377i\251\017\377a\241\014\377" + "[\234\010\377l\250\030\377{\264+\377v\260&\377t\261\035\377^\236\003\377\\\230" + "\002\377j\254\012\377c\245\006\377j\251\015\377k\253\014\377c\243\004\377g\251\003\377" + "[\230\001\377Z\227\001\377d\245\001\377h\243\001\377j\235\001\377j\240\001\377m\244\002" + "\377j\243\001\377f\237\002\377h\240\002\377k\245\002\377l\251\003\377f\247\001\377d\242" + "\002\377i\242\001\377n\247\001\377i\234\002\377o\243\002\377x\252\002\377r\241\002\377" + "t\247\001\377n\243\001\377l\240\001\377o\253\002\377j\243\001\377f\236\002\377b\231\002" + "\377\177\255\033\377b\222\006\377U\204\001\377d\233\001\377p\252\002\377j\244\001\377" + "l\253\002\377b\240\001\377a\234\002\377d\233\002\377g\241\003\377m\252\010\377_\237" + "\001\377b\237\001\377h\240\002\377r\246\002\377x\247\002\377\206\267\002\377\200\265" + "\001\377r\254\001\377k\251\002\377e\236\001\377a\232\001\377^\227\001\377a\231\001\377" + "j\241\003\377w\255\020\377z\262\025\377r\256\017\377l\254\014\377\\\236\001\377\\" + "\226\001\377b\233\001\377h\237\001\377l\245\001\377J\210\002\377S\225\016\377o\254-" + "\377K\204\004\377S\217\002\377Z\232\001\377^\241\002\377Y\234\001\377X\236\003\377[\242" + "\011\377\\\242\015\377P\230\003\377P\222\001\377P\212\001\377R\214\001\377[\223\001\377" + "g\236\002\377i\235\001\377^\222\003\377]\231\001\377Y\230\001\377U\226\002\377Q\217\002" + "\377U\224\001\377`\236\002\377c\233\001\377]\221\001\377b\241\003\377q\255\021\377_" + "\233\002\377a\230\001\377e\233\002\377d\234\002\377b\240\002\377c\246\002\377d\247\004" + "\377\\\234\001\377^\235\001\377`\235\002\377a\240\002\377^\233\002\377[\230\002\377a" + "\242\001\377^\237\000\377d\243\012\377j\247\025\377j\250\017\377d\244\003\377e\247" + "\001\377^\232\002\377W\223\001\377\\\240\006\377[\236\003\377Z\234\002\377a\241\006\377" + "s\260\026\377y\266\035\377f\245\006\377a\234\001\377a\235\002\377n\255\007\377j\250" + "\010\377j\247\011\377r\260\021\377f\246\005\377a\243\002\377Z\232\001\377f\246\012" + "\377n\253\011\377h\233\002\377l\241\001\377e\235\001\377d\240\001\377c\241\001\377b" + "\234\002\377j\245\001\377j\246\002\377g\243\002\377i\250\002\377k\245\002\377p\251\002" + "\377o\247\001\377m\241\001\377j\235\002\377q\244\002\377r\242\002\377s\246\002\377n\243" + "\001\377h\237\001\377h\243\001\377e\237\001\377`\233\002\377]\231\002\377j\246\016\377" + "`\230\003\377a\227\001\377g\240\001\377m\252\002\377i\246\001\377i\244\001\377e\235\002" + "\377a\227\002\377i\242\001\377q\253\003\377l\251\003\377b\237\001\377d\242\001\377g\240" + "\001\377m\242\001\377r\244\001\377}\257\001\377\207\271\001\377~\256\001\377t\251\001\377" + "k\242\001\377f\236\002\377b\232\001\377f\237\002\377m\245\003\377o\246\011\377z\263" + "\026\377q\256\020\377q\260\022\377_\241\002\377^\234\002\377e\235\002\377m\245\001\377" + "n\241\001\377V\230\010\377]\236\017\377w\261-\377f\244\026\377S\220\001\377V\222" + "\001\377Z\227\001\377`\234\001\377_\235\002\377[\235\002\377`\245\014\377V\232\003\377" + "W\233\002\377\\\237\001\377Y\233\001\377]\230\001\377d\232\002\377f\232\001\377b\230" + "\001\377^\230\001\377[\231\001\377W\226\002\377X\227\001\377Y\221\001\377e\240\002\377" + "g\236\002\377d\237\001\377m\253\014\377l\253\021\377[\233\001\377b\231\001\377l\237" + "\001\377h\236\002\377c\237\001\377g\250\007\377c\245\005\377\\\236\002\377^\241\001\377" + "\\\234\001\377[\232\001\377[\231\001\377^\232\001\377a\243\002\377Z\235\001\377\\\240" + "\011\377U\231\006\377`\241\012\377f\250\007\377d\247\002\377`\242\002\377V\227\002\377" + "U\232\003\377b\246\011\377\\\236\001\377^\236\001\377i\252\005\377i\251\003\377c\243" + "\002\377b\243\001\377d\245\001\377g\250\002\377a\243\002\377`\241\002\377h\251\005\377" + "e\247\002\377_\235\002\377_\237\002\377d\245\005\377e\236\003\377s\251\001\377w\254\002" + "\377j\241\001\377h\247\002\377a\235\001\377c\234\001\377j\246\002\377n\252\004\377j\247" + "\002\377k\245\001\377l\243\002\377s\255\001\377o\241\002\377k\237\002\377l\236\001\377" + "p\245\002\377m\244\001\377l\244\001\377l\243\001\377i\241\001\377h\237\001\377a\225\002" + "\377_\226\002\377]\224\001\377c\234\002\377j\237\001\377l\235\001\377l\240\001\377p\253" + "\001\377k\242\001\377e\227\002\377f\234\001\377b\226\002\377n\247\002\377s\256\002\377" + "m\241\001\377j\240\001\377j\243\002\377i\240\001\377l\242\001\377q\252\001\377t\253\001" + "\377\210\267\001\377\216\274\001\377{\257\002\377l\245\002\377j\246\001\377j\243\002" + "\377n\244\001\377t\251\005\377u\252\005\377l\245\002\377m\252\006\377r\257\021\377h" + "\246\010\377d\241\002\377f\235\001\377o\245\002\377s\244\001\377O\212\003\377W\227\004" + "\377f\243\022\377r\254\036\377V\223\001\377X\223\001\377Z\230\002\377^\223\001\377" + "a\230\001\377\\\232\001\377Z\237\004\377M\221\001\377P\223\001\377^\243\003\377\\\237" + "\001\377\\\233\001\377b\233\001\377d\241\001\377a\237\001\377\\\234\001\377\\\234\001\377" + "[\224\002\377_\233\001\377_\230\001\377k\246\003\377d\242\004\377]\236\002\377g\250\015" + "\377e\247\015\377[\233\002\377c\237\002\377f\233\002\377f\234\002\377d\242\001\377o" + "\253\017\377f\246\012\377]\236\001\377_\240\002\377Y\225\001\377[\231\001\377`\234" + "\001\377c\237\001\377c\240\001\377[\232\001\377X\232\002\377\\\237\003\377`\242\003\377" + "b\243\004\377d\245\005\377f\250\012\377Z\237\003\377W\231\002\377Y\235\002\377[\235" + "\001\377`\240\002\377b\243\001\377c\242\001\377d\244\001\377c\240\001\377g\246\002\377" + "f\247\001\377`\240\001\377^\241\002\377c\245\001\377h\251\002\377n\253\012\377j\252" + "\012\377b\241\002\377g\242\001\377t\261\002\377q\253\002\377l\247\002\377k\251\002\377" + "b\236\002\377b\236\002\377l\253\012\377}\270\034\377k\250\004\377k\246\001\377m\247" + "\002\377q\256\001\377m\241\001\377n\242\001\377o\242\001\377r\245\001\377q\247\002\377" + "n\246\001\377p\252\001\377l\242\001\377g\235\002\377c\234\001\377`\226\001\377c\227\002" + "\377l\234\001\377m\236\001\377i\231\001\377i\236\001\377i\242\001\377i\241\001\377d\230" + "\001\377h\226\002\377l\233\002\377q\244\001\377t\253\001\377o\241\001\377k\241\002\377" + "j\242\001\377j\243\001\377m\251\002\377m\247\002\377n\244\001\377{\256\001\377\203\266" + "\001\377w\254\001\377m\246\002\377o\246\001\377t\247\002\377y\250\001\377\225\266\023" + "\377\235\274\032\377u\252\003\377j\243\001\377w\264\017\377s\261\013\377g\237\002" + "\377l\242\001\377s\251\001\377s\246\001\377R\212\001\377[\227\002\377c\241\010\377l" + "\247\020\377`\235\002\377Z\225\002\377\\\234\001\377[\222\001\377\\\220\001\377`\235" + "\002\377Z\240\002\377J\223\002\377R\227\003\377V\233\002\377X\226\001\377^\223\002\377" + "a\232\001\377`\231\002\377X\222\002\377X\227\001\377[\233\001\377]\235\001\377\\\233" + "\001\377`\235\001\377k\252\003\377b\234\003\377\\\231\001\377_\243\002\377[\234\001\377" + "Y\224\002\377b\234\002\377b\232\001\377a\231\001\377a\236\002\377_\240\004\377d\247\010" + "\377\\\236\001\377_\236\002\377a\237\001\377c\244\001\377c\240\001\377_\233\001\377\\" + "\234\002\377[\236\001\377a\244\005\377b\244\004\377`\232\002\377d\237\000\377p\254\015" + "\377r\255\031\377[\234\004\377[\234\001\377]\235\001\377`\236\001\377`\235\001\377c" + "\240\001\377c\231\001\377f\246\001\377e\243\001\377g\243\001\377j\245\001\377e\240\002" + "\377_\237\002\377d\245\006\377r\262\022\377w\267\032\377c\244\007\377`\240\002\377" + "d\242\002\377p\257\001\377m\247\001\377h\246\001\377h\247\001\377d\242\002\377`\235\001" + "\377m\255\021\377z\272#\377e\247\003\377i\247\001\377j\237\001\377n\250\002\377m\241" + "\001\377l\237\002\377q\243\002\377s\246\001\377s\246\001\377p\242\001\377n\244\001\377" + "g\236\001\377g\243\001\377e\237\001\377b\227\001\377h\234\001\377n\243\001\377m\244\002" + "\377h\234\001\377g\240\002\377g\245\001\377n\251\002\377o\245\001\377o\236\002\377q\240" + "\001\377r\243\002\377u\254\002\377n\241\002\377m\246\001\377r\255\002\377o\252\002\377" + "j\237\001\377j\237\001\377m\242\001\377t\254\001\377z\257\001\377y\256\002\377t\251\001" + "\377o\241\001\377q\241\001\377v\246\001\377~\255\005\377\206\264\014\377k\242\002\377" + "i\243\001\377w\264\013\377p\256\006\377h\235\002\377n\244\002\377s\250\002\377r\244" + "\002\377e\241\002\377\\\232\002\377\\\235\002\377_\240\003\377]\235\001\377]\226\001\377" + "_\234\002\377\\\222\002\377X\215\001\377a\233\002\377^\240\002\377W\230\001\377Y\233" + "\002\377Y\232\001\377\\\227\001\377^\222\002\377d\233\002\377^\225\001\377X\224\002\377" + "X\224\001\377^\241\004\377i\252\014\377Z\233\002\377^\237\001\377k\254\006\377b\236" + "\002\377^\227\001\377`\242\002\377Y\226\001\377\\\221\001\377d\237\001\377f\241\001\377" + "b\231\002\377^\227\001\377Y\227\001\377Y\233\001\377X\225\001\377\\\233\001\377`\236" + "\001\377c\242\001\377a\237\002\377`\235\001\377^\240\001\377Z\233\001\377\\\237\001\377" + "[\231\001\377_\225\002\377a\234\001\377a\236\003\377a\237\005\377Y\232\001\377\\\234" + "\001\377b\240\001\377a\237\001\377f\244\010\377|\265\034\377i\242\002\377g\242\001\377" + "d\234\001\377i\244\001\377g\237\002\377b\240\001\377\\\236\001\377t\262\033\377\206" + "\301*\377l\254\020\377Z\236\002\377Z\235\001\377a\233\002\377k\243\002\377j\241\001" + "\377g\241\001\377c\241\001\377f\247\001\377a\241\002\377j\254\006\377f\251\010\377i" + "\254\004\377k\247\002\377i\235\001\377l\243\002\377h\234\002\377f\232\002\377g\232\002" + "\377g\232\002\377o\244\001\377n\242\001\377k\245\001\377d\237\001\377c\241\002\377b\231" + "\001\377`\224\002\377b\227\001\377k\244\002\377p\253\002\377j\237\002\377j\243\002\377" + "j\241\001\377p\250\001\377u\254\001\377s\246\002\377j\234\002\377h\233\001\377p\250\002" + "\377o\251\001\377m\244\001\377z\265\004\377r\251\001\377n\242\001\377l\241\001\377i\240" + "\001\377l\243\001\377l\237\001\377w\253\001\377w\253\001\377m\237\001\377o\241\001\377" + "o\241\002\377o\246\001\377n\252\001\377j\240\001\377l\244\001\377y\264\005\377y\262\005" + "\377l\242\001\377k\240\001\377n\245\002\377j\235\001\377a\240\001\377`\233\002\377_\237" + "\001\377[\235\001\377X\227\001\377X\222\001\377[\231\001\377[\225\002\377W\213\001\377" + "\\\223\001\377`\236\002\377\\\230\002\377\\\227\001\377Y\227\001\377\\\231\001\377[\226" + "\001\377a\237\001\377a\237\002\377Z\231\001\377X\226\001\377_\236\002\377m\254\015\377" + "^\240\002\377\\\235\001\377k\254\007\377c\240\003\377_\230\000\377b\243\001\377_\237" + "\001\377Z\222\002\377`\227\002\377d\236\002\377e\241\001\377c\235\002\377a\237\001\377" + "_\234\001\377\\\224\001\377_\231\001\377c\241\001\377b\236\002\377`\235\002\377_\237" + "\003\377d\244\017\377_\236\016\377X\231\002\377X\223\001\377\\\231\002\377a\240\001\377" + "[\230\001\377Y\230\001\377\\\234\001\377a\242\001\377b\242\001\377\\\233\002\377j\251" + "\016\377y\261\035\377j\235\000\377o\243\002\377]\221\002\377f\236\002\377g\244\001\377" + "_\237\001\377e\247\012\377\177\275)\377w\266\040\377b\244\011\377Z\236\004\377X" + "\232\002\377^\231\001\377f\236\002\377f\234\001\377f\241\001\377c\242\001\377j\254\004" + "\377h\250\003\377f\247\002\377c\241\001\377g\241\001\377n\250\001\377o\244\002\377r\246" + "\002\377m\237\002\377c\226\001\377c\226\001\377g\236\001\377o\246\001\377o\243\001\377" + "o\241\002\377m\237\002\377t\252\002\377f\230\001\377b\231\001\377a\225\001\377h\240\001" + "\377j\244\002\377q\254\001\377k\244\001\377i\235\002\377q\250\001\377u\257\002\377o\246" + "\001\377c\230\001\377e\233\002\377p\252\001\377n\247\002\377l\244\001\377t\261\002\377" + "p\253\001\377n\251\002\377l\251\003\377e\236\002\377k\244\001\377j\240\001\377u\254\002" + "\377z\256\001\377t\243\002\377m\235\001\377m\241\002\377s\256\001\377o\255\001\377h\235" + "\002\377n\244\001\377u\252\001\377\177\265\003\377q\245\001\377j\235\002\377i\241\001\377" + "f\236\002\377a\240\001\377`\231\001\377b\241\002\377`\240\001\377X\222\002\377W\220\001" + "\377\\\232\001\377[\225\001\377Y\220\001\377]\226\001\377a\232\001\377c\230\001\377a" + "\226\001\377^\222\002\377b\232\002\377`\234\004\377b\241\006\377e\245\007\377Z\226\001" + "\377[\223\001\377_\237\002\377g\247\003\377f\245\001\377a\235\001\377e\246\002\377a\240" + "\002\377a\231\001\377c\245\001\377a\243\002\377R\214\001\377Y\223\002\377`\234\002\377" + "c\244\001\377b\243\003\377_\240\002\377Z\226\002\377`\230\001\377d\231\001\377n\253\003" + "\377m\255\004\377a\243\004\377V\222\007\377Z\203)\377\213\256]\377g\235\"\377O" + "\220\000\377X\224\001\377\\\233\001\377Z\231\001\377Y\226\001\377Z\226\001\377^\234\002" + "\377a\243\001\377j\253\014\377h\247\007\377`\227\001\377m\243\001\377p\243\001\377Y" + "\217\002\377h\236\001\377h\247\002\377]\235\002\377o\257\032\377x\266\040\377j\253" + "\017\377Z\237\004\377X\236\004\377W\231\002\377\\\234\002\377j\250\007\377c\240\001\377" + "g\246\002\377j\252\004\377n\256\007\377l\254\007\377`\237\002\377c\241\001\377i\240\001" + "\377r\252\001\377w\253\001\377t\243\002\377l\234\001\377e\227\002\377a\225\001\377h\246" + "\001\377k\250\001\377l\241\002\377q\243\002\377t\251\002\377o\242\002\377h\234\001\377" + "c\232\002\377^\226\001\377f\245\001\377e\236\001\377s\260\006\377h\243\003\377g\235\002" + "\377o\247\001\377r\254\001\377j\236\002\377a\226\002\377g\236\001\377n\251\001\377l\246" + "\002\377j\247\001\377o\260\003\377i\251\001\377m\254\005\377z\267\020\377g\246\001\377" + "g\243\001\377j\246\001\377n\244\001\377t\247\002\377{\262\001\377u\245\001\377r\245\002" + "\377r\251\001\377m\243\001\377i\240\001\377n\250\001\377r\253\001\377|\264\002\377u\256" + "\002\377m\241\001\377g\235\002\377i\245\001\377X\227\001\377Y\221\002\377`\237\001\377" + "b\240\002\377\\\222\001\377^\230\000\377`\235\001\377^\225\001\377Y\217\002\377_\226" + "\002\377_\230\002\377`\234\003\377a\230\001\377d\233\002\377g\237\004\377`\233\004\377" + "g\245\020\377b\243\011\377[\232\002\377[\221\001\377_\232\001\377j\250\004\377k\253" + "\004\377b\240\001\377b\241\001\377c\241\002\377d\234\002\377m\256\003\377e\244\002\377" + "W\215\001\377[\222\001\377b\235\002\377c\241\001\377f\251\004\377f\246\005\377`\233\001" + "\377f\235\002\377m\243\001\377w\263\001\377n\251\002\377Z\223\001\377a\220\032\377\335" + "\317\305\377\377\362\365\377\373\370\361\377\225\273W\377S\220\000\377V\222" + "\001\377W\225\002\377Y\225\002\377X\217\002\377Z\232\002\377\\\235\007\377{\272(\377" + "d\240\010\377`\226\002\377l\245\002\377p\251\001\377j\236\002\377n\246\001\377j\251" + "\001\377f\245\007\377i\251\022\377h\250\014\377[\233\001\377^\240\001\377`\242\002\377" + "_\236\002\377i\251\010\377m\254\015\377Z\232\001\377]\235\002\377^\236\001\377_\240" + "\001\377i\254\004\377`\241\001\377a\234\002\377g\234\002\377r\250\002\377o\240\002\377" + "o\240\002\377k\234\001\377g\235\002\377h\246\002\377i\253\003\377h\243\001\377n\245\001" + "\377p\246\002\377q\253\001\377j\235\002\377f\236\002\377c\227\002\377b\231\001\377i\245" + "\001\377g\241\001\377n\256\005\377d\244\004\377f\240\002\377n\243\001\377s\246\001\377" + "m\242\001\377f\230\002\377h\233\002\377m\246\001\377m\245\001\377p\256\001\377m\251\002" + "\377m\247\001\377l\250\003\377v\267\014\377e\247\002\377a\243\001\377`\241\002\377c" + "\233\002\377l\244\001\377s\253\001\377r\252\001\377v\254\002\377o\244\001\377j\234\001" + "\377h\241\002\377o\256\001\377t\264\003\377t\261\002\377q\253\002\377l\246\001\377f\235" + "\002\377q\254\010\377[\230\001\377X\220\001\377[\227\001\377^\230\001\377_\225\001\377" + "a\231\001\377c\242\001\377_\232\002\377]\224\001\377\\\225\000\377e\243\010\377g\250" + "\010\377^\224\001\377e\236\002\377a\232\001\377e\237\004\377l\247\012\377c\236\002\377" + "e\235\001\377f\235\002\377i\242\002\377j\246\002\377k\253\003\377f\246\001\377k\252\002" + "\377j\244\001\377m\243\001\377r\255\002\377d\233\002\377Z\217\003\377W\214\001\377n\242" + "\001\377o\251\001\377g\245\001\377d\240\001\377g\234\002\377o\252\002\377t\255\002\377" + "v\256\001\377n\243\001\377Z\224\000\377\243\264}\377\344\326\333\377\366\352\356" + "\377\373\363\366\377\373\362\363\377\257\311\177\377N\210\000\377Y\225\002\377" + "[\227\001\377Y\226\001\377Z\235\001\377f\250\014\377x\264\034\377r\257\017\377d\237" + "\002\377q\254\002\377s\255\002\377k\236\002\377f\233\002\377d\240\001\377f\250\005\377" + "\\\235\002\377`\241\006\377Y\226\001\377_\237\001\377c\240\002\377d\236\001\377h\250" + "\003\377a\241\002\377]\237\003\377\\\236\002\377W\225\001\377_\233\002\377g\247\002\377" + "d\243\001\377[\222\001\377b\227\002\377i\236\002\377c\227\001\377e\232\000\377f\237\000" + "\377p\253\010\377g\250\003\377g\244\001\377l\243\001\377l\243\002\377o\254\001\377k" + "\251\001\377e\235\002\377d\241\001\377b\240\002\377a\234\002\377j\246\001\377i\237\001" + "\377m\250\001\377h\243\001\377j\243\002\377n\242\001\377p\244\001\377s\251\001\377l\237" + "\001\377m\241\001\377p\245\002\377r\247\001\377w\263\001\377s\250\001\377q\247\002\377" + "o\246\001\377v\267\006\377f\247\003\377]\240\001\377[\241\002\377\\\233\001\377l\246" + "\001\377s\253\002\377s\255\002\377q\254\003\377j\246\003\377c\235\002\377d\242\001\377" + "g\250\002\377k\251\003\377k\245\003\377t\255\011\377s\253\014\377l\247\013\377u\260" + "\021\377b\234\001\377`\234\001\377^\227\002\377a\231\002\377f\241\001\377f\237\001\377" + "i\243\001\377a\227\001\377X\217\000\377e\243\021\377~\271/\377a\233\001\377^\222\002" + "\377a\231\001\377g\235\003\377q\244\007\377m\241\002\377k\236\002\377m\232\001\377n\236" + "\001\377i\233\002\377_\222\001\377_\232\002\377d\246\002\377o\255\004\377r\252\001\377" + "}\261\001\377y\254\002\377^\223\002\377X\216\002\377T\212\002\377u\246\002\377w\255\002" + "\377e\237\001\377e\240\002\377i\237\002\377p\252\001\377h\234\002\377o\244\002\377l\242" + "\001\377V\222\000\377\331\320\317\377\324\303\313\377\341\317\331\377\363\345" + "\354\377\353\332\332\377\364\355\351\377y\251\061\377V\231\000\377W\221\001\377" + "_\236\004\377n\257\023\377p\257\023\377l\254\014\377p\260\013\377j\251\002\377p\252" + "\002\377s\245\001\377l\237\001\377b\226\001\377f\243\001\377j\254\003\377\\\236\001\377" + "Z\234\002\377Y\232\001\377]\234\001\377f\242\001\377e\234\001\377d\244\002\377`\243\002" + "\377_\243\005\377V\234\001\377T\220\002\377f\243\001\377k\250\001\377g\247\001\377]\224" + "\001\377_\227\000\377t\246\027\377\223\272G\377\242\277b\377u\215\071\377^\234" + "\011\377^\237\001\377f\240\002\377m\250\001\377m\252\001\377h\247\002\377d\245\001\377" + "c\243\001\377b\244\001\377]\234\001\377b\244\001\377e\244\002\377g\235\002\377p\251\001" + "\377m\244\001\377l\246\001\377j\237\002\377o\244\001\377t\255\001\377q\250\001\377q\252" + "\001\377p\244\002\377t\253\002\377y\263\002\377y\263\001\377u\253\001\377r\245\002\377" + "r\255\001\377h\240\001\377c\242\001\377e\247\004\377a\234\002\377q\252\002\377v\245\002" + "\377z\260\001\377n\254\004\377m\257\011\377d\243\001\377g\247\001\377g\245\001\377i" + "\245\001\377j\242\004\377~\263\032\377\203\263\040\377\202\264\037\377s\254\013\377" + "g\232\002\377n\245\007\377`\226\002\377`\224\002\377f\242\001\377f\240\001\377g\243\002" + "\377f\236\001\377f\240\003\377\205\274\071\377\200\270\066\377d\233\002\377b\230" + "\002\377`\226\002\377d\233\001\377z\260\015\377m\241\003\377g\226\001\377k\231\002\377" + "n\234\001\377j\234\001\377e\231\001\377`\225\001\377c\240\002\377e\243\002\377h\237\002" + "\377\210\267\001\377y\251\001\377_\225\002\377^\225\001\377X\214\001\377v\247\002\377" + "y\256\001\377e\232\002\377f\233\002\377m\240\002\377l\237\001\377]\221\002\377t\251\001" + "\377t\257\000\377k\233\034\377\326\301\315\377\313\267\301\377\347\331\343\377" + "\367\356\364\377\362\345\352\377\354\332\332\377\357\354\326\377W\221\011" + "\377Q\221\000\377c\244\011\377q\260\030\377e\246\006\377_\240\002\377[\225\002\377" + "d\244\001\377n\247\002\377u\251\001\377u\247\002\377k\236\002\377n\252\002\377l\251\002" + "\377Z\231\002\377T\225\002\377[\234\004\377a\236\003\377f\244\001\377f\240\001\377e\247" + "\002\377^\237\002\377Y\230\001\377U\221\001\377Y\225\002\377d\243\002\377d\241\002\377" + "b\240\002\377X\225\000\377\253\306s\377\363\357\336\377\353\335\332\377\345\326" + "\322\377\311\273\261\377e\212\"\377^\237\000\377d\240\001\377m\250\001\377l\246" + "\001\377b\232\002\377^\226\001\377^\236\001\377k\255\010\377o\257\007\377d\245\000\377" + "c\240\002\377g\234\002\377r\254\002\377k\243\002\377i\243\001\377e\234\001\377l\244\001" + "\377t\260\001\377v\257\001\377v\253\002\377o\240\002\377u\247\002\377z\262\001\377|\262" + "\001\377z\255\002\377r\243\003\377t\250\001\377n\243\002\377j\243\002\377p\254\003\377" + "l\245\001\377v\257\004\377q\245\001\377u\255\002\377t\263\007\377i\252\002\377e\245\002" + "\377o\254\001\377q\252\001\377o\247\002\377l\241\002\377{\257\014\377\204\263\027\377" + "\201\261\022\377r\252\004\377m\245\001\377f\236\002\377b\236\002\377d\236\002\377j\246" + "\002\377i\242\001\377i\242\001\377e\237\002\377t\255\030\377\220\304E\377u\254\032" + "\377g\233\001\377f\226\001\377f\225\001\377f\226\001\377p\252\001\377m\247\002\377c\230" + "\002\377d\232\001\377j\241\002\377g\233\002\377e\236\002\377d\236\001\377e\241\001\377" + "f\241\001\377d\227\002\377\201\261\002\377y\252\002\377g\233\001\377b\232\002\377c\230" + "\001\377u\250\002\377|\260\001\377j\236\002\377g\233\002\377i\235\002\377k\236\001\377" + "e\231\002\377{\256\001\377\203\273\014\377\230\262`\377\317\266\304\377\271\236" + "\252\377\350\332\344\377\360\342\353\377\341\316\325\377\335\307\307\377" + "\334\304\303\377\326\340\261\377`\236\020\377n\255\035\377x\267$\377e\244\004" + "\377a\233\001\377[\220\002\377e\235\001\377n\244\001\377q\245\002\377r\243\001\377t\254" + "\002\377s\253\001\377s\247\001\377d\234\001\377P\221\002\377m\251\003\377l\244\002\377" + "d\234\001\377e\244\003\377f\247\003\377`\240\002\377\\\222\002\377\\\225\002\377^\234" + "\002\377_\241\003\377X\227\000\377s\242\026\377\336\343\246\377\352\326\322\377" + "\335\306\276\377\330\303\273\377\314\271\260\377\330\311\306\377\236\245" + "r\377[\234\000\377g\250\002\377e\243\001\377d\234\001\377b\231\001\377_\230\001\377^" + "\224\001\377b\232\001\377l\251\004\377n\255\003\377h\242\001\377n\243\001\377w\261\001" + "\377m\241\002\377k\242\002\377e\233\001\377m\251\002\377u\260\002\377v\254\002\377u\250" + "\001\377q\243\002\377w\250\002\377}\264\002\377~\262\001\377z\255\001\377n\240\001\377" + "o\247\002\377n\245\002\377j\242\002\377n\252\002\377s\257\007\377n\250\003\377l\244\002" + "\377p\253\001\377s\260\003\377n\256\001\377l\246\001\377n\251\002\377t\256\001\377p\251" + "\001\377o\246\002\377|\262\014\377w\255\010\377m\246\001\377k\245\001\377h\243\002\377" + "e\243\001\377c\235\001\377f\236\001\377x\263\006\377n\242\002\377l\240\001\377d\234\001" + "\377d\231\014\377\212\301B\377l\253\020\377h\244\004\377i\240\002\377l\241\002\377" + "g\230\001\377r\253\001\377l\246\001\377h\247\002\377e\241\001\377o\250\004\377e\234\002" + "\377o\251\011\377s\256\017\377k\251\003\377h\240\001\377k\234\001\377\202\262\002\377" + "s\242\002\377h\234\001\377g\245\002\377j\250\002\377p\252\001\377x\260\002\377r\246\001" + "\377]\225\002\377g\235\003\377f\232\003\377q\244\002\377q\246\001\377i\245\000\377\245" + "\263z\377\321\275\307\377\323\277\313\377\360\345\357\377\362\347\360\377" + "\357\345\352\377\342\314\320\377\341\314\314\377\346\315\303\377\231\272" + "T\377i\246\014\377g\245\005\377_\224\002\377`\227\001\377d\230\001\377i\234\002\377" + "p\243\002\377o\241\002\377o\243\002\377s\255\001\377r\251\001\377q\245\002\377j\236\002" + "\377T\223\002\377v\255\002\377j\242\001\377e\241\002\377i\246\004\377f\242\001\377f\236" + "\002\377d\227\001\377g\235\001\377d\241\002\377]\234\002\377{\254\060\377\365\362\337" + "\377\332\305\277\377\317\265\260\377\330\302\275\377\322\274\272\377\311" + "\262\255\377\301\257\251\377\276\264\242\377U\223\002\377]\236\002\377a\237\002" + "\377c\234\002\377a\234\002\377a\236\002\377`\225\002\377c\237\001\377c\236\001\377g\244" + "\001\377l\243\002\377s\251\001\377{\263\001\377n\240\002\377m\241\001\377j\241\001\377" + "k\242\002\377o\251\001\377o\247\001\377k\243\002\377j\240\001\377p\251\001\377y\262\001" + "\377x\262\001\377x\262\001\377k\237\002\377j\242\001\377j\240\001\377j\243\002\377j\243" + "\002\377m\247\001\377k\242\002\377o\242\001\377s\252\002\377t\244\002\377t\255\002\377" + "u\257\001\377k\242\001\377m\247\001\377i\242\001\377l\245\001\377s\255\005\377f\241\001" + "\377e\243\001\377i\247\001\377g\243\001\377e\243\002\377d\232\001\377o\247\005\377u\261" + "\011\377n\250\001\377n\244\001\377l\242\001\377a\226\002\377u\260\021\377d\245\005\377" + "_\241\003\377k\252\022\377n\252\021\377k\243\005\377o\246\001\377t\252\002\377p\251" + "\001\377k\243\001\377m\244\002\377k\233\002\377j\235\002\377i\235\002\377q\253\003\377" + "y\257\001\377\177\255\001\377\207\264\001\377o\235\002\377e\231\002\377_\222\001\377" + "b\234\001\377m\252\001\377u\257\002\377j\234\002\377_\223\001\377n\242\001\377j\237\001" + "\377k\242\001\377c\227\002\377_\234\000\377\262\272\213\377\303\254\266\377\324" + "\277\312\377\336\316\333\377\372\365\371\377\355\341\351\377\344\321\331" + "\377\335\304\310\377\327\277\277\377\347\324\276\377t\247\025\377[\220\001\377" + "W\216\000\377a\233\000\377e\234\000\377k\241\000\377p\246\000\377n\243\001\377n\250\001" + "\377l\246\002\377n\246\002\377h\235\002\377d\236\001\377_\233\002\377z\260\001\377h\241" + "\002\377k\251\006\377x\261\031\377i\245\006\377i\246\003\377b\231\001\377c\235\002\377" + "^\233\000\377\217\265?\377\356\344\327\377\323\273\265\377\313\257\246\377" + "\341\315\315\377\334\313\315\377\307\263\265\377\266\240\235\377\272\244" + "\236\377\313\273\261\377Y\226\011\377_\237\003\377a\232\002\377_\226\001\377]\225" + "\002\377b\241\002\377c\237\001\377e\243\001\377c\234\002\377i\240\001\377k\236\002\377" + "{\255\002\377\201\263\001\377q\243\002\377q\250\002\377m\245\001\377l\240\001\377n\245" + "\001\377p\250\001\377h\235\002\377i\240\002\377q\254\002\377|\264\002\377}\263\002\377" + "z\263\001\377n\246\001\377m\245\001\377l\250\000\377h\245\000\377o\247\011\377\203\266" + "\035\377|\260\023\377n\241\001\377v\254\001\377x\247\002\377}\256\001\377|\257\001\377" + "s\246\002\377t\256\001\377n\245\001\377m\243\001\377j\243\001\377e\234\002\377e\237\002" + "\377j\243\001\377q\251\002\377c\236\001\377c\237\001\377k\251\004\377d\242\002\377o\255" + "\005\377o\250\002\377p\245\001\377o\243\003\377x\263\012\377g\241\000\377e\246\006\377" + "_\240\023\377d\243\024\377g\241\007\377w\255\005\377{\256\001\377z\261\001\377v\257" + "\003\377s\254\006\377o\243\005\377k\237\002\377h\234\001\377t\253\003\377\200\265\002\377" + "\211\264\001\377\214\263\002\377w\245\001\377k\242\002\377c\227\001\377_\227\001\377" + "i\247\001\377p\254\001\377d\225\002\377f\230\002\377o\241\002\377p\247\001\377h\235\002" + "\377a\230\001\377U\216\000\377\275\301\232\377\305\247\252\377\303\242\243\377" + "\347\325\335\377\364\352\362\377\364\347\357\377\346\323\334\377\312\257" + "\264\377\340\313\315\377\316\265\261\377\316\316\230\377Z\214\022\377a\225" + "\035\377`\222\"\377`\217&\377m\235\060\377p\242%\377e\235\016\377f\240\012\377" + "h\243\010\377c\234\004\377a\223\001\377d\237\001\377e\237\003\377x\261\005\377f\234" + "\000\377y\261\040\377r\257\040\377o\257\025\377f\247\005\377e\242\001\377e\235\001\377" + "\226\273G\377\354\336\316\377\304\251\245\377\342\311\310\377\327\301\277" + "\377\333\310\312\377\327\310\316\377\313\275\302\377\277\256\257\377\271" + "\246\242\377\320\276\270\377c\232\013\377d\241\001\377c\227\001\377c\226\002\377" + "h\241\001\377e\236\001\377o\256\010\377c\240\001\377a\231\001\377g\242\002\377j\235" + "\002\377}\257\001\377\201\263\001\377w\252\002\377q\246\001\377n\246\002\377l\240\002\377" + "r\247\001\377r\252\001\377f\232\002\377g\241\002\377v\260\001\377~\261\002\377{\252\001" + "\377|\257\001\377u\252\001\377v\263\010\377t\256\014\377x\263\031\377\211\300\063" + "\377\205\273+\377~\266\032\377r\254\002\377w\261\001\377|\262\002\377{\255\002\377" + "v\250\002\377p\237\001\377y\253\002\377z\252\002\377n\236\001\377l\237\001\377j\241\001" + "\377l\243\001\377n\241\002\377p\250\002\377g\235\002\377j\244\004\377m\250\006\377`\232" + "\001\377l\251\006\377r\251\001\377{\256\001\377p\241\001\377t\253\004\377o\241\001\377" + "m\246\003\377g\245\030\377Y\230\013\377l\246\027\377\211\273%\377\204\267\015\377" + "}\262\002\377}\266\012\377z\264\024\377v\260\031\377t\255\026\377\205\274'\377" + "\205\275\035\377t\246\001\377\201\255\001\377\221\271\001\377o\237\002\377f\231\002" + "\377i\242\001\377d\240\002\377d\243\002\377n\254\002\377j\235\001\377j\231\002\377r\241" + "\002\377s\245\001\377i\235\001\377a\230\002\377S\214\000\377\321\316\265\377\316\260" + "\263\377\332\277\306\377\366\352\362\377\373\367\372\377\365\355\362\377" + "\354\337\345\377\337\311\315\377\317\266\267\377\302\252\244\377\324\271" + "\253\377\270\266\232\377emd\377aff\377^bg\377_ej\377gpo\377o\200l\377s\216" + "b\377n\217M\377w\240G\377f\226(\377`\225\030\377b\225\021\377v\254\017\377k" + "\240\012\377o\246\031\377k\247\030\377h\244\017\377a\233\001\377i\244\000\377\272" + "\321u\377\331\304\264\377\301\241\227\377\302\242\232\377\337\313\310\377" + "\336\314\316\377\333\313\321\377\341\324\335\377\312\275\310\377\273\254" + "\265\377\274\251\253\377\310\266\262\377^\227\014\377c\236\002\377b\226\001\377" + "l\242\002\377r\253\001\377l\246\001\377j\252\004\377c\246\002\377`\230\001\377i\243\002" + "\377m\237\001\377\200\262\001\377w\247\002\377r\246\002\377p\247\001\377o\244\001\377" + "o\241\002\377v\256\002\377x\261\001\377e\233\002\377g\236\001\377u\251\002\377\200\263" + "\002\377z\252\001\377\206\272\016\377\203\271\031\377\211\301-\377\200\274-\377" + "o\256\027\377k\250\012\377p\255\004\377o\246\003\377m\241\001\377p\245\001\377q\246" + "\002\377r\253\002\377p\253\002\377m\236\001\377~\260\001\377|\251\001\377p\234\001\377" + "u\250\001\377s\250\001\377q\245\001\377u\252\000\377f\232\001\377r\251\006\377o\247\004" + "\377j\241\002\377g\237\001\377i\242\003\377q\250\002\377\205\265\001\377|\256\001\377" + "o\246\002\377i\237\001\377i\243\002\377m\252\035\377d\242\040\377o\254*\377l\250" + "\027\377\203\265\017\377\204\265\005\377z\255\002\377s\253\006\377v\261\027\377|\266" + "!\377~\267\040\377|\267\025\377s\250\000\377x\246\001\377\206\262\002\377z\252\002" + "\377i\234\001\377q\253\001\377l\246\001\377k\245\002\377o\252\001\377r\253\001\377o\240" + "\001\377u\250\001\377n\240\001\377j\234\002\377e\235\002\377Y\212\000\377\321\311\261" + "\377\321\266\271\377\327\277\307\377\347\325\337\377\345\323\336\377\336" + "\314\326\377\341\317\327\377\314\271\274\377\271\241\240\377\301\251\250" + "\377\212gf\377\306\250\226\377xei\377~ow\377XI\\\377XKa\377[Ne\377XLd\377" + "i`r\377tn}\377}{\206\377\201\206\210\377z\205x\377x\212d\377p\222C\377n\226" + "?\377f\225,\377l\236.\377d\227\034\377d\226\016\377\271\314q\377\301\254\237" + "\377\251\215\213\377\313\261\254\377\330\304\300\377\341\320\320\377\362" + "\350\353\377\324\306\316\377\346\332\343\377\311\274\306\377\275\251\262" + "\377\271\243\243\377\330\302\274\377i\237\022\377i\240\001\377o\241\002\377y\257" + "\001\377n\241\002\377a\227\001\377c\244\001\377g\251\003\377e\235\002\377p\246\001\377" + "t\245\002\377\202\263\001\377c\227\002\377f\235\001\377j\245\001\377m\245\002\377o\244" + "\001\377z\265\006\377x\262\003\377p\247\002\377p\243\001\377w\252\001\377|\264\000\377" + "\202\273\015\377\202\271\027\377v\261\016\377w\261\015\377]\225\000\377c\240\001" + "\377i\240\001\377q\244\001\377r\242\002\377x\251\002\377q\240\002\377p\241\001\377l\242" + "\002\377n\244\001\377y\253\001\377\201\262\001\377r\240\001\377s\241\002\377v\247\001\377" + "q\244\002\377q\246\002\377\201\271\012\377_\222\002\377l\246\004\377l\245\001\377m\241" + "\001\377q\251\001\377h\232\001\377s\250\002\377\177\260\001\377\201\263\004\377z\256" + "\020\377n\244\014\377g\237\003\377l\246\022\377p\254$\377i\247\034\377c\242\005\377" + "n\247\002\377z\253\002\377\200\260\002\377z\255\002\377u\257\006\377y\262\021\377\202" + "\273\036\377t\257\013\377u\254\002\377z\252\001\377z\247\002\377\202\261\001\377y\251" + "\002\377v\247\001\377t\250\001\377v\243\002\377\177\257\001\377v\251\001\377u\257\001\377" + "l\245\001\377h\235\002\377c\226\002\377d\231\001\377[\216\000\377\332\325\272\377\342" + "\307\311\377\335\302\307\377\361\345\354\377\375\375\374\377\367\354\363" + "\377\357\336\347\377\333\306\312\377\312\260\261\377\262\225\223\377\312" + "\260\252\377\317\264\254\377\307\256\254\377\332\306\306\377\321\277\304" + "\377\324\312\321\377\260\237\257\377wf\177\377\200m\211\377\233\215\242\377" + "\212|\222\377\207v\215\377\201r\206\377\226\207\220\377zoz\377e`h\377ggh" + "\377t|r\377\216\227\200\377\313\320\253\377\330\300\271\377\254\214\210\377" + "\312\260\254\377\330\303\277\377\323\272\272\377\357\337\343\377\332\311" + "\321\377\360\344\355\377\343\330\345\377\311\274\311\377\302\257\267\377" + "\305\260\257\377\320\277\264\377^\232\002\377m\243\001\377x\253\002\377z\252\002" + "\377m\235\002\377h\240\001\377f\246\001\377d\241\002\377j\250\001\377s\253\001\377x\252" + "\001\377~\255\002\377`\223\002\377a\225\001\377d\244\001\377l\252\001\377p\252\001\377" + "t\257\002\377q\247\001\377v\256\002\377v\250\001\377\200\267\002\377\201\270\002\377" + "\201\271\006\377s\251\002\377q\251\002\377\200\271\013\377e\232\001\377f\233\001\377" + "l\243\001\377i\231\002\377o\240\002\377|\255\002\377y\246\002\377r\237\002\377n\236\001" + "\377u\250\001\377{\260\002\377z\250\001\377w\241\002\377{\251\001\377w\250\001\377s\247" + "\001\377y\260\001\377\202\271\005\377_\223\002\377i\243\002\377p\251\003\377n\237\001\377" + "p\247\001\377l\236\001\377r\244\002\377x\252\001\377\177\261\003\377\210\267\027\377" + "\221\276\060\377m\243\006\377j\243\003\377w\260\030\377d\243\015\377l\253\017\377" + "s\255\006\377r\243\002\377v\253\001\377}\266\014\377k\247\005\377s\255\023\377\204" + "\274(\377l\240\012\377q\240\002\377~\255\001\377{\250\002\377x\245\001\377\177\261" + "\001\377y\250\002\377x\245\002\377|\247\002\377\204\260\001\377t\243\002\377p\247\002\377" + "l\247\001\377d\236\002\377Y\215\001\377]\216\001\377X\217\000\377\326\320\262\377\343" + "\303\302\377\354\321\325\377\341\321\333\377\363\353\360\377\353\335\344" + "\377\360\335\337\377\340\312\307\377\337\310\304\377\347\317\312\377\353" + "\326\323\377\345\323\321\377\360\341\346\377\361\347\354\377\365\360\363" + "\377\366\356\363\377\344\327\341\377\340\322\334\377\346\332\343\377\370" + "\361\365\377\360\351\355\377\336\322\333\377\303\256\267\377\322\276\275" + "\377\312\262\255\377\271\233\220\377\260\223\214\377\232\202\177\377\263" + "\235\226\377\301\241\220\377\215oh\377\272\233\226\377\307\256\252\377\333" + "\310\310\377\347\327\333\377\364\352\360\377\327\307\321\377\337\320\332" + "\377\325\310\326\377\303\263\300\377\277\251\260\377\305\253\252\377\310" + "\274\253\377_\240\000\377h\241\001\377k\232\002\377z\251\002\377t\245\001\377n\244" + "\001\377g\241\001\377f\236\001\377m\246\001\377u\254\002\377|\254\002\377w\247\001\377" + "[\216\002\377^\223\001\377k\250\003\377u\264\004\377r\250\001\377t\252\001\377t\251\001" + "\377u\256\001\377u\252\001\377{\260\001\377~\257\001\377\204\264\001\377\203\263\002" + "\377\200\263\002\377|\264\003\377a\223\002\377j\242\002\377k\245\002\377m\244\001\377" + "w\255\001\377t\245\002\377u\242\002\377w\246\002\377w\247\001\377v\254\001\377o\242\001" + "\377r\244\002\377\216\271\016\377\210\264\011\377{\255\002\377\177\267\002\377\201" + "\270\002\377~\261\002\377b\237\001\377c\233\002\377h\243\002\377o\252\004\377p\250\001" + "\377o\246\002\377q\251\003\377t\245\001\377~\256\001\377\207\265\020\377\226\277." + "\377l\240\003\377o\246\003\377t\255\007\377f\244\005\377r\257\022\377m\243\003\377|" + "\257\002\377w\255\001\377m\247\003\377\213\270\064\377p\251\033\377\200\271)\377" + "d\231\003\377k\235\002\377r\251\002\377r\251\002\377o\243\001\377u\253\000\377x\257\001" + "\377v\255\001\377w\256\001\377u\254\002\377m\241\001\377n\237\001\377r\255\002\377`\226" + "\002\377Y\214\002\377_\220\002\377[\220\000\377\305\307\223\377\344\277\273\377\352" + "\313\312\377\337\312\322\377\356\341\351\377\354\336\340\377\362\337\334" + "\377\362\343\337\377\367\356\355\377\342\316\317\377\277\245\247\377\344" + "\320\324\377\365\356\360\377\271\244\260\377\364\355\360\377\324\300\314" + "\377\342\322\334\377\360\346\354\377\357\345\352\377\305\263\272\377\352" + "\340\344\377\353\336\341\377\314\262\262\377\334\305\301\377\347\323\315" + "\377\342\313\302\377\334\300\263\377\343\303\257\377\333\274\243\377\303" + "\242\212\377\312\254\232\377\306\251\237\377\277\244\236\377\354\331\332" + "\377\332\305\314\377\356\342\352\377\332\311\323\377\320\276\311\377\306" + "\266\302\377\276\254\265\377\302\252\256\377\321\270\263\377\267\270\214" + "\377b\244\000\377i\243\001\377j\232\001\377|\255\002\377w\253\002\377l\235\001\377h\231" + "\002\377i\235\001\377l\237\001\377u\251\002\377{\256\001\377k\233\002\377Z\216\001\377" + "m\250\010\377x\266\014\377p\252\002\377r\246\002\377s\247\002\377v\260\002\377}\270" + "\013\377u\253\002\377{\256\001\377|\255\002\377z\246\002\377\203\261\002\377\216\275" + "\002\377u\260\002\377c\225\002\377l\245\001\377q\255\002\377o\247\001\377x\264\002\377" + "j\240\001\377k\235\002\377m\236\002\377t\251\001\377s\254\002\377n\245\001\377o\243\001" + "\377\221\302\036\377\203\266\011\377\202\267\003\377\202\272\004\377|\260\001\377" + "|\254\002\377g\243\002\377h\241\002\377e\236\001\377\200\270\016\377w\257\004\377o\247" + "\002\377q\250\002\377r\246\001\377|\253\002\377\211\267\016\377\177\255\013\377p\242" + "\003\377k\242\001\377i\243\002\377k\251\005\377j\250\005\377k\243\003\377u\254\001\377" + "r\246\001\377\204\256\022\377\260\277]\377q\250\"\377\202\271/\377n\246\006\377" + "o\245\001\377o\245\001\377u\254\012\377z\261\025\377r\254\015\377l\251\006\377k\247" + "\002\377u\262\011\377o\255\006\377i\244\001\377l\245\001\377l\245\002\377g\240\001\377" + "c\227\001\377^\217\002\377V\215\000\377\255\271x\377\340\270\262\377\337\275\266" + "\377\360\334\334\377\360\340\342\377\361\342\341\377\340\313\315\377\355" + "\340\341\377\370\360\360\377\272\230\234\377\311\255\261\377\367\355\356" + "\377\334\310\312\377\344\323\331\377\345\330\336\377\320\276\311\377\352" + "\334\345\377\330\307\315\377\261\233\243\377\317\276\276\377\375\373\373" + "\377\336\314\316\377\221wx\377\317\272\264\377\347\333\327\377\353\333\327" + "\377\353\326\314\377\336\303\261\377\344\304\254\377\351\314\262\377\357" + "\327\302\377\325\273\254\377\332\304\274\377\346\324\325\377\326\302\312" + "\377\353\335\350\377\350\334\345\377\275\254\270\377\276\255\273\377\274" + "\250\263\377\317\267\271\377\340\304\303\377\235\261_\377a\237\000\377f\233" + "\002\377u\251\002\377\204\265\002\377o\237\001\377l\236\001\377i\232\001\377k\241\002\377" + "o\244\001\377p\246\001\377p\246\001\377i\231\001\377l\242\006\377y\264\022\377p\254" + "\003\377q\255\001\377o\245\001\377q\253\001\377u\262\004\377m\246\002\377n\245\001\377" + "z\257\001\377w\246\002\377i\223\002\377|\255\001\377\206\272\003\377\200\272\023\377" + "h\234\000\377k\242\002\377w\262\002\377\201\271\001\377o\252\002\377q\260\014\377i\241" + "\002\377o\243\001\377s\247\001\377t\254\001\377p\243\001\377v\246\001\377\212\275\004\377" + "\206\272\003\377\177\264\001\377|\257\001\377w\245\002\377u\247\001\377b\235\002\377" + "e\237\002\377d\231\002\377\200\267\022\377z\260\011\377i\237\001\377k\244\002\377s" + "\253\003\377u\251\001\377~\261\005\377q\247\001\377g\235\001\377h\235\002\377e\231\001" + "\377j\246\004\377g\245\005\377f\245\010\377g\244\005\377c\231\001\377\241\263,\377" + "z\244\036\377e\241\016\377u\260\027\377w\254\010\377w\244\001\377\204\264\021\377" + "\213\272%\377\203\265\032\377i\242\005\377Z\224\001\377b\233\001\377r\253\001\377" + "s\247\001\377l\240\001\377h\243\001\377d\234\002\377f\241\001\377f\236\005\377\\\216" + "\006\377W\205\023\377\224\243p\377\352\310\312\377\312\245\250\377\356\330\330" + "\377\355\334\332\377\332\312\307\377\307\263\261\377\370\362\362\377\320" + "\272\266\377\247zr\377\365\341\335\377\344\315\313\377\335\311\311\377\343" + "\326\334\377\345\327\340\377\351\333\343\377\360\346\354\377\355\343\350" + "\377\336\317\320\377\374\361\357\377\374\367\365\377\334\307\277\377\207" + "g[\377\303\246\233\377\367\360\355\377\333\312\305\377\311\262\254\377\331" + "\301\267\377\342\310\267\377\316\261\236\377\341\305\261\377\363\346\327" + "\377\356\340\327\377\356\341\336\377\345\325\330\377\342\323\334\377\325" + "\306\324\377\267\245\265\377\274\251\271\377\277\255\272\377\337\306\304" + "\377\347\315\306\377p\236\026\377e\234\000\377j\241\001\377{\262\001\377\200\264" + "\001\377t\245\002\377o\242\002\377k\243\001\377q\256\002\377p\256\001\377m\247\001\377" + "p\251\001\377q\246\002\377\202\264\011\377m\241\004\377m\246\001\377m\252\002\377g\242" + "\002\377k\247\002\377k\250\002\377d\234\002\377t\253\003\377\177\264\002\377w\247\001\377" + "p\240\001\377z\257\002\377y\256\001\377\177\270\010\377r\244\002\377|\256\001\377\206" + "\273\002\377\203\263\000\377q\246\002\377u\261\011\377k\247\001\377p\251\001\377t\247" + "\001\377u\254\001\377z\253\001\377\205\271\001\377\205\272\002\377~\263\001\377|\260" + "\001\377}\260\002\377r\243\001\377s\247\002\377_\236\004\377c\232\001\377l\243\001\377" + "u\254\006\377~\265\024\377b\232\002\377e\237\001\377m\253\007\377r\255\005\377y\263" + "\011\377i\242\002\377e\235\003\377d\232\002\377i\235\001\377q\252\006\377k\246\004\377" + "b\236\002\377k\245\013\377h\234\002\377\213\247\015\377e\227\000\377c\232\002\377h" + "\241\003\377v\255\007\377u\252\002\377x\256\011\377k\240\002\377~\261\001\377t\247\001" + "\377]\226\001\377b\232\001\377m\247\001\377u\251\001\377v\253\001\377n\245\001\377c\235" + "\002\377g\244\024\377i\234*\377b\220\063\377r\212b\377\200\203~\377\340\303\304" + "\377\347\325\324\377\371\363\363\377\366\356\357\377\352\331\336\377\365" + "\353\354\377\376\373\372\377\344\323\313\377\252\200i\377\354\322\310\377" + "\340\310\305\377\341\315\317\377\353\336\345\377\341\322\334\377\350\333" + "\343\377\346\330\340\377\332\311\322\377\323\277\301\377\332\302\277\377" + "\361\335\321\377\341\307\265\377\204V;\377\330\275\252\377\375\375\375\377" + "\354\340\334\377\270\234\233\377\302\246\243\377\317\270\261\377\351\323" + "\304\377\340\305\257\377\347\314\272\377\365\352\341\377\353\340\332\377" + "\373\364\363\377\360\350\353\377\303\255\274\377\263\235\255\377\267\242" + "\261\377\315\262\270\377\336\275\257\377\316\277\230\377h\237\005\377i\237" + "\001\377u\261\006\377s\252\002\377|\263\001\377x\253\002\377v\262\002\377q\254\002\377" + "u\256\004\377|\261\003\377v\252\001\377r\252\001\377r\253\002\377n\242\001\377i\232\002" + "\377n\245\002\377p\252\001\377l\247\002\377k\250\001\377l\251\001\377l\245\002\377u\254" + "\003\377\200\265\004\377s\242\001\377r\241\001\377v\256\001\377u\255\004\377\216\304" + "&\377x\255\016\377\224\303\034\377\204\265\000\377\177\260\001\377{\255\001\377y" + "\257\002\377n\247\002\377s\253\002\377x\254\002\377\177\263\001\377\207\273\001\377\207" + "\274\002\377\203\271\001\377}\260\001\377\203\272\003\377{\256\001\377o\242\001\377t" + "\253\001\377r\254!\377f\232\000\377q\246\001\377q\247\001\377\202\271\031\377m\252" + "\007\377c\241\003\377`\233\002\377i\247\003\377v\262\014\377n\246\002\377e\235\002\377" + "l\244\010\377o\247\007\377r\252\005\377i\241\002\377\\\225\001\377p\247\027\377p\241" + "\014\377u\243\011\377j\230\001\377k\241\002\377r\252\012\377o\251\007\377j\236\001\377" + "n\240\002\377x\250\001\377\200\255\002\377\203\262\001\377Y\224\001\377Y\225\001\377" + "d\241\001\377j\237\001\377o\241\001\377q\246\001\377i\242\002\377h\242\030\377r\222" + "g\377{\214\200\377\177\201\210\377\254\235\246\377\346\321\315\377\374\367" + "\365\377\370\361\361\377\277\250\250\377v[\\\377}db\377\272\241\225\377\363" + "\325\307\377\345\301\253\377\364\332\313\377\343\306\275\377\344\313\311" + "\377\336\311\316\377\334\313\323\377\344\322\332\377\316\271\301\377\326" + "\302\305\377\315\266\264\377\323\273\260\377\353\320\301\377\316\255\226" + "\377\216dD\377\372\357\346\377\365\354\347\377\344\330\326\377\331\307\307" + "\377\352\332\327\377\320\267\261\377\340\311\274\377\331\277\250\377\335" + "\301\255\377\361\341\323\377\346\322\311\377\361\341\337\377\346\324\327" + "\377\317\273\306\377\263\233\250\377\274\240\246\377\340\276\263\377\352" + "\306\275\377\231\261I\377m\247\002\377i\237\001\377n\250\001\377q\243\001\377\177" + "\265\001\377z\256\002\377r\253\001\377o\237\001\377t\243\002\377\201\257\004\377\205" + "\270\012\377y\261\010\377p\252\007\377c\234\002\377d\234\002\377s\255\001\377v\252" + "\002\377z\261\001\377s\253\001\377p\250\002\377r\251\002\377}\263\007\377~\263\002\377" + "|\255\003\377z\247\001\377\201\262\001\377z\257\002\377\200\271\037\377\210\276\063" + "\377\230\310>\377z\256\000\377{\254\001\377r\240\002\377r\246\001\377r\255\001\377" + "u\261\002\377v\256\003\377\205\271\001\377\213\276\001\377~\254\001\377\201\263\002\377" + "\202\265\002\377\207\275\006\377{\256\001\377s\252\001\377n\247\001\377|\265\061\377" + "m\250\013\377f\234\001\377o\250\006\377\204\272\040\377\177\266\033\377r\253\017" + "\377l\245\012\377q\251\014\377z\261\016\377r\255\010\377d\237\001\377j\245\010\377" + "{\260\024\377|\257\022\377s\246\020\377U\221\005\377h\235\020\377x\247\023\377r" + "\243\014\377f\234\002\377o\247\001\377p\251\001\377l\241\001\377q\245\001\377t\242\002" + "\377\200\262\003\377s\241\002\377x\252\003\377k\240\006\377c\230\001\377d\232\002\377" + "j\244\001\377j\241\002\377g\236\002\377j\244\010\377s\240\060\377|\204\205\377||" + "\207\377\212\177\220\377\326\307\313\377\370\353\351\377\372\361\354\377" + "\310\244\224\377O/$\377#\011\003\377#\014\005\377\024\000\000\377D%\035\377\330\261\233" + "\377\377\366\347\377\342\314\300\377\333\277\272\377\333\305\305\377\330" + "\276\302\377\276\247\255\377\276\250\251\377\275\243\240\377\337\307\274" + "\377\360\334\316\377\355\323\277\377\325\260\221\377\343\303\251\377\306" + "\257\237\377\251\221\210\377\266\241\235\377\274\250\251\377\343\326\327" + "\377\350\330\327\377\337\312\303\377\334\301\264\377\323\272\246\377\324" + "\271\247\377\372\362\354\377\357\337\340\377\315\266\303\377\266\233\254" + "\377\257\220\234\377\323\253\236\377\341\270\250\377\333\306\255\377f\235" + "\000\377m\247\002\377l\244\001\377q\254\001\377v\256\001\377x\262\002\377o\247\001\377" + "j\243\001\377o\242\001\377q\237\001\377u\243\001\377v\254\002\377\200\271\033\377~\267" + "-\377f\237\004\377e\233\001\377s\252\002\377|\257\001\377~\260\001\377|\256\001\377y" + "\254\001\377}\257\001\377\203\270\005\377}\260\001\377}\256\002\377\202\263\001\377\177" + "\256\002\377t\247\006\377\207\300/\377\205\276\066\377\210\302\062\377r\252\000\377" + "s\254\001\377s\255\003\377m\250\001\377p\255\004\377n\247\002\377\203\266\001\377\211" + "\275\002\377\205\267\001\377|\252\002\377\201\264\001\377\204\267\006\377|\257\001\377" + "{\260\002\377v\262\002\377q\251\001\377~\267!\377u\260\015\377`\225\001\377c\234\003" + "\377\201\266\031\377\214\276'\377\200\265\034\377\177\264\036\377\200\265\035" + "\377\200\266\030\377t\256\011\377c\235\002\377_\230\001\377d\241\002\377w\254\034" + "\377w\251)\377V\217\016\377p\241\030\377\205\255\034\377\217\265,\377o\245\020" + "\377t\256\012\377q\254\002\377m\244\002\377w\253\006\377~\257\004\377x\255\003\377m" + "\246\010\377m\245\015\377\202\263\"\377\203\262$\377d\226\002\377g\240\003\377" + "X\215\001\377f\235\024\377d\226'\377\177\217w\377\200|\207\377\210}\216\377" + "\241\225\237\377\362\342\333\377\350\321\313\377\355\323\306\377\236n[\377" + "\071\025\020\377bA+\377\320\307\317\377\244\241\267\377bLB\377M(\032\377\376" + "\354\330\377\355\317\271\377\373\352\337\377\326\254\225\377\347\315\277" + "\377\323\270\260\377\340\305\272\377\325\270\254\377\372\365\357\377\375" + "\372\364\377\365\336\307\377\300\241\207\377;&\035\377\034\006\014\377\"\012\017" + "\377\040\010\010\377<&#\377\234\204}\377\346\326\324\377\350\332\326\377\310" + "\256\241\377\352\322\302\377\334\303\256\377\363\344\327\377\371\363\360" + "\377\340\317\325\377\267\234\254\377\323\262\264\377\345\277\264\377\354" + "\317\304\377pdJ\377s\255\000\377q\246\001\377w\255\003\377z\266\005\377s\256\001\377" + "u\261\005\377i\243\002\377l\241\002\377x\253\001\377{\251\002\377~\253\002\377z\253\001" + "\377n\246\002\377n\252\034\377\207\275\071\377j\240\002\377{\257\001\377\207\267" + "\002\377\177\255\001\377z\255\002\377|\261\002\377~\260\001\377\212\276\010\377|\257" + "\002\377{\254\001\377\203\270\004\377y\257\007\377t\256\016\377\217\306?\377\207\300" + ";\377x\265\036\377r\261\001\377p\254\001\377r\260\007\377m\254\007\377i\243\001\377" + "~\260\001\377\230\303\002\377\177\256\001\377u\246\001\377t\252\004\377\212\301\036" + "\377\211\300\034\377y\260\003\377{\257\001\377z\261\001\377s\250\001\377x\257\013\377" + "|\262\005\377e\236\002\377c\235\003\377w\255\011\377\206\270\030\377}\262\017\377" + "s\253\011\377g\237\002\377z\260\022\377~\264\025\377e\240\006\377^\234\003\377b\237" + "\004\377h\240\011\377e\236\021\377R\217\006\377a\230\016\377\221\264\063\377\204" + "\252*\377{\253\"\377v\255\031\377c\240\006\377m\251\022\377\203\266\"\377\210" + "\267\026\377w\250\002\377m\242\002\377r\251\013\377\203\266)\377\206\265\063\377" + "Y\211\001\377h\236\025\377h\232\034\377w\243<\377x\222\\\377\201{\206\377\205" + "w\210\377\226\203\223\377\301\260\265\377\267\237\245\377\372\362\357\377" + "\371\361\355\377\241\200}\377nP:\377\273\253|\377\307\305\260\377\247\251" + "\276\377\322\322\324\377\204dN\377\374\342\313\377\366\327\271\377\366\323" + "\260\377\366\320\252\377\370\334\276\377\366\335\306\377\357\317\275\377" + "\367\342\321\377\375\377\375\377\372\352\330\377\225t\\\377\065\034\015\377" + "B/'\377\201u{\377ymy\377^H@\377/\023\014\377\067\033\025\377\251\210u\377\333" + "\311\300\377\350\327\314\377\315\260\242\377\332\301\263\377\354\336\321" + "\377\340\317\310\377\351\331\331\377\322\261\262\377\353\303\261\377\373" + "\343\326\377\254zc\377\201tC\377y\261\011\377w\250\001\377{\257\003\377z\263\004" + "\377v\260\002\377t\257\001\377q\253\001\377o\246\002\377w\253\001\377\177\260\000\377" + "\177\255\001\377w\247\001\377n\245\001\377b\233\001\377\202\271)\377w\256\007\377~" + "\261\001\377\204\265\001\377\177\260\001\377{\254\001\377\200\262\001\377\200\262\001" + "\377\211\300\010\377u\250\002\377t\245\001\377\202\271\001\377}\267\015\377\204\276" + "\071\377\244\325`\377\217\307C\377x\265\024\377t\262\003\377y\265\006\377|\266" + "\015\377p\247\002\377s\251\001\377\206\270\002\377\204\264\002\377x\253\000\377{\262" + "\023\377\222\306=\377~\272\025\377q\252\001\377u\246\001\377~\257\001\377}\263\001" + "\377v\253\001\377p\247\007\377\202\265\007\377g\242\012\377c\240\007\377r\253\007\377" + "y\260\012\377\202\265\022\377p\247\006\377d\235\003\377v\255\025\377\200\266\036" + "\377t\254\017\377q\251\016\377b\231\001\377c\231\002\377^\233\007\377J\214\003\377" + "X\225\017\377\204\257\061\377e\226\024\377l\237\035\377v\252(\377`\233\016\377" + "t\257'\377|\262\"\377}\260\025\377r\243\002\377m\237\002\377r\247\005\377\203\270" + "\040\377w\255\031\377Y\222\005\377k\240#\377l\235/\377v\225^\377\200\200\211" + "\377~v\203\377\213|\215\377\234\210\225\377\271\241\246\377\321\272\270\377" + "\344\316\314\377\363\354\354\377\336\322\321\377\231\210\201\377\334\330" + "\273\377\346\340\303\377\355\347\314\377\333\321\303\377\265\225\215\377" + "\362\320\274\377\366\331\276\377\364\321\262\377\363\310\250\377\362\313" + "\250\377\362\316\261\377\365\326\303\377\341\271\251\377\357\320\265\377" + "tTJ\377)\031\034\377kZ\070\377\275\265\237\377\315\316\341\377\265\266\322\377" + "\325\327\333\377\213mK\377\067\031\024\377tL?\377\313\252\231\377\307\251\224" + "\377\262\217{\377\320\263\242\377\343\315\301\377\346\330\322\377\332\302" + "\303\377\306\225\203\377\330\246\211\377\371\343\323\377\303\242\223\377" + "\225\224y\377x\246-\377u\246\012\377\177\263\013\377{\257\004\377z\255\002\377" + "z\263\002\377x\263\003\377p\251\001\377s\253\001\377z\254\001\377}\255\001\377x\247\001" + "\377q\242\001\377u\247\001\377{\260\003\377~\263\003\377\177\261\001\377\203\264\001" + "\377\202\263\001\377~\250\002\377\203\263\002\377\201\264\001\377\205\273\004\377u" + "\250\001\377z\253\002\377\202\265\002\377\202\270\007\377\214\304K\377\227\314W\377" + "{\272$\377r\261\006\377r\255\001\377u\260\003\377t\254\002\377\177\257\001\377\212" + "\275\002\377\177\262\001\377v\256\001\377w\262\012\377\224\310D\377\213\300\064\377" + "u\260\000\377u\254\001\377z\256\001\377~\255\001\377\201\266\001\377v\250\002\377v\244" + "\002\377\207\267\022\377o\250!\377W\225\003\377h\245\016\377l\247\014\377|\263\037" + "\377m\247\024\377l\247\033\377j\246\026\377\200\266%\377n\243\006\377\203\264" + "\037\377l\241\013\377b\233\007\377^\233\023\377P\220\004\377Z\231\005\377n\243\017" + "\377y\253\036\377n\237\025\377x\253,\377d\234\034\377\205\274;\377{\262\"\377" + "x\256\032\377`\226\003\377[\213\001\377V\210\001\377y\254\060\377\177\264!\377\177" + "\263(\377{\253=\377}\247V\377\177\213\177\377\203~\213\377\207{\214\377\214" + "|\215\377\305\257\260\377\256\221\221\377\301\243\231\377\275\235\220\377" + "\303\247\236\377\325\300\273\377\353\334\332\377\370\364\360\377\374\373" + "\365\377\364\346\330\377\326\254\235\377\310\241\242\377\332\262\261\377" + "\341\273\274\377\333\265\267\377\314\247\254\377\266\216\217\377\323\240" + "\177\377\341\301\262\377\277\232\225\377\220b_\377oCF\377\213cP\377\264\241" + "\202\377\333\324\262\377\330\327\312\377\341\342\331\377\343\345\333\377" + "\276\270\235\377\202hW\377\347\332\321\377\364\351\340\377\312\262\250\377" + "\245\215\203\377\317\265\247\377\324\274\261\377\344\322\313\377\347\324" + "\320\377\305\236\216\377\331\271\247\377\345\311\267\377\264\201l\377\223" + "\220\221\377\207\237|\377v\242\067\377t\251\017\377r\250\002\377p\246\001\377r" + "\257\002\377m\251\004\377q\256\002\377x\256\001\377y\245\002\377}\251\001\377|\252\001" + "\377{\247\002\377{\252\002\377{\253\001\377\177\266\003\377\207\301\015\377\207\273" + "\005\377\203\262\000\377\201\254\001\377\200\257\002\377~\261\001\377\177\270\003\377" + "t\247\001\377{\254\001\377\201\265\002\377\227\311/\377\203\273\063\377\210\301" + "E\377v\265\037\377q\255\003\377s\255\001\377u\261\002\377}\265\001\377\214\276\001\377" + "\203\264\001\377w\254\001\377y\267\016\377\233\320R\377\203\273)\377s\257\005\377" + "r\256\001\377w\261\001\377v\245\001\377~\256\001\377~\257\001\377{\252\002\377\221\263" + "\001\377\200\256\012\377\203\267D\377V\225\016\377Y\230\014\377_\236\016\377s\256" + "&\377y\256\032\377\206\270\040\377q\246\006\377}\263\033\377r\250\022\377~\262" + ".\377\210\272G\377\214\275U\377\204\270N\377Z\226\007\377Z\223\001\377a\231\001" + "\377t\247\030\377y\247\036\377y\252'\377m\242!\377\177\266.\377i\240\011\377" + "v\254#\377`\227\020\377U\206\001\377Q\177\004\377\210\264X\377r\245\023\377\205" + "\266$\377~\254\071\377{\226n\377{v\204\377\214\177\216\377\214{\213\377\270" + "\242\251\377\260\224\225\377\260\217\216\377\303\241\230\377\324\265\253" + "\377\323\265\260\377\326\272\266\377\340\310\304\377\354\326\320\377\360" + "\340\330\377\357\334\314\377\366\335\302\377\302|]\377\304\177a\377\362\253" + "\227\377\365\263\241\377\314\222\202\377\231f`\377\227fW\377\310\240\211" + "\377\261\220\206\377\265\224\215\377\246gY\377\376\354\315\377\373\367\346" + "\377\356\352\330\377\357\350\323\377\360\350\325\377\347\340\321\377\324" + "\316\307\377\366\361\360\377\351\335\335\377\343\321\317\377\353\332\327" + "\377\240\214\214\377t]_\377\326\301\274\377\343\323\315\377\330\305\277\377" + "\257\214\201\377\265\224\202\377\241xa\377\216jW\377\201y\201\377\235\240" + "\247\377\224\251\207\377{\253\063\377n\244\015\377r\253\010\377q\255\007\377f" + "\236\005\377l\242\001\377{\256\002\377y\245\001\377\201\255\001\377~\250\001\377|\251" + "\001\377z\250\001\377|\254\001\377\203\274\013\377\207\300\032\377\200\270\013\377" + "\203\272\013\377\200\262\002\377x\250\001\377x\255\001\377q\245\001\377p\240\001\377" + "\202\264\017\377\233\312\062\377z\257\005\377{\263\026\377g\245\034\377\177\272" + "\067\377s\260\016\377u\260\002\377y\263\002\377\200\266\002\377\206\270\002\377|\254" + "\002\377t\251\002\377w\263\013\377\211\277(\377\217\302)\377|\263\012\377x\262" + "\001\377u\254\002\377u\252\002\377z\257\002\377}\262\001\377\177\261\002\377\234\277" + "\002\377\177\261\027\377\210\274K\377a\234'\377m\244\061\377~\264\065\377\210" + "\272\013\377\222\276\003\377\210\263\001\377\177\256\017\377\203\264\033\377u\251" + "\011\377p\246\011\377x\257\022\377\202\266\034\377v\253\012\377h\236\001\377g\236" + "\002\377h\243\002\377r\251\013\377v\254\017\377s\252\021\377~\265)\377{\263'\377" + "^\227\004\377n\243\035\377\177\264\070\377[\213\003\377Nx\007\377t\246\070\377n\240" + ")\377\177\253\064\377\203\245R\377\215\224\221\377\202v\202\377\217\200\217" + "\377\251\227\237\377\317\273\274\377\246\221\226\377\302\252\251\377\340" + "\306\277\377\355\327\317\377\324\271\261\377\306\250\244\377\340\313\305" + "\377\354\331\316\377\361\341\324\377\375\374\366\377\372\365\357\377\215" + "fX\377X%\033\377\310eE\377\260aF\377\033\005\001\377@\033\013\377B\034\027\377\316" + "\237~\377\361\323\265\377\366\347\324\377\326\265\253\377\354\332\316\377" + "\366\351\343\377\361\344\336\377\356\337\330\377\341\320\311\377\326\301" + "\271\377\311\260\251\377\243\204\200\377\211lg\377\252\217\210\377\301\252" + "\236\377\301\255\242\377ubd\377\262\234\226\377\336\313\304\377\343\317\311" + "\377\242\206\204\377mUK\377Q\065$\377`J=\377\203v\203\377\237\230\246\377" + "\246\245\255\377\237\254\227\377\206\250R\377r\242\021\377~\260\021\377n\240" + "\003\377q\241\001\377z\257\001\377x\246\002\377~\257\001\377t\242\001\377s\246\001\377" + "|\261\002\377\204\267\004\377\205\270\004\377\216\300\027\377{\257\006\377\201\267" + "\017\377~\262\001\377}\257\001\377{\255\002\377s\243\000\377~\264\023\377\242\317a" + "\377\212\270\036\377|\256\000\377m\243\002\377\\\226\000\377w\264\040\377\200\273" + "%\377}\265\006\377\203\271\001\377\203\265\001\377|\255\001\377w\250\002\377u\253\001" + "\377s\255\001\377{\266\005\377~\264\005\377}\260\001\377\177\263\001\377v\247\002\377" + "s\247\002\377z\253\001\377\202\261\000\377}\254\002\377\231\276\001\377\200\267\062" + "\377q\251#\377\205\272/\377\225\305!\377\210\272\011\377x\255\002\377r\246\001" + "\377}\257\013\377\207\270%\377\204\265\030\377\201\263\013\377\215\274\032\377" + "\233\307\065\377\227\304/\377\217\300\"\377\202\264\014\377r\251\000\377q\255" + "\014\377{\265(\377k\245\025\377e\235\021\377\206\272<\377\213\276G\377i\241" + "\035\377l\240\033\377\225\303V\377o\240\037\377i\223%\377z\243K\377\201\247" + "Y\377\201\244a\377\212\230\210\377\212\204\217\377\237\222\236\377\212y\204" + "\377\266\243\245\377\313\267\264\377\253\216\221\377\272\240\233\377\266" + "\234\224\377\265\235\225\377\271\241\235\377\306\255\250\377\364\346\333" + "\377\336\276\261\377\361\330\305\377\371\365\361\377\375\375\376\377\377" + "\377\377\377\240ru\377\230J\067\377\232VD\377uZc\377\320\300\276\377\375\365" + "\353\377\377\377\370\377\372\363\340\377\370\347\322\377\360\334\313\377" + "\351\323\312\377\351\324\317\377\300\244\245\377\271\235\235\377\317\265" + "\261\377\320\265\257\377\301\245\240\377\306\253\242\377\260\222\206\377" + "\236\202u\377\233\201u\377\245\214\177\377\226~y\377yab\377\307\262\256\377" + "\310\262\257\377\315\270\263\377\231\203}\377_HB\377eOE\377\224\203\210\377" + "\214\177\215\377\232\223\242\377\237\237\250\377\223\236\225\377\206\247" + "T\377\205\265%\377z\253\002\377{\251\002\377\177\261\001\377~\261\001\377{\261\002" + "\377q\245\001\377s\253\003\377|\264\003\377\204\266\003\377\204\262\002\377\205\265" + "\005\377\177\262\005\377|\262\012\377~\270\017\377{\256\002\377z\252\002\377w\256\000" + "\377\177\267!\377\220\302<\377z\246\000\377|\256\001\377e\226\001\377j\237\001\377" + "|\267\012\377\201\271\024\377\204\274\013\377\204\266\001\377}\261\001\377t\252" + "\001\377q\246\001\377v\257\001\377x\261\001\377x\255\001\377|\254\001\377\204\270\001\377" + "\201\262\001\377y\250\001\377r\242\001\377\216\275\030\377\217\275\015\377t\246\001" + "\377\221\274\001\377t\255\035\377\214\300\060\377\202\266\032\377o\250)\377\\" + "\227\033\377Y\225\024\377k\243\022\377r\251\011\377y\253\002\377\202\263\002\377" + "\216\275\021\377\210\272&\377\207\266\067\377\204\263\066\377\210\267:\377~" + "\257\037\377|\256\000\377~\261$\377t\246)\377w\246\063\377u\243/\377\202\256" + "\062\377\230\301T\377\210\264>\377\205\266=\377\213\274H\377s\250\064\377h" + "\232,\377w\231\\\377\203\232z\377\213\226\213\377\217\212\225\377\227\212" + "\232\377\232\214\230\377ucq\377\276\254\251\377\271\243\244\377\264\236\240" + "\377\321\271\254\377\257\227\222\377\256\225\222\377\244\214\211\377\370" + "\360\355\377\374\367\356\377\367\344\321\377\342\303\261\377\371\364\363" + "\377\375\375\375\377\376\376\376\377\304\266\300\377T/<\377\202cr\377\363" + "\360\363\377\376\376\376\377\375\375\375\377\376\375\373\377\336\303\257" + "\377\323\250\217\377\301\235\222\377\331\275\264\377\371\356\350\377\337" + "\313\311\377\267\240\242\377\302\247\245\377\274\242\237\377\322\274\272" + "\377\310\262\260\377\264\232\224\377\241\204}\377\273\247\227\377\212qi\377" + "\220uq\377nXX\377\262\236\226\377\260\233\226\377\325\300\275\377\331\305" + "\303\377\241\211\212\377\202jg\377\217{z\377\217\200\213\377\220\205\226" + "\377\220\212\232\377\222\222\234\377\221\235\225\377\207\256T\377z\252\017" + "\377v\244\001\377\177\260\003\377{\253\001\377y\256\001\377t\245\001\377w\254\001\377" + "|\254\002\377\203\263\001\377\201\260\001\377~\255\001\377\210\271\012\377\222\303" + "-\377}\264\032\377z\261\016\377~\256\001\377{\257\001\377\202\273\017\377}\257\011" + "\377|\253\001\377z\251\002\377Z\222\001\377q\251\001\377\200\267\002\377\200\265\001" + "\377~\261\001\377y\254\002\377v\257\001\377r\251\001\377q\243\002\377|\254\002\377\201" + "\262\001\377~\253\002\377\202\263\001\377\202\264\001\377\177\264\001\377z\260\001\377" + "t\251\001\377\200\271\024\377z\262\007\377t\247\002\377\215\273\007\377|\267)\377" + "b\236\022\377j\242,\377u\253@\377a\231*\377q\246\071\377\205\266+\377v\250" + "\017\377f\227\001\377\201\257\001\377\214\275\003\377{\260\015\377_\230\014\377m\244" + "!\377k\241\032\377Y\217\004\377\211\267\000\377\210\270\070\377\203\262?\377\234" + "\310\\\377\221\275@\377\201\260,\377\213\270?\377\204\263B\377q\244\064\377" + "p\244\060\377l\237*\377p\235?\377p\206m\377\205\214\216\377\222\217\235\377" + "\221\206\227\377\233\217\236\377\207{\207\377\224\206\215\377\312\270\263" + "\377\264\243\240\377\314\263\250\377\320\261\235\377zYN\377yc^\377\352\342" + "\341\377\344\316\303\377\337\300\261\377\345\310\274\377\367\351\344\377" + "\375\375\374\377\373\367\370\377\374\371\373\377\344\334\347\377\200g|\377" + "\314\276\312\377\360\353\355\377\374\371\372\377\373\371\372\377\363\346" + "\342\377\324\261\233\377\354\314\261\377\312\245\221\377\325\271\247\377" + "\321\261\237\377\353\326\316\377\325\306\307\377\232\205\204\377\264\237" + "\234\377\251\224\222\377\250\221\213\377\265\234\224\377\266\233\216\377" + "\246\213~\377\234\202y\377\225~y\377kWV\377\231\207\200\377\256\233\227\377" + "\321\277\274\377\316\274\272\377\262\237\240\377\243\216\220\377\247\224" + "\226\377\241\217\230\377\212}\215\377\201x\211\377\210\203\223\377\213\213" + "\230\377\225\244\233\377x\243J\377n\245\036\377\204\271/\377t\251\002\377x\247" + "\002\377w\246\002\377\177\262\001\377\201\260\001\377\201\263\001\377{\257\002\377u\253" + "\002\377\213\276\037\377\222\301*\377n\245\001\377t\260\010\377\200\266\001\377\201" + "\256\001\377\205\265\002\377\177\253\001\377\200\253\001\377x\246\000\377\202\256\026" + "\377\200\260\006\377\204\271\001\377\201\265\001\377}\261\003\377v\255\006\377p\252" + "\001\377w\254\001\377\207\270\002\377~\254\002\377\201\261\001\377~\254\002\377\201\262" + "\001\377\201\265\002\377y\252\001\377{\261\002\377w\260\002\377u\261\000\377u\255\001\377" + "s\246\002\377\206\276\062\377p\256\"\377p\254)\377l\246'\377o\247-\377s\252" + ".\377c\233\016\377g\236\006\377Z\220\003\377]\222\001\377u\250\001\377\207\272\007\377" + "z\260\007\377n\244\023\377f\231\022\377]\221\004\377W\215\007\377\211\264\002\377q" + "\246\030\377\225\304_\377\214\275G\377y\252\027\377y\251\027\377|\253%\377\223" + "\277G\377]\222\032\377o\241+\377r\241+\377\203\243a\377\243\244\252\377\260" + "\253\270\377\251\237\257\377\241\230\250\377\220\207\226\377wiz\377\215y" + "\206\377\270\244\242\377\272\241\237\377\341\307\271\377\277\232\204\377" + "\257\214x\377\344\321\311\377\375\371\366\377\372\370\365\377\367\350\341" + "\377\352\315\307\377\364\334\333\377\367\356\360\377\374\366\370\377\371" + "\364\370\377\275\256\274\377\204v\204\377\265\243\261\377\321\273\302\377" + "\335\307\311\377\362\344\346\377\372\363\363\377\371\356\352\377\261\207" + "r\377\266\210k\377\326\262\225\377\376\366\354\377\373\370\365\377\373\364" + "\363\377\266\241\237\377\231\205\200\377\307\265\251\377\276\252\227\377" + "\275\250\225\377\314\265\250\377\264\234\217\377\276\252\240\377\247\223" + "\216\377}eh\377\212tq\377\247\217\213\377\266\241\235\377\307\265\260\377" + "\305\262\256\377\235\205\207\377\245\216\222\377\263\244\253\377\232\214" + "\232\377\200u\206\377\200x\213\377\212\205\226\377\212\213\227\377\206\226" + "\211\377~\251V\377{\257\062\377x\253\000\377\200\260\001\377v\245\002\377}\255\001" + "\377\200\263\001\377}\264\001\377w\257\002\377r\254\007\377\222\306F\377\200\264" + "\032\377q\247\001\377q\251\003\377w\262\003\377\200\260\001\377\203\256\001\377\177" + "\250\001\377~\251\002\377x\246\001\377\207\267\010\377\207\267\004\377\205\267\002\377" + "}\257\001\377\204\266\013\377\227\302&\377u\250\000\377|\255\001\377\215\300\001\377" + "\204\262\001\377\207\264\001\377\205\260\001\377\210\267\001\377\203\262\001\377x\246" + "\002\377\177\257\001\377w\246\002\377z\257\001\377~\263\001\377s\243\001\377`\241\021" + "\377N\214\000\377c\240\011\377y\262\037\377d\240\005\377b\237\006\377p\253\017\377" + "l\243\002\377g\225\003\377w\246\014\377q\241\000\377\177\263\004\377u\255\005\377~\263" + "\"\377\\\204\000\377e\216\007\377d\217\012\377}\253\003\377\216\303\064\377\177\262" + "@\377g\236\026\377[\216\005\377h\231\006\377~\254!\377\220\274A\377u\241)\377" + "\206\255S\377\232\260\204\377\243\250\243\377\234\230\244\377\210\200\225" + "\377\222\211\233\377\217\204\226\377\224\204\225\377\215\200\216\377\242" + "\224\231\377\240\217\223\377\320\274\271\377\336\311\302\377\262\226\217" + "\377\267\233\231\377\363\357\360\377\373\370\365\377\351\324\312\377\351" + "\317\311\377\366\346\346\377\365\353\355\377\360\352\356\377\361\347\356" + "\377\322\306\322\377}i|\377P\070H\377\216\200\215\377\313\275\306\377\340" + "\322\330\377\364\347\353\377\345\316\313\377\347\320\312\377\327\265\250" + "\377\336\304\265\377\320\262\242\377\311\252\233\377\332\306\275\377\352" + "\342\342\377\331\314\316\377\216\200|\377`TR\377ygb\377iXT\377\231\200t\377" + "\314\270\255\377\301\254\247\377\262\237\236\377\234\212\211\377\202on\377" + "\266\243\237\377\234\206\205\377\267\242\240\377\302\256\256\377\253\226" + "\233\377\237\211\221\377\315\300\306\377\322\306\313\377\241\225\242\377" + "\210~\220\377\214\205\227\377\214\207\226\377\211\211\224\377\210\233\204" + "\377x\250\066\377l\232\000\377\203\257\002\377\205\265\001\377\202\265\002\377\203" + "\267\002\377|\257\002\377x\255\001\377w\262\007\377w\261\022\377n\237\001\377q\245\001" + "\377r\251\001\377t\256\002\377\202\266\004\377\204\262\002\377\205\257\002\377~\251" + "\001\377{\247\002\377\204\265\001\377\206\265\002\377\204\266\001\377~\257\001\377\205" + "\261\002\377\222\274\002\377\206\264\001\377y\251\002\377\177\261\001\377\205\271\002" + "\377\201\256\001\377\205\261\001\377\212\272\002\377\206\265\001\377{\252\002\377}" + "\253\002\377y\250\001\377}\260\001\377{\255\001\377r\241\002\377d\236\002\377[\223\002" + "\377l\250\025\377|\264\031\377t\255\011\377^\225\001\377l\246\004\377w\252\003\377" + "b\215\001\377^\215\002\377q\242\001\377\205\266\005\377v\253\007\377\216\305+\377p" + "\236\003\377f\214\001\377Ry\001\377t\254\020\377z\264$\377Q\205\010\377~\260\040\377" + "T\206\003\377_\217\005\377\177\253\040\377\260\317t\377q\230B\377k\222E\377\213" + "\230\206\377\252\250\262\377\254\245\263\377\232\216\242\377rdx\377\201m" + "}\377\205q|\377\220|\201\377\221}|\377\202ge\377\334\300\254\377\340\274" + "\242\377\255~d\377\353\333\324\377\372\367\367\377\344\325\315\377\356\337" + "\325\377\351\324\312\377\275\245\242\377\307\265\267\377\342\331\337\377" + "\307\301\310\377zq~\377\070\036+\377N\067D\377UBN\377\232\217\233\377\325\312" + "\323\377\312\273\302\377\331\310\306\377\343\320\315\377\343\313\304\377" + "\277\236\220\377\310\237\203\377\370\355\345\377\357\341\331\377\332\312" + "\306\377\327\320\315\377\274\253\246\377\273\246\235\377\271\242\232\377" + "\225}w\377mOB\377\271\233\210\377\335\312\301\377\251\216\207\377\250\220" + "\212\377nVS\377\253\227\216\377\302\257\251\377\247\220\217\377\261\234\235" + "\377\254\232\237\377\240\213\227\377\260\237\252\377\314\277\305\377\323" + "\306\314\377\235\221\241\377\214\203\226\377\205~\220\377\202\177\215\377" + "\211\217\224\377v\233U\377i\234\010\377\200\261\001\377\203\262\002\377\202\262" + "\001\377\201\262\001\377}\253\001\377}\257\002\377~\262\001\377v\247\002\377x\246\001\377" + "x\247\002\377s\241\002\377x\260\003\377y\254\001\377\177\256\001\377\202\263\001\377" + "\202\256\002\377\200\254\002\377\206\264\001\377\207\264\002\377\211\271\002\377\204" + "\255\001\377\223\267\001\377\245\307\001\377\212\263\002\377{\256\001\377s\245\002\377" + "~\260\001\377}\254\002\377\203\262\002\377\207\267\001\377\211\271\001\377\177\256" + "\001\377~\256\002\377\177\263\002\377}\257\001\377u\244\001\377z\252\002\377g\236\001\377" + "f\236\001\377s\256\026\377\210\276.\377z\262\020\377t\256\011\377i\235\001\377s" + "\246\002\377p\240\001\377o\235\001\377w\242\000\377\223\301\071\377w\254\040\377\214" + "\301/\377y\256\013\377m\240\002\377a\222\000\377z\262\025\377k\242\012\377h\226" + "\020\377x\250\024\377Gy\000\377d\214\022\377\212\246\064\377\262\316\213\377\204" + "\245l\377\207\224\211\377\220\216\234\377\207\177\222\377\205{\220\377\204" + "w\212\377l_r\377\211w\203\377\234\206\217\377\266\243\250\377\254\233\235" + "\377\277\256\255\377\367\347\340\377\326\271\243\377\314\262\244\377\336" + "\324\322\377\354\342\336\377\367\356\347\377\324\300\262\377\236\214\207" + "\377\261\247\242\377\271\262\264\377\267\260\266\377l^g\377XIP\377ven\377" + "cNZ\377eS\\\377aNY\377\210z\210\377\277\271\301\377\316\301\306\377\252\220" + "\215\377\273\240\231\377\337\306\277\377\314\270\255\377\320\267\243\377" + "\336\314\276\377\363\353\346\377\327\313\312\377\335\317\322\377\355\341" + "\342\377\364\355\355\377\341\323\315\377\234\205z\377\243\213\201\377\316" + "\272\262\377\305\256\242\377\270\241\225\377\207sm\377zd`\377\261\237\225" + "\377\254\231\225\377\262\240\235\377\262\243\247\377\227\205\222\377\221" + "~\216\377\304\266\276\377\326\311\316\377\315\300\310\377\241\226\246\377" + "\213\205\227\377\205\201\221\377\216\215\233\377z\216x\377\223\273S\377\205" + "\265\016\377\210\266\005\377\213\271\002\377\205\261\001\377~\257\001\377y\257\001\377" + "s\245\001\377z\254\001\377\200\257\002\377}\254\002\377}\253\010\377}\261\013\377y" + "\254\004\377\177\257\002\377}\253\002\377~\253\001\377v\246\002\377u\245\002\377\200" + "\260\001\377\205\265\002\377\203\253\001\377\225\275\001\377\223\267\001\377\200\253" + "\003\377\200\262\001\377{\261\002\377t\246\002\377x\251\002\377\203\264\001\377\212\267" + "\001\377\221\301\001\377\206\262\001\377\200\257\001\377\201\263\001\377z\251\002\377" + "w\246\001\377\204\264\001\377\226\275\002\377q\247\001\377m\246\002\377u\256\011\377" + "o\247\001\377y\255\001\377~\260\002\377~\256\002\377z\247\001\377}\253\001\377\220\271" + "#\377\227\302a\377Y\227\003\377\205\272\060\377}\260\026\377o\242\002\377s\253" + "\004\377v\254\003\377y\252\003\377z\247\010\377\210\263I\377}\243F\377\201\242\066" + "\377\232\264g\377\242\276\202\377z\215u\377|}\205\377\203|\214\377\204x\211" + "\377\213~\220\377~p\201\377|n{\377\265\245\252\377\327\313\317\377\354\344" + "\351\377\326\320\326\377\343\326\327\377\342\315\277\377\310\265\251\377" + "\341\324\317\377\344\326\323\377\350\335\334\377\352\343\340\377\262\243" + "\217\377\234\207l\377wjX\377\204\201v\377smk\377iZ^\377\212x\177\377\235" + "\212\226\377\221~\213\377\204nx\377\214x\200\377eV\\\377kci\377\244\237\242" + "\377\267\252\252\377\240\217\215\377\212tf\377\301\255\235\377\333\311\275" + "\377\331\316\307\377\333\312\277\377\365\357\355\377\351\336\334\377\335" + "\317\310\377\303\250\224\377\301\250\226\377\326\310\301\377\223\203\177" + "\377\270\250\242\377\333\311\303\377\264\237\221\377\220zv\377`LN\377\221" + "~z\377\236\215\206\377\226\203\204\377\247\227\233\377\234\213\230\377\232" + "\214\234\377\255\235\252\377\311\273\303\377\323\310\317\377\314\303\312" + "\377\243\233\252\377\205\177\220\377\215\212\230\377\202\207\213\377v\233" + "?\377\214\272&\377\210\264\001\377\213\257\001\377\215\264\001\377\201\260\001\377" + "t\250\001\377q\243\001\377u\244\002\377z\245\002\377z\250\001\377z\255\010\377\200\265" + "!\377\202\271'\377x\253\001\377\206\263\003\377\200\260\002\377w\247\002\377u\245" + "\001\377\201\260\002\377\207\265\002\377\206\260\001\377\214\267\001\377\214\273\004" + "\377\201\255\003\377}\262\001\377p\255\002\377k\242\002\377h\234\001\377}\257\002\377" + "\202\256\002\377\217\274\002\377\221\276\001\377\200\257\002\377{\256\002\377w\247" + "\001\377~\261\001\377\202\265\001\377\215\265\001\377\202\264\003\377x\253\006\377i\227" + "\001\377y\256\001\377w\251\001\377d\224\001\377g\226\002\377\200\255\002\377\205\262" + "\000\377\204\266\"\377f\232\020\377Z\231\001\377p\250\034\377\203\264%\377}\261" + "\035\377v\255\013\377r\251\003\377{\254\001\377\201\257\001\377\211\260i\377\216" + "\265q\377\234\276i\377|\246C\377n\225J\377\201\211\205\377\203\177\213\377" + "\203y\213\377\204w\212\377\204w\211\377\242\231\244\377\253\242\252\377\307" + "\275\306\377\342\325\336\377\313\277\306\377\277\265\276\377\323\310\314" + "\377\312\261\247\377\306\247\217\377\327\301\255\377\317\274\265\377\325" + "\307\277\377\312\266\242\377\272\242\202\377\234\202a\377oaM\377ph\\\377" + "tol\377\247\234\237\377\275\261\271\377\252\233\247\377\226\204\220\377\245" + "\225\240\377\246\230\241\377\242\230\234\377pfl\377ife\377\213\211\201\377" + "|rh\377\242\232\222\377\204t_\377\257\237\214\377\321\304\264\377\344\336" + "\331\377\365\363\364\377\343\335\330\377\317\275\257\377\250\205e\377\260" + "\217r\377\247\205j\377\230xb\377\223vi\377\332\314\311\377\316\301\277\377" + "\277\254\245\377^FD\377}ib\377\225\200|\377\222\177~\377\230\206\213\377" + "\227\210\224\377\260\244\261\377\252\232\247\377\262\243\256\377\312\274" + "\306\377\313\277\307\377\307\273\305\377\233\221\242\377\211\200\222\377" + "\203~\215\377u\203h\377u\246\022\377~\257\007\377\177\247\002\377\225\264\001\377" + "\202\253\002\377j\231\002\377z\251\002\377\201\252\001\377\201\254\001\377r\234\001\377" + "~\257\002\377}\260\007\377w\255\010\377w\251\003\377\223\277\031\377\207\270\011\377" + "\200\261\013\377x\245\001\377\206\262\001\377\213\267\001\377\206\257\002\377\212" + "\262\001\377\220\276\016\377\214\276\026\377{\264\002\377m\250\001\377n\251\001\377" + "h\235\001\377|\262\001\377}\255\001\377\210\264\001\377\221\275\002\377\203\263\002\377" + "q\245\001\377u\252\001\377|\267\003\377~\270\001\377\207\260\001\377\206\256\001\377" + "\211\266\007\377r\236\002\377y\251\002\377j\234\001\377P\202\002\377\\\216\002\377x\245" + "\001\377\210\267\026\377\206\266\021\377|\250\002\377g\237\012\377c\232#\377\200" + "\264\060\377t\253\034\377l\247\017\377m\244\014\377\206\264\032\377\227\274\070" + "\377w\240\037\377z\246\064\377\216\267X\377}\252S\377q\217`\377\212\207\217" + "\377\215\205\222\377\230\214\234\377\230\215\235\377\241\223\242\377\210" + "z\210\377\302\263\275\377\335\321\331\377\353\340\347\377\325\314\324\377" + "\266\245\255\377\247\217\214\377\243\213\200\377\330\312\302\377\326\310" + "\300\377\303\255\241\377\302\245\210\377\301\246\210\377\263\227z\377\221" + "v\\\377`M@\377pgb\377\252\247\251\377\312\304\310\377\305\276\305\377\313" + "\306\314\377\260\250\262\377\275\264\275\377\274\263\274\377\254\245\254" + "\377\255\250\256\377xss\377ysl\377ri`\377uja\377\242\232\212\377\265\257" + "\231\377\302\275\252\377\317\310\271\377\331\325\320\377\340\332\332\377" + "\325\305\276\377\303\252\224\377\322\272\246\377\277\244\212\377\237}a\377" + "tS@\377\275\243\216\377\333\313\277\377\343\331\326\377\214{}\377xd`\377" + "ve\\\377\204rq\377\210w\200\377\224\204\221\377\251\232\247\377\274\256\270" + "\377\273\253\266\377\265\242\256\377\313\275\306\377\330\313\323\377\321" + "\305\314\377\217\201\225\377\211\200\221\377x~y\377o\234<\377w\253.\377p" + "\245\001\377\201\256\001\377\177\250\001\377r\236\002\377\177\254\002\377\206\261\002" + "\377\201\253\001\377{\245\001\377\177\250\001\377~\247\001\377\202\261\001\377r\242" + "\002\377|\253\001\377\202\262\002\377|\254\003\377|\252\001\377\211\267\001\377\206\262" + "\001\377\203\256\001\377\206\257\001\377\202\253\001\377\201\264\000\377\201\272\006" + "\377n\244\001\377q\252\001\377l\240\002\377~\261\004\377\206\266\012\377\215\266\002" + "\377\213\264\001\377\211\265\001\377p\251\001\377s\254\001\377{\257\001\377\202\265" + "\001\377e\221\001\377\203\255\002\377\216\270\001\377\207\261\001\377j\232\001\377_\217" + "\002\377X\210\002\377s\241\002\377z\254\001\377\214\274A\377g\230\020\377g\223\002\377" + "y\251\010\377\203\265'\377\215\277@\377y\256\063\377\233\303i\377\236\302a" + "\377\177\254\015\377{\254\003\377l\236\011\377n\236#\377o\235\071\377p\230L\377" + "}\205\202\377\217\210\226\377\242\234\247\377\221\210\230\377\214\177\220" + "\377\226\206\224\377\256\234\245\377\320\303\311\377\334\322\332\377\311" + "\271\302\377\277\257\270\377\252\226\241\377\245\226\227\377\177j_\377\320" + "\300\264\377\320\276\257\377\320\275\252\377\312\271\244\377\301\257\234" + "\377\274\254\232\377\274\256\241\377\236\224\216\377\250\244\243\377\302" + "\300\304\377\277\275\301\377\311\307\314\377\317\315\322\377\300\270\301" + "\377\303\300\306\377\311\307\314\377\266\263\270\377\315\314\320\377\271" + "\271\274\377\235\234\230\377~ys\377TFB\377YOS\377\215}e\377\277\264\237\377" + "\266\253\223\377\273\253\220\377\300\264\243\377\336\325\323\377\337\324" + "\322\377\330\311\301\377\321\275\255\377\273\240\206\377vVA\377\225sZ\377" + "\336\316\300\377\350\336\327\377\260\244\250\377\227\210\221\377\224\207" + "\205\377ucd\377\206x\202\377\223\205\222\377\243\225\242\377\262\242\256" + "\377\300\261\272\377\273\252\263\377\301\261\271\377\312\273\301\377\317" + "\300\306\377\321\306\312\377\233\222\240\377z{\203\377w\221o\377\211\264" + "c\377p\247\004\377t\250\002\377y\247\002\377}\253\001\377~\251\001\377\201\257\001\377" + "{\247\001\377z\244\002\377v\237\002\377\203\252\001\377\204\261\002\377w\245\002\377" + "s\243\001\377z\253\001\377}\261\001\377\201\262\002\377\203\255\002\377\207\263\002\377" + "\203\256\002\377\201\254\002\377\204\255\001\377\206\267\002\377z\257\002\377s\251" + "\001\377t\254\002\377j\233\001\377n\237\002\377\220\300\024\377\212\270\000\377\211" + "\264\001\377{\251\002\377{\260\002\377v\252\002\377\177\257\001\377\202\263\001\377b" + "\221\002\377g\225\001\377\213\267\001\377\224\276\012\377\205\261\005\377l\232\001\377" + "d\221\002\377w\246\002\377{\253\001\377r\247\000\377T\211\000\377P\207\002\377O\210\002" + "\377{\255#\377\227\303K\377\231\304Z\377|\256\067\377z\251\037\377\204\260" + "\002\377\210\261\007\377\202\253*\377q\237.\377o\233>\377q\217[\377\231\227\241" + "\377\226\216\236\377\200u\211\377\207}\221\377\200t\206\377\235\215\232\377" + "\303\267\273\377\306\267\276\377\251\221\233\377\266\240\253\377\315\276" + "\306\377\311\274\304\377\241\216\217\377\264\237\226\377\275\243\214\377" + "\272\241\206\377\264\235\177\377\242\210j\377\254\225}\377\304\264\253\377" + "\331\323\322\377\316\313\315\377\300\277\300\377\300\300\300\377\271\271" + "\272\377\311\311\315\377\312\311\316\377\302\301\306\377\304\303\311\377" + "\310\307\315\377\312\311\316\377\273\272\276\377\320\320\324\377\276\301" + "\277\377\266\266\263\377\233\232\223\377\210\177\204\377jY]\377\212pV\377" + "\305\273\247\377\276\263\235\377\301\262\232\377\301\265\241\377\327\317" + "\310\377\316\277\261\377\301\261\237\377\304\261\237\377\261\231~\377|\\" + "C\377\312\263\232\377\342\325\312\377\300\262\257\377l`g\377\200t~\377\243" + "\232\241\377\215\201\213\377\230\213\227\377\217\201\221\377\243\225\244" + "\377\271\252\264\377\310\271\277\377\261\240\251\377\274\255\264\377\276" + "\255\265\377\323\306\311\377\315\303\311\377\205\202\216\377m|q\377\234\272" + "\220\377z\261\034\377l\241\000\377r\247\003\377\177\256\015\377s\246\001\377|\262" + "\012\377{\256\006\377v\244\001\377x\246\001\377\177\256\001\377s\241\002\377p\236\001" + "\377z\251\002\377z\250\001\377w\251\001\377y\260\001\377|\256\002\377\201\262\001\377" + "\177\252\001\377{\245\002\377\206\261\001\377\207\271\002\377o\242\001\377r\255\006\377" + "u\256\005\377p\240\001\377j\233\002\377\204\270\025\377\231\304.\377\207\270\004\377" + "x\252\002\377k\240\001\377|\254\001\377~\255\001\377~\261\001\377k\235\001\377m\235\002" + "\377{\252\003\377\223\277\031\377}\253\002\377}\254\001\377~\256\002\377|\261\003\377" + "m\236\002\377p\245\001\377i\245\004\377u\257&\377_\232\037\377\214\275f\377\215" + "\277T\377z\255\013\377m\237\002\377p\230\002\377\211\262\001\377\213\262\004\377u" + "\237\003\377]\214\000\377h\224\062\377\213\225\214\377\222\213\227\377~t\204\377" + "xp\200\377}u\207\377\265\254\271\377\276\260\264\377\271\244\250\377\267" + "\240\244\377\270\243\253\377\303\264\276\377\277\256\266\377\273\254\264" + "\377\241\217\223\377\227{p\377\276\241\213\377\267\235\210\377\272\246\223" + "\377\275\253\227\377\271\246\222\377\314\276\267\377\340\333\334\377\333" + "\331\335\377\307\307\307\377\275\276\271\377\261\262\254\377\275\302\276" + "\377\276\301\300\377\271\272\272\377\272\273\274\377\303\304\307\377\301" + "\303\304\377\257\262\255\377\274\300\273\377\307\314\312\377\311\313\312" + "\377\302\302\303\377\274\273\276\377\264\257\260\377\256\241\234\377\326" + "\321\312\377\265\256\234\377\305\274\253\377\266\246\223\377\314\300\261" + "\377\301\270\261\377\320\306\272\377\306\272\254\377\304\253\226\377\216" + "pS\377\242\207l\377\312\271\243\377\256\231\216\377yjs\377tdj\377rek\377" + "\245\234\246\377\264\251\261\377\223\204\223\377\237\215\235\377\256\236" + "\250\377\301\262\271\377\277\256\267\377\265\242\254\377\271\250\260\377" + "\273\253\257\377\343\327\327\377\236\225\242\377sux\377\215\243\203\377\177" + "\260)\377p\243\000\377n\236\002\377r\244\003\377j\231\003\377|\262\016\377p\244\001" + "\377u\253\003\377\200\264\021\377t\247\002\377k\232\002\377t\242\002\377y\246\001\377" + "\204\262\002\377u\244\002\377t\250\001\377m\237\001\377x\257\002\377|\255\001\377~\251" + "\002\377\213\273\007\377\201\264\002\377q\246\003\377u\260\011\377n\240\001\377s\243" + "\001\377y\250\002\377\201\266\011\377\243\310B\377\201\261\006\377j\237\002\377a\227" + "\002\377\217\274\002\377\206\260\001\377\201\262\001\377h\227\002\377u\246\001\377l\234" + "\002\377p\243\017\377{\256\030\377e\234\006\377Y\220\003\377v\257\024\377l\242\004\377" + "p\246\002\377u\255\010\377\211\277:\377\177\263:\377r\250\065\377\200\264B\377" + "`\227\022\377[\216\001\377|\253\001\377\215\266\002\377\210\257\006\377\227\265\065" + "\377\201\246@\377w\230a\377\211\216\210\377\214\207\217\377\217\204\222\377" + "\226\217\236\377\253\241\256\377\233\207\222\377\264\240\244\377\303\261" + "\263\377\270\244\252\377\270\246\260\377\246\223\236\377\275\256\267\377" + "\315\300\311\377\244\217\225\377\206ig\377\250\216{\377\265\236\213\377\252" + "\223\203\377\261\232\206\377\261\235\214\377\317\306\301\377\327\322\322" + "\377\327\325\326\377\313\314\311\377\263\266\251\377\243\251\231\377\254" + "\261\244\377\261\266\253\377\263\270\256\377\265\272\262\377\273\301\272" + "\377\271\300\271\377\265\272\262\377\263\271\261\377\301\306\300\377\305" + "\312\310\377\316\320\322\377\317\317\323\377\316\315\321\377\326\326\330" + "\377\315\312\305\377\302\274\263\377\273\261\243\377\270\256\233\377\255" + "\237\211\377\277\265\244\377\315\305\273\377\307\275\257\377\301\263\241" + "\377\227~h\377gK\063\377\245\215u\377\211xk\377XLL\377h`c\377\204z\177\377" + "\204u\200\377\255\242\252\377\261\242\254\377\236\214\232\377\252\231\244" + "\377\273\253\264\377\277\260\266\377\271\250\256\377\267\246\255\377\272" + "\251\254\377\325\307\310\377\304\270\300\377\177y\203\377\214\232{\377\211" + "\265\067\377r\250\002\377k\233\001\377q\246\003\377s\247\004\377r\247\004\377j\237\002" + "\377^\217\001\377z\246\004\377~\253\007\377r\234\001\377\177\253\000\377\203\257\002" + "\377~\253\002\377z\251\002\377p\245\002\377k\235\001\377n\237\001\377|\257\004\377\201" + "\263\011\377{\256\003\377\202\267\014\377\201\270\023\377o\246\000\377o\241\001\377" + "o\240\002\377~\254\001\377y\251\000\377\212\267\016\377w\246\002\377h\235\002\377Y\221" + "\002\377|\260\001\377\217\272\002\377\212\265\000\377z\246\002\377v\245\001\377f\225" + "\002\377_\215\001\377v\251\014\377\205\266$\377e\233\003\377_\224\001\377w\254\032" + "\377\204\267+\377\207\273)\377~\262\020\377z\254\000\377{\255\014\377\205\263" + "\067\377\205\265\063\377U\216\003\377f\234\005\377\207\262\013\377\211\260\030\377" + "\301\301\247\377\212\217x\377{\204y\377\204\204\210\377\221\207\223\377\242" + "\227\247\377\233\222\240\377\220~\216\377\232\207\221\377\302\260\267\377" + "\311\272\301\377\271\250\260\377\254\227\242\377\265\243\255\377\276\257" + "\271\377\301\264\274\377\274\256\265\377\222\200}\377p_R\377\256\223~\377" + "\250\215r\377\253\216s\377\306\262\244\377\277\261\253\377\322\314\311\377" + "\324\324\323\377\305\307\301\377\266\271\252\377\247\255\224\377\237\251" + "\212\377\242\253\215\377\242\256\220\377\240\256\221\377\252\266\237\377" + "\255\272\245\377\255\271\243\377\255\270\245\377\266\277\262\377\303\310" + "\302\377\313\316\316\377\316\322\325\377\330\331\335\377\332\332\334\377" + "\317\314\307\377\301\271\255\377\275\261\240\377\273\257\241\377\217zc\377" + "~iP\377\214{c\377\233\213x\377\311\273\261\377\241\211w\377kVH\377q\\J\377" + "aNB\377UF?\377bUU\377xlt\377\212~\212\377\225\207\221\377\245\227\240\377" + "\232\213\230\377\260\242\255\377\257\236\252\377\312\272\302\377\300\261" + "\267\377\260\236\250\377\301\261\267\377\321\302\305\377\312\275\301\377" + "\200x\207\377\213\225l\377\217\262=\377i\241\003\377r\250\012\377t\247\004\377" + "o\234\001\377g\224\002\377[\213\001\377m\231\002\377\206\253\002\377\206\261\002\377" + "~\250\005\377\232\301\020\377\203\256\001\377|\250\002\377w\247\002\377s\250\001\377" + "k\233\002\377n\236\002\377s\246\000\377\216\275/\377{\260\005\377x\254\002\377{\263" + "\006\377v\254\004\377r\244\002\377v\245\002\377\202\256\002\377n\235\002\377l\235\001\377" + "s\244\001\377j\237\001\377c\234\001\377\202\273\031\377\210\270\001\377\207\262\002" + "\377\206\260\001\377i\226\002\377U\206\001\377_\215\002\377i\232\001\377e\227\006\377" + "y\257\026\377z\255\035\377\220\277\066\377\206\265\037\377m\237\002\377p\240\000" + "\377\177\256\000\377\221\270\000\377\214\267\061\377v\241G\377^\177\070\377awE" + "\377q{c\377c_h\377G>N\377TLY\377olt\377\227\223\235\377\241\231\247\377\224" + "\210\230\377\203t\206\377\222\200\216\377\256\236\245\377\310\273\300\377" + "\243\217\231\377\266\243\253\377\231\204\220\377\300\262\271\377\300\262" + "\273\377\246\225\234\377\261\240\242\377\265\246\243\377\211so\377rQF\377" + "nK>\377\227xe\377\252\212{\377\276\253\241\377\306\272\264\377\273\263\253" + "\377\265\262\244\377\251\251\222\377\245\251\207\377\233\244y\377\227\241" + "q\377\221\235i\377\214\231g\377\222\236p\377\222\240u\377\225\243|\377\244" + "\261\222\377\250\265\235\377\267\301\262\377\306\315\306\377\306\313\311" + "\377\323\327\327\377\327\330\332\377\323\322\322\377\311\304\277\377\304" + "\274\266\377\271\254\243\377\302\272\264\377\271\256\245\377\252\232\214" + "\377\252\223{\377\270\245\217\377\264\237\217\377\203ie\377t`\\\377[EC\377" + "wfd\377vkm\377znu\377\202t}\377\217\201\212\377\231\211\224\377\232\207\222" + "\377\222\200\216\377\255\236\252\377\274\255\264\377\304\265\273\377\252" + "\230\242\377\233\207\222\377\257\233\237\377\320\303\305\377\271\254\267" + "\377\240\236{\377\225\260H\377\202\261\064\377\200\260\036\377x\251\003\377u" + "\243\003\377l\226\001\377j\223\002\377{\242\001\377\205\256\007\377\206\264\016\377" + "\206\260\031\377\255\315;\377\201\263\002\377\177\250\002\377\177\247\002\377{\244" + "\002\377y\242\002\377w\237\000\377\215\273$\377\227\304\067\377z\252\003\377z\247" + "\001\377\200\257\002\377~\255\004\377o\236\002\377\203\256\002\377\204\255\003\377q\236" + "\002\377m\235\002\377y\252\001\377u\247\002\377k\237\003\377t\252\003\377y\247\002\377" + "\206\263\002\377z\246\002\377o\237\002\377Hw\002\377\\\213\001\377d\225\003\377c\226" + "\014\377\224\306<\377\214\276\065\377\210\264\026\377\201\247\003\377q\241\002\377" + "p\237\003\377c\204,\377Yo\064\377alI\377KDN\377=\064?\377G=J\377RET\377@\060=" + "\377-\033(\377NAL\377\216\207\225\377\232\221\236\377\217\205\223\377\213" + "~\217\377\203u\205\377\221\200\216\377\312\273\301\377\272\251\254\377\272" + "\247\250\377\254\230\235\377\236\212\224\377\276\257\265\377\262\241\251" + "\377\252\227\240\377\257\235\236\377\242\224\222\377\266\250\237\377\213" + "uh\377qWM\377pTC\377\206gO\377\207jV\377\216q`\377\241\215|\377\234\215z" + "\377\230\222v\377\230\227t\377\211\211`\377}}N\377oo=\377tvE\377\203\211" + "W\377\205\216\\\377\210\220d\377\232\245~\377\250\261\224\377\251\262\233" + "\377\266\274\255\377\276\304\273\377\303\306\300\377\307\307\306\377\326" + "\326\326\377\316\312\311\377\310\301\275\377\273\256\246\377\257\235\217" + "\377\264\246\234\377\247\222{\377\275\250\235\377\242\205e\377\231}d\377" + "\215wo\377\202pk\377\203wt\377\201xu\377shj\377\211z\200\377\207w|\377\212" + "x~\377\235\213\222\377\256\240\250\377\217\200\212\377\252\232\244\377\261" + "\243\254\377\261\241\251\377\253\232\242\377\237\216\226\377\240\216\226" + "\377\263\242\250\377\324\310\314\377\257\245\216\377\236\257[\377r\243(\377" + "\226\303N\377s\246\010\377o\235\001\377n\233\002\377e\220\002\377\177\242\002\377" + "\221\270\034\377\207\266#\377\247\311J\377\233\277'\377|\252\000\377\211\263" + "\001\377\207\256\000\377\230\265\024\377\231\266\034\377|\244\000\377\177\253\011" + "\377}\254\002\377~\250\002\377z\245\001\377\204\264\003\377\201\261\003\377t\241\002" + "\377y\243\002\377z\245\002\377o\234\002\377w\250\001\377z\254\001\377}\260\003\377r\241" + "\001\377u\250\001\377n\236\002\377\204\261\001\377x\245\001\377k\232\002\377k\232\001\377" + "t\244\005\377\214\274\"\377\220\300&\377s\252\016\377b\235\005\377\215\272\017" + "\377x\252\005\377k\240\020\377\177\226V\377\200\201\203\377\237\234\242\377" + "\220\207\217\377ymt\377XHT\377=+\071\377;)\063\377cT]\377qfn\377gZe\377{p\200" + "\377\203w\207\377\207y\212\377\214~\217\377\213}\215\377\246\227\241\377" + "\305\265\264\377\254\230\232\377\241\215\217\377\220}\206\377\270\250\254" + "\377\274\254\261\377\254\233\242\377\266\243\251\377\262\242\242\377\236" + "\216\217\377\214\177~\377\245\227\221\377\227\203t\377jL\063\377iO\067\377" + "ubO\377\\H;\377dND\377^K=\377XF\064\377P@)\377aV\070\377bV\064\377uoI\377\207" + "\207\\\377\212\214b\377\221\224k\377\214\216i\377\224\227w\377\244\247\217" + "\377\235\237\212\377\245\247\224\377\237\234\214\377\265\262\251\377\271" + "\263\257\377\304\276\276\377\273\256\250\377\265\241\220\377\255\227\203" + "\377\240\203h\377\241\207v\377\222va\377\231|a\377\214wh\377nS<\377n[M\377" + "zfb\377\244\226\223\377}qs\377{po\377\212{|\377\223\204\207\377\221\203\206" + "\377\220~\201\377\220~\203\377\242\222\234\377\240\220\232\377\232\210\222" + "\377\267\253\260\377\266\251\257\377\226\205\217\377\241\220\227\377\255" + "\232\236\377\313\300\300\377\274\267\252\377\227\253i\377i\234\027\377t\246" + "\032\377y\253\034\377n\241\003\377o\241\002\377g\221\001\377y\240\001\377\226\274\064" + "\377t\243\012\377\262\320M\377\205\256\010\377\200\255\003\377}\254\001\377{\250" + "\002\377\201\251\002\377\212\255\004\377~\245\002\377i\230\001\377s\243\001\377\200\254" + "\002\377u\243\001\377y\250\002\377w\252\001\377r\242\002\377w\250\002\377w\246\002\377" + "u\244\001\377u\250\002\377{\257\012\377w\246\013\377{\253\007\377v\247\002\377w\251" + "\003\377v\243\001\377y\251\001\377_\214\001\377v\251\012\377\224\306%\377\206\267" + "\022\377{\253\001\377]\221\001\377W\215\001\377_\227\004\377d\200>\377LJR\377\063#" + "\065\377\067!\065\377_KZ\377\226\214\224\377\270\261\267\377\206|\203\377E\066" + ":\377/\033'\377P<K\377|kx\377l^m\377qgu\377\200v\206\377\203z\213\377\215" + "\200\221\377\226\210\227\377\270\251\256\377\310\267\267\377\255\232\232" + "\377\232\206\214\377\207q}\377\256\235\245\377\262\242\250\377\253\227\240" + "\377\256\233\236\377\243\214\213\377\232\204\202\377\211xw\377\217\203\201" + "\377\262\247\234\377\244\226\206\377\252\241\223\377\264\257\245\377\253" + "\245\232\377\242\231\212\377\217\207p\377wpQ\377ohD\377lg?\377\214\207^\377" + "\225\223n\377\227\230r\377\231\232w\377\230\232y\377\232\232}\377\216\212" + "n\377\214\207p\377\201zj\377xpd\377l_O\377\203q]\377\221|j\377\236\210~\377" + "{aV\377mO?\377x[J\377\206jY\377qP;\377\216vp\377\\A.\377_F\060\377iYN\377" + "UE\064\377~sh\377\212\202y\377nef\377{je\377zig\377\205tu\377\202nr\377\211" + "uv\377\225\201\200\377\240\217\223\377\234\215\226\377\227\210\223\377\235" + "\217\227\377\257\244\253\377\236\220\233\377\203q}\377\245\222\224\377\302" + "\267\266\377\266\264\257\377\205\240j\377u\241.\377n\237\016\377v\247\021\377" + "n\233\001\377t\243\003\377l\231\002\377c\221\001\377\202\254\030\377\215\256\030\377" + "\245\303+\377\200\254\004\377~\253\012\377t\250\004\377n\240\001\377}\246\002\377" + "\212\260\001\377\206\256\001\377q\235\002\377r\242\002\377|\252\001\377s\242\002\377" + "w\244\002\377v\247\001\377r\250\002\377n\243\001\377m\240\002\377o\245\001\377n\237\001" + "\377q\244\001\377s\246\003\377n\235\003\377}\255\016\377w\252\004\377y\251\003\377w" + "\250\002\377\215\276\036\377\205\273\033\377t\245\007\377}\253\001\377\177\256\001" + "\377b\230\002\377M\177\015\377V\177(\377@F=\377*$*\377\040\023\031\377&\031\032\377" + "\027\011\014\377!\030\033\377+&*\377\013\010\012\377\025\016\024\377\071.\071\377\060\037" + "-\377\230\211\233\377tjx\377pfr\377|r\200\377\204y\210\377\222\206\225\377" + "\230\214\231\377\306\267\273\377\313\274\275\377\245\222\223\377\213u~\377" + "\200jw\377\260\235\246\377\271\252\260\377\250\225\235\377\267\245\242\377" + "\221|}\377\232\205\206\377\241\217\220\377zmn\377}qk\377\251\243\232\377" + "\274\266\260\377\261\255\250\377\256\254\241\377\223\223{\377\225\226}\377" + "\234\235\201\377\207\204\\\377\216\216e\377\227\230p\377\226\227q\377\231" + "\232w\377\225\231w\377\233\237\202\377\240\242\207\377\232\230|\377\212\204" + "j\377bS;\377aQ:\377`M\065\377V=\"\377H-\024\377bH\071\377U<,\377=$\021\377A'" + "\024\377nZL\377^C\062\377mUI\377ue\\\377R>,\377j_O\377uog\377pjf\377aZZ\377" + "i^Z\377\217~y\377\204qj\377\211ys\377\220\200|\377\233\213\207\377\220}z" + "\377\264\245\242\377\231\214\225\377\206w\202\377\243\227\236\377\260\246" + "\252\377\232\213\224\377\226\204\216\377\246\221\225\377\310\273\274\377" + "\273\265\265\377~\232j\377t\234:\377o\236\021\377r\241\007\377v\245\003\377u\245" + "\001\377r\242\013\377~\260\071\377l\234\000\377\253\303\062\377\206\252\010\377s" + "\240\001\377s\241\002\377p\242\001\377q\236\001\377~\250\002\377\213\261\002\377\211" + "\255\001\377\202\251\002\377v\242\002\377z\244\002\377~\252\011\377y\247\004\377t\243" + "\001\377u\250\001\377q\243\001\377j\235\002\377o\250\002\377u\250\001\377s\242\001\377" + "g\230\002\377\\\220\001\377\200\257$\377r\244\013\377\206\265\021\377\222\302\035" + "\377\203\265\024\377[\213\000\377x\242\001\377\205\260\001\377t\241\002\377p\243\010" + "\377Ts\071\377?V\061\377$%\031\377\017\013\006\377\015\011\003\377\007\006\002\377\000\000\001\377" + "!\037!\377\000\000\000\377\000\000\000\377%!$\377\012\005\011\377$\040&\377'\024#\377i[h\377" + "zk{\377\203u\204\377\203w\204\377\223\206\225\377\246\232\242\377\317\302" + "\305\377\313\274\275\377\230\200\206\377yem\377\212v\200\377\264\244\253" + "\377\250\227\236\377\253\225\233\377\272\244\241\377\232\203\200\377\241" + "\212\205\377\226\203}\377uc_\377M\071\061\377o^V\377\250\242\232\377\265\260" + "\247\377\210~h\377{oO\377ta?\377[@\027\377U<\022\377dR-\377aN*\377bN*\377l" + "`\070\377\204\202Z\377\206\206_\377\217\217m\377\233\234\177\377\227\227z" + "\377\213\206h\377\202yY\377\221\204c\377\201pQ\377udA\377\212y\\\377~nN\377" + "^I-\377W>#\377u]M\377gJ\060\377v`G\377\245\234\224\377\231\221\201\377\204" + "zi\377mbS\377cXQ\377i`\\\377od^\377~lg\377|jg\377\204sr\377\225\205\203\377" + "\203qp\377\206qo\377\254\235\233\377\203u\201\377\221\206\220\377\231\213" + "\223\377\252\235\241\377\234\215\224\377zju\377\215|\204\377\270\253\256" + "\377\302\272\276\377\177\225n\377~\240A\377}\245\026\377o\234\001\377r\240\001" + "\377z\255\001\377u\244\010\377z\255\026\377{\250\007\377\201\250\004\377z\241\001\377" + "\214\261\033\377r\236\003\377w\247\002\377w\243\002\377\213\264\001\377\215\261\002" + "\377\212\255\002\377\207\256\002\377\202\252\001\377p\233\002\377x\242\014\377\212" + "\265,\377|\253\014\377y\251\001\377|\257\001\377s\240\001\377z\251\003\377x\245\001" + "\377q\236\001\377g\227\002\377i\233\006\377\211\265%\377\213\271\060\377~\261\026" + "\377h\233\005\377i\231\001\377p\234\001\377\201\253\002\377\220\271\003\377s\237\035" + "\377Zz+\377?S(\377\061@\036\377\012\012\003\377\000\000\000\377\000\000\000\377\000\000\000\377\015" + "\015\016\377\004\004\004\377\000\000\000\377\001\001\001\377\001\000\001\377\020\015\020\377\002\002\003\377" + "\001\000\000\377;-\071\377xgv\377zlz\377\217~\221\377\217}\216\377\243\222\235\377" + "\324\312\312\377\264\240\241\377\220{{\377lZb\377\212z\201\377\266\246\254" + "\377\261\240\243\377\303\263\261\377\301\255\250\377\266\235\221\377\231" + "~s\377\226|q\377}fa\377l[U\377g]T\377k`M\377{nU\377\177pT\377\215~b\377\210" + "y^\377q_?\377]G!\377\\D\032\377aK\037\377iV&\377m^,\377\200xI\377|tC\377wp" + "B\377\177xQ\377~xS\377\214\205`\377\206~X\377xkC\377\201uN\377\203zW\377" + "\205}^\377\233\226~\377\236\231\206\377\224\212w\377\235\223\200\377\232" + "\214u\377\237\224~\377\227\213x\377yl[\377bSA\377^UC\377PC/\377XJ;\377cV" + "L\377xmg\377\203tr\377wdd\377vef\377\204qs\377\224\200\201\377\256\240\240" + "\377\204x\201\377\204y\203\377\233\216\226\377\240\221\232\377\232\212\224" + "\377veq\377\223\201\207\377\263\247\247\377\310\304\305\377\221\241\201\377" + "m\227)\377n\231\010\377s\236\003\377t\232\003\377\213\267\032\377x\250\003\377{\251" + "\001\377k\237\002\377h\233\001\377w\247\000\377\260\277\061\377\216\246\024\377q\232" + "\001\377\177\252\002\377\203\261\002\377}\242\002\377\220\264\002\377\213\261\001\377" + "{\244\002\377u\240\003\377z\245\010\377x\246\012\377k\234\002\377z\257\002\377y\250" + "\002\377s\236\002\377\177\253\003\377z\246\001\377i\230\002\377j\231\002\377w\241\003\377" + "y\244\002\377u\246\004\377v\256\006\377e\220\002\377q\230\001\377\205\253\001\377\214" + "\261\000\377\211\265\017\377f\215\037\377Vi\063\377+>\015\377\040\062\012\377\000\000" + "\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000" + "\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377!\027\036\377h[g\377\200q\177\377" + "\237\223\241\377\204v\206\377\251\233\243\377\303\267\270\377\244\216\221" + "\377\204pv\377mYe\377\224\204\211\377\270\251\254\377\264\242\246\377\263" + "\233\232\377\271\242\231\377\267\237\224\377\237\203|\377\235\204\177\377" + "\200h`\377aH>\377ZA\064\377n_E\377sfG\377\204zX\377\242\237\204\377\243\241" + "\210\377\227\224w\377\200uT\377\203vS\377\210|U\377\203vL\377\213\204Z\377" + "\212\205Z\377\213\205]\377\213\204_\377\177vO\377xk?\377m]/\377iY.\377pb" + "\067\377skB\377}zZ\377\226\227\204\377\223\216|\377\237\235\213\377\250\246" + "\224\377\240\235\210\377\213\200k\377Q<'\377VD\066\377eVO\377O>'\377XH+\377" + "^O/\377]J,\377eT:\377\217\200x\377\210xx\377\177nl\377\202pn\377\214|x\377" + "\210sq\377\236\215\212\377~pz\377\215\201\212\377\246\231\241\377\221\201" + "\213\377\237\222\231\377rdn\377\215}\207\377\256\241\244\377\274\266\267" + "\377\226\243\205\377g\223\033\377e\224\003\377j\222\002\377p\225\004\377\224\272" + "\061\377\204\256\020\377~\251\002\377i\237\001\377b\230\000\377n\237\001\377\210\247" + "\021\377\276\311P\377|\241\004\377x\243\002\377{\253\002\377v\240\001\377\215\264" + "\002\377\202\250\002\377\200\246\002\377\204\254\002\377s\232\001\377y\245\001\377t\241" + "\001\377r\240\002\377o\234\002\377o\237\002\377y\250\002\377v\242\002\377s\237\002\377" + "l\232\002\377i\224\002\377u\242\001\377q\236\001\377r\244\002\377m\233\002\377\203\257" + "\003\377\211\262\003\377\222\272\021\377\213\263E\377\221\266V\377w\215d\377a" + "\202E\377\065M\"\377\034.\020\377\016\032\002\377\000\000\000\377\000\000\000\377\000\000\000\377" + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\"" + "\035!\377b[c\377sds\377\230\212\235\377\204u\211\377\246\227\241\377\302\267" + "\266\377\232\210\210\377\213y\200\377s`m\377|jv\377\247\225\233\377\216z" + "\203\377\260\234\230\377\254\225\216\377\262\232\215\377\224zo\377\207le" + "\377oVO\377s\\S\377fRE\377\\N\066\377h^=\377ld@\377}wW\377\215\211k\377zu" + "Z\377}x\\\377\206|^\377|mF\377\215\202]\377\215\203\\\377|qI\377\212\200" + "\\\377\224\215n\377\203uP\377{kA\377m\\.\377hW/\377gW\061\377ujI\377\203|" + "b\377\203}c\377\202y]\377|rO\377xkH\377YF)\377maG\377K<\034\377RE'\377zqf" + "\377SC&\377P@\036\377VA!\377P:\031\377aO\063\377\204tc\377\226\213\213\377u" + "cb\377\213zw\377\220\177y\377\216xt\377\230\205\203\377wep\377\206u\201\377" + "\246\234\241\377\220\206\216\377\227\214\223\377k^h\377qcm\377\244\227\232" + "\377\274\270\272\377\212\227w\377e\222\035\377`\216\001\377p\233\002\377r\231" + "\003\377\225\273-\377|\243\001\377\201\257\003\377r\244\007\377r\247\017\377g\230" + "\001\377t\231\002\377\270\306S\377\214\256\033\377y\245\001\377o\234\002\377r\237" + "\001\377{\246\001\377\201\250\001\377\201\246\002\377\206\250\002\377}\240\003\377\211" + "\257\002\377\177\247\001\377w\241\001\377q\240\001\377w\252\002\377f\232\002\377w\244" + "\001\377~\244\001\377j\223\002\377q\227\002\377t\243\002\377v\246\002\377y\251\005\377" + "g\227\001\377s\243\002\377|\252\002\377u\241\002\377l\232\010\377c\215+\377=]$\377" + "Ms,\377Jb>\377WlL\377[mX\377XlW\377NcM\377N`H\377AR?\377-\066,\377\012\016\011" + "\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377'#'\377JAI\377ses\377\225\207" + "\230\377\205v\210\377\270\255\262\377\271\254\254\377\245\224\224\377}kt" + "\377k[g\377\201t}\377\253\232\236\377\240\215\220\377\251\222\216\377\255" + "\222\213\377\274\242\225\377\220ra\377\225xj\377\220ti\377x^R\377iRA\377" + "N\071\036\377=,\013\377dW\064\377{rO\377\221\213m\377\214\204j\377}qW\377|lP" + "\377\203sU\377\210wZ\377\201pO\377\212yX\377\204rW\377\234\224\200\377\231" + "\221{\377\211|b\377\221\207m\377\211\201h\377\207\201h\377\212\206m\377\203" + "ze\377\204{e\377\200xZ\377YO$\377_R(\377reF\377gZ\064\377[M%\377Q@\030\377" + "rdP\377@/\013\377VC\040\377ZD#\377\\E(\377yfP\377wdT\377~oj\377\210yy\377~" + "je\377\206pi\377\224\200y\377\227\203\201\377wfr\377\215~\207\377\252\236" + "\244\377\235\220\227\377\235\217\227\377l^j\377\203u}\377\230\213\215\377" + "\265\256\264\377u\211X\377_\212\022\377_\214\001\377x\244\022\377u\243\011\377" + "|\247\013\377y\244\001\377u\245\000\377\203\265)\377\201\265\063\377g\236\017\377" + "}\250\004\377\207\252\014\377\240\270\035\377\214\256\002\377\201\245\002\377|\243" + "\001\377k\231\002\377x\243\002\377}\243\002\377\217\261\002\377\215\255\002\377p\230" + "\002\377u\236\002\377~\252\001\377~\254\001\377u\245\002\377Y\216\002\377l\230\002\377" + "v\235\001\377q\230\002\377u\234\002\377z\252\003\377p\231\003\377x\240\001\377g\236\003" + "\377t\247\001\377z\246\002\377u\234\002\377x\240\002\377W\201\003\377;a\003\377#H\002\377" + "\036\064\004\377\013\013\006\377\004\004\003\377\001\001\001\377\001\000\001\377\000\001\001\377\003\011\003\377" + "(\067%\377b{^\377w\222y\377AQ?\377\015\023\011\377\035\037\023\377==\066\377<:<\377" + "kbn\377\215\177\220\377\216\177\217\377\264\251\255\377\270\254\253\377\240" + "\216\217\377\211w~\377m\\g\377\202v|\377\267\252\254\377\234\206\216\377" + "\244\215\214\377\226yq\377\256\225\211\377\237\201p\377\221qa\377~bO\377" + "rWB\377fN\066\377UB\"\377C\064\020\377?\061\017\377J\066\026\377kV\070\377n\\B\377" + "\213\205v\377\230\224\205\377\211\200m\377\215\200k\377\231\214w\377\241" + "\226\201\377\232\216w\377\215\201i\377\241\234\210\377\243\241\215\377\235" + "\234\207\377\223\220y\377\224\216t\377\205}[\377ykC\377kZ\061\377sd<\377]" + "H\033\377Q\071\014\377sb=\377l^\064\377VC\033\377G\063\020\377]L\070\377G.\024\377" + "K\063\025\377M\066\027\377q^D\377zfT\377r]Q\377\202oi\377zgb\377\230\207|\377" + "\223\200u\377\205qn\377\226\207\210\377udp\377\200q|\377\223\210\216\377" + "\232\220\224\377\220\205\214\377fYe\377o`k\377\240\224\231\377\261\254\260" + "\377s\211X\377a\212\037\377f\222\027\377i\230\010\377x\250\010\377v\244\003\377" + "v\241\001\377{\246\007\377\200\261\032\377t\250\013\377l\243\006\377e\234\002\377q" + "\237\002\377\200\247\011\377\230\267\013\377\231\267\002\377\225\265\002\377m\232" + "\002\377u\241\002\377\205\260\002\377\223\270\002\377\212\254\001\377i\225\002\377x\242" + "\002\377\206\256\001\377\202\254\002\377u\242\002\377l\232\002\377c\222\001\377y\245" + "\003\377u\237\001\377p\233\002\377t\237\002\377w\233\001\377}\241\003\377g\240\006\377" + "u\250\001\377y\245\002\377}\247\001\377z\242\002\377]\211\001\377Ak\004\377%@\002\377." + "\063#\377!%\026\377\016\016\013\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000" + "\000\000\377\000\000\000\377\000\000\000\377\011\015\011\377:J#\377`l;\377@G*\377;<\064\377l" + "gn\377\224\210\224\377\207}\210\377\255\244\250\377\272\257\260\377\233\214" + "\216\377xjo\377^PZ\377{ms\377\260\244\245\377\246\225\230\377\243\220\213" + "\377\212ql\377\272\245\235\377\240\202q\377~XB\377yT?\377V\063&\377Z=,\377" + "s^E\377mW\070\377S<\033\377G/\013\377K\064\023\377xhR\377\202ub\377wiV\377\225" + "\217}\377\220\211v\377\230\221\200\377\235\226\204\377\250\241\216\377\243" + "\236\211\377\223\214q\377\221\212m\377\215\204d\377ykE\377xgB\377vb\064\377" + "lV%\377gP#\377\\D\031\377aK!\377ziB\377\177qF\377fP&\377B*\013\377\060\027\003" + "\377ZA\063\377W=,\377pYC\377\202nX\377\213xj\377fMC\377pYP\377nUN\377\206" + "oj\377\237\212\202\377\202ka\377\231\206}\377\235\220\214\377~v{\377\212" + "\201\210\377\235\221\230\377\241\226\234\377\205x\202\377`S`\377l_j\377\241" + "\232\240\377\244\243\246\377i~\071\377`\202\025\377x\244@\377`\216\002\377|\254" + "\005\377v\243\001\377y\247\002\377z\250\006\377w\246\004\377t\241\000\377}\256\005\377" + "i\235\001\377k\225\001\377|\242\001\377\210\251\002\377\214\255\001\377\214\257\001\377" + "y\241\001\377v\240\001\377\201\250\002\377\203\247\002\377\205\250\002\377s\233\001\377" + "~\247\002\377\210\264\002\377}\250\001\377x\242\002\377x\245\001\377m\232\001\377{\245" + "\004\377}\250\020\377x\245\002\377s\232\002\377l\217\002\377\207\246\002\377n\251\003" + "\377k\237\002\377k\232\002\377k\233\001\377g\231\003\377]\221\001\377Hx\003\377\031+\005" + "\377'\060\030\377MOE\377,**\377\012\007\010\377\000\000\000\377\000\000\000\377\000\000\000\377\000" + "\000\000\377\000\000\000\377\001\002\000\377\011\027\002\377,D\010\377\060I\010\377\062E\020\377=" + "H)\377rtq\377\232\221\231\377\221\206\216\377\221\205\214\377\261\245\244" + "\377\211y\177\377hX`\377UHP\377\221\206\212\377\252\240\243\377\243\224\227" + "\377\235\212\204\377\215yl\377\253\227\212\377\257\224\206\377\203]I\377" + "\222o^\377\205h\\\377t]R\377nWA\377xaD\377u`;\377hR*\377aI#\377eN+\377Y:" + "\030\377wbK\377xiS\377\177pZ\377\215\177h\377\177pT\377\230\216t\377\226\212" + "n\377\204vR\377\205wU\377\222\210i\377\216\206f\377\214\203e\377\221\206" + "h\377\223\204f\377\202pW\377\224\203o\377\215}a\377xdB\377hM-\377;\040\006\377" + "@'\015\377A'\015\377{fR\377s\\@\377jR<\377oZK\377yf[\377aKG\377eOI\377oWQ\377" + "\241\213\203\377\210lg\377\203bZ\377\232\203\200\377\233\221\223\377\205" + "\200\205\377\230\224\230\377\252\242\245\377\252\237\244\377\216\200\211" + "\377VGR\377gXe\377\230\216\226\377\236\233\235\377{\210S\377g\201\060\377" + "{\251F\377f\234\006\377p\236\002\377\177\252\002\377z\245\003\377y\244\002\377s\241" + "\003\377t\237\002\377\200\250\001\377|\252\004\377j\226\002\377w\240\001\377}\241\003\377" + "\177\243\001\377\200\244\002\377\177\245\001\377\177\246\003\377\201\251\002\377s\232" + "\002\377\177\243\001\377\200\244\002\377\207\260\002\377|\251\002\377w\246\001\377r\234" + "\001\377v\244\000\377\212\256\016\377l\222\002\377|\252\027\377r\240\002\377w\236\002" + "\377|\237\002\377\177\241\002\377p\253\011\377U\200\000\377Z\204\002\377Y\206\002\377" + "[\220\006\377\\\232\006\377S\211\004\377\020\034\003\377\000\000\000\377\023\022\016\377\"\034" + "\025\377\013\012\006\377\000\000\000\377\000\000\000\377\000\000\000\377\001\001\001\377\007\014\001\377\027" + ")\001\377&E\003\377\066^\011\377;e\020\377Mr&\377.A\030\377_[Z\377\220\203\215\377" + "\214\200\211\377\231\216\224\377\276\263\262\377\220\200\203\377g[d\377O" + "@K\377QDH\377\236\223\222\377\247\227\226\377\243\217\213\377\200kd\377\231" + "\204y\377\262\235\221\377\237\201t\377\201aS\377mOA\377I*\036\377hO>\377r" + "X?\377|gI\377v`;\377lW-\377r\\/\377oV)\377~iA\377u_\071\377~jH\377\210yY\377" + "\231\217q\377\235\224x\377\241\231}\377\216\202b\377\215\200a\377\205z]\377" + "\211~d\377\200s\\\377\177r`\377\213\177p\377\222\206z\377~oZ\377|jJ\377Q" + "\071\024\377:!\005\377F.\020\377\\H#\377nX\066\377\231\210s\377{gK\377nYE\377v" + "cQ\377]L>\377aQB\377bL>\377zaT\377\220{l\377|bT\377\200fW\377\273\262\252" + "\377\222\205\210\377\200pz\377\210}\202\377\227\216\220\377\216\205\212\377" + "i^d\377L?K\377d[d\377\226\214\225\377\207\206|\377l|M\377k\225>\377t\251" + "M\377i\240\021\377i\227\001\377t\237\002\377x\241\002\377w\237\000\377\200\254\016" + "\377v\236\003\377\206\250\002\377\230\274\026\377|\250\010\377t\240\002\377~\250" + "\002\377y\237\001\377\220\256\002\377~\240\002\377\205\254\001\377\203\253\002\377\200" + "\247\001\377\202\247\002\377}\243\001\377\204\255\002\377m\233\002\377z\256\016\377" + "{\254\012\377m\226\002\377\207\251\011\377\210\254\015\377\177\254\017\377k\227" + "\002\377\205\252\006\377r\226\002\377{\245\004\377b\243\013\377`\230\015\377Z\206\004" + "\377_\215\001\377Y\212\002\377]\224\000\377[\231\012\377/O\006\377\022\035\002\377\001\002" + "\001\377\000\000\000\377\000\000\002\377\002\003\001\377\006\011\002\377\005\007\002\377\012\030\002\377\031" + ".\002\377;X\006\377:_\003\377\066_\003\377=j\016\377=_\032\377\071D*\377a[^\377\213\177" + "\211\377\225\213\224\377\214\200\211\377\253\237\242\377\231\211\214\377" + "pdk\377ZOW\377d^`\377\203{z\377\231\215\216\377\273\254\246\377\237\210\201" + "\377\177rh\377\261\242\226\377\263\242\224\377\215r^\377v\\H\377|bT\377i" + "O?\377s^O\377xdN\377\206sU\377\205pK\377\222\177W\377\200k?\377oU&\377\204" + "oK\377zfF\377\205rV\377\201nU\377\236\224~\377\205tX\377\216\200`\377\222" + "\204c\377\215|Y\377\230\210h\377\206wU\377\203pU\377t`G\377fS>\377\\K\066" + "\377=*\026\377\061\035\004\377N\070\021\377eR%\377ub\066\377\215{U\377\217\177h\377" + "T<\036\377zeN\377bJ\066\377bJ<\377}f\\\377xaW\377\247\223\216\377w]V\377`F" + ";\377\204rj\377\274\264\254\377\212}\200\377\217\204\211\377\237\226\232" + "\377\230\217\225\377\211\201\210\377`Xa\377F?J\377`Ya\377\243\236\240\377" + "sx`\377l\216>\377\\\217\027\377u\252>\377j\235\006\377o\233\002\377k\225\001\377" + "~\245\002\377z\241\002\377v\235\000\377w\237\002\377\217\264\021\377\212\255\006\377" + "\207\256\010\377t\240\001\377y\244\002\377w\237\002\377\214\254\002\377\211\251\001" + "\377\207\250\002\377\201\246\002\377y\240\002\377}\245\001\377w\236\002\377|\250\002" + "\377b\222\002\377x\252\011\377t\234\001\377~\240\002\377\206\252\007\377}\242\005\377" + "\200\252\014\377m\225\002\377x\236\001\377y\235\003\377\202\253\025\377U\223\001\377" + "c\237\020\377a\232\012\377_\222\001\377c\223\001\377d\227\002\377Y\206\002\377\\\220" + "\011\377R\177\014\377#\067\002\377\023$\002\377\013\031\002\377\034'\002\377?F\013\377;H" + "\013\377\012*\002\377!E\003\377\067^\002\377Ly\003\377Nz\012\377t\246H\377\067R\021\377" + "?O+\377]`Y\377\200z\177\377\201w}\377|px\377\247\233\234\377\233\215\216" + "\377rfk\377SEQ\377LCK\377\214\205\204\377\252\236\234\377\273\256\246\377" + "\250\215}\377pZJ\377\217|p\377\302\266\255\377\234\205r\377z[B\377rS<\377" + "~`I\377oQ:\377mO?\377|cO\377\213wY\377\230\205d\377\222\200^\377\210uR\377" + "\206qO\377\202jF\377|b<\377\212rQ\377\206oL\377\206oI\377\202jC\377za\070" + "\377tZ\060\377\207uX\377\213|_\377vfL\377\\N\064\377\065\"\012\377\065\040\010\377" + "\066\040\004\377Q:\026\377r_\070\377\214zW\377\223\202a\377\206rU\377\201kV\377" + "kT;\377\\A*\377fK\067\377sZK\377|d[\377\233\213\204\377\232\213\205\377}h" + "_\377hRI\377\240\221\207\377\263\253\250\377|ou\377\214\202\206\377\211\177" + "\205\377\243\233\240\377\203\177\205\377UNX\377JAL\377h`g\377z|o\377kzV\377" + "g\231\064\377c\225#\377\202\261A\377n\232\004\377n\232\002\377p\222\002\377\224" + "\251\002\377\215\251\001\377x\231\001\377}\252\006\377{\241\003\377\205\253\002\377\205" + "\255\002\377|\246\001\377y\242\002\377z\242\002\377\201\244\001\377~\236\001\377\207" + "\252\002\377\202\247\002\377\177\244\001\377\202\251\002\377\215\270\003\377x\244\002" + "\377`\217\002\377o\237\002\377r\231\002\377\207\254\002\377p\225\003\377n\223\002\377" + "y\245\010\377c\215\002\377s\234\002\377\204\256\007\377x\237\002\377d\230\010\377c" + "\227\006\377\\\214\001\377Q}\002\377]\211\001\377^\206\001\377`\206\002\377Z~\001\377Y" + "\210\005\377=a\003\377%G\002\377\060J\002\377/B\003\377/?\002\377GV\005\377-F\002\377*O\003" + "\377\065\\\002\377Q|\002\377`\220\015\377X\205\031\377;c\006\377Ih\"\377m{_\377\205" + "\206~\377\204~}\377\201vz\377\246\236\236\377\232\217\217\377pbf\377I:D\377" + "<-\067\377WJM\377\201rq\377\241\223\216\377\266\243\225\377\201fV\377dNG\377" + "\236\213~\377\250\221|\377\211lP\377pL/\377}]@\377\205hN\377\177dJ\377mL" + "\061\377qR\066\377yaF\377\221\202g\377\226\213p\377\236\225z\377\247\236\204" + "\377\232\215t\377\231\211n\377\215|_\377\222\201d\377\230\210l\377\210vV" + "\377~jK\377vbG\377iS\070\377aJ/\377S>\036\377V@\033\377mY\067\377hP.\377[@\040" + "\377\231\205e\377\243\223u\377zdM\377v^D\377\203nS\377w[B\377^@)\377\210" + "pZ\377\237\211y\377\214uh\377\242\222\211\377]LF\377G\065\062\377\204rm\377" + "\304\275\271\377\222\210\207\377\204y~\377\226\214\217\377\237\226\231\377" + "\235\227\235\377oms\377@:E\377@\071F\377pmo\377ip\\\377m\206Y\377d\222\067" + "\377a\224(\377m\244\036\377`\220\000\377~\252)\377y\232\006\377\232\260\004\377" + "\215\251\002\377\200\245\002\377z\244\004\377n\224\002\377\200\245\002\377\205\251" + "\002\377\215\263\002\377t\235\001\377t\235\002\377~\242\002\377\204\251\002\377z\237" + "\002\377\207\256\001\377\177\244\002\377\211\260\001\377\204\251\001\377~\246\002\377" + "q\236\002\377a\216\001\377s\234\001\377w\235\002\377f\214\002\377l\221\000\377v\237\003" + "\377l\223\002\377r\232\002\377\201\247\002\377{\241\000\377\204\260N\377}\246\060" + "\377a\212\002\377Do\002\377Y|\002\377X{\002\377Rx\001\377\\\203\001\377Mv\002\377Jw\003\377" + "Ky\004\377Cd\002\377\064O\003\377\035\067\001\377)=\001\377:M\002\377>V\002\377\062O\002\377" + "<a\002\377a\220\022\377[\210\004\377Iq\001\377Hj\030\377N\\@\377ytw\377{pv\377zo" + "v\377\233\221\223\377\227\215\213\377ymq\377WKT\377?\065>\377e[b\377\204z" + "y\377\210xw\377\307\267\256\377\221wj\377^H>\377\201i_\377\215uh\377\227" + "{g\377\242\206j\377\234}[\377\207gE\377sS\066\377\201bH\377a@\"\377jL-\377" + "\177jK\377\201pT\377\221\210u\377\243\235\212\377\234\226\202\377\245\236" + "\216\377\240\233\214\377\243\233\214\377\235\223\204\377\223\206v\377\213" + "|l\377\224\205w\377\206sa\377\200nV\377\206tX\377\207oR\377z_;\377\203hH" + "\377\231\204b\377\251\234y\377}gP\377eI\065\377\216yb\377~iP\377fI-\377}a" + "G\377\241\213q\377\250\227\204\377\226\205s\377\217\202u\377A,$\377\\J?\377" + "\244\230\217\377\303\276\271\377\203\177\202\377\202{\200\377mck\377\213" + "\203\207\377\203y\200\377NDN\377JDL\377MIP\377ppm\377ahR\377{\235j\377Y\207" + "-\377d\225+\377a\226\014\377a\220\003\377p\232\012\377n\221\002\377{\244\002\377" + "y\241\002\377z\243\003\377k\223\002\377o\230\002\377}\250\002\377\203\254\002\377\207" + "\263\002\377p\241\003\377j\226\002\377\177\246\001\377\210\256\001\377\205\253\001\377" + "\202\252\002\377~\246\002\377\206\255\001\377w\234\002\377\206\254\006\377u\233\002\377" + "x\241\003\377w\240\002\377l\221\001\377m\224\001\377|\252\017\377\204\265\030\377|" + "\256\016\377\211\272\035\377\224\300)\377\215\270\036\377^\222\005\377p\233\012" + "\377r\226\007\377n\215\007\377`}\001\377_\177\001\377]\177\001\377Z\203\002\377Kt\002\377" + "It\002\377J\177\003\377Cj\002\377\060O\001\377@X\004\377\032\070\002\377\037<\002\377,I\000\377" + "\063W\001\377Mv\004\377\\\206\037\377Jj\002\377Yx\005\377]x\036\377Xe?\377poi\377\205" + "{\201\377\205z\201\377\225\213\215\377\232\217\217\377~tz\377_S[\377A\071" + ">\377\071\063\064\377]YU\377\177xv\377\272\255\245\377\253\227\203\377lP@\377" + "T\066-\377\203m`\377\264\240\215\377\253\226y\377\252\224v\377\231\177c\377" + "\207mS\377tU;\377fE$\377nP/\377bH%\377\201oP\377\215\177d\377\204uZ\377\210" + "}f\377\224\217\201\377\222\216\200\377\212\201r\377\232\221\204\377\243\235" + "\215\377\226\216z\377\227\211t\377\215|f\377\203pS\377q[\067\377\206nJ\377" + "\240\214k\377\257\242\205\377\242\222t\377{dK\377^A.\377w^I\377zcK\377nR" + "\070\377\200eM\377\237\213x\377\261\245\223\377\236\217|\377\220\201q\377" + "S?\062\377P<\061\377\214zj\377\271\262\244\377\244\233\223\377\205|{\377\220" + "\207\207\377\220\207\213\377\206{\200\377obl\377OEP\377F?G\377VRU\377qrg" + "\377brQ\377r\241S\377\\\216-\377b\227%\377T\204\005\377f\222\010\377g\215\001" + "\377k\223\001\377v\244\003\377\177\255\013\377y\246\004\377g\222\002\377x\243\002\377" + "\177\254\002\377\201\255\002\377t\243\001\377m\243\002\377l\232\001\377|\244\001\377" + "\210\256\001\377\201\247\002\377}\245\002\377|\247\002\377\177\247\001\377{\237\002\377" + "\210\254\002\377{\237\002\377\206\262\005\377z\244\005\377\204\257\016\377\224\275" + "$\377\225\277#\377\206\263\017\377\205\264\013\377y\243\004\377\207\265\033\377" + "\214\270#\377V\213\003\377\\\215\002\377Z}\001\377x\222\021\377]v\003\377^x\001\377" + "Zv\001\377^}\003\377Wu\002\377A`\002\377\"K\002\377<^\002\377Rk\003\377<L\002\377AW\002\377" + "Xw\007\377\217\235,\377`y\023\377d\215*\377Fg\002\377Hc\002\377@Z\002\377Je\007\377" + "`s\067\377nq`\377\214\215\207\377odk\377vkq\377\217\205\206\377\217\206\207" + "\377f]^\377L@B\377J@A\377\201zv\377\224\212\201\377\201vi\377\263\251\232" + "\377\212wd\377Z@\060\377dM=\377\204ra\377\242\223|\377\230\203i\377\216tZ" + "\377\236\210k\377\226~_\377oM)\377jJ\037\377v^\065\377kU-\377oY\062\377ygB\377" + "udA\377\215\200f\377~qV\377yiP\377\212\177l\377xjT\377kZA\377vcG\377gQ\060" + "\377lS-\377\237\217j\377\250\232y\377\216\177b\377\177lV\377sWA\377tW@\377" + "rV;\377v]D\377jL\061\377\222{b\377\245\221~\377\261\241\220\377\242\222\202" + "\377\235\217\201\377uka\377L\066+\377nUA\377\261\250\224\377\254\244\226\377" + "\200vt\377|sp\377rjh\377sjk\377ohk\377e_e\377XU[\377KIO\377jhi\377~\204w" + "\377p\213`\377p\231Q\377j\225\066\377b\226\024\377V\202\002\377^\215\002\377c\215" + "\002\377\205\260\011\377y\246\003\377u\240\003\377{\247\002\377e\221\002\377z\245\001" + "\377\216\261\002\377\222\264\002\377p\232\001\377o\235\001\377x\246\003\377~\243\001" + "\377\212\256\001\377\202\244\002\377|\242\001\377\200\247\002\377\205\254\002\377\203" + "\246\002\377\215\253\002\377\207\252\001\377}\241\002\377\203\247\001\377\204\242\003" + "\377\212\242\002\377\220\254\002\377\200\240\002\377\205\257\005\377\204\252\005\377" + "\204\252\006\377\210\256\004\377h\231\024\377Z\210\002\377Ou\001\377p\224\011\377]" + "x\001\377_x\001\377`y\002\377_z\002\377Tn\001\377<W\002\377)I\002\377\065S\002\377Eg\001\377" + "Rx\003\377Rw\000\377f\227\004\377Gp\006\377Js\026\377Oy\027\377Bb\000\377Hf\002\377AY\001" + "\377B]\003\377Tl#\377Yb@\377{\200p\377wpo\377vlm\377\206{|\377\234\217\217" + "\377shl\377[PW\377aW_\377g__\377pkg\377}xs\377\226\216\202\377\251\235\212" + "\377q[F\377`E\071\377_J<\377\230\210y\377\222{i\377{^O\377\240\213y\377\274" + "\254\233\377\250\221v\377\216rM\377\206lE\377\224~[\377\204pE\377\200nD\377" + "}lE\377\211|Z\377\205wZ\377\214\201f\377\217\204g\377\203wX\377\215\203e" + "\377\214~\\\377\227\206b\377\210uN\377\236\217l\377\220\177_\377oV@\377j" + "Q=\377cH/\377\200eH\377iK.\377mO\062\377\217vZ\377\253\232\204\377\260\240" + "\216\377\253\235\214\377\235\212y\377\216\177q\377ZKC\377th[\377\240\223" + "\203\377\266\260\237\377\217\207~\377\200vu\377\201zv\377wqo\377khh\377X" + "WY\377HGL\377QOU\377[Z_\377vvu\377luc\377c\220K\377]\215\064\377V\212\023\377" + "^\225\020\377T\207\001\377l\234\010\377z\245\015\377\202\255\005\377u\235\002\377" + "p\226\002\377k\227\001\377t\242\003\377}\252\001\377\214\261\002\377\205\253\001\377" + "p\234\002\377s\244\005\377}\257\007\377\207\253\007\377\204\244\002\377y\232\001\377" + "\205\241\010\377\210\253\002\377\221\265\003\377\210\253\002\377\226\260\006\377\202" + "\244\001\377\200\244\002\377\201\241\002\377\204\235\004\377\215\243\016\377\224\263" + "\016\377\205\255\004\377x\236\003\377x\233\003\377\202\255\002\377\203\252\001\377_" + "\211\001\377S\201\002\377Z\205\002\377j\223\002\377c}\002\377f\201\001\377g\200\001\377" + "g\206\002\377Yx\001\377Lm\001\377Jp\003\377Ks\002\377R}\004\377:_\001\377c\221\033\377W" + "\203\027\377Pu\020\377q\232<\377?m\010\377\066\\\004\377Nq\017\377Lj\007\377So\015" + "\377k\202\065\377i|I\377x{l\377pnj\377xrq\377\207\177}\377\236\223\221\377" + "ukl\377^SZ\377ZQX\377kfj\377e^a\377\177xs\377\203yp\377\261\251\234\377\244" + "\227\201\377mXA\377}k^\377|jb\377\217~s\377nXJ\377\213yi\377\262\244\220" + "\377\257\237\204\377\235\206d\377\213qN\377\216sM\377\240\216j\377\227\205" + "a\377\224\204`\377\202sO\377\204tS\377\204vT\377\225\210h\377\211|\\\377" + "\223\211j\377\223\212n\377\233\215s\377\207vZ\377\206rQ\377\216zY\377v`?" + "\377hR\060\377cJ*\377u[;\377\210oQ\377\227\200e\377\251\230\202\377\256\240" + "\216\377\247\231\207\377\230\207v\377\222\203v\377S@\062\377I\064\"\377\202" + "q\\\377\247\235\213\377\215\203v\377phc\377voj\377nfd\377]VU\377ZUY\377h" + "fl\377c`g\377ROX\377a`e\377xwx\377XdI\377c\236H\377I|\015\377Q\211\007\377U" + "\217\011\377S\211\001\377n\237\003\377o\234\002\377t\235\001\377x\236\002\377r\231\002" + "\377g\222\002\377m\230\003\377\204\254\001\377\201\247\002\377|\245\001\377r\242\002" + "\377k\237\016\377p\253%\377\201\250\025\377\201\244\001\377p\224\002\377\201\231" + "\007\377\225\257\004\377\226\260\003\377\217\263\001\377\232\267\012\377w\230\001\377" + "z\235\002\377\203\246\002\377\203\241\003\377\230\263\027\377\225\261\015\377\212" + "\254\001\377y\232\002\377|\242\002\377\177\254\002\377}\250\002\377X\204\002\377Hy\001" + "\377T\202\003\377Jp\004\377`\177\002\377m\222\003\377e\215\002\377b\212\002\377X~\002\377" + "Sz\003\377Ry\001\377Fc\002\377\062J\002\377\064J\002\377>Z\003\377o\237I\377j\223>\377" + "_\210\030\377Hm\003\377Or\007\377Tv\006\377g\207!\377g\205!\377b\177!\377u\206U" + "\377_^O\377pmg\377vsn\377tqj\377\221\211\200\377\210\177x\377h^^\377g\\_" + "\377dYa\377ZRY\377GAD\377]XP\377\200zl\377\270\261\227\377\214\177a\377G" + "\060!\377V?.\377{fR\377\232\211{\377\212yh\377}jU\377\240\217y\377\227\204" + "i\377\205iH\377\201e?\377\210oI\377\206pJ\377\217\200]\377\177oK\377\211" + "{X\377\213\203^\377\200wU\377\215\206d\377\212\202a\377\222\215o\377\220" + "\207n\377\226\212p\377\200oK\377\177hC\377~e=\377\207tO\377\210uT\377\232" + "\211k\377\244\224z\377\257\242\214\377\267\253\232\377\252\235\213\377\231" + "\210v\377\203sf\377scZ\377K\066(\377fN\067\377\246\231\204\377\252\244\223" + "\377\203wk\377ynd\377ka[\377\177{v\377\213\211\207\377xtx\377d^g\377`Zc\377" + "igk\377ddc\377w|t\377bwS\377]\216\066\377My\002\377R\203\005\377Y\215\011\377f" + "\230\005\377|\244\004\377w\235\004\377u\234\002\377p\226\002\377r\231\002\377r\232\001" + "\377j\226\002\377\202\252\002\377\201\252\002\377|\246\001\377u\243\007\377t\246\031" + "\377\211\277U\377\201\255\021\377~\246\002\377n\230\002\377\177\251\004\377\207" + "\251\002\377\250\275\025\377\230\263\016\377\205\240\002\377\221\260\023\377\210" + "\257\010\377\204\251\020\377}\232\006\377\216\250\002\377\254\271\035\377\222\256" + "\003\377\201\242\001\377\206\257\001\377\200\251\001\377z\246\001\377T\203\002\377V\206" + "\006\377[\214\006\377@e\001\377[\207\005\377a\221\004\377Z\203\001\377`\207\006\377S~\002" + "\377Z\202\001\377Op\004\377Vs\002\377Gf\002\377\063S\002\377Dd\002\377Ec\007\377h\243\060" + "\377S\205\000\377Lq\003\377C`\001\377Tq\003\377Lg\001\377o\211'\377{\230F\377drC\377" + "VYE\377yvn\377yvo\377||s\377rph\377\225\221\211\377~vu\377WLS\377ZNW\377" + "nhm\377^[[\377_\\U\377\\XL\377\213\205r\377\250\241\207\377o_J\377M:\"\377" + ">)\023\377{pe\377\222\212z\377kXC\377uaL\377\231\211r\377\243\223y\377\226" + "\201b\377\202jB\377\207pI\377\210wN\377\212|T\377\221\206_\377~tN\377\207" + "\200^\377\203~Z\377}uT\377\215\205j\377\204uX\377\217\200_\377\204qJ\377" + "\210tL\377\204tK\377\242\224t\377\250\232~\377\264\252\226\377\234\215u\377" + "\264\250\225\377\237\222\200\377\221\202n\377\226\210w\377{na\377G\061+\377" + "T?\071\377\236\217}\377\265\253\235\377\233\220\207\377\177rl\377ped\377~" + "wu\377}xy\377c^e\377D;I\377H?L\377c`e\377||z\377lri\377s\201n\377f\213U\377" + "X\177!\377Z\213\010\377X\211\003\377`\216\003\377t\240\002\377\206\253\017\377r\232" + "\002\377x\244\002\377f\215\002\377\202\246\007\377\201\243\002\377|\236\003\377\205\257" + "\002\377\177\245\002\377\200\250\001\377p\237\007\377n\236\015\377\225\304n\377}\246" + "\024\377x\240\002\377y\245\002\377~\247\002\377\201\247\002\377\246\300\022\377\262" + "\265/\377~\230\004\377\236\277&\377}\253\006\377{\246\015\377\201\242\003\377\221" + "\252\001\377\242\250\025\377\226\257\011\377\206\251\002\377\204\257\001\377\203" + "\253\000\377\177\245\000\377a\222\001\377q\242\023\377V\207\002\377M~\002\377L|\003\377" + "Y\216\002\377W\214\002\377Y\217\016\377Y\213\026\377T~\023\377X|\006\377Kf\001\377b" + "\223\015\377En\001\377Z\201\012\377f\223*\377V\213\010\377W\215\003\377Hn\001\377" + "Pp\002\377Qp\004\377Oo\007\377t\223H\377[|\060\377Le%\377HT.\377Y[J\377kl_\377d" + "dZ\377{ws\377\207~|\377vlm\377ZMV\377f[c\377i^f\377\\RT\377kea\377}yn\377" + "xth\377\224\217z\377\251\244\210\377{mR\377cSF\377P>\065\377via\377\206ug" + "\377\202o_\377\207ue\377\245\226\202\377\250\234\201\377\224\204c\377\220" + "}Z\377\205sL\377\212|U\377\212\201[\377\211\201\\\377\212\177]\377\216\205" + "b\377\203vT\377\220\204f\377\206wW\377\223\205b\377\215}Z\377\235\216l\377" + "\237\220m\377\232\215k\377\245\230|\377\243\227\200\377\222\202j\377\221" + "\201j\377~l[\377\214~m\377uf]\377Q:\070\377bN@\377\227\211o\377\246\232\205" + "\377\237\226\205\377\200yn\377\200}v\377vtr\377xtu\377khi\377okn\377a^e\377" + "KIO\377\\]^\377pzo\377n}j\377bwZ\377e\234K\377Hz\004\377V\211\003\377b\226\005" + "\377g\231\002\377k\232\001\377t\244\005\377q\240\002\377t\245\004\377j\227\001\377|\251" + "\003\377|\234\000\377|\237\002\377v\236\002\377z\246\002\377n\232\002\377p\235\001\377" + "y\250\062\377\240\313\213\377z\250%\377\177\252\000\377m\232\002\377\200\246\002" + "\377\213\260\002\377\224\265\003\377\243\267!\377\227\265\036\377w\237\000\377u" + "\236\001\377z\247\002\377\201\252\002\377\204\247\002\377\216\255\016\377\224\266" + "\012\377\211\262\002\377|\244\002\377\235\273\026\377\212\246\001\377b\232\006\377" + "g\233\020\377]\215\002\377X\214\002\377Y\217\004\377^\222\004\377X\211\001\377N|\003\377" + "S\200\007\377a\216\020\377p\221\"\377Ru\002\377Py\002\377e\230\004\377k\226\024\377" + "m\236\035\377e\225\002\377\\\215\001\377V\212\001\377Hr\002\377Jq\003\377`\204,\377" + "Y\177)\377Qq!\377Og#\377EU\040\377bfJ\377ij[\377xvl\377}tp\377\210~|\377n" + "ad\377eW]\377pdl\377S@N\377WJO\377j`^\377rog\377||r\377ywk\377\224\216v\377" + "\236\225v\377{qY\377L<\060\377D\060-\377mZV\377\230\215z\377\216{k\377\215" + "{h\377\235\216z\377\241\224{\377\240\222u\377\224\206e\377\222\203d\377\205" + "vY\377\217\203g\377\217\204g\377\223\210k\377\207y\\\377\224\214q\377\213" + "\203e\377\234\222u\377\215\177]\377\243\225s\377\225\206b\377\212xR\377\204" + "pK\377\205qO\377\222\201i\377\235\220|\377\217\203w\377vi]\377O\071\061\377" + "M/(\377\235\216|\377\256\243\222\377\225\210y\377vk`\377xpk\377spn\377zz" + "z\377utw\377^Y\\\377B;C\377TNU\377baf\377pss\377qys\377m\201l\377_\203R\377" + "X\215\"\377T\205\001\377\\\217\004\377Y\211\003\377b\231\007\377c\227\006\377u\236" + "\020\377q\236\002\377t\242\003\377s\240\002\377p\233\001\377\207\260#\377v\237\002\377" + "i\224\001\377s\241\002\377c\223\002\377p\237\002\377e\226\002\377\222\302z\377\200" + "\264\065\377y\243\000\377\204\250\001\377\220\262\003\377\221\270\001\377\207\260" + "\002\377\207\253\006\377\256\302C\377\204\245\014\377w\233\001\377\204\254\002\377" + "\212\257\002\377\217\255\012\377\211\245\004\377\217\262\001\377|\241\002\377\177" + "\244\004\377\215\242\016\377\214\245\001\377_\227\004\377a\230\004\377]\223\002\377" + "R\206\001\377U\211\002\377]\221\003\377W\204\001\377Ot\002\377Y\200\002\377Z}\002\377U" + "w\001\377Nr\001\377Qw\002\377Ow\000\377a\224\007\377\\\216\002\377s\241\002\377e\224\002" + "\377`\222\002\377X\220\004\377l\233=\377Y\177'\377X}\032\377b\206*\377Zx&\377" + "Xo,\377aoC\377tzd\377vvl\377xso\377|sq\377znn\377|tt\377zps\377jad\377ul" + "g\377H>?\377\\XT\377lja\377oh^\377_TB\377\205}`\377~sR\377\177pV\377n\\L" + "\377YIE\377D\062*\377rdV\377ygV\377\177kX\377\235\220\177\377\236\224|\377" + "\235\220u\377\236\220p\377\206wW\377\207vY\377\207x\\\377\211y\\\377\177" + "lO\377\221\203e\377\223\207f\377\212|[\377\214|Z\377\210wR\377xe:\377wb\066" + "\377\217\177\\\377\230\210l\377\222\207q\377\231\220\200\377i^Y\377QCA\377" + "H\067\061\377\217\177b\377\261\246\221\377\235\221\202\377\215\203x\377\216" + "\205~\377jaa\377zyy\377wxx\377]^a\377C>D\377*\040*\377RQQ\377]_[\377rxv\377" + "{\206|\377s\216l\377b\230G\377Jz\000\377b\230\006\377^\223\003\377\\\221\001\377" + "e\234\016\377h\233\021\377u\241!\377n\233\002\377\177\253\004\377w\246\003\377[\204" + "\000\377v\247\034\377m\232\005\377l\227\004\377p\236\001\377v\250\020\377{\252\002\377" + "o\233\001\377n\241\014\377y\255\022\377u\236\001\377\211\251\002\377\231\263\010\377" + "\244\300\010\377\204\246\000\377\221\260\026\377\215\250\"\377\270\315n\377\201" + "\243\006\377\202\246\002\377\210\250\000\377\232\252\017\377\213\235\001\377\233\273" + "\001\377\211\254\001\377\204\252\002\377v\231\001\377\206\250\002\377e\234\014\377c" + "\231\012\377^\222\002\377Z\214\002\377a\221\003\377b\216\003\377e\212\003\377_\200\002" + "\377Su\002\377[y\002\377Vr\001\377[{\002\377`\210\002\377i\223#\377]\213\016\377Nu\005" + "\377v\241\005\377T\202\002\377\067d\000\377^\212'\377o\234\064\377S\200\000\377v\241" + "\020\377\223\265\022\377\237\301(\377\214\260Q\377g\202:\377`tB\377~\200v\377" + "\201\200|\377\205\202\177\377\210\205\200\377\204\204~\377\214\222\210\377" + "fa`\377?\060\066\377<\061\064\377PIK\377d[[\377phc\377uo`\377rjQ\377\201zZ\377" + "\247\237\204\377\227\211l\377fVC\377SB\065\377\067$\036\377QA;\377dSG\377uh" + "[\377\217\202o\377\214zf\377\240\220w\377\215|[\377\210y[\377\200sX\377}" + "oS\377\200pQ\377weB\377\203sO\377\212{W\377vbC\377\202oQ\377\207uZ\377\232" + "\212r\377\224\204p\377\225\207v\377ti`\377bVT\377L=?\377jZN\377\231\211n" + "\377\261\246\213\377\237\221w\377\215\201k\377\202{j\377ytk\377\204\205\200" + "\377{\177|\377rtt\377YZZ\377QTQ\377\\dU\377bp[\377\\gX\377mzk\377o\210m\377" + "Eu%\377P\207\036\377^\220\001\377[\221\002\377V\213\003\377c\227\002\377c\224\013\377" + "g\227\010\377Z\201\000\377h\220\002\377\202\252\001\377~\251\020\377\201\262/\377" + "\203\261\063\377\202\260\063\377\203\254\025\377\204\261\040\377v\244\021\377" + "y\247\002\377h\227\002\377o\237\003\377|\264;\377}\257\026\377\214\264\002\377\204" + "\246\002\377\225\261\001\377\246\267\002\377\212\245\013\377\233\267<\377\244\302" + "U\377\223\267*\377z\237\000\377\216\257\005\377\246\263$\377\247\274/\377\231" + "\266\000\377\216\254\002\377\203\246\003\377\203\251\003\377\217\263\002\377_\220\001" + "\377Y\212\000\377M~\000\377U\204\000\377V\205\000\377a\217\003\377c\214\002\377_\203" + "\000\377_\204\002\377b\212\003\377X\177\002\377Y\204\003\377d\223\023\377Oy\033\377C" + "o\000\377h\212\036\377~\246\024\377O\200\000\377Z\211)\377Kp&\377U\202\001\377f\225" + "\003\377x\241\003\377\211\254\002\377o\220\010\377\216\260R\377u\226;\377Yv,\377" + "\205\213\203\377\227\236\225\377\221\227\217\377\221\224\217\377\201{\200" + "\377\217\207\211\377cW`\377B\062<\377NAH\377i^e\377\202v~\377\223\214\217" + "\377\206\204z\377yq^\377rkP\377\233\224x\377\246\240\203\377\234\221s\377" + "\213yb\377cQC\377\070&\040\377=+(\377K=:\377RD>\377]J@\377vgX\377m^O\377qe" + "W\377wiX\377\177p[\377\210wa\377\225\206l\377\220\201i\377\227\212t\377\206" + "xf\377{l^\377\211~q\377\207|s\377i[Q\377S?:\377I\066\065\377]LG\377\205vi\377" + "\240\223~\377\255\242\216\377\245\231\204\377\203qX\377\202t_\377vnd\377" + "\203~|\377\221\221\221\377~~\202\377NOT\377MVL\377Q^N\377BP@\377\070D\064\377" + "VfO\377bzU\377Sz?\377H~\032\377P\204\012\377V\213\003\377P\202\003\377W\206\002\377" + "i\225\002\377g\222\012\377a\217\001\377p\232\003\377l\226\002\377p\235\002\377k\225" + "\002\377z\247\007\377p\236\006\377h\235\010\377\207\262\067\377r\244\020\377j\234" + "\003\377\202\261\013\377m\236\003\377s\243\006\377\204\266:\377s\255\061\377\202" + "\253\001\377\201\242\002\377\216\256\002\377\212\250\002\377\256\267\007\377\244\300" + "M\377\215\260\031\377\210\260\040\377~\247\007\377\206\253\013\377\242\273,\377" + "\230\271\037\377\222\264\002\377\211\251\002\377\216\262\004\377\205\250\001\377\207" + "\251\001\377u\235\065\377\236\277v\377\302\333\270\377t\244\066\377\220\266M" + "\377m\225\025\377_\216\006\377\\\217\024\377S\205\005\377\\\221\004\377_\225\003\377" + "Y\211\001\377e\227\031\377En\000\377Ks\001\377U~\002\377n\241\003\377Y\211\030\377O|" + "\017\377W\211\005\377g\231\015\377V\203\001\377]\210\000\377V\177\000\377]\207\033\377" + "y\244<\377h\224-\377c\211\066\377o\212U\377~\205x\377\231\231\227\377\235" + "\233\233\377\233\230\230\377\223\216\214\377qim\377\\QV\377h`b\377ztw\377" + "\211\203\210\377\233\226\224\377\210\202x\377\212\203s\377\200u_\377\207" + "}b\377\233\223t\377\246\240\203\377\242\231{\377\240\221u\377|iX\377eOH\377" + "`MJ\377A*(\377G\060.\377L;\070\377A/*\377WG>\377M\071,\377^L>\377{jZ\377\220" + "\201r\377\207zj\377\202wj\377pe[\377UIB\377WHC\377^LB\377wfW\377q`Q\377}" + "j]\377\243\232\205\377\260\251\226\377\260\250\224\377\235\222~\377\201s" + "]\377\201s`\377\202ym\377\177vo\377\204~{\377\250\247\246\377\221\225\222" + "\377q}n\377PUO\377AEE\377ENE\377:L/\377<W!\377Ck\035\377J~\034\377h\230\060" + "\377Iv\002\377X\215\006\377V\207\006\377c\222\001\377z\234\010\377i\226\013\377\225" + "\271\066\377x\236\000\377`\216\002\377o\240\001\377k\232\010\377o\237\002\377o\236" + "\003\377y\253-\377|\246\023\377\200\260\033\377j\231\001\377}\252\005\377p\241\001" + "\377u\242\010\377\221\273R\377g\235(\377\246\303`\377\215\246\002\377\221\256" + "\001\377u\231\002\377\213\251\005\377\264\315W\377\210\253\002\377y\234\000\377\221" + "\276@\377\205\256\013\377\222\272\016\377\226\274\022\377\230\276\025\377\220" + "\257\001\377\224\261\003\377\217\252\002\377\243\276\030\377\324\344\321\377x\244" + "\066\377d\226\021\377X\212\004\377Q\202\003\377\\\220\004\377e\222\014\377_\221\003" + "\377]\216\001\377J|\002\377O\200\002\377`\225\007\377R{\004\377Ej\001\377U|\003\377[\207" + "\005\377f\233\002\377P}\013\377V~\004\377\\\204\006\377Kl\001\377Y\204\002\377u\235\025" + "\377w\235\027\377X\207\013\377S\204\010\377^\215\027\377E`\033\377Rh\064\377my" + "_\377\224\224\215\377\237\237\232\377\225\225\220\377\203|x\377}vv\377wr" + "t\377gaf\377ojl\377\224\215\217\377\263\260\254\377\227\223\213\377\207\205" + "x\377\223\215{\377\177x]\377zoM\377\226\217m\377\225\215m\377\251\237\202" + "\377\250\237\204\377\262\252\224\377\230\213r\377\177oY\377p]O\377jWN\377" + "YC\067\377kXL\377T?\063\377eSG\377jXH\377{h[\377veW\377l\\M\377i\\M\377k\\" + "J\377zhT\377\235\214y\377\260\241\215\377\254\235\211\377\266\251\225\377" + "\257\244\220\377\260\250\224\377\214}d\377\214~c\377\221\204n\377xlY\377" + "\226\222\207\377\230\227\220\377\222\225\212\377\213\231\200\377\177\227" + "r\377etX\377>>?\377>A=\377UjH\377W\177:\377N\203&\377F\210\016\377T\223\025" + "\377t\231\023\377c\216\004\377Q\201\001\377`\214\002\377_\211\002\377c\210\001\377o" + "\233\026\377\201\253\064\377\205\245\012\377e\222\002\377n\235\002\377j\236\014\377" + "l\243\002\377c\225\010\377^\221\005\377r\244\005\377x\247\012\377q\235\001\377w\253" + "\003\377t\251\030\377x\237\013\377\226\270W\377u\235\040\377|\251E\377\217\255" + "\005\377\223\262\003\377\204\244\002\377\203\244\003\377\253\312J\377\222\266\023" + "\377~\244\000\377\211\266\034\377\213\271#\377\207\262\010\377\215\270\007\377" + "\231\274\017\377\233\266\003\377\247\275\011\377\223\253\001\377\233\270\002\377" + "o\257\061\377[\221\000\377d\230\001\377Q\203\002\377Y\223\017\377O\205\002\377Ix\001" + "\377[\214\002\377W\213\002\377V\212\003\377T\205\004\377\\\225\013\377\\\217\016\377" + "S}\003\377Tz\001\377^\216\007\377_\221\005\377U\200\005\377Z\201\020\377o\236\016\377" + "h\227\005\377\207\241\017\377e\206\005\377f\210\002\377p\227\002\377Z}\001\377Y|\012" + "\377\067R\000\377Fb\030\377izN\377t}f\377\231\232\224\377\227\227\217\377\220" + "\217\207\377\202{x\377h]d\377lfl\377lgm\377\231\220\225\377\262\253\247\377" + "\252\244\234\377\221\216\201\377\220\213y\377\211\202j\377|tS\377\216\202" + "`\377~qI\377\213{Y\377\253\243\211\377\263\255\230\377\252\243\211\377\256" + "\244\216\377\241\222}\377\233\212w\377\237\216{\377\250\232\207\377\231\213" + "x\377\225\207u\377\212{m\377\240\222\203\377\247\232\213\377\234\215}\377" + "\245\227\200\377\254\234\202\377\251\230~\377\255\236\206\377\273\255\233" + "\377\277\266\244\377\262\252\226\377\235\225\201\377\224\212u\377\211}e\377" + "\227\216x\377\220\210u\377\224\217\201\377\211\207}\377\217\216\207\377\247" + "\250\242\377\235\252\224\377gw`\377bkT\377ScN\377bv`\377Hc\065\377\030=\000\377" + "+Z\005\377E\203\013\377B}\007\377\\\222\003\377\227\240\011\377X\204\002\377c\215\002" + "\377_\207\002\377a\211\001\377e\224\014\377R\200\003\377\206\256(\377c\214\001\377" + "s\237\001\377k\233\002\377l\243\023\377g\231\010\377d\223\003\377q\242\003\377p\237" + "\002\377\177\260\005\377k\233\002\377k\235\000\377\201\250\006\377w\246\034\377\203" + "\253\066\377\251\273W\377\215\253\037\377\250\267\040\377\215\251\004\377\210" + "\252\002\377\212\263\010\377\214\263\016\377\177\242\001\377\246\273\005\377\217" + "\274B\377\213\271\040\377\214\271\013\377\205\251\001\377\243\276\006\377\230\260" + "\002\377\220\252\003\377\231\263\002\377Z\220\001\377g\233\002\377W\211\002\377Y\216" + "\005\377_\224\003\377b\223\002\377V\210\002\377_\222\003\377^\220\003\377b\235\002\377" + "d\235\003\377]\227\002\377^\230\003\377R\210\003\377[\221\003\377d\231\012\377b\227" + "\006\377g\226\023\377e\227\007\377l\232\011\377\215\253&\377_z\002\377Z}\004\377q\213" + "\003\377p\212\002\377Ts\003\377\065W\002\377Cg\004\377-Q\001\377X\202\004\377_tD\377t|n" + "\377y{r\377\212\211\201\377\222\220\213\377\217\214\210\377XQY\377b[c\377" + "~w\177\377\230\223\223\377\270\263\254\377\237\232\217\377\217\210w\377\224" + "\215x\377\220\212q\377\215\202b\377\215}Z\377\221\203_\377\217\202a\377\227" + "\214p\377\245\234\202\377\253\244\215\377\267\255\230\377\260\244\217\377" + "\264\250\225\377\264\252\230\377\262\247\226\377\253\240\217\377\254\241" + "\222\377\251\235\216\377\232\213z\377\262\245\223\377\262\244\215\377\255" + "\235\205\377\264\242\211\377\247\223z\377\267\250\225\377\272\255\233\377" + "\232\215v\377\221\207r\377\231\222~\377\215\206p\377\223\215y\377\231\223" + "\204\377\221\220\205\377\213\213\203\377\211\211\200\377\241\246\226\377" + "\201\217u\377|\211d\377\201\177U\377Q[I\377)E\035\377.T\040\377p\227Z\377J" + "\200\021\377=p\002\377P\210\003\377[\222\003\377o\212\016\377c\203\003\377b\210\002\377" + "h\224\002\377e\222\001\377R\202\001\377M\200\002\377\204\254/\377b\212\000\377q\237" + "\002\377i\236\013\377p\247\023\377j\235\005\377s\241\011\377u\243\001\377t\246\002\377" + "q\242\003\377h\232\002\377m\236\004\377|\247\003\377n\245\024\377\210\266G\377\260" + "\313P\377o\234\010\377\234\263\022\377\250\265!\377\222\256\017\377\212\261" + "\024\377\221\271'\377\203\245\001\377\236\243\003\377\221\271\060\377\216\272:" + "\377\223\300\017\377\222\272\004\377\220\256\002\377\213\247\002\377\221\255\002\377" + "\222\257\002\377_\223\002\377m\235\001\377g\230\010\377p\230\011\377n\221\012\377" + "z\234\033\377_\213\005\377W\206\003\377\\\220\002\377^\225\002\377c\234\011\377Z\210" + "\001\377j\226\026\377s\244'\377^\220\026\377V\204\014\377_\217\002\377]\206\001\377" + "o\227\002\377{\230\023\377\205\243\030\377Mp\001\377Ln\002\377f\202\002\377m\206\002" + "\377Uo\002\377\065J\001\377;T\002\377Ff\003\377?c\001\377If\040\377Sa@\377ei^\377\177" + "~v\377\220\221\204\377\201\201w\377gfc\377cac\377a]a\377\233\227\225\377" + "\252\245\235\377\223\214\201\377\224\220\203\377\215\213{\377\231\226\205" + "\377\212\205j\377\206\200]\377\216\205c\377\217\205g\377\222\206j\377\204" + "uU\377\217\201a\377\241\225x\377\260\244\211\377\250\235\202\377\235\220" + "w\377\252\240\207\377\237\224\177\377\260\247\224\377\227\211u\377\224\203" + "o\377\247\233\206\377\266\252\223\377\250\231\201\377\260\243\214\377\254" + "\237\210\377\247\232\204\377\250\233\205\377\230\213u\377\221\205r\377\212" + "\201o\377\235\227\207\377\234\233\216\377\232\232\221\377\202\202|\377\207" + "\207\177\377\177\202t\377\216\241w\377\177\217d\377r\177^\377eoc\377G\\>" + "\377&K\015\377)V\003\377Fy\021\377n\232H\377J\201\014\377d\235\002\377[\217\020\377" + "x\241=\377o\217\012\377o\220\005\377d\222\003\377_\217\001\377Z\215\003\377Y\212\002" + "\377t\241#\377p\235\017\377p\243\010\377k\234\015\377o\243\010\377f\223\005\377" + "p\236\005\377w\245\002\377}\254\002\377{\255\004\377n\237\002\377\\\217\000\377\205\256" + "\000\377f\241\017\377\210\270G\377\224\273(\377x\243\002\377u\245\013\377\202\244" + "\000\377\225\257#\377\224\263#\377\223\271\063\377\203\250\001\377\222\246\004\377" + "\200\246\006\377\206\256+\377\207\262\011\377\204\251\001\377\217\264\002\377\214" + "\256\002\377\214\264\007\377\215\261\006\377a\225\003\377e\230\002\377Y\220\004\377U" + "\213\002\377U\205\001\377`\215\001\377Sq\001\377]\211\002\377^\216\003\377]\222\003\377" + "_\220\030\377\212\264T\377k\234\025\377`\222\001\377U\203\001\377Fp\001\377b\217" + "\002\377S|\003\377[\210\005\377\223\257>\377f\217\006\377W\201\002\377Z~\005\377i\223" + "\002\377Yw\003\377Xi\001\377do\007\377Vg\004\377Rm\006\377Km\011\377:\\\000\377Qr\016\377" + "\067H\040\377]kK\377|\206l\377\214\216\200\377\227\230\217\377kih\377ead\377" + "\221\213\213\377\205{w\377\216\204{\377\214\203y\377\206\177t\377\217\214" + "|\377\217\214u\377\222\215o\377\200zX\377\203~]\377\226\215k\377\204vP\377" + "\216~Z\377\216\200]\377\230\213h\377\230\215j\377\241\230u\377\234\222t\377" + "\242\227}\377\245\233\207\377\222\205s\377\226\212t\377\250\236\211\377\256" + "\241\213\377\253\235\205\377\253\235\205\377\227\213u\377\240\224\202\377" + "\207\177m\377\214\200o\377\215\205t\377\245\241\220\377\227\226\211\377\216" + "\217\205\377\213\213\203\377\177~y\377}}t\377\220\236x\377y\221V\377^qK\377" + "Q^K\377L]D\377.N\024\377+Q\004\377@m\005\377M\203\011\377?s\001\377\202\260R\377" + "a\232\001\377Bm\025\377\203\255O\377k\217\035\377X\177\006\377O\177\001\377_\216" + "\001\377c\225\002\377V\202\002\377V\202\000\377\231\302J\377j\231\010\377i\230\002\377" + "t\246\002\377w\245\002\377t\243\003\377l\232\002\377\200\261\003\377l\236\003\377l\241" + "\001\377W\217\017\377\222\270&\377r\246\024\377\215\276Y\377\224\273,\377\201" + "\246\000\377}\247\002\377\200\255\002\377\177\245\002\377\200\246\005\377\242\302G" + "\377\177\251\006\377w\235\001\377\220\261#\377\220\256.\377\206\261.\377v\237" + "\000\377\212\265\001\377\205\253\002\377\224\271\005\377\243\305#\377O\204\001\377" + "Z\217\003\377Z\221\003\377P\210\002\377Z\224\004\377W\213\003\377\\\215\000\377e\226" + "\007\377d\226\005\377Vx\005\377t\222\024\377c\217\006\377\202\240>\377a\205\010\377" + "_\207\004\377U~\002\377f\227\006\377t\251\036\377\204\261#\377\202\252'\377q\235" + "\010\377^\214\001\377a\214\015\377\\\212\000\377T~\001\377]\205\003\377_\206\002\377" + "[|\002\377Xw\004\377Ss\004\377Db\001\377;Z\001\377\063P\003\377p\224D\377`fS\377tvh\377" + "~\177t\377d^]\377tps\377uoq\377\240\230\223\377\254\245\234\377\243\236\222" + "\377\230\222\205\377{yk\377\204\203r\377\215\213r\377\217\212k\377\211\202" + "`\377\207\200[\377\212\203]\377\227\217j\377\230\220l\377\242\232{\377\223" + "\211j\377\232\224u\377\247\240\204\377\223\215s\377\234\224\177\377\206y" + "f\377\220\203p\377\226\212t\377\244\230\177\377\254\240\207\377\247\234\206" + "\377\222\207u\377~ua\377\226\221\200\377\234\232\213\377\230\230\212\377" + "\230\231\216\377\206\206}\377\226\225\217\377\212\212\204\377\177~y\377\201" + "\201z\377\215\244h\377k\177Q\377ERA\377/B&\377\062M\031\377,N\007\377Af\007\377" + "Fr\002\377V\214\007\377F~\003\377_\237\002\377d\230,\377[\204\023\377s\235D\377Mv" + "\000\377p\216-\377Ft\000\377]\213\002\377Y\211\001\377W\207\003\377`\222\002\377\226" + "\300H\377c\215\007\377h\227\001\377i\232\003\377u\244\002\377g\230\002\377i\230\002\377" + "x\254\002\377m\235\015\377b\231\000\377{\257<\377\234\306h\377\213\266\063\377" + "\217\272\061\377\206\260\022\377\212\257\031\377\244\300=\377~\251\035\377\216" + "\261\006\377\201\244\000\377\255\310N\377\317\326\217\377n\222\000\377\220\244" + "'\377\246\276M\377r\240\006\377\211\256\023\377\223\264\002\377\206\246\002\377" + "\214\257\001\377\227\273\030\377h\236\013\377P\206\001\377W\215\003\377_\226\003\377" + "T\212\002\377^\226\000\377q\243\034\377q\245\037\377\\\216\001\377}\223\027\377\257" + "\257F\377Z\203\001\377\\\212\017\377Rz\002\377d\217\015\377c\215\007\377s\244\003\377" + "q\234\002\377\233\272\066\377h\206\001\377l\220\003\377V}\001\377o\233\004\377m\232" + "\016\377h\216\013\377b\203\001\377]|\002\377Zw\002\377Vr\002\377Ee\002\377?a\002\377Cb" + "\002\377[~\004\377Lk\004\377!\063\006\377?K,\377prd\377\214\213\204\377\212\213\204" + "\377\210\203\201\377\232\223\224\377\225\222\220\377\235\234\226\377\203" + "\201x\377|{r\377ccZ\377\214\214|\377\221\216y\377\220\214q\377\224\217q\377" + "\206~\\\377\214\204`\377\222\214j\377\251\245\214\377\223\220t\377\222\220" + "s\377\217\214p\377\222\213n\377\225\211n\377\210y`\377\203r[\377\216~h\377" + "\245\232\200\377\240\230\177\377\232\223\177\377\230\221\200\377\240\233" + "\212\377\243\243\227\377\224\224\211\377\214\215\203\377yyr\377lkh\377on" + "o\377xxw\377YYY\377x\177h\377p\213N\377DND\377ES?\377)C\030\377+M\012\377?" + "k\017\377/Z\002\377=l\002\377M\202\010\377G\201\002\377\\\226\004\377Bl\022\377{\253" + "F\377y\244H\377Cn\000\377\245\274m\377d\222\017\377b\225\003\377^\222\012\377^" + "\226\020\377\\\222\002\377n\232\026\377\201\255'\377_\221\001\377l\236\002\377d\227" + "\003\377]\220\002\377o\242\002\377o\242\006\377\214\257G\377\223\277]\377i\235\014" + "\377\\\216\003\377~\262\030\377p\230\004\377\204\263\035\377\212\273L\377\227\305" + "h\377\231\304r\377\265\327\215\377\240\307F\377\221\267\065\377\245\272\071" + "\377\223\251,\377\250\272I\377\271\313`\377\276\320`\377\233\271/\377\211" + "\245\001\377x\226\002\377\212\254\001\377\242\301)\377V\210\003\377V\211\003\377c\223" + "\004\377\\\225\004\377]\223\005\377Y\217\000\377`\222\004\377e\224\001\377d\216\004\377" + "n\223\003\377h\214\002\377n\232\002\377h\231\003\377u\247\040\377\216\274J\377\201" + "\256\015\377}\244\002\377\224\264\022\377\224\261A\377Z\201\000\377a\215\002\377" + "p\232\012\377u\227\004\377w\222\003\377l\201\002\377l\200\002\377_p\002\377`p\001\377" + "J_\002\377So\003\377+C\000\377Jp\013\377z\237\036\377<]\002\377\031\065\000\377Oi%\377" + "dv?\377np_\377kjb\377}wz\377xmu\377ndn\377qfn\377^SZ\377>\070<\377>\071=\377" + "efc\377]^V\377\207\210t\377\227\225z\377\206\202`\377\213\210d\377\216\211" + "g\377\230\227|\377\177\207]\377\236\235\177\377\226\224v\377\234\226y\377" + "\201uX\377\207z\\\377\222\207j\377\237\230}\377\230\222{\377\233\225\201" + "\377\235\232\206\377\231\230\205\377\231\231\212\377\226\227\213\377\231" + "\232\220\377wwr\377^]]\377>==\377B?A\377JFI\377B>B\377\231\245v\377]bQ\377" + "-<\"\377(A\025\377(I\011\377\062Y\017\377*S\001\377\063d\006\377\067k\005\377Cx\002\377" + "U\224\005\377Cl\002\377Nt\000\377o\233+\377y\245M\377Q\203\000\377Y\212\024\377\214" + "\266Q\377S\205\002\377R\202\002\377S\201\002\377b\222\002\377e\226\015\377{\252&\377" + "j\236\001\377k\235\001\377`\217\003\377i\227\000\377v\246\001\377s\250\026\377s\247" + "\062\377f\233\015\377p\237\003\377m\232\005\377y\255\040\377v\232\003\377t\245\012" + "\377o\236\000\377\225\273?\377\300\341\224\377\215\271<\377\204\260\027\377" + "\204\263)\377\212\261(\377\254\306]\377\247\264?\377\214\257\030\377\207\256" + "\023\377\232\303B\377\217\267(\377u\217\001\377\202\236\002\377\236\301/\377`" + "\221\003\377\\\221\003\377\\\227\004\377`\231\005\377n\237\012\377\200\245\035\377" + "g\227\001\377Y\215\002\377X\212\001\377q\231\004\377p\227\002\377f\224\002\377g\231\002" + "\377u\251\"\377f\224\005\377m\230\001\377u\236\001\377s\233\006\377b\221\004\377a\221" + "\004\377a\212\003\377m\217\006\377k\212\002\377l\210\001\377x\225\003\377j\212\002\377" + "a\203\002\377a\201\003\377`\201\007\377h\216\007\377\\\203\011\377o\244\026\377Lk\012" + "\377Hf\020\377Xy\034\377<T\006\377:M\013\377S\\\070\377UVF\377GC?\377VJQ\377xk" + "s\377ujp\377]RZ\377#\027\035\377\062*.\377;\065\067\377ONJ\377ute\377\217\213" + "q\377\214\210h\377\233\231x\377\207\210a\377\204\207[\377\200\205W\377\234" + "\232w\377\220\214i\377\227\220n\377\203zV\377\226\221q\377\231\224x\377\226" + "\221y\377\243\240\214\377\236\237\212\377\224\225\202\377\217\217\177\377" + "\223\224\206\377\230\231\217\377\221\220\213\377lfe\377JCE\377\060)+\377>" + "\071;\377\063.\060\377zx[\377\210\230h\377XdV\377\064K*\377\036@\010\377-V\016\377" + "\037L\002\377,\\\005\377:m\007\377F{\004\377X\204\012\377`\215\021\377Lu\010\377`\207" + "\013\377U\202\024\377~\261C\377U\210\000\377U\204\000\377\210\270G\377Z\213\004\377" + "Q\204\001\377c\226\003\377W\205\002\377`\215\012\377|\252\032\377l\242\002\377[\215" + "\002\377g\232\007\377\207\264\064\377|\254\012\377h\237\014\377`\227\020\377r\245" + "\004\377}\246\001\377z\252\037\377p\244(\377\202\235\001\377\204\264\060\377\242" + "\312^\377\260\323k\377\200\243\020\377v\244\004\377\214\275@\377\230\303T\377" + "\255\320g\377\204\261.\377\240\274\040\377\210\255\020\377\235\253\040\377\224" + "\273@\377\230\274G\377\225\264\021\377\217\260\002\377\227\302\070\377V\206\003" + "\377Y\223\011\377O\216\002\377W\222\002\377U\220\003\377Q\212\003\377U\214\002\377Z" + "\220\001\377\\\221\002\377^\222\001\377n\236\006\377t\247\024\377[\211\001\377i\233" + "\015\377g\224\002\377h\217\002\377b\206\000\377}\240\022\377\224\267\011\377r\237" + "\001\377j\226\002\377r\237\003\377i\221\002\377l\227\002\377q\225\002\377k\203\003\377" + "`l\002\377eo\002\377{\230\002\377u\235\002\377Sl\010\377l\217\034\377o\213,\377Ei\005" + "\377?`\001\377Np\022\377Pc\037\377!\060\006\377FN\071\377Z[S\377XUS\377skk\377\211" + "\203\200\377ka]\377H\071\061\377TF>\377L?\071\377_VO\377e^R\377uo\\\377\211" + "\210k\377\211\215g\377{\204S\377\210\212a\377~|V\377\222\222m\377\224\221" + "m\377\177|T\377\203\177W\377\233\232x\377\213\211k\377\220\220v\377\221\222" + "~\377\222\227\200\377\227\240\204\377\210\213x\377\226\226\211\377\233\234" + "\223\377\216\214\205\377zri\377tk_\377zqe\377~yn\377kh]\377\224\245r\377" + "ViB\377\067O\060\377>Y,\377\064T\024\377\032C\002\377\037Q\001\377;s\020\377A{\006\377" + "X\213\020\377p\231#\377Nz\031\377M\204\015\377I{\000\377b\226\031\377v\253\062\377" + "_\220\002\377W\201\001\377t\245\023\377^\220\004\377`\224\005\377K}\003\377U\203\002\377" + "m\235\011\377\203\262%\377c\224\000\377[\214\000\377i\233\006\377j\227\004\377t\247" + "\002\377i\240\012\377c\226\002\377\206\260\004\377~\246\012\377l\236\017\377i\242" + "/\377\226\276K\377\221\272I\377\201\256&\377\212\237\020\377\211\241\005\377" + "o\230\005\377\235\275O\377\221\257:\377\206\252!\377}\252\022\377\214\242\006" + "\377\203\236\004\377\213\254\011\377\325\336q\377\272\311>\377\224\260\005\377" + "\221\260\002\377\225\300=\377Bx\002\377T\217\004\377S\214\002\377U\215\002\377Y\221" + "\003\377]\223\002\377X\213\002\377p\236\027\377p\233\010\377f\225\003\377b\221\007\377" + "a\220\002\377\\\212\002\377W\205\001\377f\220\002\377X\202\002\377_\211\002\377\210\256" + "\005\377\221\263\002\377l\222\002\377r\232\003\377v\236\001\377z\245\002\377q\216\003\377" + "k\200\002\377hz\004\377jw\002\377x\206\005\377{\225\001\377g\210\011\377m\230\024\377" + "q\226\040\377Zl\016\377Tl\012\377Uy\012\377Oi\034\377\040.\000\377\061<\025\377js[" + "\377\202\204u\377{zn\377qh_\377}tm\377\230\220\200\377\225\210p\377\230\210" + "m\377\230\211l\377\213|c\377\202u]\377|w\\\377tuO\377v\200N\377\206\214b" + "\377\216\220n\377~}W\377\203\201Z\377\213\212b\377\203\201R\377\212\210^" + "\377\224\223q\377\214\214l\377\213\213n\377\201\201j\377\223\226\200\377" + "\227\236\201\377\224\232\200\377\225\226\211\377\230\231\220\377\211\206" + "|\377\216\206y\377\226\216|\377\235\227\206\377\214\211|\377\201\205o\377" + "\212\262j\377BY\064\377&?\031\377+K\021\377$H\010\377\"J\002\377<m\022\377O\206" + "\031\377M\205\012\377N\203\003\377R\202\030\377c\222%\377P\177\000\377P\177\002\377" + "^\217\025\377c\224!\377f\226\003\377Ov\002\377h\234\003\377R\206\002\377e\231\016\377" + "R\200\004\377q\236\011\377\202\260'\377\226\277\070\377\212\270C\377l\234\036" + "\377n\236\025\377t\241\003\377q\242\013\377y\253\011\377\211\265\004\377m\237\022" + "\377\206\264D\377p\244\021\377\203\267E\377\225\276?\377\201\256#\377t\245" + "\007\377\246\257\062\377\232\260,\377\232\272\066\377\177\243\"\377}\235\017\377" + "\232\300H\377n\234\001\377|\237\005\377\207\243\000\377\266\306/\377\231\275-\377" + "\205\256\026\377x\233\004\377\206\253\006\377\215\271\063\377S\213\003\377O\213\003" + "\377G}\002\377Z\210\001\377U\204\002\377Z\215\003\377]\217\013\377b\217\004\377l\231" + "\007\377c\217\003\377\\\215\003\377c\224\017\377a\220\010\377i\230\014\377b\222\000" + "\377b\222\002\377j\231\001\377\230\274\011\377p\222\002\377p\223\002\377v\230\002\377" + "{\233\005\377e}\002\377fx\002\377\215\241\006\377~\222\006\377z\245\004\377n\225\002\377" + "s\214\031\377\206\257:\377_\205\002\377^}\004\377q\216\035\377s\215\032\377g\177" + "\014\377>J\001\377<I\001\377Wg!\377JW&\377nqQ\377\207\205s\377zsg\377\215\205" + "}\377\205}s\377\237\222\201\377\254\237\210\377\244\226y\377\224\204g\377" + "xhJ\377vqF\377pq?\377}{S\377}{Z\377\210\207f\377\211\212g\377\207\206`\377" + "\206\204Z\377\206\204X\377\226\224m\377\213\212d\377\204\202c\377\211\212" + "l\377\206\206m\377\221\223}\377\220\225~\377\230\242\213\377\227\231\217" + "\377\201~x\377\214\207~\377\214\205x\377~wl\377}yo\377mji\377\203\234f\377" + "y\242X\377\062L%\377\034<\015\377Fn!\377&F\003\377\071`\010\377[\217!\377K\205\007" + "\377Fz\002\377_\223\015\377f\235!\377L\200\000\377P\202\002\377W\207\002\377Z\211" + "\022\377f\225\025\377f\220\003\377R\177\002\377j\234\003\377^\215\002\377b\222\016\377" + "{\244\005\377\206\262=\377g\236\007\377\206\265\061\377a\225\016\377Z\212\002\377" + "g\223\003\377{\250\002\377y\246\017\377\222\271\007\377\200\253\006\377j\230\020\377" + "\206\263\066\377\257\321n\377e\230\014\377i\233\002\377q\236\003\377i\236\007\377" + "p\235\002\377\215\262\004\377x\234\003\377q\227\000\377\253\274H\377\215\263\062\377" + "u\246\024\377\201\245\005\377\246\270\030\377\237\257\003\377\240\273\026\377\214" + "\265\033\377\202\245\010\377\236\301\033\377\205\266(\377Y\227\002\377K\207\003" + "\377Y\223\003\377f\220\012\377\\\207\002\377^\214\002\377]\217\002\377`\221\004\377" + "[\215\002\377Y\213\002\377p\234\022\377l\225\024\377c\213\007\377g\221\005\377a\215" + "\002\377c\217\002\377g\222\002\377\210\256\003\377s\232\001\377s\227\002\377t\223\002\377" + "t\220\004\377\202\225\005\377j}\002\377\211\227\004\377\177\224\007\377j\203\005\377" + "q\215)\377y\242*\377i\236\003\377i\226\007\377d\213\006\377a\205\005\377Qq\001\377" + "Ni\001\377`v\006\377z\212\031\377dn\006\377mo\016\377]`\037\377ggB\377po_\377\177" + "|t\377voi\377\220\206z\377\222\204q\377\202rX\377\207yW\377|tA\377\203\177" + "D\377\200uG\377xmG\377rkH\377}y\\\377\213\212k\377\214\212h\377}|S\377\212" + "\210`\377\231\230r\377\212\210c\377\213\207g\377\220\217r\377\215\215u\377" + "\220\222}\377\223\226\202\377\232\242\214\377\221\221\211\377vqi\377ysh\377" + "\205~q\377wti\377TSN\377^eS\377c\217E\377r\235R\377\065U\033\377Nv\060\377&" + "K\001\377:e\006\377Gy\014\377>x\005\377;p\001\377e\230\027\377Z\217\003\377Q\204\001\377" + "Hz\002\377I{\001\377Z\212\002\377a\224\022\377l\226\021\377n\225\004\377`\212\002\377" + "l\227\003\377p\230\004\377i\231\007\377j\227\014\377\205\265H\377o\240\031\377\211" + "\265/\377c\227\014\377Z\211\002\377m\232\004\377l\231\002\377\220\257\003\377z\251" + "\002\377u\236\026\377q\240\035\377\212\271F\377s\242\032\377h\230\001\377q\240\001" + "\377\251\315\065\377n\237\016\377u\244\006\377k\230\003\377\204\251\001\377\230\262" + "\017\377u\242\016\377\225\270\066\377v\247+\377\230\271*\377\246\276#\377\245" + "\270\013\377\240\252\001\377\241\274\014\377\215\264\007\377\207\260\000\377\202" + "\257\003\377\\\233\003\377T\221\004\377O\206\003\377T\200\003\377Ao\001\377c\225\004\377" + "c\226\004\377d\221\005\377d\224\002\377X\205\002\377O|\001\377s\232\033\377g\221\012" + "\377a\211\001\377^\212\002\377`\212\001\377i\223\002\377}\247\004\377\205\244\004\377" + "z\224\003\377p\214\003\377h\205\001\377\221\234\023\377v\212\004\377z\231\002\377s\234" + "\005\377}\234B\377[x\011\377e\225\006\377Z\205\003\377[\210\007\377h\220\020\377_\203" + "\005\377Qo\002\377Sn\001\377^{\005\377H_\002\377:M\001\377FU\003\377\066F\006\377aj@\377z" + "{k\377\177\201t\377{zr\377gdW\377\201xe\377\223\214i\377\234\232e\377\237" + "\234_\377\236\217a\377\226\201[\377\203qL\377q`@\377wlO\377\202|_\377\205" + "\201b\377|yQ\377\201\200Y\377\220\220j\377\217\216i\377\221\220r\377\211" + "\211m\377\217\221|\377\221\222\204\377\224\226\211\377\222\236|\377ztn\377" + "qj_\377nf[\377WNI\377JFF\377B@B\377ivU\377^\205D\377}\253R\377Iv#\377\062" + "\\\016\377Kx\030\377\065f\005\377/e\004\377\066l\002\377N\201\006\377]\220\003\377P\203" + "\002\377Q\201\003\377[\216\002\377\\\220\002\377F{\001\377]\225\023\377_\221\012\377" + "_\217\004\377Fv\001\377t\235\003\377]\206\002\377^\221\015\377\216\274R\377n\235\004" + "\377T\200\002\377\212\271\067\377a\227\010\377m\227\010\377l\227\002\377\240\264" + "\014\377r\231\002\377p\243\012\377`\225\011\377t\247\040\377p\231\014\377\177\251" + "\002\377n\234\003\377e\226\001\377\230\300\040\377\221\271\064\377k\230\004\377k\230" + "\003\377\177\244\002\377\240\270!\377\200\247\016\377\226\272'\377a\224\004\377" + "\202\262\023\377\223\273\033\377\245\300\"\377\233\257\007\377\221\252\001\377" + "\213\260\013\377\210\265\022\377\272\320H\377L\210\001\377T\217\003\377L\205\002" + "\377R\213\005\377[\224\004\377b\223\006\377`\205\002\377o\222\004\377g\215\000\377X\203" + "\000\377]\207\010\377[\177\001\377e\215\005\377f\217\016\377i\223\012\377W\202\001\377" + "]\205\001\377x\241\013\377g\215\004\377j\212\003\377o\213\002\377n\215\002\377i\212" + "\004\377~\234\010\377\204\250\013\377|\241\"\377x\222\027\377]\205\003\377g\225" + "\002\377\\\201\001\377Ot\003\377^\213\023\377^\214\012\377^\204\010\377f\206\015\377" + "Xr\002\377Pi\003\377Ga\002\377G_\001\377?W\003\377F[\021\377fnH\377rsb\377ii]\377kk" + "`\377[[I\377s\200E\377\224\221e\377\241\224o\377\203pP\377nY\070\377ub<\377" + "ziC\377yjH\377{pS\377yqT\377{vV\377|yU\377\202\177]\377\214\214k\377\215" + "\216o\377\214\215t\377\225\226\204\377\213\213\200\377~}t\377\202\220f\377" + "pmZ\377icZ\377]ZT\377JGF\377KJJ\377RRO\377r\212U\377ZoE\377t\244O\377Gv\036" + "\377W\214&\377?u\024\377\067p\005\377M\212\004\377Q\210\004\377T\212\002\377W\212\002" + "\377Dw\002\377O|\002\377Y\212\003\377V\211\003\377J~\002\377X\224\020\377N\202\007\377" + "L}\003\377o\230\005\377o\233\004\377e\222\004\377s\242'\377m\230\016\377t\236\004\377" + "h\220\012\377\207\265\062\377Y\205\000\377o\222\005\377\226\255\007\377o\217\003\377" + "l\236\005\377s\247\063\377f\232\030\377d\230\007\377v\236\001\377z\240\003\377u\240" + "\005\377s\241\003\377\212\270\013\377\200\254\026\377\\\212\002\377q\234\001\377\177" + "\246\002\377\214\261\005\377\177\250\006\377l\234\005\377h\233\002\377}\257\015\377" + "\223\274\"\377\246\273$\377\273\311R\377\236\264\023\377\216\261\011\377\203" + "\257\027\377\216\261,\377H~\002\377M\205\004\377L~\003\377G\200\002\377j\246\015\377" + "`\231\015\377h\241\023\377|\254*\377\213\267A\377\205\265/\377\202\253\065\377" + "f\220\004\377j\224\004\377O|\002\377[\211\013\377X\207\001\377e\204\020\377\202\256" + "\004\377Y\200\002\377Y~\002\377_\204\003\377V{\002\377_\202\003\377\200\245\004\377t\234" + "\022\377~\222\032\377w\225\014\377e\216\003\377_\215\004\377\\\214\013\377S\202\003" + "\377Jo\001\377W\203\017\377o\240'\377^\202\002\377]|\003\377_\202\002\377Uz\003\377" + "X\177\005\377Oo\002\377Da\003\377DZ\016\377S[\060\377__H\377fiQ\377Yt\061\377ZXG\377" + "tlY\377iYD\377qcE\377{lG\377\221\201U\377\233\211^\377\202oG\377\177mL\377" + "m_B\377kbE\377\200z_\377{uX\377\202~a\377\222\220y\377\213\212v\377\207\207" + "y\377{yn\377eaX\377ekP\377x\205X\377\\UN\377eb[\377ec_\377`^W\377`bQ\377" + "q\215T\377w\233Y\377s\247C\377Ar\031\377\067i\020\377\066m\007\377D\201\005\377I" + "\205\002\377Bz\002\377C}\001\377Av\002\377\067l\004\377a\227\010\377L\202\003\377I}\001\377" + "K\201\001\377]\232\016\377>u\005\377k\230\005\377^\211\002\377T\205\003\377c\226\022" + "\377x\243\061\377r\232\006\377\207\250\003\377j\213\004\377\220\267\066\377b\215" + "\000\377\200\235\004\377\252\270\005\377f\224\002\377n\244\031\377\\\220\025\377v\253" + "\060\377u\241\001\377\201\245\005\377{\235\002\377z\242\003\377z\254\006\377\205\262" + "\002\377k\232\002\377`\222\003\377q\237\005\377\200\252\003\377\201\251\005\377}\252" + "\005\377i\235\006\377i\237\004\377w\242\004\377\255\311V\377\311\322a\377\256\304" + "@\377\234\271!\377\220\262\032\377\202\261$\377t\237\023\377v\244\030\377J~" + "\004\377Av\002\377;v\004\377\\\217\015\377v\252\"\377\232\307h\377\234\307k\377" + "\241\314v\377k\230.\377N|\000\377t\237\022\377f\226\007\377e\226\003\377b\230\003" + "\377]\222\002\377`\223\002\377\231\275\004\377r\222\004\377h\206\002\377l\211\002\377" + "s\221\003\377~\237\004\377o\231\017\377\205\247\037\377d\220\007\377g\224\014\377" + "h\225\004\377]\215\002\377[\211\016\377\\\211\013\377Rw\002\377Qy\005\377\201\253N" + "\377b\213\027\377f\210\024\377a\204\013\377Xv\001\377[y\004\377Ul\003\377GZ\001\377" + "HZ\007\377GV\022\377w\203H\377~\210Q\377qpX\377ZVI\377`YJ\377nfL\377\221\207" + "^\377\237\222e\377\222|P\377\222yN\377\217uM\377\217wS\377}jL\377aR<\377" + "rkX\377wr[\377\204~i\377\213\206u\377\205\200t\377yri\377[QJ\377KC\070\377" + "GD\066\377\205\227O\377wo_\377yrc\377yuh\377oma\377x\207^\377a\211=\377\204" + "\256[\377Ai\025\377\065\\\023\377.\\\003\377P\210\003\377Dv\002\377F{\010\377Av\005\377" + "N\202\002\377\061j\002\377L\201\003\377O\211\003\377O\210\002\377N\202\003\377K\201\002" + "\377Y\221\007\377t\240\006\377g\221\002\377X\204\001\377^\220\002\377q\251/\377e\232" + "\021\377x\236\004\377q\216\002\377l\207\014\377\221\272A\377c\215\000\377\253\267" + "\011\377~\232\002\377q\241\000\377x\252,\377y\252\031\377{\255\"\377\224\270\010" + "\377y\236\011\377\224\257\006\377\177\246\006\377\210\265\002\377\200\253\002\377" + "m\233\010\377_\222\002\377b\222\004\377\177\247\013\377\222\271'\377\206\256\036" + "\377q\236\003\377\243\270\027\377\232\260!\377\215\260.\377\200\244\022\377\233" + "\272&\377\216\256\025\377\212\253\024\377\243\304Y\377\203\257\"\377[\217\002" + "\377N\177\002\377I|\002\377Q\204\004\377L{\002\377o\235!\377x\250\061\377\234\304" + "i\377p\226-\377Z\206\002\377\\\205\005\377^\210\005\377m\211\004\377X{\003\377^\212" + "\005\377O\200\002\377X\221\014\377\242\305\002\377\202\240\026\377q\217\001\377z\231" + "\002\377u\230\003\377h\221\003\377\\\211\004\377s\246\033\377d\233\016\377`\226\011" + "\377v\244\035\377a\225\021\377e\222\036\377d\213!\377c\205\020\377]|\003\377k\217" + "\037\377s\227\065\377n\223/\377n\227&\377a\204\017\377^\200\014\377Yr\021\377" + "du\031\377@N\004\377Md\007\377r}\071\377\224\212h\377\205~b\377zx`\377xx^\377s" + "pW\377zsW\377qbF\377w_?\377\231\200^\377\242\211f\377\234\202a\377\216v[" + "\377XH;\377G<\061\377geX\377spd\377zsi\377|si\377wka\377fYK\377dXG\377woT" + "\377\203\235+\377vzS\377qsT\377so_\377xtf\377\213\242m\377W\204%\377w\251" + "K\377Ds\030\377Ar\016\377Z\217\004\377M|\001\377\070g\011\377Y\213\033\377L\177\002" + "\377I\177\002\377M\201\003\377F}\001\377W\215\003\377P\210\002\377_\220\002\377Z\204" + "\002\377s\240\005\377b\213\003\377f\216\003\377a\215\003\377[\215\002\377\\\231\025\377" + "e\234\017\377\222\260\011\377j\222\014\377c\214\003\377|\255\060\377\224\252\007" + "\377~\245\004\377m\233\002\377f\225\000\377\203\264\061\377|\253\013\377|\251\005\377" + "\202\252\002\377\204\245\002\377\241\270\005\377v\247\003\377\201\255\003\377\203\256" + "\002\377x\234\005\377i\224\007\377|\247\015\377}\244\003\377\205\255\000\377\210\261" + "\000\377\216\257\013\377z\236\004\377v\245\040\377\203\252\012\377\203\247\007\377" + "\252\300\031\377\215\252\004\377\230\263&\377\271\320w\377r\237\000\377`\205\014" + "\377_\205\003\377\\\200\003\377Z|\004\377Rw\003\377V|\003\377t\221\005\377]\201\007\377" + "e\212\004\377m\223\002\377e\215\010\377[\207\002\377e\213\006\377j\214\005\377r\232" + "\003\377W\203\003\377Y\202\002\377\246\310\007\377\202\255(\377r\236\016\377k\227" + "\002\377f\227\000\377k\233\012\377`\224\003\377`\221\014\377`\216\005\377i\225\010\377" + "`\213\006\377u\231\015\377\\\205\014\377l\240\067\377j\245E\377b\230=\377^\223" + "-\377\\\215\027\377Q\177\020\377Y\214\016\377X\177\020\377=V\002\377@P\001\377We" + "\002\377e\210\010\377fx\030\377qp\070\377\202}U\377\225\220k\377\220\213i\377" + "\204~c\377xk[\377|n]\377\212yb\377\244\217n\377\253\224r\377\242\213h\377" + "\240\207h\377\222zc\377PH=\377\027\022\020\377<\067\070\377RLE\377maU\377\203" + "vc\377vdO\377mWD\377]I:\377TB\066\377}\214=\377qrP\377am\071\377o\177E\377" + "h}H\377d\221>\377Bf\023\377\204\263R\377P\207\026\377;g\002\377J~\005\377<k\004\377" + "@r\014\377>o\001\377K\177\001\377J\200\004\377H~\003\377F~\001\377M\203\003\377]\220\003" + "\377c\222\003\377}\251\002\377g\233\031\377R\201\006\377U\200\003\377i\221\003\377t" + "\247\001\377l\232'\377n\240\023\377\226\267\004\377f\237\022\377P\207\007\377s\242" + "\017\377\241\254\013\377u\240\004\377n\232\002\377i\225\005\377\177\262\016\377w\251" + "\011\377w\247\004\377l\226\003\377\224\264\003\377\201\250\003\377w\246\003\377u\244" + "\003\377|\251\004\377d\216\007\377i\223\007\377\207\255\002\377\225\275\002\377\200\260" + "\013\377v\252\017\377k\237\032\377k\236\003\377{\255;\377\203\243\000\377\202\254" + "\021\377\211\255\006\377\221\261\013\377\246\303N\377n\222\005\377\207\250\012\377" + "q\212&\377Hh\002\377Zz\003\377Hr\003\377Uy\002\377Xy\003\377Gc\002\377i\215\003\377a\207" + "\003\377_}\003\377U\200\002\377U\202\006\377i\220\003\377k\212\002\377\202\245\002\377" + "j\211\004\377j\223\010\377\230\276\011\377j\224\010\377p\241\001\377e\227\007\377" + "w\250\065\377s\236\067\377k\225\033\377d\220\012\377c\205\003\377i\212\002\377q\222" + "\006\377f\217\003\377U~\003\377[\212\010\377Z\215\021\377c\230!\377b\235$\377Y\226" + "\030\377W\222\030\377N\206\012\377Y\220\020\377d\224\016\377f\212\016\377h\214" + "\020\377cz\024\377Wj\013\377Zk\026\377\233\234m\377\236\227x\377\225\207s\377" + "\241\220\201\377\236\215~\377\236\216}\377\226\205o\377\215y_\377\231\202" + "e\377\251\224s\377\245\220r\377\224}g\377OJC\377\011\007\005\377'\035\032\377\\" + "K?\377nXG\377x_J\377u[G\377zeU\377wh\\\377WJ?\377}\210T\377PY/\377DR$\377" + "Zt<\377X\213\062\377S\212+\377Z\204\063\377n\240\062\377Ct\007\377Y\221\022\377" + "<l\004\377:j\010\377\063e\001\377O\205\002\377F~\002\377N\205\003\377J~\004\377L\202\003" + "\377Z\222\002\377Z\216\003\377l\233\006\377u\232\022\377O\177\000\377O\201\003\377U" + "\203\002\377\206\257\007\377j\231\010\377d\234\036\377r\243\023\377\216\265\004\377" + "X\205\001\377a\222\031\377\217\261\026\377\177\240\016\377}\243\001\377n\227\003\377" + "w\243\010\377\205\255\001\377x\242\002\377y\246\005\377o\237\003\377l\233\002\377v\242" + "\005\377k\232\004\377r\241\002\377|\251\004\377n\231\005\377\212\264\012\377\235\271" + "\016\377\200\243\012\377\177\247\016\377z\244\027\377\215\272/\377u\251\014\377" + "\211\277H\377\212\274?\377\211\273A\377}\260$\377\213\270-\377v\234\015\377" + "~\235\014\377\207\247\006\377Pz\002\377\\\201\010\377]\210\003\377L\177\004\377X\216" + "\006\377Q}\002\377^\206\007\377\207\231\025\377d\214\002\377X|\004\377S}\005\377Ao\001\377" + "R\202\004\377b\216\003\377y\235\002\377`\203\001\377b\212\003\377\210\264\011\377o\232" + "\013\377x\243\007\377d\225\023\377\244\314\207\377\245\316\177\377\256\324{\377" + "\250\313c\377\205\244'\377\232\256'\377w\234\040\377s\235\037\377h\221\016\377" + "w\243\017\377d\220\003\377x\247\027\377\213\265@\377\177\256\063\377w\255*\377" + "\\\231\015\377\\\225\011\377]\215\007\377Sv\007\377Vx\006\377i\212\022\377Y|\011\377" + "ct+\377\300\265\244\377\253\235\217\377\234\213\204\377\237\215\205\377\236" + "\214\203\377\220~s\377o]T\377fVD\377\200qW\377\242\221t\377\245\223y\377" + "\232\207q\377SLD\377\025\022\007\377N=\062\377kTH\377iO;\377oVC\377iO=\377L\064" + "(\377?\060'\377\063+!\377oyR\377M[\061\377L\\/\377Y}\060\377Jq\"\377Q\211\040" + "\377W\217*\377c\234*\377I\204\013\377@q\001\377Ao\011\377\063W\001\377M\203\003\377" + "N\210\002\377S\220\004\377Q\215\005\377Fz\005\377P\205\003\377S\210\002\377u\241\006\377" + "b\211\002\377d\212\007\377P\202\012\377R\205\004\377Y\212\003\377h\226\004\377g\223" + "\015\377G\201\006\377x\253\020\377~\255\003\377a\226\012\377u\250\013\377y\247\031" + "\377t\234\003\377v\234\001\377j\230\020\377\177\257\005\377\177\242\013\377\215\262" + "\004\377q\242\013\377p\247\015\377n\234\002\377\221\257\004\377\202\252\011\377\177" + "\250\001\377\232\274\003\377\211\251\003\377n\236\012\377\227\274\060\377\214\257" + "\061\377\210\251\003\377~\233\001\377s\224\003\377\202\254\033\377\204\264/\377\201" + "\251\002\377|\240\006\377\201\261\010\377t\243\003\377r\237\001\377\206\243\023\377" + "\217\247\011\377Mp\002\377\\{\003\377Y~\002\377Hl\001\377Vw\003\377Ow\002\377Y\205\003\377" + "k\221\002\377h\227\004\377T\200\003\377o\220\030\377Hs\002\377R\177\003\377c\224\003\377" + "m\236\010\377Y\207\003\377e\224\004\377\214\266\002\377\204\257\004\377p\241\024\377" + "t\237'\377\203\237\026\377\230\247\034\377\233\260(\377\202\255K\377\255\325" + "\204\377\241\315w\377t\242\066\377g\232!\377v\247\063\377d\233\027\377m\245" + "!\377m\235\"\377j\233\026\377a\222\016\377Z\214\004\377d\230\017\377`\232\007\377" + "X\216\002\377Ry\003\377f\203\014\377No\007\377Sn\013\377m\201(\377\261\247\233\377" + "\264\247\237\377\245\226\223\377\224\204\200\377\230\210\200\377\223\206" + "q\377\206\201]\377lgF\377kaH\377\224\203n\377\254\235\206\377\246\224\202" + "\377\\QL\377'\040\020\377dPE\377v]P\377|bP\377tT@\377iI\067\377cF\067\377WB\063" + "\377F\064$\377iqD\377F^\035\377Qs!\377Qz\022\377Hx\011\377=l\006\377c\222\061\377" + "c\234'\377J{\013\377Q\204\017\377M\204\011\377S\213\005\377W\221\002\377N\211\002" + "\377X\224\002\377S\213\001\377H}\002\377Y\223\003\377`\227\003\377m\237\011\377a\225" + "\031\377V\213\016\377y\253:\377x\253\031\377e\231\005\377v\246\015\377n\241\"\377" + "w\246'\377v\247\006\377{\254\005\377\\\214\003\377\211\257\004\377y\244\011\377\215" + "\261\003\377\202\251\006\377p\230\003\377{\251\004\377s\237\006\377\217\265\016\377" + "p\233\002\377a\230\014\377x\241\005\377\234\267\004\377\223\262\002\377}\247\004\377" + "\214\257\003\377\177\243\020\377g\222\001\377v\231\000\377\222\251\003\377\217\262" + "\023\377\226\271\064\377u\233\012\377p\233\012\377~\256$\377\242\310P\377\202" + "\242\002\377\203\246\005\377\211\246\032\377m\226\001\377z\243\001\377\215\253\004\377" + "Ul\003\377^|\003\377P{\003\377U~\004\377j\216\005\377c\212\006\377f\215\005\377h\227\006" + "\377o\246\004\377_\217\005\377`\213\006\377Js\001\377X\207\002\377b\224\003\377b\220" + "\003\377X\213\002\377j\233\004\377\214\265\004\377p\233\003\377h\220\006\377~\231\012" + "\377b\202\012\377j\220\007\377h\227\035\377n\245-\377f\235\025\377a\234\016\377" + "\213\302O\377\213\276R\377n\237&\377Z\204\011\377e\210%\377s\236\061\377p\231" + "\036\377p\243\031\377o\247\024\377`\235\011\377]\234\014\377K\205\003\377T\212\002" + "\377a\221\002\377b\202\005\377c\204\004\377Y~\023\377\234\242\202\377\235\224\216" + "\377\222\206\204\377\220\210{\377\220\230l\377\210\220a\377\230\235s\377" + "\231\233s\377\233\234s\377\247\246\200\377\252\251\203\377\237\243|\377r" + "\177Y\377Vj\067\377s\202G\377|\206G\377{\177=\377rs\061\377`]\030\377[W\034\377" + "`Z+\377cc\066\377h|\070\377a\213&\377K\177\006\377I~\005\377Dz\003\377H~\010\377\207" + "\263<\377T\203\021\377Q\207\023\377Z\232\023\377b\233\015\377[\220\002\377P\211" + "\004\377:p\002\377R\212\004\377V\214\005\377b\236\023\377Z\217\002\377p\243\004\377X\222" + "\011\377Z\222\013\377P\204\000\377\245\310^\377m\237\022\377m\233\011\377u\240" + "\005\377{\246\027\377y\252\004\377v\253\010\377{\250\005\377\200\250\004\377Uu\002\377" + "u\243\027\377~\250\003\377{\237\015\377y\247\002\377q\237\007\377\206\250\006\377\203" + "\255$\377x\250\023\377s\244\024\377\262\307\006\377\225\271\015\377\201\251#\377" + "u\236\000\377\177\245\004\377n\230\004\377i\226\004\377q\245\017\377\177\256\035\377" + "y\243\005\377~\255\006\377\204\256,\377\201\247$\377s\227\010\377\253\324u\377" + "\203\251\014\377\206\255#\377\214\255\030\377z\237\002\377\205\246\002\377\206" + "\244\002\377bs\005\377i\216\003\377Dt\004\377V|\004\377Yh\002\377V_\002\377hv\003\377Pf\002" + "\377m\241\003\377X\220\004\377e\227\005\377\210\263\007\377t\245\016\377q\245\002\377" + "g\235\002\377Y\220\004\377\177\255\004\377}\245\030\377s\237.\377g\221\007\377r\231" + "$\377^\216\013\377V\205\005\377u\232\014\377f\232\010\377W\214\001\377V\206\000\377" + "Z\217\000\377u\253\061\377z\257\071\377[\224\006\377_\224\011\377q\242\035\377q\243" + "\026\377\\\225\001\377\\\233\005\377X\224\006\377_\232\015\377\\\231\010\377S\214" + "\004\377\\\226\006\377b\231\011\377Z\216\006\377Y\217\005\377t\226.\377t\220-\377" + "t\220+\377\202\217]\377kwJ\377stX\377ieK\377iaJ\377\200r\\\377\231\205n\377" + "\242\216t\377\222za\377S?\066\377]H<\377\220tZ\377\211nQ\377|a>\377w`<\377" + "n]\061\377hc*\377n{\065\377^w!\377u\224)\377W\202\020\377Jz\004\377T\216\010\377" + "V\215\024\377Z\227\033\377i\243\062\377f\242+\377`\230\034\377V\215\010\377W\214" + "\001\377M\204\005\377H\200\006\377O\203\003\377L\177\002\377Y\210\006\377U|\003\377u\243" + "\036\377S\213\003\377Q\204\002\377Q~\006\377y\242.\377\211\265D\377[\221\006\377n" + "\224\005\377\204\251\013\377\202\256)\377g\230\002\377q\245\005\377\201\250\004\377" + "\210\253\002\377`\217\002\377p\245\012\377\202\255\002\377z\246\001\377o\236\003\377" + "`\221\002\377\254\270$\377\201\240(\377\241\274\017\377\231\262\004\377\205\250" + "\003\377r\233\004\377f\215\001\377i\221\003\377{\242\006\377s\232\005\377t\233\002\377" + "}\245\013\377{\242\022\377p\233\014\377|\250\002\377o\230\000\377x\236!\377|\233" + "\010\377\213\254\023\377\224\276D\377\200\246\000\377\231\301Z\377\200\256\061" + "\377\227\270\025\377\203\237\004\377Pk\002\377V|\003\377=c\001\377Sp\002\377Zk\002\377" + "Nc\002\377]z\002\377j\202\003\377z\243\003\377o\224\005\377Z\220\012\377O\212\005\377" + "{\253\003\377t\246\002\377_\217\004\377]\213\002\377\232\277\002\377u\240\025\377[\211" + "\023\377e\227\013\377e\225\034\377t\243\037\377e\235\017\377m\237\"\377\206\260" + "N\377~\254C\377c\226\021\377m\230\025\377e\230\002\377_\220\003\377a\224\004\377" + "n\237\010\377m\231\022\377\221\262\067\377\260\303\064\377\254\275=\377c\231" + "\021\377Z\225\024\377a\236\026\377Z\223\007\377_\230\012\377W\220\001\377V\216\002" + "\377U\211\002\377b\217\011\377q\230\026\377g\221\015\377_\212\017\377b\205\034\377" + "i\202)\377|\214J\377\212\220c\377\223\225o\377\213\213c\377\213\201a\377" + "\215\177c\377W@\070\377zdR\377\250\225q\377}nC\377\207yL\377\205zG\377zx\071" + "\377gn\037\377j\203+\377Qt\015\377[~\026\377Hl\013\377Is\003\377m\245,\377k\243" + ".\377}\260J\377Q\210\040\377u\253A\377V\212\004\377Z\215\003\377M\177\002\377I~" + "\004\377<m\002\377J~\004\377U\211\002\377u\236.\377Rp\005\377e\234\025\377\214\272d" + "\377N\177\000\377\227\261\061\377\274\317\215\377a\222\016\377q\237\005\377h\223" + "\002\377\216\271\034\377b\222\015\377V\214\014\377m\241\007\377\200\244\003\377\204" + "\251\003\377o\235\003\377v\242\004\377p\231\003\377v\241\002\377c\221\003\377\207\254" + "\006\377\231\254\006\377\277\306\017\377~\242\006\377Uw\002\377{\245\004\377d\221\004" + "\377k\223\003\377o\225\002\377k\224\004\377i\224\004\377{\237\002\377\203\244\001\377" + "\204\246\003\377q\230\004\377w\242\002\377p\223\003\377\177\236\003\377\222\252\002\377" + "\205\240\001\377\201\255\022\377\212\263\030\377\201\251\035\377\204\256(\377" + "p\222\002\377z\224\001\377S{\003\377S\206\002\377U\205\004\377Y\211\006\377[\213\005\377" + "`\220\003\377\\}\003\377`\200\003\377p\235\003\377}\242\015\377R\204\010\377T\216\004" + "\377]\222\004\377o\237\002\377n\221\015\377\201\251\012\377\224\273\006\377c\220" + "\012\377]\213\002\377q\235\014\377^\217\004\377b\223\004\377]\221\003\377U\210\002\377" + "`\220\010\377U{\000\377f\201\005\377}\226\024\377n\231\004\377e\224\007\377Y\215\016" + "\377b\225\023\377z\246\032\377Z\210\005\377\\\215\013\377f\220\022\377i\225\034" + "\377^\215\020\377^\220\016\377\\\215\006\377]\221\005\377X\214\003\377L|\002\377S\204" + "\002\377V\206\006\377g\221#\377Lx\015\377[\210\037\377s\232\071\377w\220@\377o\215" + "\065\377X\177\032\377]\213\040\377_\216!\377b\215\"\377h\216)\377j\206\062\377" + "\232\251s\377\224\233k\377\204rB\377\223uJ\377\224sG\377\253\217@\377z~\035" + "\377^|\021\377Ej\000\377i\214\061\377R{\023\377[\215\004\377\213\271N\377Y\216\026" + "\377f\237*\377`\234)\377J\202\003\377T\211\016\377a\225\006\377i\227\004\377f\223" + "\003\377Op\001\377U\214\002\377g\230\032\377\211\251<\377k\234\006\377P\203\006\377" + "b\216\040\377n\236.\377\216\266\070\377\231\271@\377\177\256\004\377P{\020\377" + "^\223\010\377\212\265\033\377_\221\001\377T\215\016\377y\245\014\377\261\302\004" + "\377x\243\005\377u\240\003\377~\252\005\377h\222\004\377c\222\003\377\200\241\003\377" + "\256\275\006\377\202\240\004\377\216\245\007\377i\220\002\377f\215\002\377v\240\004\377" + "f\214\004\377k\221\003\377m\230\003\377f\220\001\377m\226\005\377\177\243\004\377\206" + "\246\006\377\177\243\002\377v\235\004\377n\225\002\377y\240\004\377\223\254\002\377\207" + "\235\004\377i\217\001\377~\243\024\377\233\273D\377\201\247\026\377{\244\005\377" + "\200\252\025\377\206\226\017\377Fp\002\377Dq\002\377K|\003\377N|\002\377b\204\005\377" + "Y{\012\377Sv\007\377W|\005\377s\240\026\377{\237\004\377a\201\005\377H}\004\377P\207" + "\002\377b\227\003\377o\243\004\377]\220\003\377p\235\004\377M~\002\377X\211\004\377S\203" + "\003\377h\226\004\377\\\217\003\377J\200\003\377X\214\003\377R\204\002\377d\220\003\377" + "b\211\002\377l\221\002\377l\231\005\377K\177\002\377Z\213\002\377\210\252\013\377i\220" + "\020\377`\220\021\377d\227$\377_\230\034\377d\235\017\377W\213\004\377V\205\003\377" + "U\206\005\377Lx\003\377i\224\007\377p\227\004\377\216\247#\377\245\262<\377\231\256" + ",\377\214\247\033\377\203\247\023\377\201\251\030\377\204\255\035\377\223\265" + "\064\377\217\256\071\377\205\241\066\377v\223(\377|\233,\377j\217\017\377`\213" + "\011\377g\215!\377d\207\"\377i\210#\377h\207!\377g\211!\377q\220\015\377y\233" + "\007\377Iq\011\377\\|\037\377}\253\066\377j\232\025\377l\233\010\377\177\255C\377" + "]\227\020\377\\\224\016\377Fu\001\377Cv\004\377g\232\016\377U\203\003\377S\202\003\377" + "^\214\004\377t\245\007\377_\233\010\377k\240\024\377g\235\021\377^\222\004\377Z\205" + "\004\377W\202\003\377\201\261?\377t\236\025\377\203\254\023\377o\236\040\377`\224" + "\007\377U\211\011\377\217\273\013\377a\223\001\377b\240\034\377t\234\005\377\224\256" + "\004\377p\234\002\377\207\253\006\377\202\251\004\377m\231\003\377\220\257\005\377\246" + "\274\005\377b\214\002\377d\221\003\377\210\243\011\377}\233\002\377\240\277\"\377" + "e\216\001\377\210\253\006\377o\224\002\377f\223\002\377~\251\017\377n\223\011\377{" + "\240\001\377\230\262\027\377\177\242\004\377v\227\004\377}\237\005\377\212\252\006\377" + "r\221\003\377s\226\002\377r\235\002\377\236\270<\377\216\236:\377\257\313j\377" + "t\235\000\377|\245\017\377\222\276\037\377T\205\003\377R\204\002\377K\177\002\377D" + "r\001\377[v\021\377d}\017\377\210\202\031\377x\233\060\377m\234\001\377M\202\002\377" + "W\214\004\377W\215\022\377J\201\003\377g\236\003\377c\230\003\377z\252\003\377^\221" + "\003\377V\214\003\377M\202\002\377Qw\002\377^\207\003\377c\217\003\377`\220\003\377X\214" + "\003\377_\224\000\377b\217\005\377c\213\002\377f\226\002\377P\204\003\377]\217\002\377" + "p\235\003\377\223\255\004\377~\236\006\377f\235\010\377m\241\035\377d\226\007\377[" + "\210\002\377T{\006\377U\177\006\377Z\207\004\377]\216\002\377^\216\003\377R~\003\377X\202" + "\010\377\200\235.\377\250\260e\377\230\245a\377\216\246a\377\220\250a\377" + "\240\250r\377\231\224b\377\206wC\377\230\210R\377\222\217L\377\227\214X\377" + "\206\201L\377^m\061\377as\071\377\211\226M\377\226\240P\377l\204&\377T~\027" + "\377[\214\016\377r\235\002\377x\234\021\377\220\256@\377\202\254M\377\\\221\023" + "\377s\243\020\377f\232(\377_\226\022\377Dn\003\377[\204\000\377u\244'\377S|\001\377" + "Kq\002\377?e\002\377J\204\004\377J\210\006\377T\214\011\377\177\260\031\377u\245\003" + "\377Qz\004\377Hs\002\377V\203\006\377k\232\023\377z\247\024\377f\231\016\377Y\213" + "\010\377W\207\004\377P\202\004\377~\256\006\377[\220\006\377^\227\026\377\230\265\003" + "\377j\222\004\377u\242\002\377\200\240\014\377\212\260\004\377\221\265\004\377s\231" + "\004\377\201\245\004\377Y\206\002\377q\227\005\377\207\251\003\377}\232\004\377\224\261" + "\003\377\213\254\005\377y\236\002\377g\221\002\377s\241\005\377\201\250\004\377d\215" + "\002\377q\233\004\377\221\260\016\377x\226\003\377z\225\006\377~\241\006\377x\243\003" + "\377h\227\002\377{\250\025\377\200\251\021\377\203\257\027\377~\240\032\377{\231" + "\035\377\206\253&\377z\241\001\377x\250\017\377U\210\004\377Y\207\003\377Z\204\002" + "\377bg\004\377\202t\005\377{\200\004\377h\210&\377S\210\005\377T\216\003\377T\212\005" + "\377V\207\003\377X\205\004\377S\204\005\377g\241\002\377]\226\003\377e\232\003\377i\231" + "\002\377K\177\003\377V\215\013\377Z\201\012\377^\213\006\377`\220\007\377\\\217\003\377" + "[\223\003\377~\250?\377b\222\010\377h\230\005\377R\210\003\377]\224\003\377d\234\002" + "\377r\251\004\377k\237\001\377d\233\004\377c\232\015\377_\224\005\377T\206\002\377[" + "\204\004\377Zz\014\377_\201\020\377h\223\026\377Lz\004\377@b\003\377\070Y\003\377(I\002" + "\377lw!\377}\203\060\377\223\226L\377\273\265|\377y\206%\377Sm\026\377Wq.\377" + "d|>\377j\206;\377l\207\061\377y\214;\377w\211\071\377Rf!\377?S\016\377`t\025" + "\377j\203\020\377o\213\011\377m\212\004\377~\225\004\377q\232\003\377\200\220\003\377" + "{\230\061\377\201\252L\377j\227\004\377l\235\023\377\203\250\061\377]\222\031\377" + "]\215\003\377m\232\030\377[{\034\377Fj\002\377@g\003\377By\005\377F}\012\377]\230'\377" + "l\252\060\377r\250\014\377]\214\003\377l\234\011\377a\215\007\377b\226\006\377~\252" + "\023\377n\234\014\377O~\002\377d\226\013\377W\207\025\377j\227\014\377\211\262\003" + "\377\\\214\011\377b\235\025\377\226\260\003\377k\225\007\377z\247\002\377\234\261" + "\025\377q\240\003\377f\221\005\377|\241\004\377x\236\002\377\\\206\002\377w\233\004\377" + "\206\245\002\377\210\244\004\377\223\255\010\377y\232\003\377|\242\013\377s\235\004" + "\377x\242\003\377\215\254\005\377e\217\002\377m\237\014\377u\233\000\377\242\264." + "\377\204\223\016\377\221\261\003\377\201\255\002\377t\252\026\377t\247\023\377\207" + "\270\060\377\205\260\037\377\211\267\021\377s\235\004\377\211\261\"\377\205\256" + "\024\377q\231\002\377ct\004\377u\230\005\377p\241\004\377j\225\005\377Z\210\004\377l\235" + ")\377v\237'\377_\202\005\377g\231\004\377L\201\001\377l\230\016\377Q\177\003\377N" + "\202\002\377b\233\002\377O\212\002\377_\226\002\377p\250\003\377O\202\001\377X\211\005" + "\377l\235\030\377p\236\063\377T\202\020\377T\203\007\377m\233*\377Z\224\007\377" + "L\203\002\377b\227\003\377T\207\002\377`\231\002\377d\235\014\377S\213\003\377P\204" + "\004\377J~\003\377V\213\003\377[\214\004\377`\212\002\377b\212\004\377w\236\012\377{\250" + "\016\377a\217\024\377Nu\003\377Nf\011\377IW\007\377\\o\010\377z\211#\377\220\241" + "I\377\207\252=\377\243\274X\377\201\222-\377x\213\036\377Qe\010\377`x\031\377" + "n\220\064\377d\204\032\377]\205\012\377\\\213\012\377U\204\002\377Gp\001\377Pu\000" + "\377R}\010\377q\232\023\377\223\265\061\377Rt\012\377`\214\000\377r\243-\377w\241" + "\071\377h\237\017\377X\211\014\377\177\233%\377f\215&\377M\177\002\377:j\000\377" + "Z\207!\377N|\012\377Cm\001\377H{\004\377<m\000\377\177\254R\377x\252S\377c\217\020" + "\377a\223\005\377Et\002\377f\210\021\377p\231\007\377r\246\003\377\203\256\014\377" + "X\205\003\377U\205\002\377c\226\016\377Co\004\377h\216\004\377\205\256\004\377_\217" + "\004\377\202\264\032\377~\244\005\377a\217\006\377\203\251\007\377\224\252\015\377" + "u\245\002\377^\215\003\377\204\253\003\377o\231\012\377\\\210\002\377\202\245\005\377" + "}\241\005\377\222\263\004\377\210\243\003\377n\220\002\377|\240\006\377x\224\004\377" + "u\231\004\377\217\255\010\377q\226\002\377{\242\010\377}\240\000\377\217\256\001\377" + "\202\234\010\377\215\267\005\377\207\262\004\377r\231\010\377p\230\002\377o\232\007" + "\377z\252\024\377\202\255\035\377\202\256\005\377\206\263\021\377\203\254\005\377" + "\177\243\002\377l|\005\377Q\200\003\377X\177\005\377_\205\004\377g\234\006\377^\230\006" + "\377S\212\001\377i\234\004\377d\226\003\377_u\006\377i\220\017\377O\201\004\377[\222" + "\003\377^\224\003\377B{\002\377h\236\003\377Lz\001\377d\226\011\377Y\203\003\377[\215" + "\000\377P\201\001\377{\245\061\377{\237\071\377Sy\010\377Gw\002\377a\230\025\377c\231" + "\002\377X\215\003\377\\\223\005\377^\226\015\377T\213\001\377b\230\020\377\\\220\005" + "\377V\212\010\377e\234\011\377b\231\015\377n\236\031\377c\220\032\377Y\214\017" + "\377a\227\012\377]\216\002\377v\246\017\377i\225\020\377e\212\025\377d\202\031\377" + "\236\271c\377\207\261I\377r\231%\377a\177\024\377v\215!\377dy\000\377m\214\022" + "\377X\202\007\377V\206\004\377\\\220\011\377M~\004\377Gv\004\377Jv\007\377U\206\023\377" + "y\251&\377\205\252\063\377Oe\013\377Ni\016\377n\224\003\377t\236\"\377x\243D\377" + "c\230\001\377L\200\013\377y\244\040\377G{\007\377Bp\003\377Q~\034\377b\223\061\377" + "\063W\002\377Ap\017\377J\203\016\377x\252H\377h\237;\377L}\014\377u\230\011\377" + "Uu\002\377\\{\005\377g\220\010\377t\240\001\377\233\271;\377\223\261\"\377a\230" + "\005\377g\226\025\377R|\004\377S}\002\377l\224\004\377\205\257\003\377h\227\023\377\224" + "\267\012\377z\244\010\377t\237\006\377\236\265\005\377o\233\002\377v\244\011\377i" + "\230\010\377|\243\002\377h\223\004\377f\221\003\377v\236\003\377s\233\002\377\213\260" + "\003\377p\225\004\377u\234\003\377}\244\002\377w\233\003\377d\215\003\377n\230\001\377" + "o\230\003\377v\240\020\377w\241\007\377\203\257\026\377\200\254\031\377\177\250" + "\006\377\221\266\003\377z\217\004\377v\224\002\377s\226\001\377w\241\017\377\200\253" + "\026\377u\244\004\377s\244\004\377x\244\003\377u\232\002\377X\210\003\377`\212\007\377" + "}\210\023\377d{\003\377\\\206\003\377Gv\002\377C}\002\377V\214\003\377m\235\006\377v\222" + "\011\377Z\210\003\377O\206\004\377k\242\006\377Z\221\002\377T\206\004\377`\223\003\377" + "Jy\002\377Pz\002\377_\213\003\377a\222\003\377Z\212\004\377{\233\030\377T|\010\377t\241" + "\067\377L\200\001\377W\220\014\377g\237\007\377\\\221\002\377a\213\011\377V\211\002" + "\377a\226\013\377\204\260/\377q\240\020\377s\243\022\377v\244)\377{\254@\377" + "d\232#\377K\200\032\377Ev\037\377a\213\060\377j\227*\377\\\214\026\377Q\201\010" + "\377M}\004\377p\246/\377\224\277[\377u\245)\377g\230\016\377e\225\011\377\177" + "\250*\377j\231\013\377^\216\003\377`\223\003\377W\207\004\377Do\004\377Q\200\005\377" + "Ku\002\377h\230\027\377\225\275F\377\246\311_\377\203\237B\377j\212!\377d\201" + "\021\377w\241\017\377l\237\022\377\226\267N\377[\213\000\377U\204\014\377m\240" + "\021\377@j\005\377Ov\011\377a\211\034\377Y\200\040\377>a\001\377n\235@\377\223\304" + "o\377s\252K\377Dk\013\377Is\004\377m\232\010\377`\212\002\377c\216\004\377m\223\004" + "\377\224\265(\377\202\243\033\377\204\247\015\377d\237\026\377P\203\004\377V\206" + "\011\377X\206\012\377u\236\010\377\206\256\002\377\210\262\031\377\214\264\007\377" + "\214\240\015\377\211\252\005\377\237\267\034\377~\253\024\377\207\257\023\377m" + "\224\004\377z\237\004\377r\227\011\377i\223\011\377u\242\004\377\212\257\003\377\203" + "\247\003\377u\234\004\377z\242\002\377q\235\003\377u\236\002\377u\226\015\377u\235\006" + "\377f\225\003\377o\236\003\377{\245\006\377\220\264\010\377\214\252\004\377\206\252" + "\003\377\215\261\004\377\204\246\003\377[z\001\377\212\241\020\377\206\232\004\377\224" + "\246\005\377\226\263\024\377x\247\034\377\200\255\036\377s\236\000\377i\233\006\377" + "g\230\007\377_\227\005\377\\\214\004\377Fn\000\377V\206\003\377Aw\004\377R\207\003\377" + "f\232\005\377Y\204\002\377\\\215\003\377V\220\002\377f\234\003\377^\223\004\377_\216" + "\004\377p\237\004\377P{\003\377W\177\013\377b\221\004\377v\252\002\377P\204\003\377V\204" + "\004\377a\213\010\377P\201\000\377k\236\037\377b\217\027\377o\242+\377U\213\000\377" + "_\221\006\377Z\216\007\377X\223\007\377m\242\024\377o\241\013\377k\240\016\377z\254" + ";\377y\254?\377a\230\027\377]\220\007\377f\222\031\377Wx\025\377Nk\002\377q\225" + "\067\377o\241\065\377q\245\"\377z\254'\377Z\212\006\377]~\007\377]\210\022\377c" + "\221\025\377c\226\017\377Y\177\022\377_\220\006\377_\223\003\377O}\007\377c\221\030" + "\377v\243/\377\206\271/\377~\255'\377\223\266K\377\220\261K\377\227\276]" + "\377\237\311o\377\230\306k\377m\236\020\377h\230\016\377\210\257-\377\\\226" + "\012\377Y\216\023\377d\226\006\377Hs\000\377n\222/\377_\177\035\377Rl\004\377\202" + "\255G\377|\256P\377}\256=\377Kt\015\377a\217$\377t\244\011\377X\212\006\377S" + "\203\010\377a\222\012\377y\243\002\377\240\275\070\377Q\207\012\377j\237\013\377" + "h\227\021\377Kx\003\377m\243\021\377Y\211\006\377w\241\003\377\203\262\011\377\203" + "\260\005\377\177\246\014\377y\231\005\377\216\256\002\377o\222\003\377v\240\005\377" + "g\221\002\377\200\251\004\377k\227\006\377m\240\013\377h\231\004\377y\244\005\377\231" + "\300\010\377s\240\011\377n\230\004\377w\237\002\377e\221\002\377}\234\003\377\250\254" + "\024\377l\224\003\377k\232\003\377e\226\002\377\202\247\030\377\204\246\002\377\212" + "\253\003\377\217\262\004\377\227\270\003\377\221\262\003\377d\211\002\377k\223\003\377" + "~\240\004\377\227\245\006\377\220\237\006\377\222\255\015\377\214\257\015\377y\250" + "\007\377c\222\005\377[\213\004\377r\245\021\377q\253\030\377k\246\030\377Bv\001\377" + "@s\002\377J}\002\377S\203\003\377U|\011\377U\211\003\377c\232\004\377f\225\002\377W\210" + "\003\377h\230\002\377m\233\002\377Z\210\005\377c\222\023\377L\214\006\377p\244\003\377" + "l\236\003\377R\201\004\377M\177\002\377_\217\002\377^\215\002\377a\216\024\377o\243" + "=\377a\240\011\377h\241\034\377\205\270N\377b\236\026\377T\216\010\377i\233\016" + "\377_\222\003\377x\254/\377\200\265;\377d\234\014\377g\240\005\377e\230\001\377" + "X\207\013\377h\224\065\377f\222\026\377~\250\060\377~\255=\377}\255/\377q\234" + "\021\377t\240\023\377e\231\005\377\\\216\003\377a\225\004\377p\243\016\377o\243\016" + "\377}\265\061\377j\236\066\377\226\302v\377\220\276J\377q\243\035\377c\214\023" + "\377Vt\014\377u\235\061\377\210\264\\\377V\204\037\377Z\221\031\377\201\266;" + "\377z\257,\377w\250\025\377^\213\004\377V}\016\377l\223\012\377i\221#\377e\212" + "%\377]\200\007\377\177\252O\377_\222-\377v\244(\377Rx\022\377m\237\061\377W\204" + "\027\377m\232\003\377h\227\005\377W\203\006\377q\233\003\377\225\267\062\377s\227\020" + "\377n\233\034\377h\234\014\377i\233\011\377f\233\015\377g\225\026\377j\231\013" + "\377\205\266\003\377m\252\025\377s\245\010\377a\217\004\377o\237\004\377~\254\002\377" + "m\234\004\377\211\256\007\377z\240\010\377i\224\004\377y\242\007\377r\236\020\377n" + "\235\003\377\203\257\004\377t\244\007\377`\214\005\377s\236\003\377n\231\003\377l\226" + "\005\377\225\247\002\377{\236\024\377k\223\002\377t\233\007\377g\217\002\377~\253\005" + "\377p\233\004\377s\232\003\377\211\261\002\377\216\263\002\377\200\247\002\377\212" + "\260\004\377p\227\002\377\204\244\003\377}\224\003\377\243\257\002\377\242\271'\377" + "}\241\002\377t\241\006\377R\206\002\377Z\222\005\377O\205\006\377`\226\027\377w\247" + "-\377v\246\062\377[\216\"\377M\202\000\377>r\001\377W\205\005\377N\204\003\377W\212" + "\004\377o\240\010\377Kz\003\377d\230\004\377Y\213\004\377[\214\012\377Z\216\004\377F" + "~\002\377O\205\003\377{\254\002\377i\226\003\377R{\003\377X\214\003\377]\217\004\377Y\212" + "\013\377q\236'\377|\265;\377q\251-\377o\241+\377`\224\016\377L\202\003\377M\200" + "\003\377M~\010\377V\205\003\377d\213\023\377y\231\030\377p\235\035\377d\231\026\377" + "s\247)\377\\\220\021\377{\257<\377\201\260P\377]\224\010\377d\231\007\377a\231" + "\004\377h\242\022\377^\220\011\377t\241\024\377\212\264'\377k\225\013\377o\227" + "\024\377\207\252A\377\225\273P\377|\256\061\377k\235\035\377k\230\035\377}\245" + "/\377\201\260E\377r\247>\377e\231!\377^\220\022\377m\234!\377[\215\016\377" + "V\213\020\377b\227\026\377y\244\033\377~\247\064\377o\222\015\377u\243\066\377" + "Z\207\037\377|\255H\377W\177\037\377s\252*\377Rz\005\377f\223\"\377T\204\015\377" + "Gp\001\377[\204\002\377w\245+\377x\242\003\377v\236\023\377\204\250\024\377k\217" + "\026\377h\230\006\377l\236\031\377o\236\007\377q\234\030\377p\240\007\377\206\266" + "\010\377r\244\011\377h\246\036\377y\250\000\377i\226\002\377r\240\003\377\200\261" + "\003\377q\235\003\377\201\242\020\377\215\261\032\377q\236\003\377Zs\002\377l\230\003" + "\377r\231\003\377\214\263\004\377u\242\005\377n\230\006\377\203\245\013\377q\224\020" + "\377p\234\011\377\201\247\036\377u\241\013\377v\236\006\377y\243\001\377s\241\001" + "\377m\233\003\377]\212\004\377t\237\004\377{\245\003\377\222\267\004\377n\227\002\377" + "\204\246\006\377\204\246\005\377\227\266\013\377\220\252\004\377\231\257\005\377\270" + "\274@\377|\243\016\377p\233\001\377`\225\003\377a\225\002\377a\223\003\377T\206\004" + "\377X\216\003\377Y\220\001\377b\220\031\377\225\275`\377c\211\030\377T\204\003\377" + "H~\002\377V\212\003\377g\240\002\377M\205\003\377a\227\004\377Q\202\002\377Ky\002\377^" + "\212\014\377S\204\002\377U\207\003\377m\236\003\377^\210\002\377h\235\002\377a\227\003" + "\377L\205\003\377a\232\011\377h\240\021\377j\242\033\377}\260A\377\232\305h\377" + "g\237\023\377Fw\002\377Z\215\003\377V\213\006\377V\206\003\377f\235\012\377V\216\004" + "\377]\222\002\377U\213\002\377V\217\002\377^\226\003\377[\224\005\377R\213\005\377o\240" + "\033\377r\241\016\377a\214\015\377f\232\"\377b\226\011\377i\236\013\377o\236\037" + "\377{\250?\377e\221\027\377\225\267\065\377\200\244\031\377^\205\004\377t\241" + "'\377i\237\037\377k\240\"\377l\232%\377Fg\006\377^\216\024\377z\241\063\377\212" + "\235<\377b\220\031\377L~\003\377V\211\004\377p\235\016\377g}\035\377\207\264\065" + "\377z\246*\377}\264B\377^\215'\377l\221\062\377d\214!\377k\222\033\377Mu\010" + "\377@f\002\377Z\205\004\377v\244\"\377w\247\022\377m\224\001\377\241\272*\377h\213" + "\017\377^\214\011\377j\230\005\377\216\257#\377k\227\004\377\207\260\005\377\204" + "\255\007\377h\224\005\377f\235\021\377j\244\024\377|\252\002\377q\240\004\377\206\256" + "\004\377u\241\002\377h\224\002\377r\217\007\377\211\251\013\377j\227\003\377]\201\003" + "\377i\220\002\377\227\270\003\377p\227\002\377z\243\020\377u\242\001\377\177\255\031" + "\377g\221\003\377g\217\010\377g\215\012\377n\230\005\377\177\252\007\377y\242\014" + "\377{\243\025\377l\225\003\377f\221\004\377\210\261\004\377s\234\003\377\200\246\003" + "\377}\240\003\377\207\247\003\377\214\250\003\377\200\241\006\377\220\267\021\377" + "\202\245\003\377\242\261\031\377\226\260-\377u\236\002\377]\227\023\377Y\210\001" + "\377Nv\000\377_\202\017\377U\210\005\377]\231\010\377a\236\010\377Y\216\000\377_\223" + "\027\377W\214\006\377G\202\003\377b\226\023\377d\232\001\377[\223\007\377f\225\002\377" + "Q}\005\377Hs\002\377`\212\013\377S\200\004\377W\212\003\377X\212\002\377^\206\003\377" + "l\234\004\377n\245\004\377J\177\003\377i\235\007\377t\250\026\377|\260+\377u\253\065" + "\377\207\266L\377\225\300T\377\207\264B\377r\225\066\377^\201\023\377`\220" + "\021\377Iu\003\377L~\006\377R\205\004\377S\201\003\377]\221\015\377`\233\005\377M\201" + "\000\377_\224\005\377d\225\013\377`\220\011\377h\231\021\377\\\214\004\377h\241\017" + "\377b\227\012\377v\246\036\377k\231\035\377j\232\014\377u\245\022\377~\241\033" + "\377r\230\030\377\204\260Q\377\200\255J\377i\210+\377}\227A\377}\251A\377" + "\200\257I\377b\226)\377]\222\036\377\\\222\026\377F{\005\377\\\222\007\377v\245" + "\005\377j\225\011\377t\254\024\377^\214\020\377p\245\035\377Y\213\014\377u\246(" + "\377Z\212!\377R~\016\377F_\004\377JX\006\377h\216\007\377u\250#\377\214\261\001\377" + "\207\244\012\377\177\251\026\377l\224\024\377i\232\002\377t\251\035\377h\231\011" + "\377\204\260\005\377x\244\010\377\200\251\005\377`\216\011\377k\245.\377j\240\013" + "\377w\246\002\377\205\260\004\377w\235\004\377i\225\002\377v\235\003\377l\221\005\377" + "}\247\002\377u\245\006\377q\235\007\377r\232\003\377\224\265\010\377v\237$\377l\232" + "\012\377l\231\004\377~\254\002\377w\247\030\377r\236\015\377w\236\007\377{\243\004\377" + "u\232\004\377\212\261\032\377`\214\003\377\222\267)\377v\243\004\377\200\253\005\377" + "p\225\000\377\210\255\004\377\203\246\005\377\207\247\007\377\215\245\001\377l\212" + "\003\377~\225\004\377\204\242\010\377\222\261\010\377\211\247\024\377\220\262\016" + "\377=u\005\377[\216\"\377\213\271G\377Fw\005\377Dp\002\377:j\001\377b\231\013\377" + "Y\217\002\377Q\210\005\377o\250\005\377X\212\001\377p\244\030\377\\\225\001\377]\225" + "\007\377a\223\003\377Ls\005\377V\203\005\377U\202\005\377Xv\010\377c\223\004\377N\201" + "\003\377Y\213\005\377a\220\006\377a\215\005\377\\\213\003\377V\206\001\377~\251\061\377" + "\216\301F\377l\242\"\377\241\313i\377\211\267A\377\215\274L\377\262\334\214" + "\377h\215<\377h\214/\377h\240\007\377U\216\005\377W\216\004\377^\215\004\377Q\203" + "\003\377e\234\004\377s\254\034\377\202\262E\377z\244\060\377i\227\011\377e\223\013" + "\377d\225\013\377j\237\015\377c\222\017\377j\225\011\377\211\261\011\377{\245" + "\012\377\177\250\037\377\234\300c\377|\251F\377\204\251Z\377{\241G\377g\226" + "/\377R\206\015\377a\210\020\377dw\004\377\201\262\032\377\201\255\067\377x\247" + "\061\377r\251.\377i\233\017\377z\245\002\377q\243-\377l\240\020\377`\224\027\377" + "d\233\"\377d\234\030\377|\261-\377v\252(\377c\223\010\377[\205\005\377Nu\005\377" + "x\244\005\377\200\260\022\377x\234\005\377\204\245\023\377z\245\031\377m\233\005\377" + "q\233\005\377}\256&\377\204\260\005\377V\204\004\377z\247\015\377^\204\004\377g\222" + "!\377\211\265a\377\200\254\011\377}\253\003\377v\241\002\377n\230\004\377c\212\002" + "\377{\233\010\377\\\210\002\377r\243\014\377n\233\002\377q\232\002\377\201\250\005" + "\377y\231\016\377u\237\011\377\217\254\017\377\202\256\025\377\236\312Q\377\206" + "\261\061\377p\237\005\377{\245\013\377\234\274\016\377q\225\002\377\215\264\010\377" + "t\237\021\377a\211\005\377\214\271\022\377z\254\016\377}\254\034\377\231\273\016" + "\377\207\244\011\377\216\251\012\377\211\236\033\377\211\247\006\377Oc\001\377w" + "\233\003\377\211\261\017\377\205\247\013\377r\227\006\377[\207\003\377\200\246A\377" + "y\253\071\377d\221\034\377@c\002\377;a\002\377Iq\003\377W\211\005\377J\177\001\377g\231" + "\003\377Lu\004\377W\216\003\377b\242\006\377[\230\010\377P\203\000\377u\230.\377U\202" + "\005\377T\201\002\377Ir\003\377U\215\003\377I\177\003\377]\225\010\377Hi\003\377Vq\007\377" + "Or\002\377]\212\004\377;X\001\377^\207\015\377c\217\020\377w\253\032\377\203\270\060" + "\377\205\273\066\377\210\274\067\377r\244%\377Ms\015\377\177\241,\377a\213\023" + "\377l\244\025\377[\217\003\377c\234\004\377a\227\005\377j\234\005\377v\251\013\377" + "s\244\016\377x\247'\377y\245.\377q\242'\377o\237(\377g\226\036\377_\222\032" + "\377]\217\016\377`\222\017\377h\234\033\377Z\215\010\377\201\257\020\377\201\242" + "\040\377\177\253\037\377{\254%\377x\251\015\377~\246\013\377\206\254\031\377w" + "\246\020\377m\243\027\377d\231\025\377b\232\027\377W\213\011\377v\246\003\377]\205" + "\013\377e\225\013\377n\243\040\377z\253*\377X\211\020\377P~\004\377{\247=\377{" + "\245*\377Wz\006\377Qv\011\377\200\256\003\377p\240\001\377\240\272+\377r\243\027" + "\377\205\252\005\377s\240\004\377\214\264\004\377~\253\004\377^\216\020\377y\252\007" + "\377R\201\003\377h\230\027\377t\242%\377\231\300S\377\243\303!\377\234\271\"" + "\377\232\264$\377\207\240\021\377r\216\005\377\202\237\005\377h\226\003\377o\235" + "\013\377\206\254\003\377j\227\003\377\214\261\005\377y\241\006\377r\236\007\377\221" + "\262\014\377\205\255\016\377V\201\010\377}\247\015\377\216\261\013\377n\225\013" + "\377\220\265\007\377\205\260\005\377\210\256\024\377z\243\004\377x\241\003\377v\243" + "\010\377\215\267)\377\250\301.\377\252\302\033\377\222\257(\377\224\260\025" + "\377~\233\006\377\220\256\007\377\203\241\003\377\207\254\002\377y\232\002\377\212" + "\247\011\377\207\256\022\377", +}; + diff --git a/examples/cat.h b/examples/cat.h new file mode 100644 index 00000000..46dc50f6 --- /dev/null +++ b/examples/cat.h @@ -0,0 +1,13 @@ +#ifndef _CAT_H +#define _CAT_H + +struct gimp_texture { + unsigned int width; + unsigned int height; + unsigned int bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */ + unsigned char pixel_data[128 * 128 * 4 + 1]; +}; + +extern const struct gimp_texture cat_tex; + +#endif diff --git a/examples/dmabuf-capture.c b/examples/dmabuf-capture.c new file mode 100644 index 00000000..ebbe0a70 --- /dev/null +++ b/examples/dmabuf-capture.c @@ -0,0 +1,850 @@ +#define _POSIX_C_SOURCE 199309L +#include <libavformat/avformat.h> +#include <libavutil/display.h> +#include <libavutil/hwcontext_drm.h> +#include <libavutil/pixdesc.h> +#include <poll.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <pthread.h> +#include <stdbool.h> +#include <drm_fourcc.h> +#include "wlr-export-dmabuf-unstable-v1-client-protocol.h" + +struct wayland_output { + struct wl_list link; + uint32_t id; + struct wl_output *output; + char *make; + char *model; + int width; + int height; + AVRational framerate; +}; + +struct fifo_buffer { + AVFrame **queued_frames; + int num_queued_frames; + int max_queued_frames; + pthread_mutex_t lock; + pthread_cond_t cond; + pthread_mutex_t cond_lock; +}; + +struct capture_context { + AVClass *class; /* For pretty logging */ + struct wl_display *display; + struct wl_registry *registry; + struct zwlr_export_dmabuf_manager_v1 *export_manager; + + struct wl_list output_list; + + /* Target */ + struct wl_output *target_output; + bool with_cursor; + + /* Main frame callback */ + struct zwlr_export_dmabuf_frame_v1 *frame_callback; + + /* If something happens during capture */ + int err; + bool quit; + + /* FFmpeg specific parts */ + pthread_t vid_thread; + AVFrame *current_frame; + AVFormatContext *avf; + AVCodecContext *avctx; + AVBufferRef *drm_device_ref; + AVBufferRef *drm_frames_ref; + AVBufferRef *mapped_device_ref; + AVBufferRef *mapped_frames_ref; + + /* Sync stuff */ + struct fifo_buffer vid_frames; + + int64_t start_pts; + + /* Config */ + enum AVPixelFormat software_format; + enum AVHWDeviceType hw_device_type; + AVDictionary *encoder_opts; + int is_software_encoder; + char *hardware_device; + char *out_filename; + char *encoder_name; + float out_bitrate; +}; + +static int init_fifo(struct fifo_buffer *buf, int max_queued_frames) { + pthread_mutex_init(&buf->lock, NULL); + pthread_cond_init(&buf->cond, NULL); + pthread_mutex_init(&buf->cond_lock, NULL); + buf->num_queued_frames = 0; + buf->max_queued_frames = max_queued_frames; + buf->queued_frames = av_mallocz(buf->max_queued_frames * sizeof(AVFrame)); + return !buf->queued_frames ? AVERROR(ENOMEM) : 0; +} + +static int get_fifo_size(struct fifo_buffer *buf) { + pthread_mutex_lock(&buf->lock); + int ret = buf->num_queued_frames; + pthread_mutex_unlock(&buf->lock); + return ret; +} + +static int push_to_fifo(struct fifo_buffer *buf, AVFrame *f) { + int ret; + pthread_mutex_lock(&buf->lock); + if ((buf->num_queued_frames + 1) > buf->max_queued_frames) { + av_frame_free(&f); + ret = 1; + } else { + buf->queued_frames[buf->num_queued_frames++] = f; + ret = 0; + } + pthread_mutex_unlock(&buf->lock); + pthread_cond_signal(&buf->cond); + return ret; +} + +static AVFrame *pop_from_fifo(struct fifo_buffer *buf) { + pthread_mutex_lock(&buf->lock); + + if (!buf->num_queued_frames) { + pthread_mutex_unlock(&buf->lock); + pthread_cond_wait(&buf->cond, &buf->cond_lock); + pthread_mutex_lock(&buf->lock); + } + + AVFrame *rf = buf->queued_frames[0]; + for (int i = 1; i < buf->num_queued_frames; i++) { + buf->queued_frames[i - 1] = buf->queued_frames[i]; + } + buf->num_queued_frames--; + buf->queued_frames[buf->num_queued_frames] = NULL; + + pthread_mutex_unlock(&buf->lock); + return rf; +} + +static void free_fifo(struct fifo_buffer *buf) { + pthread_mutex_lock(&buf->lock); + if (buf->num_queued_frames) { + for (int i = 0; i < buf->num_queued_frames; i++) { + av_frame_free(&buf->queued_frames[i]); + } + } + av_freep(&buf->queued_frames); + pthread_mutex_unlock(&buf->lock); +} + +static void output_handle_geometry(void *data, struct wl_output *wl_output, + int32_t x, int32_t y, int32_t phys_width, int32_t phys_height, + int32_t subpixel, const char *make, const char *model, + int32_t transform) { + struct wayland_output *output = data; + output->make = av_strdup(make); + output->model = av_strdup(model); +} + +static void output_handle_mode(void *data, struct wl_output *wl_output, + uint32_t flags, int32_t width, int32_t height, int32_t refresh) { + if (flags & WL_OUTPUT_MODE_CURRENT) { + struct wayland_output *output = data; + output->width = width; + output->height = height; + output->framerate = (AVRational){ refresh, 1000 }; + } +} + +static void output_handle_done(void* data, struct wl_output *wl_output) { + /* Nothing to do */ +} + +static void output_handle_scale(void* data, struct wl_output *wl_output, + int32_t factor) { + /* Nothing to do */ +} + +static const struct wl_output_listener output_listener = { + .geometry = output_handle_geometry, + .mode = output_handle_mode, + .done = output_handle_done, + .scale = output_handle_scale, +}; + +static void registry_handle_add(void *data, struct wl_registry *reg, + uint32_t id, const char *interface, uint32_t ver) { + struct capture_context *ctx = data; + + if (!strcmp(interface, wl_output_interface.name)) { + struct wayland_output *output = av_mallocz(sizeof(*output)); + + output->id = id; + output->output = wl_registry_bind(reg, id, &wl_output_interface, 1); + + wl_output_add_listener(output->output, &output_listener, output); + wl_list_insert(&ctx->output_list, &output->link); + } + + if (!strcmp(interface, zwlr_export_dmabuf_manager_v1_interface.name)) { + ctx->export_manager = wl_registry_bind(reg, id, + &zwlr_export_dmabuf_manager_v1_interface, 1); + } +} + +static void remove_output(struct wayland_output *out) { + wl_list_remove(&out->link); + av_free(out->make); + av_free(out->model); + av_free(out); +} + +static struct wayland_output *find_output(struct capture_context *ctx, + struct wl_output *out, uint32_t id) { + struct wayland_output *output, *tmp; + wl_list_for_each_safe(output, tmp, &ctx->output_list, link) { + if ((output->output == out) || (output->id == id)) { + return output; + } + } + return NULL; +} + +static void registry_handle_remove(void *data, struct wl_registry *reg, + uint32_t id) { + remove_output(find_output((struct capture_context *)data, NULL, id)); +} + +static const struct wl_registry_listener registry_listener = { + .global = registry_handle_add, + .global_remove = registry_handle_remove, +}; + +static void frame_free(void *opaque, uint8_t *data) { + AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)data; + + for (int i = 0; i < desc->nb_objects; ++i) { + close(desc->objects[i].fd); + } + + zwlr_export_dmabuf_frame_v1_destroy(opaque); + + av_free(data); +} + +static void frame_start(void *data, struct zwlr_export_dmabuf_frame_v1 *frame, + uint32_t width, uint32_t height, uint32_t offset_x, uint32_t offset_y, + uint32_t buffer_flags, uint32_t flags, uint32_t format, + uint32_t mod_high, uint32_t mod_low, uint32_t num_objects) { + struct capture_context *ctx = data; + int err = 0; + + /* Allocate DRM specific struct */ + AVDRMFrameDescriptor *desc = av_mallocz(sizeof(*desc)); + if (!desc) { + err = AVERROR(ENOMEM); + goto fail; + } + + desc->nb_objects = num_objects; + desc->objects[0].format_modifier = ((uint64_t)mod_high << 32) | mod_low; + + desc->nb_layers = 1; + desc->layers[0].format = format; + + /* Allocate a frame */ + AVFrame *f = av_frame_alloc(); + if (!f) { + err = AVERROR(ENOMEM); + goto fail; + } + + /* Set base frame properties */ + ctx->current_frame = f; + f->width = width; + f->height = height; + f->format = AV_PIX_FMT_DRM_PRIME; + + /* Set the frame data to the DRM specific struct */ + f->buf[0] = av_buffer_create((uint8_t*)desc, sizeof(*desc), + &frame_free, frame, 0); + if (!f->buf[0]) { + err = AVERROR(ENOMEM); + goto fail; + } + + f->data[0] = (uint8_t*)desc; + + return; + +fail: + ctx->err = err; + frame_free(frame, (uint8_t *)desc); +} + +static void frame_object(void *data, struct zwlr_export_dmabuf_frame_v1 *frame, + uint32_t index, int32_t fd, uint32_t size, uint32_t offset, + uint32_t stride, uint32_t plane_index) { + struct capture_context *ctx = data; + AVFrame *f = ctx->current_frame; + AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)f->data[0]; + + desc->objects[index].fd = fd; + desc->objects[index].size = size; + + desc->layers[0].planes[plane_index].object_index = index; + desc->layers[0].planes[plane_index].offset = offset; + desc->layers[0].planes[plane_index].pitch = stride; +} + +static enum AVPixelFormat drm_fmt_to_pixfmt(uint32_t fmt) { + switch (fmt) { + case DRM_FORMAT_NV12: return AV_PIX_FMT_NV12; + case DRM_FORMAT_ARGB8888: return AV_PIX_FMT_BGRA; + case DRM_FORMAT_XRGB8888: return AV_PIX_FMT_BGR0; + case DRM_FORMAT_ABGR8888: return AV_PIX_FMT_RGBA; + case DRM_FORMAT_XBGR8888: return AV_PIX_FMT_RGB0; + case DRM_FORMAT_RGBA8888: return AV_PIX_FMT_ABGR; + case DRM_FORMAT_RGBX8888: return AV_PIX_FMT_0BGR; + case DRM_FORMAT_BGRA8888: return AV_PIX_FMT_ARGB; + case DRM_FORMAT_BGRX8888: return AV_PIX_FMT_0RGB; + default: return AV_PIX_FMT_NONE; + }; +} + +static int attach_drm_frames_ref(struct capture_context *ctx, AVFrame *f, + enum AVPixelFormat sw_format) { + int err = 0; + AVHWFramesContext *hwfc; + + if (ctx->drm_frames_ref) { + hwfc = (AVHWFramesContext*)ctx->drm_frames_ref->data; + if (hwfc->width == f->width && hwfc->height == f->height && + hwfc->sw_format == sw_format) { + goto attach; + } + av_buffer_unref(&ctx->drm_frames_ref); + } + + ctx->drm_frames_ref = av_hwframe_ctx_alloc(ctx->drm_device_ref); + if (!ctx->drm_frames_ref) { + err = AVERROR(ENOMEM); + goto fail; + } + + hwfc = (AVHWFramesContext*)ctx->drm_frames_ref->data; + + hwfc->format = f->format; + hwfc->sw_format = sw_format; + hwfc->width = f->width; + hwfc->height = f->height; + + err = av_hwframe_ctx_init(ctx->drm_frames_ref); + if (err) { + av_log(ctx, AV_LOG_ERROR, "AVHWFramesContext init failed: %s!\n", + av_err2str(err)); + goto fail; + } + +attach: + /* Set frame hardware context referencce */ + f->hw_frames_ctx = av_buffer_ref(ctx->drm_frames_ref); + if (!f->hw_frames_ctx) { + err = AVERROR(ENOMEM); + goto fail; + } + + return 0; + +fail: + av_buffer_unref(&ctx->drm_frames_ref); + return err; +} + +static void register_cb(struct capture_context *ctx); + +static void frame_ready(void *data, struct zwlr_export_dmabuf_frame_v1 *frame, + uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) { + struct capture_context *ctx = data; + AVFrame *f = ctx->current_frame; + AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)f->data[0]; + enum AVPixelFormat pix_fmt = drm_fmt_to_pixfmt(desc->layers[0].format); + int err = 0; + + /* Timestamp, nanoseconds timebase */ + f->pts = ((((uint64_t)tv_sec_hi) << 32) | tv_sec_lo) * 1000000000 + tv_nsec; + + if (!ctx->start_pts) { + ctx->start_pts = f->pts; + } + + f->pts = av_rescale_q(f->pts - ctx->start_pts, (AVRational){ 1, 1000000000 }, + ctx->avctx->time_base); + + /* Attach the hardware frame context to the frame */ + err = attach_drm_frames_ref(ctx, f, pix_fmt); + if (err) { + goto end; + } + + /* TODO: support multiplane stuff */ + desc->layers[0].nb_planes = av_pix_fmt_count_planes(pix_fmt); + + AVFrame *mapped_frame = av_frame_alloc(); + if (!mapped_frame) { + err = AVERROR(ENOMEM); + goto end; + } + + AVHWFramesContext *mapped_hwfc; + mapped_hwfc = (AVHWFramesContext *)ctx->mapped_frames_ref->data; + mapped_frame->format = mapped_hwfc->format; + mapped_frame->pts = f->pts; + + /* Set frame hardware context referencce */ + mapped_frame->hw_frames_ctx = av_buffer_ref(ctx->mapped_frames_ref); + if (!mapped_frame->hw_frames_ctx) { + err = AVERROR(ENOMEM); + goto end; + } + + err = av_hwframe_map(mapped_frame, f, 0); + if (err) { + av_log(ctx, AV_LOG_ERROR, "Error mapping: %s!\n", av_err2str(err)); + goto end; + } + + if (push_to_fifo(&ctx->vid_frames, mapped_frame)) { + av_log(ctx, AV_LOG_WARNING, "Dropped frame!\n"); + } + + if (!ctx->quit && !ctx->err) { + register_cb(ctx); + } + +end: + ctx->err = err; + av_frame_free(&ctx->current_frame); +} + +static void frame_cancel(void *data, struct zwlr_export_dmabuf_frame_v1 *frame, + uint32_t reason) { + struct capture_context *ctx = data; + av_log(ctx, AV_LOG_WARNING, "Frame cancelled!\n"); + av_frame_free(&ctx->current_frame); + if (reason == ZWLR_EXPORT_DMABUF_FRAME_V1_CANCEL_REASON_PERMANENT) { + av_log(ctx, AV_LOG_ERROR, "Permanent failure, exiting\n"); + ctx->err = true; + } else { + register_cb(ctx); + } +} + +static const struct zwlr_export_dmabuf_frame_v1_listener frame_listener = { + .frame = frame_start, + .object = frame_object, + .ready = frame_ready, + .cancel = frame_cancel, +}; + +static void register_cb(struct capture_context *ctx) { + ctx->frame_callback = zwlr_export_dmabuf_manager_v1_capture_output( + ctx->export_manager, ctx->with_cursor, ctx->target_output); + + zwlr_export_dmabuf_frame_v1_add_listener(ctx->frame_callback, + &frame_listener, ctx); +} + +void *vid_encode_thread(void *arg) { + int err = 0; + struct capture_context *ctx = arg; + + do { + AVFrame *f = NULL; + if (get_fifo_size(&ctx->vid_frames) || !ctx->quit) { + f = pop_from_fifo(&ctx->vid_frames); + } + + if (ctx->is_software_encoder && f) { + AVFrame *soft_frame = av_frame_alloc(); + av_hwframe_transfer_data(soft_frame, f, 0); + soft_frame->pts = f->pts; + av_frame_free(&f); + f = soft_frame; + } + + err = avcodec_send_frame(ctx->avctx, f); + + av_frame_free(&f); + + if (err) { + av_log(ctx, AV_LOG_ERROR, "Error encoding: %s!\n", av_err2str(err)); + goto end; + } + + while (1) { + AVPacket pkt; + av_init_packet(&pkt); + + int ret = avcodec_receive_packet(ctx->avctx, &pkt); + if (ret == AVERROR(EAGAIN)) { + break; + } else if (ret == AVERROR_EOF) { + av_log(ctx, AV_LOG_INFO, "Encoder flushed!\n"); + goto end; + } else if (ret) { + av_log(ctx, AV_LOG_ERROR, "Error encoding: %s!\n", + av_err2str(ret)); + err = ret; + goto end; + } + + pkt.stream_index = 0; + err = av_interleaved_write_frame(ctx->avf, &pkt); + + av_packet_unref(&pkt); + + if (err) { + av_log(ctx, AV_LOG_ERROR, "Writing packet fail: %s!\n", + av_err2str(err)); + goto end; + } + }; + + av_log(ctx, AV_LOG_INFO, "Encoded frame %i (%i in queue)\n", + ctx->avctx->frame_number, get_fifo_size(&ctx->vid_frames)); + + } while (!ctx->err); + +end: + if (!ctx->err) { + ctx->err = err; + } + return NULL; +} + +static int init_lavu_hwcontext(struct capture_context *ctx) { + /* DRM hwcontext */ + ctx->drm_device_ref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_DRM); + if (!ctx->drm_device_ref) + return AVERROR(ENOMEM); + + AVHWDeviceContext *ref_data = (AVHWDeviceContext*)ctx->drm_device_ref->data; + AVDRMDeviceContext *hwctx = ref_data->hwctx; + + /* We don't need a device (we don't even know it and can't open it) */ + hwctx->fd = -1; + + av_hwdevice_ctx_init(ctx->drm_device_ref); + + /* Mapped hwcontext */ + int err = av_hwdevice_ctx_create(&ctx->mapped_device_ref, + ctx->hw_device_type, ctx->hardware_device, NULL, 0); + if (err < 0) { + av_log(ctx, AV_LOG_ERROR, "Failed to create a hardware device: %s\n", + av_err2str(err)); + return err; + } + + return 0; +} + +static int set_hwframe_ctx(struct capture_context *ctx, + AVBufferRef *hw_device_ctx) { + AVHWFramesContext *frames_ctx = NULL; + int err = 0; + + if (!(ctx->mapped_frames_ref = av_hwframe_ctx_alloc(hw_device_ctx))) { + return AVERROR(ENOMEM); + } + + AVHWFramesConstraints *cst = + av_hwdevice_get_hwframe_constraints(ctx->mapped_device_ref, NULL); + if (!cst) { + av_log(ctx, AV_LOG_ERROR, "Failed to get hw device constraints!\n"); + av_buffer_unref(&ctx->mapped_frames_ref); + return AVERROR(ENOMEM); + } + + frames_ctx = (AVHWFramesContext *)(ctx->mapped_frames_ref->data); + frames_ctx->format = cst->valid_hw_formats[0]; + frames_ctx->sw_format = ctx->avctx->pix_fmt; + frames_ctx->width = ctx->avctx->width; + frames_ctx->height = ctx->avctx->height; + + av_hwframe_constraints_free(&cst); + + if ((err = av_hwframe_ctx_init(ctx->mapped_frames_ref))) { + av_log(ctx, AV_LOG_ERROR, "Failed to initialize hw frame context: %s!\n", + av_err2str(err)); + av_buffer_unref(&ctx->mapped_frames_ref); + return err; + } + + if (!ctx->is_software_encoder) { + ctx->avctx->pix_fmt = frames_ctx->format; + ctx->avctx->hw_frames_ctx = av_buffer_ref(ctx->mapped_frames_ref); + if (!ctx->avctx->hw_frames_ctx) { + av_buffer_unref(&ctx->mapped_frames_ref); + err = AVERROR(ENOMEM); + } + } + + return err; +} + +static int init_encoding(struct capture_context *ctx) { + int err; + + /* lavf init */ + err = avformat_alloc_output_context2(&ctx->avf, NULL, + NULL, ctx->out_filename); + if (err) { + av_log(ctx, AV_LOG_ERROR, "Unable to init lavf context!\n"); + return err; + } + + AVStream *st = avformat_new_stream(ctx->avf, NULL); + if (!st) { + av_log(ctx, AV_LOG_ERROR, "Unable to alloc stream!\n"); + return 1; + } + + /* Find encoder */ + AVCodec *out_codec = avcodec_find_encoder_by_name(ctx->encoder_name); + if (!out_codec) { + av_log(ctx, AV_LOG_ERROR, "Codec not found (not compiled in lavc?)!\n"); + return AVERROR(EINVAL); + } + ctx->avf->oformat->video_codec = out_codec->id; + ctx->is_software_encoder = !(out_codec->capabilities & AV_CODEC_CAP_HARDWARE); + + ctx->avctx = avcodec_alloc_context3(out_codec); + if (!ctx->avctx) + return 1; + + ctx->avctx->opaque = ctx; + ctx->avctx->bit_rate = (int)ctx->out_bitrate*1000000.0f; + ctx->avctx->pix_fmt = ctx->software_format; + ctx->avctx->time_base = (AVRational){ 1, 1000 }; + ctx->avctx->compression_level = 7; + ctx->avctx->width = find_output(ctx, ctx->target_output, 0)->width; + ctx->avctx->height = find_output(ctx, ctx->target_output, 0)->height; + + if (ctx->avf->oformat->flags & AVFMT_GLOBALHEADER) { + ctx->avctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; + } + + st->id = 0; + st->time_base = ctx->avctx->time_base; + st->avg_frame_rate = find_output(ctx, ctx->target_output, 0)->framerate; + + /* Init hw frames context */ + err = set_hwframe_ctx(ctx, ctx->mapped_device_ref); + if (err) { + return err; + } + + err = avcodec_open2(ctx->avctx, out_codec, &ctx->encoder_opts); + if (err) { + av_log(ctx, AV_LOG_ERROR, "Cannot open encoder: %s!\n", + av_err2str(err)); + return err; + } + + if (avcodec_parameters_from_context(st->codecpar, ctx->avctx) < 0) { + av_log(ctx, AV_LOG_ERROR, "Couldn't copy codec params: %s!\n", + av_err2str(err)); + return err; + } + + /* Debug print */ + av_dump_format(ctx->avf, 0, ctx->out_filename, 1); + + /* Open for writing */ + err = avio_open(&ctx->avf->pb, ctx->out_filename, AVIO_FLAG_WRITE); + if (err) { + av_log(ctx, AV_LOG_ERROR, "Couldn't open %s: %s!\n", ctx->out_filename, + av_err2str(err)); + return err; + } + + err = avformat_write_header(ctx->avf, NULL); + if (err) { + av_log(ctx, AV_LOG_ERROR, "Couldn't write header: %s!\n", av_err2str(err)); + return err; + } + + return err; +} + +struct capture_context *q_ctx = NULL; + +void on_quit_signal(int signo) { + printf("\r"); + av_log(q_ctx, AV_LOG_WARNING, "Quitting!\n"); + q_ctx->quit = true; +} + +static int main_loop(struct capture_context *ctx) { + int err; + + q_ctx = ctx; + + if (signal(SIGINT, on_quit_signal) == SIG_ERR) { + av_log(ctx, AV_LOG_ERROR, "Unable to install signal handler!\n"); + return AVERROR(EINVAL); + } + + err = init_lavu_hwcontext(ctx); + if (err) { + return err; + } + + err = init_encoding(ctx); + if (err) { + return err; + } + + /* Start video encoding thread */ + err = init_fifo(&ctx->vid_frames, 16); + if (err) { + return err; + } + pthread_create(&ctx->vid_thread, NULL, vid_encode_thread, ctx); + + /* Start the frame callback */ + register_cb(ctx); + + /* Run capture */ + while (wl_display_dispatch(ctx->display) != -1 && !ctx->err && !ctx->quit); + + /* Join with encoder thread */ + pthread_join(ctx->vid_thread, NULL); + + err = av_write_trailer(ctx->avf); + if (err) { + av_log(ctx, AV_LOG_ERROR, "Error writing trailer: %s!\n", + av_err2str(err)); + return err; + } + + av_log(ctx, AV_LOG_INFO, "Wrote trailer!\n"); + + return ctx->err; +} + +static int init(struct capture_context *ctx) { + ctx->display = wl_display_connect(NULL); + if (!ctx->display) { + av_log(ctx, AV_LOG_ERROR, "Failed to connect to display!\n"); + return AVERROR(EINVAL); + } + + wl_list_init(&ctx->output_list); + + ctx->registry = wl_display_get_registry(ctx->display); + wl_registry_add_listener(ctx->registry, ®istry_listener, ctx); + + wl_display_roundtrip(ctx->display); + wl_display_dispatch(ctx->display); + + if (!ctx->export_manager) { + av_log(ctx, AV_LOG_ERROR, "Compositor doesn't support %s!\n", + zwlr_export_dmabuf_manager_v1_interface.name); + return -1; + } + + return 0; +} + +static void uninit(struct capture_context *ctx); + +int main(int argc, char *argv[]) { + int err; + struct capture_context ctx = { 0 }; + ctx.class = &((AVClass) { + .class_name = "dmabuf-capture", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, + }); + + err = init(&ctx); + if (err) { + goto end; + } + + struct wayland_output *o, *tmp_o; + wl_list_for_each_reverse_safe(o, tmp_o, &ctx.output_list, link) { + printf("Capturable output: %s Model: %s: ID: %i\n", + o->make, o->model, o->id); + } + + if (argc != 8) { + printf("Invalid number of arguments! Usage and example:\n" + "./dmabuf-capture <source id> <hardware device type> <device> " + "<encoder name> <pixel format> <bitrate in Mbps> <file path>\n" + "./dmabuf-capture 0 vaapi /dev/dri/renderD129 libx264 nv12 12 " + "dmabuf_recording_01.mkv\n"); + return 1; + } + + const int o_id = strtol(argv[1], NULL, 10); + o = find_output(&ctx, NULL, o_id); + if (!o) { + printf("Unable to find output with ID %i!\n", o_id); + return 1; + } + + ctx.target_output = o->output; + ctx.with_cursor = true; + ctx.hw_device_type = av_hwdevice_find_type_by_name(argv[2]); + ctx.hardware_device = argv[3]; + + ctx.encoder_name = argv[4]; + ctx.software_format = av_get_pix_fmt(argv[5]); + ctx.out_bitrate = strtof(argv[6], NULL); + ctx.out_filename = argv[7]; + + av_dict_set(&ctx.encoder_opts, "preset", "veryfast", 0); + + err = main_loop(&ctx); + if (err) { + goto end; + } + +end: + uninit(&ctx); + return err; +} + +static void uninit(struct capture_context *ctx) { + struct wayland_output *output, *tmp_o; + wl_list_for_each_safe(output, tmp_o, &ctx->output_list, link) { + remove_output(output); + } + + if (ctx->export_manager) { + zwlr_export_dmabuf_manager_v1_destroy(ctx->export_manager); + } + + free_fifo(&ctx->vid_frames); + + av_buffer_unref(&ctx->drm_frames_ref); + av_buffer_unref(&ctx->drm_device_ref); + av_buffer_unref(&ctx->mapped_frames_ref); + av_buffer_unref(&ctx->mapped_device_ref); + + av_dict_free(&ctx->encoder_opts); + + avcodec_close(ctx->avctx); + if (ctx->avf) { + avio_closep(&ctx->avf->pb); + } + avformat_free_context(ctx->avf); +} diff --git a/examples/foreign-toplevel.c b/examples/foreign-toplevel.c new file mode 100644 index 00000000..40ddbb09 --- /dev/null +++ b/examples/foreign-toplevel.c @@ -0,0 +1,358 @@ +#define _POSIX_C_SOURCE 200809L +#include <getopt.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wayland-client.h> +#include "wlr-foreign-toplevel-management-unstable-v1-client-protocol.h" + +/** + * Usage: + * 1. foreign-toplevel + * Prints a list of opened toplevels + * 2. foreign-toplevel -f <id> + * Focus the toplevel with the given id + * 3. foreign-toplevel -a <id> + * Maximize the toplevel with the given id + * 4. foreign-toplevel -u <id> + * Unmaximize the toplevel with the given id + * 5. foreign-toplevel -i <id> + * Minimize the toplevel with the given id + * 6. foreign-toplevel -r <id> + * Restore(unminimize) the toplevel with the given id + * 7. foreign-toplevel -c <id> + * Close the toplevel with the given id + * 8. foreign-toplevel -m + * Continuously print changes to the list of opened toplevels. + * Can be used together with some of the previous options. + */ + +enum toplevel_state_field { + TOPLEVEL_STATE_MAXIMIZED = 1, + TOPLEVEL_STATE_MINIMIZED = 2, + TOPLEVEL_STATE_ACTIVATED = 4, + TOPLEVEL_STATE_INVALID = 8, +}; + +struct toplevel_state { + char *title; + char *app_id; + + uint32_t state; +}; + +static void copy_state(struct toplevel_state *current, + struct toplevel_state *pending) { + if (current->title && pending->title) { + free(current->title); + } + if (current->app_id && pending->app_id) { + free(current->app_id); + } + + if (pending->title) { + current->title = pending->title; + pending->title = NULL; + } + if (pending->app_id) { + current->app_id = pending->app_id; + pending->app_id = NULL; + } + + if (!(pending->state & TOPLEVEL_STATE_INVALID)) { + current->state = pending->state; + } + + pending->state = TOPLEVEL_STATE_INVALID; +} + +static uint32_t global_id = 0; +struct toplevel_v1 { + struct wl_list link; + struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel; + + uint32_t id; + struct toplevel_state current, pending; +}; + +static void print_toplevel(struct toplevel_v1 *toplevel, bool print_endl) { + printf("-> %d. title=%s app_id=%s", toplevel->id, + toplevel->current.title ?: "(nil)", + toplevel->current.app_id ?: "(nil)"); + + if (print_endl) { + printf("\n"); + } +} + +static void print_toplevel_state(struct toplevel_v1 *toplevel, bool print_endl) { + if (toplevel->current.state & TOPLEVEL_STATE_MAXIMIZED) { + printf(" maximized"); + } else { + printf(" unmaximized"); + } + if (toplevel->current.state & TOPLEVEL_STATE_MINIMIZED) { + printf(" minimized"); + } else { + printf(" unminimized"); + } + if (toplevel->current.state & TOPLEVEL_STATE_ACTIVATED) { + printf(" active"); + } else { + printf(" inactive"); + } + + if (print_endl) { + printf("\n"); + } +} + +static void toplevel_handle_title(void *data, + struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel, + const char *title) { + struct toplevel_v1 *toplevel = data; + free(toplevel->pending.title); + toplevel->pending.title = strdup(title); +} + +static void toplevel_handle_app_id(void *data, + struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel, + const char *app_id) { + struct toplevel_v1 *toplevel = data; + free(toplevel->pending.app_id); + toplevel->pending.app_id = strdup(app_id); +} + +static void toplevel_handle_output_enter(void *data, + struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel, + struct wl_output *output) { + struct toplevel_v1 *toplevel = data; + print_toplevel(toplevel, false); + printf(" enter output %u\n", + (uint32_t)(size_t)wl_output_get_user_data(output)); +} + +static void toplevel_handle_output_leave(void *data, + struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel, + struct wl_output *output) { + struct toplevel_v1 *toplevel = data; + print_toplevel(toplevel, false); + printf(" leave output %u\n", + (uint32_t)(size_t)wl_output_get_user_data(output)); +} + +static uint32_t array_to_state(struct wl_array *array) { + uint32_t state = 0; + uint32_t *entry; + wl_array_for_each(entry, array) { + if (*entry == ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MAXIMIZED) + state |= TOPLEVEL_STATE_MAXIMIZED; + if (*entry == ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MINIMIZED) + state |= TOPLEVEL_STATE_MINIMIZED; + if (*entry == ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED) + state |= TOPLEVEL_STATE_ACTIVATED; + } + + return state; +} + +static void toplevel_handle_state(void *data, + struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel, + struct wl_array *state) { + struct toplevel_v1 *toplevel = data; + toplevel->pending.state = array_to_state(state); +} + +static void toplevel_handle_done(void *data, + struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel) { + struct toplevel_v1 *toplevel = data; + bool state_changed = toplevel->current.state != toplevel->pending.state; + + copy_state(&toplevel->current, &toplevel->pending); + + print_toplevel(toplevel, !state_changed); + if (state_changed) { + print_toplevel_state(toplevel, true); + } +} + +static void toplevel_handle_closed(void *data, + struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel) { + struct toplevel_v1 *toplevel = data; + print_toplevel(toplevel, false); + printf(" closed\n"); + + zwlr_foreign_toplevel_handle_v1_destroy(zwlr_toplevel); +} + +static const struct zwlr_foreign_toplevel_handle_v1_listener toplevel_impl = { + .title = toplevel_handle_title, + .app_id = toplevel_handle_app_id, + .output_enter = toplevel_handle_output_enter, + .output_leave = toplevel_handle_output_leave, + .state = toplevel_handle_state, + .done = toplevel_handle_done, + .closed = toplevel_handle_closed, +}; + +static struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager = NULL; +static struct wl_list toplevel_list; + +static void toplevel_manager_handle_toplevel(void *data, + struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager, + struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel) { + struct toplevel_v1 *toplevel = calloc(1, sizeof(struct toplevel_v1)); + if (!toplevel) { + fprintf(stderr, "Failed to allocate memory for toplevel\n"); + return; + } + + toplevel->id = global_id++; + toplevel->zwlr_toplevel = zwlr_toplevel; + wl_list_insert(&toplevel_list, &toplevel->link); + + zwlr_foreign_toplevel_handle_v1_add_listener(zwlr_toplevel, &toplevel_impl, + toplevel); +} + +static void toplevel_manager_handle_finished(void *data, + struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager) { + zwlr_foreign_toplevel_manager_v1_destroy(toplevel_manager); +} + +static const struct zwlr_foreign_toplevel_manager_v1_listener toplevel_manager_impl = { + .toplevel = toplevel_manager_handle_toplevel, + .finished = toplevel_manager_handle_finished, +}; + +struct wl_seat *seat = NULL; +static void handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) { + if (strcmp(interface, wl_output_interface.name) == 0) { + struct wl_output *output = wl_registry_bind(registry, name, + &wl_output_interface, version); + wl_output_set_user_data(output, (void*)(size_t)name); // assign some ID to the output + } else if (strcmp(interface, + zwlr_foreign_toplevel_manager_v1_interface.name) == 0) { + toplevel_manager = wl_registry_bind(registry, name, + &zwlr_foreign_toplevel_manager_v1_interface, 1); + + wl_list_init(&toplevel_list); + zwlr_foreign_toplevel_manager_v1_add_listener(toplevel_manager, + &toplevel_manager_impl, NULL); + } else if (strcmp(interface, wl_seat_interface.name) == 0 && seat == NULL) { + seat = wl_registry_bind(registry, name, &wl_seat_interface, version); + } +} + +static void handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) { + // who cares +} + +static const struct wl_registry_listener registry_listener = { + .global = handle_global, + .global_remove = handle_global_remove, +}; + +/* return NULL when id == -1 + * exit if the given ID cannot be found in the list of toplevels */ +static struct toplevel_v1 *toplevel_by_id_or_bail(int32_t id) { + if (id == -1) { + return NULL; + } + + struct toplevel_v1 *toplevel; + wl_list_for_each(toplevel, &toplevel_list, link) { + if (toplevel->id == (uint32_t)id) { + return toplevel; + } + } + + fprintf(stderr, "No toplevel with the given id: %d\n", id); + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) { + int focus_id = -1, close_id = -1; + int maximize_id = -1, unmaximize_id = -1; + int minimize_id = -1, restore_id = -1; + int one_shot = 1; + int c; + + // TODO maybe print usage with -h? + while ((c = getopt(argc, argv, "f:a:u:i:r:c:m")) != -1) { + switch (c) { + case 'f': + focus_id = atoi(optarg); + break; + case 'a': + maximize_id = atoi(optarg); + break; + case 'u': + unmaximize_id = atoi(optarg); + break; + case 'i': + minimize_id = atoi(optarg); + break; + case 'r': + restore_id = atoi(optarg); + break; + case 'c': + close_id = atoi(optarg); + break; + case 'm': + one_shot = 0; + break; + } + } + + struct wl_display *display = wl_display_connect(NULL); + if (display == NULL) { + fprintf(stderr, "Failed to create display\n"); + return EXIT_FAILURE; + } + + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_dispatch(display); + wl_display_roundtrip(display); + + if (toplevel_manager == NULL) { + fprintf(stderr, "wlr-foreign-toplevel not available\n"); + return EXIT_FAILURE; + } + wl_display_roundtrip(display); // load list of toplevels + wl_display_roundtrip(display); // load toplevel details + + struct toplevel_v1 *toplevel; + if ((toplevel = toplevel_by_id_or_bail(focus_id))) { + zwlr_foreign_toplevel_handle_v1_activate(toplevel->zwlr_toplevel, seat); + } + if ((toplevel = toplevel_by_id_or_bail(maximize_id))) { + zwlr_foreign_toplevel_handle_v1_set_maximized(toplevel->zwlr_toplevel); + } + if ((toplevel = toplevel_by_id_or_bail(unmaximize_id))) { + zwlr_foreign_toplevel_handle_v1_unset_maximized(toplevel->zwlr_toplevel); + } + if ((toplevel = toplevel_by_id_or_bail(minimize_id))) { + zwlr_foreign_toplevel_handle_v1_set_minimized(toplevel->zwlr_toplevel); + } + if ((toplevel = toplevel_by_id_or_bail(restore_id))) { + zwlr_foreign_toplevel_handle_v1_unset_minimized(toplevel->zwlr_toplevel); + } + if ((toplevel = toplevel_by_id_or_bail(close_id))) { + zwlr_foreign_toplevel_handle_v1_close(toplevel->zwlr_toplevel); + } + + wl_display_flush(display); + + if (one_shot == 0) { + while (wl_display_dispatch(display) != -1) { + // This space intentionally left blank + } + } + + return EXIT_SUCCESS; +} diff --git a/examples/gamma-control.c b/examples/gamma-control.c new file mode 100644 index 00000000..a060b883 --- /dev/null +++ b/examples/gamma-control.c @@ -0,0 +1,195 @@ +#define _POSIX_C_SOURCE 200809L +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <wayland-client-protocol.h> +#include <wayland-client.h> +#include "wlr-gamma-control-unstable-v1-client-protocol.h" + +struct output { + struct wl_output *wl_output; + struct zwlr_gamma_control_v1 *gamma_control; + uint32_t ramp_size; + int table_fd; + uint16_t *table; + struct wl_list link; +}; + +static struct wl_list outputs; +static struct zwlr_gamma_control_manager_v1 *gamma_control_manager = NULL; + +static int create_anonymous_file(off_t size) { + char template[] = "/tmp/wlroots-shared-XXXXXX"; + int fd = mkstemp(template); + if (fd < 0) { + return -1; + } + + int ret; + do { + errno = 0; + ret = ftruncate(fd, size); + } while (errno == EINTR); + if (ret < 0) { + close(fd); + return -1; + } + + unlink(template); + return fd; +} + +static int create_gamma_table(uint32_t ramp_size, uint16_t **table) { + size_t table_size = ramp_size * 3 * sizeof(uint16_t); + int fd = create_anonymous_file(table_size); + if (fd < 0) { + fprintf(stderr, "failed to create anonymous file\n"); + return -1; + } + + void *data = + mmap(NULL, table_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) { + fprintf(stderr, "failed to mmap()\n"); + close(fd); + return -1; + } + + *table = data; + return fd; +} + +static void gamma_control_handle_gamma_size(void *data, + struct zwlr_gamma_control_v1 *gamma_control, uint32_t ramp_size) { + struct output *output = data; + output->ramp_size = ramp_size; + output->table_fd = create_gamma_table(ramp_size, &output->table); + if (output->table_fd < 0) { + exit(EXIT_FAILURE); + } +} + +static void gamma_control_handle_failed(void *data, + struct zwlr_gamma_control_v1 *gamma_control) { + fprintf(stderr, "failed to set gamma table\n"); + exit(EXIT_FAILURE); +} + +static const struct zwlr_gamma_control_v1_listener gamma_control_listener = { + .gamma_size = gamma_control_handle_gamma_size, + .failed = gamma_control_handle_failed, +}; + +static void registry_handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) { + if (strcmp(interface, wl_output_interface.name) == 0) { + struct output *output = calloc(1, sizeof(struct output)); + output->wl_output = wl_registry_bind(registry, name, + &wl_output_interface, 1); + wl_list_insert(&outputs, &output->link); + } else if (strcmp(interface, + zwlr_gamma_control_manager_v1_interface.name) == 0) { + gamma_control_manager = wl_registry_bind(registry, name, + &zwlr_gamma_control_manager_v1_interface, 1); + } +} + +static void registry_handle_global_remove(void *data, + struct wl_registry *registry, uint32_t name) { + // Who cares? +} + +static const struct wl_registry_listener registry_listener = { + .global = registry_handle_global, + .global_remove = registry_handle_global_remove, +}; + +static void fill_gamma_table(uint16_t *table, uint32_t ramp_size, + double contrast, double brightness, double gamma) { + uint16_t *r = table; + uint16_t *g = table + ramp_size; + uint16_t *b = table + 2 * ramp_size; + for (uint32_t i = 0; i < ramp_size; ++i) { + double val = (double)i / (ramp_size - 1); + val = contrast * pow(val, 1.0 / gamma) + (brightness - 1); + if (val > 1.0) { + val = 1.0; + } else if (val < 0.0) { + val = 0.0; + } + r[i] = g[i] = b[i] = (uint16_t)(UINT16_MAX * val); + } +} + +static const char usage[] = "usage: gamma-control [options]\n" + " -h show this help message\n" + " -c <value> set contrast (default: 1)\n" + " -b <value> set brightness (default: 1)\n" + " -g <value> set gamma (default: 1)\n"; + +int main(int argc, char *argv[]) { + wl_list_init(&outputs); + + double contrast = 1, brightness = 1, gamma = 1; + int opt; + while ((opt = getopt(argc, argv, "hc:b:g:")) != -1) { + switch (opt) { + case 'c': + contrast = strtod(optarg, NULL); + break; + case 'b': + brightness = strtod(optarg, NULL); + break; + case 'g': + gamma = strtod(optarg, NULL); + break; + case 'h': + default: + fprintf(stderr, usage); + return opt == 'h' ? EXIT_SUCCESS : EXIT_FAILURE; + } + } + + struct wl_display *display = wl_display_connect(NULL); + if (display == NULL) { + fprintf(stderr, "failed to create display\n"); + return -1; + } + + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_dispatch(display); + wl_display_roundtrip(display); + + if (gamma_control_manager == NULL) { + fprintf(stderr, + "compositor doesn't support wlr-gamma-control-unstable-v1\n"); + return EXIT_FAILURE; + } + + struct output *output; + wl_list_for_each(output, &outputs, link) { + output->gamma_control = zwlr_gamma_control_manager_v1_get_gamma_control( + gamma_control_manager, output->wl_output); + zwlr_gamma_control_v1_add_listener(output->gamma_control, + &gamma_control_listener, output); + } + wl_display_roundtrip(display); + + wl_list_for_each(output, &outputs, link) { + fill_gamma_table(output->table, output->ramp_size, + contrast, brightness, gamma); + zwlr_gamma_control_v1_set_gamma(output->gamma_control, + output->table_fd); + } + + while (wl_display_dispatch(display) != -1) { + // This space is intentionnally left blank + } + + return EXIT_SUCCESS; +} diff --git a/examples/idle-inhibit.c b/examples/idle-inhibit.c new file mode 100644 index 00000000..48c812e8 --- /dev/null +++ b/examples/idle-inhibit.c @@ -0,0 +1,233 @@ +#include <GLES2/gl2.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wayland-client.h> +#include <wayland-egl.h> +#include <wlr/render/egl.h> +#include "idle-inhibit-unstable-v1-client-protocol.h" +#include "xdg-shell-client-protocol.h" + +#ifdef __linux__ +#include <linux/input-event-codes.h> +#elif __FreeBSD__ +#include <dev/evdev/input-event-codes.h> +#endif + +/** + * Usage: idle-inhibit + * Creates a xdg-toplevel using the idle-inhibit protocol. + * It will be solid green, when it has an idle inhibitor, and solid yellow if + * it does not. + * Left click with a pointer will toggle this state. (Touch is not supported + * for now). + */ + +static int width = 500, height = 300; + +static struct wl_compositor *compositor = NULL; +static struct wl_seat *seat = NULL; +static struct xdg_wm_base *wm_base = NULL; +static struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager = NULL; +static struct zwp_idle_inhibitor_v1 *idle_inhibitor = NULL; + +struct wlr_egl egl; +struct wl_egl_window *egl_window; +struct wlr_egl_surface *egl_surface; + +static void draw(void) { + eglMakeCurrent(egl.display, egl_surface, egl_surface, egl.context); + + float color[] = {1.0, 1.0, 0.0, 1.0}; + if (idle_inhibitor) { + color[0] = 0.0; + } + + glViewport(0, 0, width, height); + glClearColor(color[0], color[1], color[2], 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + eglSwapBuffers(egl.display, egl_surface); +} + +static void pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial, + uint32_t time, uint32_t button, uint32_t state_w) { + struct wl_surface *surface = data; + + if (button == BTN_LEFT && state_w == WL_POINTER_BUTTON_STATE_PRESSED) { + if (idle_inhibitor) { + zwp_idle_inhibitor_v1_destroy(idle_inhibitor); + idle_inhibitor = NULL; + } else { + idle_inhibitor = zwp_idle_inhibit_manager_v1_create_inhibitor( + idle_inhibit_manager, surface); + } + } + + draw(); +} + +static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, struct wl_surface *surface, + wl_fixed_t surface_x, wl_fixed_t surface_y) { + // This space intentionally left blank +} + +static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, struct wl_surface *surface) { + // This space intentionally left blank +} + +static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, + uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { + // This space intentionally left blank +} + +static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, + uint32_t time, uint32_t axis, wl_fixed_t value) { + // This space intentionally left blank +} + +static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) { + // This space intentionally left blank +} + +static void pointer_handle_axis_source(void *data, + struct wl_pointer *wl_pointer, uint32_t axis_source) { + // This space intentionally left blank +} + +static void pointer_handle_axis_stop(void *data, + struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis) { + // This space intentionally left blank +} + +static void pointer_handle_axis_discrete(void *data, + struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete) { + // This space intentionally left blank +} + +static const struct wl_pointer_listener pointer_listener = { + .enter = pointer_handle_enter, + .leave = pointer_handle_leave, + .motion = pointer_handle_motion, + .button = pointer_handle_button, + .axis = pointer_handle_axis, + .frame = pointer_handle_frame, + .axis_source = pointer_handle_axis_source, + .axis_stop = pointer_handle_axis_stop, + .axis_discrete = pointer_handle_axis_discrete, +}; + +static void xdg_surface_handle_configure(void *data, + struct xdg_surface *xdg_surface, uint32_t serial) { + xdg_surface_ack_configure(xdg_surface, serial); + wl_egl_window_resize(egl_window, width, height, 0, 0); + draw(); +} + +static const struct xdg_surface_listener xdg_surface_listener = { + .configure = xdg_surface_handle_configure, +}; + +static void xdg_toplevel_handle_configure(void *data, + struct xdg_toplevel *xdg_toplevel, int32_t w, int32_t h, + struct wl_array *states) { + width = w; + height = h; +} + +static void xdg_toplevel_handle_close(void *data, + struct xdg_toplevel *xdg_toplevel) { + exit(EXIT_SUCCESS); +} + +static const struct xdg_toplevel_listener xdg_toplevel_listener = { + .configure = xdg_toplevel_handle_configure, + .close = xdg_toplevel_handle_close, +}; + +static void handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) { + if (strcmp(interface, "wl_compositor") == 0) { + compositor = wl_registry_bind(registry, name, + &wl_compositor_interface, 1); + } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { + wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); + } else if (strcmp(interface, zwp_idle_inhibit_manager_v1_interface.name) == 0) { + idle_inhibit_manager = wl_registry_bind(registry, name, + &zwp_idle_inhibit_manager_v1_interface, 1); + } else if (strcmp(interface, wl_seat_interface.name) == 0) { + seat = wl_registry_bind(registry, name, &wl_seat_interface, version); + } +} + +static void handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) { + // who cares +} + +static const struct wl_registry_listener registry_listener = { + .global = handle_global, + .global_remove = handle_global_remove, +}; + +int main(int argc, char **argv) { + struct wl_display *display = wl_display_connect(NULL); + if (display == NULL) { + fprintf(stderr, "Failed to create display\n"); + return EXIT_FAILURE; + } + + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_dispatch(display); + wl_display_roundtrip(display); + + if (compositor == NULL) { + fprintf(stderr, "wl-compositor not available\n"); + return EXIT_FAILURE; + } + if (wm_base == NULL) { + fprintf(stderr, "xdg-shell not available\n"); + return EXIT_FAILURE; + } + if (idle_inhibit_manager == NULL) { + fprintf(stderr, "idle-inhibit not available\n"); + return EXIT_FAILURE; + } + + wlr_egl_init(&egl, EGL_PLATFORM_WAYLAND_EXT, display, NULL, + WL_SHM_FORMAT_ARGB8888); + + struct wl_surface *surface = wl_compositor_create_surface(compositor); + struct xdg_surface *xdg_surface = + xdg_wm_base_get_xdg_surface(wm_base, surface); + struct xdg_toplevel *xdg_toplevel = xdg_surface_get_toplevel(xdg_surface); + + idle_inhibitor = + zwp_idle_inhibit_manager_v1_create_inhibitor(idle_inhibit_manager, + surface); + + struct wl_pointer *pointer = wl_seat_get_pointer(seat); + wl_pointer_add_listener(pointer, &pointer_listener, surface); + + + xdg_surface_add_listener(xdg_surface, &xdg_surface_listener, NULL); + xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, NULL); + + wl_surface_commit(surface); + + egl_window = wl_egl_window_create(surface, width, height); + egl_surface = wlr_egl_create_surface(&egl, egl_window); + + wl_display_roundtrip(display); + + draw(); + + while (wl_display_dispatch(display) != -1) { + // This space intentionally left blank + } + + return EXIT_SUCCESS; +} diff --git a/examples/idle.c b/examples/idle.c new file mode 100644 index 00000000..a6a4f5c0 --- /dev/null +++ b/examples/idle.c @@ -0,0 +1,197 @@ +#include <getopt.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <wayland-client-protocol.h> +#include <wayland-client.h> +#include "idle-client-protocol.h" + +static struct org_kde_kwin_idle *idle_manager = NULL; +static struct wl_seat *seat = NULL; +static uint32_t timeout = 0, simulate_activity_timeout = 0, close_timeout = 0; +static int run = 1; + +struct thread_args { + struct wl_display *display; + struct org_kde_kwin_idle_timeout *timer; +}; + +static void handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) { + fprintf(stdout, "interfaces found: %s\n", interface); + if (strcmp(interface, "org_kde_kwin_idle") == 0) { + idle_manager = wl_registry_bind(registry, name, &org_kde_kwin_idle_interface, 1); + } + else if (strcmp(interface, "wl_seat") == 0) { + seat = wl_registry_bind(registry, name, &wl_seat_interface, 1); + } +} + +static void handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) { + //TODO +} + +static const struct wl_registry_listener registry_listener = { + .global = handle_global, + .global_remove = handle_global_remove, +}; + +static void handle_idle(void* data, struct org_kde_kwin_idle_timeout *timer) { + fprintf(stdout, "idle state\n"); +} + +static void handle_resume(void* data, struct org_kde_kwin_idle_timeout *timer) { + fprintf(stdout, "active state\n"); +} + +static const struct org_kde_kwin_idle_timeout_listener idle_timer_listener = { + .idle = handle_idle, + .resumed = handle_resume, +}; + +int parse_args(int argc, char *argv[]) { + int c; + while ((c = getopt(argc, argv, "c:hs:t:")) != -1) { + switch(c) + { + case 'c': + close_timeout = strtoul(optarg, NULL, 10); + break; + case 's': + simulate_activity_timeout = strtoul(optarg, NULL, 10); + break; + case 't': + timeout = strtoul(optarg, NULL, 10); + break; + case 'h': + case '?': + printf("Usage: %s [OPTIONS]\n", argv[0]); + printf(" -t seconds\t\t\tidle timeout in seconds\n"); + printf(" -s seconds optional\t\tsimulate user activity after x seconds\n"); + printf(" -c seconds optional\t\tclose program after x seconds\n"); + printf(" -h\t\t\t\tthis help menu\n"); + return 1; + default: + return 1; + } + } + return 0; +} + +void *simulate_activity(void *data) { + sleep(simulate_activity_timeout); + fprintf(stdout, "simulate user activity\n"); + struct thread_args *arg = data; + org_kde_kwin_idle_timeout_simulate_user_activity(arg->timer); + wl_display_roundtrip(arg->display); + return NULL; +} + +void *close_program(void *data) { + sleep(close_timeout); + struct thread_args *arg = data; + org_kde_kwin_idle_timeout_release(arg->timer); + wl_display_roundtrip(arg->display); + fprintf(stdout, "close program\n"); + run = 0; + return NULL; +} + +void *main_loop(void *data) { + struct wl_display *display = data; + while (wl_display_dispatch(display) != -1) { + ; + } + return NULL; +} + +int main(int argc, char *argv[]) { + if (parse_args(argc, argv) != 0) { + return -1; + } + if (timeout == 0) { + printf("idle timeout 0 is invalid\n"); + return -1; + } + + struct wl_display *display = wl_display_connect(NULL); + if (display == NULL) { + fprintf(stderr, "failed to create display\n"); + return -1; + } + + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_dispatch(display); + wl_display_roundtrip(display); + free(registry); + + if (idle_manager == NULL) { + fprintf(stderr, "display doesn't support idle protocol\n"); + return -1; + } + if (seat== NULL) { + fprintf(stderr, "seat error\n"); + return -1; + } + struct org_kde_kwin_idle_timeout *timer = + org_kde_kwin_idle_get_idle_timeout(idle_manager, seat, timeout * 1000); + + if (timer == NULL) { + fprintf(stderr, "Could not create idle_timeout\n"); + return -1; + } + + pthread_t t1, t2, t3; + struct thread_args arg = { + .timer = timer, + .display = display, + }; + + bool create_t1 = (simulate_activity_timeout != 0) && + (simulate_activity_timeout < close_timeout); + + if (create_t1) { + if (pthread_create(&t1, NULL, &simulate_activity, (void *)&arg) != 0) { + return -1; + } + } + + bool create_t2 = (close_timeout != 0); + + if (create_t2) { + if (pthread_create(&t2, NULL, &close_program, (void *)&arg) != 0) { + if (create_t1) { + pthread_cancel(t1); + } + return -1; + } + } + + org_kde_kwin_idle_timeout_add_listener(timer, &idle_timer_listener, timer); + fprintf(stdout, "waiting\n"); + + if (pthread_create(&t3, NULL, &main_loop, (void *)display) != 0) { + if (create_t1) { + pthread_cancel(t1); + } + if (create_t2) { + pthread_cancel(t2); + } + return -1; + } + + if (create_t1) { + pthread_join(t1, NULL); + } + if (create_t2) { + pthread_join(t2, NULL); + } + pthread_cancel(t3); + + wl_display_disconnect(display); + return 0; +} diff --git a/examples/input-inhibitor.c b/examples/input-inhibitor.c new file mode 100644 index 00000000..25e46c73 --- /dev/null +++ b/examples/input-inhibitor.c @@ -0,0 +1,189 @@ +#include <GLES2/gl2.h> +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <wayland-client.h> +#include <wayland-egl.h> +#include <wlr/render/egl.h> +#include "wlr-input-inhibitor-unstable-v1-client-protocol.h" +#include "xdg-shell-client-protocol.h" + +static int width = 500, height = 300; +static int keys = 0; + +static struct wl_compositor *compositor = NULL; +static struct wl_seat *seat = NULL; +static struct xdg_wm_base *wm_base = NULL; +static struct zwlr_input_inhibit_manager_v1 *input_inhibit_manager = NULL; +static struct zwlr_input_inhibitor_v1 *input_inhibitor = NULL; + +struct wlr_egl egl; +struct wl_egl_window *egl_window; +struct wlr_egl_surface *egl_surface; + +static void render_frame(void) { + eglMakeCurrent(egl.display, egl_surface, egl_surface, egl.context); + + glViewport(0, 0, width, height); + if (keys) { + glClearColor(1.0, 1.0, 1.0, 1.0); + } else { + glClearColor(0.8, 0.4, 1.0, 1.0); + } + glClear(GL_COLOR_BUFFER_BIT); + + eglSwapBuffers(egl.display, egl_surface); +} + +static void xdg_surface_handle_configure(void *data, + struct xdg_surface *xdg_surface, uint32_t serial) { + xdg_surface_ack_configure(xdg_surface, serial); + wl_egl_window_resize(egl_window, width, height, 0, 0); + render_frame(); +} + +static const struct xdg_surface_listener xdg_surface_listener = { + .configure = xdg_surface_handle_configure, +}; + +static void xdg_toplevel_handle_configure(void *data, + struct xdg_toplevel *xdg_toplevel, int32_t w, int32_t h, + struct wl_array *states) { + width = w; + height = h; +} + +static void xdg_toplevel_handle_close(void *data, + struct xdg_toplevel *xdg_toplevel) { + exit(0); +} + +static const struct xdg_toplevel_listener xdg_toplevel_listener = { + .configure = xdg_toplevel_handle_configure, + .close = xdg_toplevel_handle_close, +}; + +static void wl_keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, + uint32_t format, int32_t fd, uint32_t size) { +} +static void wl_keyboard_enter(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { +} +static void wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, struct wl_surface *surface) { +} +static void wl_keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, + uint32_t mods_locked, uint32_t group) { +} +static void wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, + int32_t rate, int32_t delay) { +} + +static void wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { + ++keys; + } else { + --keys; + } + render_frame(); +} + +static struct wl_keyboard_listener keyboard_listener = { + .keymap = wl_keyboard_keymap, + .enter = wl_keyboard_enter, + .leave = wl_keyboard_leave, + .key = wl_keyboard_key, + .modifiers = wl_keyboard_modifiers, + .repeat_info = wl_keyboard_repeat_info, +}; + +static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, + enum wl_seat_capability caps) { + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD)) { + struct wl_keyboard *keyboard = wl_seat_get_keyboard(wl_seat); + wl_keyboard_add_listener(keyboard, &keyboard_listener, NULL); + } +} + +static void seat_handle_name(void *data, struct wl_seat *wl_seat, + const char *name) { + // Who cares +} + +const struct wl_seat_listener seat_listener = { + .capabilities = seat_handle_capabilities, + .name = seat_handle_name, +}; + +static void handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) { + if (strcmp(interface, wl_compositor_interface.name) == 0) { + compositor = wl_registry_bind(registry, name, + &wl_compositor_interface, 1); + } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { + wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); + } else if (strcmp(interface, zwlr_input_inhibit_manager_v1_interface.name) == 0) { + input_inhibit_manager = wl_registry_bind(registry, name, + &zwlr_input_inhibit_manager_v1_interface, 1); + } else if (strcmp(interface, wl_seat_interface.name) == 0) { + seat = wl_registry_bind(registry, name, &wl_seat_interface, version); + wl_seat_add_listener(seat, &seat_listener, seat); + } +} + +static void handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) { + // who cares +} + +static const struct wl_registry_listener registry_listener = { + .global = handle_global, + .global_remove = handle_global_remove, +}; + +int main(int argc, char **argv) { + struct wl_display *display = wl_display_connect(NULL); + assert(display); + struct wl_registry *registry = wl_display_get_registry(display); + assert(registry); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_dispatch(display); + wl_display_roundtrip(display); + assert(compositor && seat && wm_base && input_inhibit_manager); + + input_inhibitor = zwlr_input_inhibit_manager_v1_get_inhibitor( + input_inhibit_manager); + assert(input_inhibitor); + + wlr_egl_init(&egl, EGL_PLATFORM_WAYLAND_EXT, display, NULL, + WL_SHM_FORMAT_ARGB8888); + + struct wl_surface *surface = wl_compositor_create_surface(compositor); + assert(surface); + struct xdg_surface *xdg_surface = + xdg_wm_base_get_xdg_surface(wm_base, surface); + assert(xdg_surface); + struct xdg_toplevel *xdg_toplevel = xdg_surface_get_toplevel(xdg_surface); + assert(xdg_toplevel); + + xdg_surface_add_listener(xdg_surface, &xdg_surface_listener, NULL); + xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, NULL); + + wl_surface_commit(surface); + + egl_window = wl_egl_window_create(surface, width, height); + egl_surface = wlr_egl_create_surface(&egl, egl_window); + + wl_display_roundtrip(display); + + render_frame(); + + while (wl_display_dispatch(display) != -1) { + // This space intentionally left blank + } + + return 0; +} diff --git a/examples/input-method.c b/examples/input-method.c new file mode 100644 index 00000000..4e375306 --- /dev/null +++ b/examples/input-method.c @@ -0,0 +1,402 @@ +#define _POSIX_C_SOURCE 200809L +#include <assert.h> +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/epoll.h> +#include <sys/timerfd.h> +#include <unistd.h> +#include <wayland-client.h> +#include <wayland-egl.h> +#include "input-method-unstable-v2-client-protocol.h" +#include "text-input-unstable-v3-client-protocol.h" +#include "xdg-shell-client-protocol.h" + +const char usage[] = "Usage: input-method [seconds]\n\ +\n\ +Creates an input method using the input-method protocol.\n\ +\n\ +Whenever a text input is activated, this program sends a few sequences of\n\ +commands and checks the validity of the responses, relying on returned\n\ +surrounding text.\n\ +\n\ +The \"seconds\" argument is optional and defines the maximum delay between\n\ +stages."; + +struct input_method_state { + enum zwp_text_input_v3_change_cause change_cause; + struct { + enum zwp_text_input_v3_content_hint hint; + enum zwp_text_input_v3_content_purpose purpose; + } content_type; + struct { + char *text; + uint32_t cursor; + uint32_t anchor; + } surrounding; +}; + +static int sleeptime = 0; + +static struct wl_display *display = NULL; +static struct wl_compositor *compositor = NULL; +static struct wl_seat *seat = NULL; +static struct zwp_input_method_manager_v2 *input_method_manager = NULL; +static struct zwp_input_method_v2 *input_method = NULL; + +struct input_method_state pending; +struct input_method_state current; + +static uint32_t serial = 0; +bool active = false; +bool pending_active = false; +bool unavailable = false; +bool running = false; + +uint32_t update_stage = 0; + +int timer_fd = 0; + +static void print_state_diff(struct input_method_state previous, + struct input_method_state future) { + if (previous.content_type.hint != future.content_type.hint) { + char *strs[] = { "COMPLETION", "SPELLCHECK", "AUTO_CAPITALIZATION", + "LOWERCASE", "UPPERCASE", "TITLECASE", "HIDDEN_TEXT", + "SENSITIVE_DATA", "LATIN", "MULTILINE"}; + printf("content_type.hint:"); + uint32_t hint = future.content_type.hint; + if (!hint) { + printf(" NONE"); + } + for (unsigned i = 0; i < sizeof(strs) / sizeof(*strs); i++) { + if (hint & 1 << i) { + printf(" %s", strs[i]); + } + } + printf("\n"); + } + if (previous.content_type.purpose != future.content_type.purpose) { + char *strs[] = { "NORMAL", "ALPHA", "DIGITS", "NUMBER", "PHONE", "URL", + "EMAIL", "NAME", "PASSWORD", "PIN", "DATE", "TIME", "DATETIME", + "TERMINAL" }; + printf("content_type.purpose: %s\n", strs[future.content_type.purpose]); + } + if (!!previous.surrounding.text != !!future.surrounding.text + || (previous.surrounding.text && future.surrounding.text + && strcmp(previous.surrounding.text, future.surrounding.text) != 0) + || previous.surrounding.anchor != future.surrounding.anchor + || previous.surrounding.cursor != future.surrounding.cursor) { + char *text = future.surrounding.text; + if (!text) { + printf("Removed surrounding text\n"); + } else { + printf("Surrounding text: %s\n", text); + uint32_t anchor = future.surrounding.anchor; + uint32_t cursor = future.surrounding.cursor; + if (cursor == anchor) { + char *temp = strndup(text, cursor); + printf("Cursor after %d: %s\n", cursor, temp); + free(temp); + } else { + if (cursor > anchor) { + uint32_t tmp = anchor; + anchor = cursor; + cursor = tmp; + } + char *temp = strndup(&text[cursor], anchor - cursor); + printf("Selection: %s\n", temp); + free(temp); + } + } + } + if (previous.change_cause != future.change_cause) { + char *strs[] = { "INPUT_METHOD", "OTHER" }; + printf("Change cause: %s\n", strs[future.change_cause]); + } +} + +static void handle_content_type(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2, + uint32_t hint, uint32_t purpose) { + pending.content_type.hint = hint; + pending.content_type.purpose = purpose; +} + +static void handle_surrounding_text(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2, + const char *text, uint32_t cursor, uint32_t anchor) { + free(pending.surrounding.text); + pending.surrounding.text = strdup(text); + pending.surrounding.cursor = cursor; + pending.surrounding.anchor = anchor; +} + +static void handle_text_change_cause(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2, + uint32_t cause) { + pending.change_cause = cause; +} + +static void handle_activate(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2) { + pending_active = true; +} + +static void handle_deactivate(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2) { + pending_active = false; +} + +static void handle_unavailable(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2) { + printf("IM disappeared\n"); + zwp_input_method_v2_destroy(zwp_input_method_v2); + input_method = NULL; + running = false; +} + +static void im_activate(void *data, + struct zwp_input_method_v2 *id) { + update_stage = 0; +} + +static void timer_arm(unsigned seconds) { + printf("Timer armed\n"); + struct itimerspec spec = { + .it_interval = {0}, + .it_value = { + .tv_sec = seconds, + .tv_nsec = 0 + } + }; + if (timerfd_settime(timer_fd, 0, &spec, NULL)) { + fprintf(stderr, "Failed to arm timer: %s\n", strerror(errno)); + } +} + +static void do_updates() { + printf("Update %d\n", update_stage); + switch (update_stage) { + case 0: + // TODO: remember initial surrounding text + zwp_input_method_v2_set_preedit_string(input_method, "Preedit", 2, 4); + zwp_input_method_v2_commit(input_method, serial); + // don't expect an answer, preedit doesn't change anything visible + timer_arm(sleeptime); + update_stage++; + return; + case 1: + zwp_input_method_v2_set_preedit_string(input_method, "Præedit2", strlen("Pr"), strlen("Præed")); + zwp_input_method_v2_commit_string(input_method, "_Commit_"); + zwp_input_method_v2_commit(input_method, serial); + update_stage++; + break; + case 2: + if (strcmp(current.surrounding.text, "_Commit_") != 0) { + return; + } + zwp_input_method_v2_commit_string(input_method, "_CommitNoPreed_"); + zwp_input_method_v2_commit(input_method, serial); + timer_arm(sleeptime); + update_stage++; + break; + case 3: + if (strcmp(current.surrounding.text, "_Commit__CommitNoPreed_") != 0) { + return; + } + zwp_input_method_v2_commit_string(input_method, "_WaitNo_"); + zwp_input_method_v2_delete_surrounding_text(input_method, strlen("_CommitNoPreed_"), 0); + zwp_input_method_v2_commit(input_method, serial); + update_stage++; + break; + case 4: + if (strcmp(current.surrounding.text, "_Commit__WaitNo_") != 0) { + return; + } + zwp_input_method_v2_set_preedit_string(input_method, "PreedWithDel", strlen("Preed"), strlen("Preed")); + zwp_input_method_v2_delete_surrounding_text(input_method, strlen("_WaitNo_"), 0); + zwp_input_method_v2_commit(input_method, serial); + update_stage++; + break; + case 5: + if (strcmp(current.surrounding.text, "_Commit_") != 0) { + return; + } + zwp_input_method_v2_delete_surrounding_text(input_method, strlen("mit_"), 0); + zwp_input_method_v2_commit(input_method, serial); + update_stage++; + break; + case 6: + if (strcmp(current.surrounding.text, "_Com") != 0) { + printf("Failed\n"); + } + update_stage++; + break; + default: + printf("Submitted everything\n"); + return; + }; +} + +static void handle_timer() { + printf("Timer dispatched at %d\n", update_stage); + do_updates(); +} + +static void im_deactivate(void *data, + struct zwp_input_method_v2 *context) { + // No special action needed +} + +static void handle_done(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2) { + bool prev_active = active; + serial++; + printf("Handle serial %d\n", serial); + if (active != pending_active) { + printf("Now %s\n", pending_active ? "active" : "inactive"); + } + if (pending_active) { + print_state_diff(current, pending); + } + active = pending_active; + free(current.surrounding.text); + struct input_method_state default_state = {0}; + current = pending; + pending = default_state; + if (active && !prev_active) { + im_activate(data, zwp_input_method_v2); + } else if (!active && prev_active) { + im_deactivate(data, zwp_input_method_v2); + } + + do_updates(); +} + +static const struct zwp_input_method_v2_listener im_listener = { + .activate = handle_activate, + .deactivate = handle_deactivate, + .surrounding_text = handle_surrounding_text, + .text_change_cause = handle_text_change_cause, + .content_type = handle_content_type, + .done = handle_done, + .unavailable = handle_unavailable, +}; + +static void handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) { + if (strcmp(interface, "wl_compositor") == 0) { + compositor = wl_registry_bind(registry, name, + &wl_compositor_interface, 1); + } else if (strcmp(interface, zwp_input_method_manager_v2_interface.name) == 0) { + input_method_manager = wl_registry_bind(registry, name, + &zwp_input_method_manager_v2_interface, 1); + } else if (strcmp(interface, wl_seat_interface.name) == 0) { + seat = wl_registry_bind(registry, name, &wl_seat_interface, version); + } +} + +static void handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) { + // who cares +} + +static const struct wl_registry_listener registry_listener = { + .global = handle_global, + .global_remove = handle_global_remove, +}; + +int main(int argc, char **argv) { + if (argc > 1) { + if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) { + printf(usage); + return 0; + } + sleeptime = atoi(argv[1]); + } + display = wl_display_connect(NULL); + if (display == NULL) { + fprintf(stderr, "Failed to create display\n"); + return EXIT_FAILURE; + } + + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_dispatch(display); + wl_display_roundtrip(display); + + if (compositor == NULL) { + fprintf(stderr, "wl-compositor not available\n"); + return EXIT_FAILURE; + } + if (input_method_manager == NULL) { + fprintf(stderr, "input-method not available\n"); + return EXIT_FAILURE; + } + if (seat == NULL) { + fprintf(stderr, "seat not available\n"); + return EXIT_FAILURE; + } + + input_method = zwp_input_method_manager_v2_get_input_method( + input_method_manager, seat); + running = true; + zwp_input_method_v2_add_listener(input_method, &im_listener, NULL); + + int display_fd = wl_display_get_fd(display); + timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); + if (timer_fd < 0) { + fprintf(stderr, "Failed to start timer\n"); + return EXIT_FAILURE; + } + int epoll = epoll_create1(EPOLL_CLOEXEC); + if (epoll < 0) { + fprintf(stderr, "Failed to start epoll\n"); + return EXIT_FAILURE; + } + + struct epoll_event epoll_display = { + .events = EPOLLIN | EPOLLOUT, + .data = {.fd = display_fd}, + }; + if (epoll_ctl(epoll, EPOLL_CTL_ADD, display_fd, &epoll_display)) { + fprintf(stderr, "Failed to epoll display\n"); + return EXIT_FAILURE; + } + + wl_display_roundtrip(display); // timer may be armed here + + struct epoll_event epoll_timer = { + .events = EPOLLIN, + .data = {.fd = timer_fd}, + }; + if (epoll_ctl(epoll, EPOLL_CTL_ADD, timer_fd, &epoll_timer)) { + fprintf(stderr, "Failed to epoll timer\n"); + return EXIT_FAILURE; + } + + timer_arm(2); + + struct epoll_event caught; + while (epoll_wait(epoll, &caught, 1, -1)) { + if (!running) { + printf("Exiting\n"); + return EXIT_SUCCESS; + } + if (caught.data.fd == display_fd) { + if (wl_display_dispatch(display) == -1) { + break; + } + } else if (caught.data.fd == timer_fd) { + uint64_t expirations; + ssize_t n = read(timer_fd, &expirations, sizeof(expirations)); + assert(n >= 0); + handle_timer(); + } else { + printf("Unknown source\n"); + } + } + return EXIT_SUCCESS; +} diff --git a/examples/layer-shell.c b/examples/layer-shell.c new file mode 100644 index 00000000..77b2f6c3 --- /dev/null +++ b/examples/layer-shell.c @@ -0,0 +1,653 @@ +#define _POSIX_C_SOURCE 200112L +#ifdef __linux__ +#include <linux/input-event-codes.h> +#elif __FreeBSD__ +#include <dev/evdev/input-event-codes.h> +#endif +#include <assert.h> +#include <GLES2/gl2.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <wayland-client.h> +#include <wayland-cursor.h> +#include <wayland-egl.h> +#include <wlr/render/egl.h> +#include <wlr/util/log.h> +#include "wlr-layer-shell-unstable-v1-client-protocol.h" +#include "xdg-shell-client-protocol.h" + +static struct wl_display *display; +static struct wl_compositor *compositor; +static struct wl_seat *seat; +static struct wl_shm *shm; +static struct wl_pointer *pointer; +static struct wl_keyboard *keyboard; +static struct xdg_wm_base *xdg_wm_base; +static struct zwlr_layer_shell_v1 *layer_shell; + +struct zwlr_layer_surface_v1 *layer_surface; +static struct wl_output *wl_output; + +struct wl_surface *wl_surface; +struct wlr_egl egl; +struct wl_egl_window *egl_window; +struct wlr_egl_surface *egl_surface; +struct wl_callback *frame_callback; + +static uint32_t output = UINT32_MAX; +struct xdg_popup *popup; +struct wl_surface *popup_wl_surface; +struct wl_egl_window *popup_egl_window; +static uint32_t popup_width = 256, popup_height = 256; +struct wlr_egl_surface *popup_egl_surface; +struct wl_callback *popup_frame_callback; +float popup_alpha = 1.0, popup_red = 0.5f; + +static uint32_t layer = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND; +static uint32_t anchor = 0; +static uint32_t width = 256, height = 256; +static int32_t margin_top = 0; +static double alpha = 1.0; +static bool run_display = true; +static bool animate = false; +static bool keyboard_interactive = false; +static double frame = 0; +static int cur_x = -1, cur_y = -1; +static int buttons = 0; + +struct wl_cursor_image *cursor_image; +struct wl_cursor_image *popup_cursor_image; +struct wl_surface *cursor_surface, *input_surface; + +static struct { + struct timespec last_frame; + float color[3]; + int dec; +} demo; + +static void draw(void); +static void draw_popup(void); + +static void surface_frame_callback( + void *data, struct wl_callback *cb, uint32_t time) { + wl_callback_destroy(cb); + frame_callback = NULL; + draw(); +} + +static struct wl_callback_listener frame_listener = { + .done = surface_frame_callback +}; + +static void popup_surface_frame_callback( + void *data, struct wl_callback *cb, uint32_t time) { + wl_callback_destroy(cb); + popup_frame_callback = NULL; + if (popup) { + draw_popup(); + } +} + +static struct wl_callback_listener popup_frame_listener = { + .done = popup_surface_frame_callback +}; + +static void draw(void) { + eglMakeCurrent(egl.display, egl_surface, egl_surface, egl.context); + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + + long ms = (ts.tv_sec - demo.last_frame.tv_sec) * 1000 + + (ts.tv_nsec - demo.last_frame.tv_nsec) / 1000000; + int inc = (demo.dec + 1) % 3; + + if (!buttons) { + demo.color[inc] += ms / 2000.0f; + demo.color[demo.dec] -= ms / 2000.0f; + + if (demo.color[demo.dec] < 0.0f) { + demo.color[inc] = 1.0f; + demo.color[demo.dec] = 0.0f; + demo.dec = inc; + } + } + + if (animate) { + frame += ms / 50.0; + int32_t old_top = margin_top; + margin_top = -(20 - ((int)frame % 20)); + if (old_top != margin_top) { + zwlr_layer_surface_v1_set_margin(layer_surface, + margin_top, 0, 0, 0); + wl_surface_commit(wl_surface); + } + } + + glViewport(0, 0, width, height); + if (buttons) { + glClearColor(1, 1, 1, alpha); + } else { + glClearColor(demo.color[0], demo.color[1], demo.color[2], alpha); + } + glClear(GL_COLOR_BUFFER_BIT); + + if (cur_x != -1 && cur_y != -1) { + glEnable(GL_SCISSOR_TEST); + glScissor(cur_x, height - cur_y, 5, 5); + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + glDisable(GL_SCISSOR_TEST); + } + + frame_callback = wl_surface_frame(wl_surface); + wl_callback_add_listener(frame_callback, &frame_listener, NULL); + + eglSwapBuffers(egl.display, egl_surface); + + demo.last_frame = ts; +} + +static void draw_popup(void) { + static float alpha_mod = -0.01; + + eglMakeCurrent(egl.display, popup_egl_surface, popup_egl_surface, egl.context); + glViewport(0, 0, popup_width, popup_height); + glClearColor(popup_red, 0.5f, 0.5f, popup_alpha); + popup_alpha += alpha_mod; + if (popup_alpha < 0.01 || popup_alpha >= 1.0f) { + alpha_mod *= -1.0; + } + glClear(GL_COLOR_BUFFER_BIT); + + popup_frame_callback = wl_surface_frame(popup_wl_surface); + assert(popup_frame_callback); + wl_callback_add_listener(popup_frame_callback, &popup_frame_listener, NULL); + eglSwapBuffers(egl.display, popup_egl_surface); + wl_surface_commit(popup_wl_surface); +} + +static void xdg_surface_handle_configure(void *data, + struct xdg_surface *xdg_surface, uint32_t serial) { + xdg_surface_ack_configure(xdg_surface, serial); +} + +static const struct xdg_surface_listener xdg_surface_listener = { + .configure = xdg_surface_handle_configure, +}; + +static void xdg_popup_configure(void *data, struct xdg_popup *xdg_popup, + int32_t x, int32_t y, int32_t width, int32_t height) { + wlr_log(WLR_DEBUG, "Popup configured %dx%d@%d,%d", + width, height, x, y); + popup_width = width; + popup_height = height; + if (popup_egl_window) { + wl_egl_window_resize(popup_egl_window, width, height, 0, 0); + } +} + +static void popup_destroy(void) { + wlr_egl_destroy_surface(&egl, popup_egl_surface); + wl_egl_window_destroy(popup_egl_window); + xdg_popup_destroy(popup); + wl_surface_destroy(popup_wl_surface); + popup_wl_surface = NULL; + popup = NULL; + popup_egl_window = NULL; +} + +static void xdg_popup_done(void *data, struct xdg_popup *xdg_popup) { + wlr_log(WLR_DEBUG, "Popup done"); + popup_destroy(); +} + +static const struct xdg_popup_listener xdg_popup_listener = { + .configure = xdg_popup_configure, + .popup_done = xdg_popup_done, +}; + +static void create_popup(uint32_t serial) { + if (popup) { + return; + } + struct wl_surface *surface = wl_compositor_create_surface(compositor); + assert(xdg_wm_base && surface); + struct xdg_surface *xdg_surface = + xdg_wm_base_get_xdg_surface(xdg_wm_base, surface); + struct xdg_positioner *xdg_positioner = + xdg_wm_base_create_positioner(xdg_wm_base); + assert(xdg_surface && xdg_positioner); + + xdg_positioner_set_size(xdg_positioner, popup_width, popup_height); + xdg_positioner_set_offset(xdg_positioner, 0, 0); + xdg_positioner_set_anchor_rect(xdg_positioner, cur_x, cur_y, 1, 1); + xdg_positioner_set_anchor(xdg_positioner, XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT); + + popup = xdg_surface_get_popup(xdg_surface, NULL, xdg_positioner); + xdg_popup_grab(popup, seat, serial); + + assert(popup); + + zwlr_layer_surface_v1_get_popup(layer_surface, popup); + + xdg_surface_add_listener(xdg_surface, &xdg_surface_listener, NULL); + xdg_popup_add_listener(popup, &xdg_popup_listener, NULL); + + wl_surface_commit(surface); + wl_display_roundtrip(display); + + xdg_positioner_destroy(xdg_positioner); + + popup_wl_surface = surface; + popup_egl_window = wl_egl_window_create(surface, popup_width, popup_height); + assert(popup_egl_window); + popup_egl_surface = wlr_egl_create_surface(&egl, popup_egl_window); + assert(popup_egl_surface); + draw_popup(); +} + +static void layer_surface_configure(void *data, + struct zwlr_layer_surface_v1 *surface, + uint32_t serial, uint32_t w, uint32_t h) { + width = w; + height = h; + if (egl_window) { + wl_egl_window_resize(egl_window, width, height, 0, 0); + } + zwlr_layer_surface_v1_ack_configure(surface, serial); +} + +static void layer_surface_closed(void *data, + struct zwlr_layer_surface_v1 *surface) { + wlr_egl_destroy_surface(&egl, egl_surface); + wl_egl_window_destroy(egl_window); + zwlr_layer_surface_v1_destroy(surface); + wl_surface_destroy(wl_surface); + run_display = false; +} + +struct zwlr_layer_surface_v1_listener layer_surface_listener = { + .configure = layer_surface_configure, + .closed = layer_surface_closed, +}; + +static void wl_pointer_enter(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, struct wl_surface *surface, + wl_fixed_t surface_x, wl_fixed_t surface_y) { + struct wl_cursor_image *image; + if (surface == popup_wl_surface) { + image = popup_cursor_image; + } else { + image = cursor_image; + } + wl_surface_attach(cursor_surface, + wl_cursor_image_get_buffer(image), 0, 0); + wl_surface_damage(cursor_surface, 1, 0, + image->width, image->height); + wl_surface_commit(cursor_surface); + wl_pointer_set_cursor(wl_pointer, serial, cursor_surface, + image->hotspot_x, image->hotspot_y); + input_surface = surface; +} + +static void wl_pointer_leave(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, struct wl_surface *surface) { + cur_x = cur_y = -1; + buttons = 0; +} + +static void wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, + uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { + cur_x = wl_fixed_to_int(surface_x); + cur_y = wl_fixed_to_int(surface_y); +} + +static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { + if (input_surface == wl_surface) { + if (state == WL_POINTER_BUTTON_STATE_PRESSED) { + if (button == BTN_RIGHT) { + if (popup_wl_surface) { + popup_destroy(); + } else { + create_popup(serial); + } + } else { + buttons++; + } + } else { + if (button != BTN_RIGHT) { + buttons--; + } + } + } else if (input_surface == popup_wl_surface) { + if (state == WL_POINTER_BUTTON_STATE_PRESSED) { + if (button == BTN_LEFT && popup_red <= 0.9f) { + popup_red += 0.1; + } else if (button == BTN_RIGHT && popup_red >= 0.1f) { + popup_red -= 0.1; + } + } + } else { + assert(false && "Unknown surface"); + } +} + +static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, + uint32_t time, uint32_t axis, wl_fixed_t value) { + // Who cares +} + +static void wl_pointer_frame(void *data, struct wl_pointer *wl_pointer) { + // Who cares +} + +static void wl_pointer_axis_source(void *data, struct wl_pointer *wl_pointer, + uint32_t axis_source) { + // Who cares +} + +static void wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer, + uint32_t time, uint32_t axis) { + // Who cares +} + +static void wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer, + uint32_t axis, int32_t discrete) { + // Who cares +} + +struct wl_pointer_listener pointer_listener = { + .enter = wl_pointer_enter, + .leave = wl_pointer_leave, + .motion = wl_pointer_motion, + .button = wl_pointer_button, + .axis = wl_pointer_axis, + .frame = wl_pointer_frame, + .axis_source = wl_pointer_axis_source, + .axis_stop = wl_pointer_axis_stop, + .axis_discrete = wl_pointer_axis_discrete, +}; + +static void wl_keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, + uint32_t format, int32_t fd, uint32_t size) { + // Who cares +} + +static void wl_keyboard_enter(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { + wlr_log(WLR_DEBUG, "Keyboard enter"); +} + +static void wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, struct wl_surface *surface) { + wlr_log(WLR_DEBUG, "Keyboard leave"); +} + +static void wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { + wlr_log(WLR_DEBUG, "Key event: %d %d", key, state); +} + +static void wl_keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, + uint32_t mods_locked, uint32_t group) { + // Who cares +} + +static void wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, + int32_t rate, int32_t delay) { + // Who cares +} + +static struct wl_keyboard_listener keyboard_listener = { + .keymap = wl_keyboard_keymap, + .enter = wl_keyboard_enter, + .leave = wl_keyboard_leave, + .key = wl_keyboard_key, + .modifiers = wl_keyboard_modifiers, + .repeat_info = wl_keyboard_repeat_info, +}; + +static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, + enum wl_seat_capability caps) { + if ((caps & WL_SEAT_CAPABILITY_POINTER)) { + pointer = wl_seat_get_pointer(wl_seat); + wl_pointer_add_listener(pointer, &pointer_listener, NULL); + } + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD)) { + keyboard = wl_seat_get_keyboard(wl_seat); + wl_keyboard_add_listener(keyboard, &keyboard_listener, NULL); + } +} + +static void seat_handle_name(void *data, struct wl_seat *wl_seat, + const char *name) { + // Who cares +} + +const struct wl_seat_listener seat_listener = { + .capabilities = seat_handle_capabilities, + .name = seat_handle_name, +}; + +static void handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) { + if (strcmp(interface, wl_compositor_interface.name) == 0) { + compositor = wl_registry_bind(registry, name, + &wl_compositor_interface, 1); + } else if (strcmp(interface, wl_shm_interface.name) == 0) { + shm = wl_registry_bind(registry, name, + &wl_shm_interface, 1); + } else if (strcmp(interface, "wl_output") == 0) { + if (output != UINT32_MAX) { + if (!wl_output) { + wl_output = wl_registry_bind(registry, name, + &wl_output_interface, 1); + } else { + output--; + } + } + } else if (strcmp(interface, wl_seat_interface.name) == 0) { + seat = wl_registry_bind(registry, name, + &wl_seat_interface, 1); + wl_seat_add_listener(seat, &seat_listener, NULL); + } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { + layer_shell = wl_registry_bind( + registry, name, &zwlr_layer_shell_v1_interface, 1); + } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { + xdg_wm_base = wl_registry_bind( + registry, name, &xdg_wm_base_interface, 1); + } +} + +static void handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) { + // who cares +} + +static const struct wl_registry_listener registry_listener = { + .global = handle_global, + .global_remove = handle_global_remove, +}; + +int main(int argc, char **argv) { + wlr_log_init(WLR_DEBUG, NULL); + char *namespace = "wlroots"; + int exclusive_zone = 0; + int32_t margin_right = 0, margin_bottom = 0, margin_left = 0; + bool found; + int c; + while ((c = getopt(argc, argv, "knw:h:o:l:a:x:m:t:")) != -1) { + switch (c) { + case 'o': + output = atoi(optarg); + break; + case 'w': + width = atoi(optarg); + break; + case 'h': + height = atoi(optarg); + break; + case 'x': + exclusive_zone = atoi(optarg); + break; + case 'l': { + struct { + char *name; + enum zwlr_layer_shell_v1_layer value; + } layers[] = { + { "background", ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND }, + { "bottom", ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM }, + { "top", ZWLR_LAYER_SHELL_V1_LAYER_TOP }, + { "overlay", ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY }, + }; + found = false; + for (size_t i = 0; i < sizeof(layers) / sizeof(layers[0]); ++i) { + if (strcmp(optarg, layers[i].name) == 0) { + layer = layers[i].value; + found = true; + break; + } + } + if (!found) { + fprintf(stderr, "invalid layer %s\n", optarg); + return 1; + } + break; + } + case 'a': { + struct { + char *name; + uint32_t value; + } anchors[] = { + { "top", ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP }, + { "bottom", ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM }, + { "left", ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT }, + { "right", ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT }, + }; + found = false; + for (size_t i = 0; i < sizeof(anchors) / sizeof(anchors[0]); ++i) { + if (strcmp(optarg, anchors[i].name) == 0) { + anchor |= anchors[i].value; + found = true; + break; + } + } + if (!found) { + fprintf(stderr, "invalid anchor %s\n", optarg); + return 1; + } + break; + } + case 't': + alpha = atof(optarg); + break; + case 'm': { + char *endptr = optarg; + margin_top = strtol(endptr, &endptr, 10); + assert(*endptr == ','); + margin_right = strtol(endptr + 1, &endptr, 10); + assert(*endptr == ','); + margin_bottom = strtol(endptr + 1, &endptr, 10); + assert(*endptr == ','); + margin_left = strtol(endptr + 1, &endptr, 10); + assert(!*endptr); + break; + } + case 'n': + animate = true; + break; + case 'k': + keyboard_interactive = true; + break; + default: + break; + } + } + + display = wl_display_connect(NULL); + if (display == NULL) { + fprintf(stderr, "Failed to create display\n"); + return 1; + } + + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_roundtrip(display); + + if (compositor == NULL) { + fprintf(stderr, "wl_compositor not available\n"); + return 1; + } + if (shm == NULL) { + fprintf(stderr, "wl_shm not available\n"); + return 1; + } + if (layer_shell == NULL) { + fprintf(stderr, "layer_shell not available\n"); + return 1; + } + + struct wl_cursor_theme *cursor_theme = + wl_cursor_theme_load(NULL, 16, shm); + assert(cursor_theme); + struct wl_cursor *cursor = + wl_cursor_theme_get_cursor(cursor_theme, "crosshair"); + if (cursor == NULL) { + cursor = wl_cursor_theme_get_cursor(cursor_theme, "left_ptr"); + } + assert(cursor); + cursor_image = cursor->images[0]; + + cursor = wl_cursor_theme_get_cursor(cursor_theme, "tcross"); + if (cursor == NULL) { + cursor = wl_cursor_theme_get_cursor(cursor_theme, "left_ptr"); + } + assert(cursor); + popup_cursor_image = cursor->images[0]; + + cursor_surface = wl_compositor_create_surface(compositor); + assert(cursor_surface); + + EGLint attribs[] = { EGL_ALPHA_SIZE, 8, EGL_NONE }; + wlr_egl_init(&egl, EGL_PLATFORM_WAYLAND_EXT, display, + attribs, WL_SHM_FORMAT_ARGB8888); + + wl_surface = wl_compositor_create_surface(compositor); + assert(wl_surface); + + layer_surface = zwlr_layer_shell_v1_get_layer_surface(layer_shell, + wl_surface, wl_output, layer, namespace); + assert(layer_surface); + zwlr_layer_surface_v1_set_size(layer_surface, width, height); + zwlr_layer_surface_v1_set_anchor(layer_surface, anchor); + zwlr_layer_surface_v1_set_exclusive_zone(layer_surface, exclusive_zone); + zwlr_layer_surface_v1_set_margin(layer_surface, + margin_top, margin_right, margin_bottom, margin_left); + zwlr_layer_surface_v1_set_keyboard_interactivity( + layer_surface, keyboard_interactive); + zwlr_layer_surface_v1_add_listener(layer_surface, + &layer_surface_listener, layer_surface); + wl_surface_commit(wl_surface); + wl_display_roundtrip(display); + + egl_window = wl_egl_window_create(wl_surface, width, height); + assert(egl_window); + egl_surface = wlr_egl_create_surface(&egl, egl_window); + assert(egl_surface); + + wl_display_roundtrip(display); + draw(); + + while (wl_display_dispatch(display) != -1 && run_display) { + // This space intentionally left blank + } + + wl_cursor_theme_destroy(cursor_theme); + return 0; +} diff --git a/examples/meson.build b/examples/meson.build new file mode 100644 index 00000000..589a7326 --- /dev/null +++ b/examples/meson.build @@ -0,0 +1,133 @@ +threads = dependency('threads') +wayland_cursor = dependency('wayland-cursor') +libpng = dependency('libpng', required: false) +# These versions correspond to ffmpeg 4.0 +libavutil = dependency('libavutil', version: '>=56.14.100', required: false) +libavcodec = dependency('libavcodec', version: '>=58.18.100', required: false) +libavformat = dependency('libavformat', version: '>=58.12.100', required: false) + +# epoll is a separate library in FreeBSD +if host_machine.system() == 'freebsd' + libepoll = [dependency('epoll-shim')] +else + libepoll = [] +endif + +# Small hack until https://github.com/mesonbuild/meson/pull/3386/ is merged +foreach dep : ['libpng', 'libavutil', 'libavcodec', 'libavformat'] + if not get_variable(dep).found() + set_variable(dep, disabler()) + endif +endforeach + +if not cc.has_header('libavutil/hwcontext_drm.h', dependencies: libavutil) + libavutil = disabler() +endif + +examples = { + 'simple': { + 'src': 'simple.c', + 'dep': [wlroots], + }, + 'pointer': { + 'src': 'pointer.c', + 'dep': [wlroots], + }, + 'touch': { + 'src': ['touch.c', 'cat.c'], + 'dep': [wlroots], + }, + 'tablet': { + 'src': 'tablet.c', + 'dep': [wlroots], + }, + 'rotation': { + 'src': ['rotation.c', 'cat.c'], + 'dep': [wlroots], + }, + 'multi-pointer': { + 'src': 'multi-pointer.c', + 'dep': [wlroots], + }, + 'output-layout': { + 'src': ['output-layout.c', 'cat.c'], + 'dep': [wlroots], + }, + 'screenshot': { + 'src': 'screenshot.c', + 'dep': [wayland_client, wlr_protos, rt], + }, + 'idle': { + 'src': 'idle.c', + 'dep': [wayland_client, wlr_protos, threads], + }, + 'idle-inhibit': { + 'src': 'idle-inhibit.c', + 'dep': [wayland_client, wlr_protos, wlroots], + }, + 'layer-shell': { + 'src': 'layer-shell.c', + 'dep': [wayland_client, wayland_cursor, wlr_protos, wlroots], + }, + 'input-inhibitor': { + 'src': 'input-inhibitor.c', + 'dep': [wayland_client, wayland_cursor, wlr_protos, wlroots], + }, + 'gamma-control': { + 'src': 'gamma-control.c', + 'dep': [wayland_client, wayland_cursor, wlr_protos, math], + }, + 'pointer-constraints': { + 'src': 'pointer-constraints.c', + 'dep': [wayland_client, wlr_protos, wlroots], + }, + 'dmabuf-capture': { + 'src': 'dmabuf-capture.c', + 'dep': [ + libavcodec, + libavformat, + libavutil, + drm.partial_dependency(compile_args: true), # <drm_fourcc.h> + threads, + wayland_client, + wlr_protos, + ], + }, + 'screencopy': { + 'src': 'screencopy.c', + 'dep': [libpng, wayland_client, wlr_protos, rt], + }, + 'toplevel-decoration': { + 'src': 'toplevel-decoration.c', + 'dep': [wayland_client, wlr_protos, wlroots], + }, + 'input-method': { + 'src': 'input-method.c', + 'dep': [wayland_client, wlr_protos] + libepoll, + }, + 'text-input': { + 'src': 'text-input.c', + 'dep': [wayland_cursor, wayland_client, wlr_protos, wlroots], + }, + 'foreign-toplevel': { + 'src': 'foreign-toplevel.c', + 'dep': [wayland_client, wlr_protos, wlroots], + }, +} + +foreach name, info : examples + all_dep_found = true + foreach d : info.get('dep') + all_dep_found = all_dep_found and d.found() + endforeach + if all_dep_found + executable( + name, + info.get('src'), + dependencies: info.get('dep'), + build_by_default: get_option('examples'), + ) + else + warning('Dependencies not satisfied for ' + name) + endif +endforeach diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c new file mode 100644 index 00000000..49670c39 --- /dev/null +++ b/examples/multi-pointer.c @@ -0,0 +1,340 @@ +#define _POSIX_C_SOURCE 200112L +#include <assert.h> +#include <GLES2/gl2.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <wayland-server-protocol.h> +#include <wayland-server.h> +#include <wlr/backend.h> +#include <wlr/backend/session.h> +#include <wlr/render/gles2.h> +#include <wlr/render/wlr_renderer.h> +#include <wlr/types/wlr_cursor.h> +#include <wlr/types/wlr_keyboard.h> +#include <wlr/types/wlr_list.h> +#include <wlr/types/wlr_matrix.h> +#include <wlr/types/wlr_output_layout.h> +#include <wlr/util/log.h> +#include <wlr/xcursor.h> +#include <xkbcommon/xkbcommon.h> + +struct sample_state { + struct wl_display *display; + struct wlr_xcursor *xcursor; + float default_color[4]; + float clear_color[4]; + struct wlr_output_layout *layout; + struct wl_list cursors; // sample_cursor::link + struct wl_list pointers; // sample_pointer::link + struct wl_list outputs; // sample_output::link + struct timespec last_frame; + struct wl_listener new_output; + struct wl_listener new_input; +}; + +struct sample_cursor { + struct sample_state *sample; + struct wlr_input_device *device; + struct wlr_cursor *cursor; + struct wl_list link; + + struct wl_listener cursor_motion; + struct wl_listener cursor_motion_absolute; + struct wl_listener cursor_button; + struct wl_listener cursor_axis; + struct wl_listener destroy; +}; + +struct sample_pointer { + struct wlr_input_device *device; + struct wl_list link; +}; + +struct sample_output { + struct sample_state *sample; + struct wlr_output *output; + struct wl_listener frame; + struct wl_listener destroy; + struct wl_list link; +}; + +struct sample_keyboard { + struct sample_state *sample; + struct wlr_input_device *device; + struct wl_listener key; + struct wl_listener destroy; +}; + +void configure_cursor(struct wlr_cursor *cursor, struct wlr_input_device *device, + struct sample_state *sample) { + struct sample_output *output; + wlr_log(WLR_ERROR, "Configuring cursor %p for device %p", cursor, device); + + // reset mappings + wlr_cursor_map_to_output(cursor, NULL); + wlr_cursor_detach_input_device(cursor, device); + wlr_cursor_map_input_to_output(cursor, device, NULL); + + wlr_cursor_attach_input_device(cursor, device); + + // configure device to output mappings + wl_list_for_each(output, &sample->outputs, link) { + wlr_cursor_map_to_output(cursor, output->output); + + wlr_cursor_map_input_to_output(cursor, device, output->output); + } +} + +void output_frame_notify(struct wl_listener *listener, void *data) { + struct sample_output *output = wl_container_of(listener, output, frame); + struct sample_state *sample = output->sample; + struct wlr_output *wlr_output = output->output; + + wlr_output_make_current(wlr_output, NULL); + + glClearColor(sample->clear_color[0], sample->clear_color[1], + sample->clear_color[2], sample->clear_color[3]); + glClear(GL_COLOR_BUFFER_BIT); + + wlr_output_swap_buffers(wlr_output, NULL, NULL); +} + +static void handle_cursor_motion(struct wl_listener *listener, void *data) { + struct sample_cursor *cursor = + wl_container_of(listener, cursor, cursor_motion); + struct wlr_event_pointer_motion *event = data; + wlr_cursor_move(cursor->cursor, event->device, event->delta_x, + event->delta_y); +} + +static void handle_cursor_motion_absolute(struct wl_listener *listener, + void *data) { + struct sample_cursor *cursor = + wl_container_of(listener, cursor, cursor_motion_absolute); + struct wlr_event_pointer_motion_absolute *event = data; + wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x, event->y); +} + +static void cursor_destroy(struct sample_cursor *cursor) { + wl_list_remove(&cursor->link); + wl_list_remove(&cursor->cursor_motion.link); + wl_list_remove(&cursor->cursor_motion_absolute.link); + wlr_cursor_destroy(cursor->cursor); + free(cursor); +} + +void input_remove_notify(struct wl_listener *listener, void *data) { + struct wlr_input_device *device = data; + struct sample_cursor *sample_cursor = wl_container_of(listener, sample_cursor, destroy); + struct sample_state *sample = sample_cursor->sample; + struct sample_cursor *cursor; + wl_list_for_each(cursor, &sample->cursors, link) { + if (cursor->device == device) { + cursor_destroy(cursor); + break; + } + } + struct sample_pointer *pointer; + wl_list_for_each(pointer, &sample->pointers, link) { + if (pointer->device == device) { + free(pointer); + break; + } + } +} + +void output_remove_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = wl_container_of(listener, sample_output, destroy); + struct sample_state *sample = sample_output->sample; + wl_list_remove(&sample_output->frame.link); + wl_list_remove(&sample_output->destroy.link); + wl_list_remove(&sample_output->link); + free(sample_output); + + struct sample_cursor *cursor; + wl_list_for_each(cursor, &sample->cursors, link) { + configure_cursor(cursor->cursor, cursor->device, sample); + } +} + +void new_output_notify(struct wl_listener *listener, void *data) { + struct wlr_output *output = data; + struct sample_state *sample = wl_container_of(listener, sample, new_output); + struct sample_output *sample_output = calloc(1, sizeof(struct sample_output)); + if (!wl_list_empty(&output->modes)) { + struct wlr_output_mode *mode = wl_container_of(output->modes.prev, mode, link); + wlr_output_set_mode(output, mode); + } + sample_output->output = output; + sample_output->sample = sample; + wl_signal_add(&output->events.frame, &sample_output->frame); + sample_output->frame.notify = output_frame_notify; + wl_signal_add(&output->events.destroy, &sample_output->destroy); + sample_output->destroy.notify = output_remove_notify; + + wlr_output_layout_add_auto(sample->layout, output); + + + struct sample_cursor *cursor; + wl_list_for_each(cursor, &sample->cursors, link) { + configure_cursor(cursor->cursor, cursor->device, sample); + + struct wlr_xcursor_image *image = sample->xcursor->images[0]; + wlr_cursor_set_image(cursor->cursor, image->buffer, image->width * 4, + image->width, image->height, image->hotspot_x, image->hotspot_y, 0); + + wlr_cursor_warp(cursor->cursor, NULL, cursor->cursor->x, + cursor->cursor->y); + } + wl_list_insert(&sample->outputs, &sample_output->link); +} + +void keyboard_key_notify(struct wl_listener *listener, void *data) { + struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); + struct sample_state *sample = keyboard->sample; + struct wlr_event_keyboard_key *event = data; + uint32_t keycode = event->keycode + 8; + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, + keycode, &syms); + for (int i = 0; i < nsyms; i++) { + xkb_keysym_t sym = syms[i]; + if (sym == XKB_KEY_Escape) { + wl_display_terminate(sample->display); + } + } +} + +void keyboard_destroy_notify(struct wl_listener *listener, void *data) { + struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, destroy); + wl_list_remove(&keyboard->destroy.link); + wl_list_remove(&keyboard->key.link); + free(keyboard); +} + +void new_input_notify(struct wl_listener *listener, void *data) { + struct wlr_input_device *device = data; + struct sample_state *sample = wl_container_of(listener, sample, new_input); + switch (device->type) { + case WLR_INPUT_DEVICE_KEYBOARD:; + struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); + keyboard->device = device; + keyboard->sample = sample; + wl_signal_add(&device->events.destroy, &keyboard->destroy); + keyboard->destroy.notify = keyboard_destroy_notify; + wl_signal_add(&device->keyboard->events.key, &keyboard->key); + keyboard->key.notify = keyboard_key_notify; + struct xkb_rule_names rules = { 0 }; + rules.rules = getenv("XKB_DEFAULT_RULES"); + rules.model = getenv("XKB_DEFAULT_MODEL"); + rules.layout = getenv("XKB_DEFAULT_LAYOUT"); + rules.variant = getenv("XKB_DEFAULT_VARIANT"); + rules.options = getenv("XKB_DEFAULT_OPTIONS"); + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!context) { + wlr_log(WLR_ERROR, "Failed to create XKB context"); + exit(1); + } + struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) { + wlr_log(WLR_ERROR, "Failed to create XKB keymap"); + exit(1); + } + wlr_keyboard_set_keymap(device->keyboard, keymap); + xkb_keymap_unref(keymap); + xkb_context_unref(context); + break; + case WLR_INPUT_DEVICE_POINTER:; + struct sample_cursor *cursor = calloc(1, sizeof(struct sample_cursor)); + struct sample_pointer *pointer = calloc(1, sizeof(struct sample_pointer)); + pointer->device = device; + cursor->sample = sample; + cursor->device = device; + + cursor->cursor = wlr_cursor_create(); + + wlr_cursor_attach_output_layout(cursor->cursor, sample->layout); + + wl_signal_add(&cursor->cursor->events.motion, &cursor->cursor_motion); + cursor->cursor_motion.notify = handle_cursor_motion; + wl_signal_add(&cursor->cursor->events.motion_absolute, + &cursor->cursor_motion_absolute); + cursor->cursor_motion_absolute.notify = handle_cursor_motion_absolute; + + wlr_cursor_attach_input_device(cursor->cursor, device); + configure_cursor(cursor->cursor, device, sample); + + struct wlr_xcursor_image *image = sample->xcursor->images[0]; + wlr_cursor_set_image(cursor->cursor, image->buffer, image->width * 4, + image->width, image->height, image->hotspot_x, image->hotspot_y, 0); + + wl_list_insert(&sample->cursors, &cursor->link); + wl_list_insert(&sample->pointers, &pointer->link); + break; + default: + break; + } +} + +int main(int argc, char *argv[]) { + wlr_log_init(WLR_DEBUG, NULL); + struct wl_display *display = wl_display_create(); + struct sample_state state = { + .default_color = { 0.25f, 0.25f, 0.25f, 1 }, + .clear_color = { 0.25f, 0.25f, 0.25f, 1 }, + .display = display, + }; + struct wlr_backend *wlr = wlr_backend_autocreate(display, NULL); + if (!wlr) { + exit(1); + } + wl_list_init(&state.cursors); + wl_list_init(&state.pointers); + wl_list_init(&state.outputs); + + state.layout = wlr_output_layout_create(); + + wl_signal_add(&wlr->events.new_output, &state.new_output); + state.new_output.notify = new_output_notify; + wl_signal_add(&wlr->events.new_input, &state.new_input); + state.new_input.notify = new_input_notify; + + clock_gettime(CLOCK_MONOTONIC, &state.last_frame); + + struct wlr_xcursor_theme *theme = wlr_xcursor_theme_load("default", 16); + if (!theme) { + wlr_log(WLR_ERROR, "Failed to load cursor theme"); + return 1; + } + state.xcursor = wlr_xcursor_theme_get_cursor(theme, "left_ptr"); + if (!state.xcursor) { + wlr_log(WLR_ERROR, "Failed to load left_ptr cursor"); + return 1; + } + + if (!wlr_backend_start(wlr)) { + wlr_log(WLR_ERROR, "Failed to start backend"); + wlr_backend_destroy(wlr); + exit(1); + } + wl_display_run(display); + wl_display_destroy(display); + + struct sample_cursor *cursor, *tmp_cursor; + wl_list_for_each_safe(cursor, tmp_cursor, &state.cursors, link) { + cursor_destroy(cursor); + } + + struct sample_pointer *pointer, *tmp_pointer; + wl_list_for_each_safe(pointer, tmp_pointer, &state.pointers, link) { + free(pointer); + } + + wlr_xcursor_theme_destroy(theme); + wlr_output_layout_destroy(state.layout); +} diff --git a/examples/output-layout.c b/examples/output-layout.c new file mode 100644 index 00000000..440b3188 --- /dev/null +++ b/examples/output-layout.c @@ -0,0 +1,295 @@ +#define _POSIX_C_SOURCE 200112L +#include <GLES2/gl2.h> +#include <limits.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <time.h> +#include <unistd.h> +#include <wayland-server-protocol.h> +#include <wayland-server.h> +#include <wlr/backend.h> +#include <wlr/backend/session.h> +#include <wlr/render/wlr_renderer.h> +#include <wlr/types/wlr_keyboard.h> +#include <wlr/types/wlr_matrix.h> +#include <wlr/types/wlr_input_device.h> +#include <wlr/types/wlr_output_layout.h> +#include <wlr/types/wlr_output.h> +#include <wlr/util/log.h> +#include <xkbcommon/xkbcommon.h> +#include "cat.h" + +struct sample_state { + struct wl_display *display; + struct wl_listener new_output; + struct wl_listener new_input; + struct wlr_renderer *renderer; + struct wlr_texture *cat_texture; + struct wlr_output_layout *layout; + float x_offs, y_offs; + float x_vel, y_vel; + struct timespec ts_last; +}; + +struct sample_output { + struct sample_state *sample; + struct wlr_output *output; + struct wl_listener frame; + struct wl_listener destroy; +}; + +struct sample_keyboard { + struct sample_state *sample; + struct wlr_input_device *device; + struct wl_listener key; + struct wl_listener destroy; +}; + +static void animate_cat(struct sample_state *sample, + struct wlr_output *output) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + long ms = (ts.tv_sec - sample->ts_last.tv_sec) * 1000 + + (ts.tv_nsec - sample->ts_last.tv_nsec) / 1000000; + // how many seconds have passed since the last time we animated + float seconds = ms / 1000.0f; + + if (seconds > 0.1f) { + // XXX when we switch vt, the rendering loop stops so try to detect + // that and pause when it happens. + seconds = 0.0f; + } + + // check for collisions and bounce + bool ur_collision = !wlr_output_layout_output_at(sample->layout, + sample->x_offs + 128, sample->y_offs); + bool ul_collision = !wlr_output_layout_output_at(sample->layout, + sample->x_offs, sample->y_offs); + bool ll_collision = !wlr_output_layout_output_at(sample->layout, + sample->x_offs, sample->y_offs + 128); + bool lr_collision = !wlr_output_layout_output_at(sample->layout, + sample->x_offs + 128, sample->y_offs + 128); + + if (ur_collision && ul_collision && ll_collision && lr_collision) { + // oops we went off the screen somehow + struct wlr_output_layout_output *l_output = + wlr_output_layout_get(sample->layout, output); + sample->x_offs = l_output->x + 20; + sample->y_offs = l_output->y + 20; + } else if (ur_collision && ul_collision) { + sample->y_vel = fabs(sample->y_vel); + } else if (lr_collision && ll_collision) { + sample->y_vel = -fabs(sample->y_vel); + } else if (ll_collision && ul_collision) { + sample->x_vel = fabs(sample->x_vel); + } else if (ur_collision && lr_collision) { + sample->x_vel = -fabs(sample->x_vel); + } else { + if (ur_collision || lr_collision) { + sample->x_vel = -fabs(sample->x_vel); + } + if (ul_collision || ll_collision) { + sample->x_vel = fabs(sample->x_vel); + } + if (ul_collision || ur_collision) { + sample->y_vel = fabs(sample->y_vel); + } + if (ll_collision || lr_collision) { + sample->y_vel = -fabs(sample->y_vel); + } + } + + sample->x_offs += sample->x_vel * seconds; + sample->y_offs += sample->y_vel * seconds; + sample->ts_last = ts; +} + +void output_frame_notify(struct wl_listener *listener, void *data) { + struct sample_output *output = wl_container_of(listener, output, frame); + struct sample_state *sample = output->sample; + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + + struct wlr_output *wlr_output = output->output; + + wlr_output_make_current(wlr_output, NULL); + wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); + wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); + + animate_cat(sample, output->output); + + struct wlr_box box = { + .x = sample->x_offs, .y = sample->y_offs, + .width = 128, .height = 128, + }; + if (wlr_output_layout_intersects(sample->layout, output->output, &box)) { + // transform global coordinates to local coordinates + double local_x = sample->x_offs; + double local_y = sample->y_offs; + wlr_output_layout_output_coords(sample->layout, output->output, + &local_x, &local_y); + + wlr_render_texture(sample->renderer, sample->cat_texture, + wlr_output->transform_matrix, local_x, local_y, 1.0f); + } + + wlr_renderer_end(sample->renderer); + wlr_output_swap_buffers(wlr_output, NULL, NULL); +} + +static void update_velocities(struct sample_state *sample, + float x_diff, float y_diff) { + sample->x_vel += x_diff; + sample->y_vel += y_diff; +} + +void output_remove_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = wl_container_of(listener, sample_output, destroy); + struct sample_state *sample = sample_output->sample; + wlr_output_layout_remove(sample->layout, sample_output->output); + wl_list_remove(&sample_output->frame.link); + wl_list_remove(&sample_output->destroy.link); + free(sample_output); +} + +void new_output_notify(struct wl_listener *listener, void *data) { + struct wlr_output *output = data; + struct sample_state *sample = wl_container_of(listener, sample, new_output); + struct sample_output *sample_output = calloc(1, sizeof(struct sample_output)); + if (!wl_list_empty(&output->modes)) { + struct wlr_output_mode *mode = wl_container_of(output->modes.prev, mode, link); + wlr_output_set_mode(output, mode); + } + wlr_output_layout_add_auto(sample->layout, output); + sample_output->output = output; + sample_output->sample = sample; + wl_signal_add(&output->events.frame, &sample_output->frame); + sample_output->frame.notify = output_frame_notify; + wl_signal_add(&output->events.destroy, &sample_output->destroy); + sample_output->destroy.notify = output_remove_notify; +} + +void keyboard_key_notify(struct wl_listener *listener, void *data) { + struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); + struct sample_state *sample = keyboard->sample; + struct wlr_event_keyboard_key *event = data; + uint32_t keycode = event->keycode + 8; + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, + keycode, &syms); + for (int i = 0; i < nsyms; i++) { + xkb_keysym_t sym = syms[i]; + if (sym == XKB_KEY_Escape) { + wl_display_terminate(sample->display); + } + // NOTE: It may be better to simply refer to our key state during each frame + // and make this change in pixels/sec^2 + // Also, key repeat + int delta = 75; + if (event->state == WLR_KEY_PRESSED) { + switch (sym) { + case XKB_KEY_Left: + update_velocities(sample, -delta, 0); + break; + case XKB_KEY_Right: + update_velocities(sample, delta, 0); + break; + case XKB_KEY_Up: + update_velocities(sample, 0, -delta); + break; + case XKB_KEY_Down: + update_velocities(sample, 0, delta); + break; + } + } + } +} + +void keyboard_destroy_notify(struct wl_listener *listener, void *data) { + struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, destroy); + wl_list_remove(&keyboard->destroy.link); + wl_list_remove(&keyboard->key.link); + free(keyboard); +} + +void new_input_notify(struct wl_listener *listener, void *data) { + struct wlr_input_device *device = data; + struct sample_state *sample = wl_container_of(listener, sample, new_input); + switch (device->type) { + case WLR_INPUT_DEVICE_KEYBOARD:; + struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); + keyboard->device = device; + keyboard->sample = sample; + wl_signal_add(&device->events.destroy, &keyboard->destroy); + keyboard->destroy.notify = keyboard_destroy_notify; + wl_signal_add(&device->keyboard->events.key, &keyboard->key); + keyboard->key.notify = keyboard_key_notify; + struct xkb_rule_names rules = { 0 }; + rules.rules = getenv("XKB_DEFAULT_RULES"); + rules.model = getenv("XKB_DEFAULT_MODEL"); + rules.layout = getenv("XKB_DEFAULT_LAYOUT"); + rules.variant = getenv("XKB_DEFAULT_VARIANT"); + rules.options = getenv("XKB_DEFAULT_OPTIONS"); + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!context) { + wlr_log(WLR_ERROR, "Failed to create XKB context"); + exit(1); + } + struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) { + wlr_log(WLR_ERROR, "Failed to create XKB keymap"); + exit(1); + } + wlr_keyboard_set_keymap(device->keyboard, keymap); + xkb_keymap_unref(keymap); + xkb_context_unref(context); + break; + default: + break; + } +} + + +int main(int argc, char *argv[]) { + wlr_log_init(WLR_DEBUG, NULL); + struct wl_display *display = wl_display_create(); + struct sample_state state = { + .x_vel = 500, + .y_vel = 500, + .display = display, + }; + + state.layout = wlr_output_layout_create(); + clock_gettime(CLOCK_MONOTONIC, &state.ts_last); + + struct wlr_backend *wlr = wlr_backend_autocreate(display, NULL); + if (!wlr) { + exit(1); + } + + wl_signal_add(&wlr->events.new_output, &state.new_output); + state.new_output.notify = new_output_notify; + wl_signal_add(&wlr->events.new_input, &state.new_input); + state.new_input.notify = new_input_notify; + + state.renderer = wlr_backend_get_renderer(wlr); + state.cat_texture = wlr_texture_from_pixels(state.renderer, + WL_SHM_FORMAT_ABGR8888, cat_tex.width * 4, cat_tex.width, cat_tex.height, + cat_tex.pixel_data); + + if (!wlr_backend_start(wlr)) { + wlr_log(WLR_ERROR, "Failed to start backend"); + wlr_backend_destroy(wlr); + exit(1); + } + wl_display_run(display); + + wlr_texture_destroy(state.cat_texture); + + wl_display_destroy(state.display); + wlr_output_layout_destroy(state.layout); +} diff --git a/examples/pointer-constraints.c b/examples/pointer-constraints.c new file mode 100644 index 00000000..1df9f6ce --- /dev/null +++ b/examples/pointer-constraints.c @@ -0,0 +1,260 @@ +#include <GLES2/gl2.h> +#include <linux/input-event-codes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wayland-client.h> +#include <wayland-egl.h> +#include <wlr/render/egl.h> +#include "xdg-shell-client-protocol.h" +#include "pointer-constraints-unstable-v1-client-protocol.h" + +static int width = 512, height = 512; + +static struct wl_compositor *compositor = NULL; +static struct wl_seat *seat = NULL; +static struct xdg_wm_base *wm_base = NULL; +static struct zwp_pointer_constraints_v1 *pointer_constraints = NULL; + +struct wlr_egl egl; +struct wl_egl_window *egl_window; +struct wlr_egl_surface *egl_surface; +struct zwp_locked_pointer_v1* locked_pointer; +struct zwp_confined_pointer_v1* confined_pointer; + +enum { + REGION_TYPE_NONE, + REGION_TYPE_DISJOINT, + REGION_TYPE_JOINT, + REGION_TYPE_MAX +} region_type = REGION_TYPE_NONE; + +struct wl_region *regions[3]; + +static void draw(void) { + eglMakeCurrent(egl.display, egl_surface, egl_surface, egl.context); + + float color[] = {1.0, 1.0, 0.0, 1.0}; + + glViewport(0, 0, width, height); + glClearColor(color[0], color[1], color[2], 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + eglSwapBuffers(egl.display, egl_surface); +} + +static void pointer_handle_button(void *data, struct wl_pointer *pointer, + uint32_t serial, uint32_t time, uint32_t button, uint32_t state_w) { + struct wl_surface *surface = data; + + if (button == BTN_LEFT && state_w == WL_POINTER_BUTTON_STATE_PRESSED) { + region_type = (region_type + 1) % REGION_TYPE_MAX; + + if (locked_pointer) { + zwp_locked_pointer_v1_set_region(locked_pointer, + regions[region_type]); + } else if (confined_pointer) { + zwp_confined_pointer_v1_set_region(confined_pointer, + regions[region_type]); + } + + wl_surface_commit(surface); + } +} + +static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, struct wl_surface *surface, + wl_fixed_t surface_x, wl_fixed_t surface_y) { + // This space intentionally left blank +} + +static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, struct wl_surface *surface) { + // This space intentionally left blank +} + +static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, + uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { + // This space intentionally left blank +} + +static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, + uint32_t time, uint32_t axis, wl_fixed_t value) { + // This space intentionally left blank +} + +static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) { + // This space intentionally left blank +} + +static void pointer_handle_axis_source(void *data, + struct wl_pointer *wl_pointer, uint32_t axis_source) { + // This space intentionally left blank +} + +static void pointer_handle_axis_stop(void *data, + struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis) { + // This space intentionally left blank +} + +static void pointer_handle_axis_discrete(void *data, + struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete) { + // This space intentionally left blank +} + +static const struct wl_pointer_listener pointer_listener = { + .enter = pointer_handle_enter, + .leave = pointer_handle_leave, + .motion = pointer_handle_motion, + .button = pointer_handle_button, + .axis = pointer_handle_axis, + .frame = pointer_handle_frame, + .axis_source = pointer_handle_axis_source, + .axis_stop = pointer_handle_axis_stop, + .axis_discrete = pointer_handle_axis_discrete, +}; + +static void xdg_surface_handle_configure(void *data, + struct xdg_surface *xdg_surface, uint32_t serial) { + xdg_surface_ack_configure(xdg_surface, serial); + wl_egl_window_resize(egl_window, width, height, 0, 0); + draw(); +} + +static const struct xdg_surface_listener xdg_surface_listener = { + .configure = xdg_surface_handle_configure, +}; + +static void xdg_toplevel_handle_configure(void *data, + struct xdg_toplevel *xdg_toplevel, int32_t w, int32_t h, + struct wl_array *states) { + width = w; + height = h; +} + +static void xdg_toplevel_handle_close(void *data, + struct xdg_toplevel *xdg_toplevel) { + exit(EXIT_SUCCESS); +} + +static const struct xdg_toplevel_listener xdg_toplevel_listener = { + .configure = xdg_toplevel_handle_configure, + .close = xdg_toplevel_handle_close, +}; + +static void handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) { + if (strcmp(interface, wl_compositor_interface.name) == 0) { + compositor = wl_registry_bind(registry, name, + &wl_compositor_interface, 1); + } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { + wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); + } else if (strcmp(interface, wl_seat_interface.name) == 0) { + seat = wl_registry_bind(registry, name, &wl_seat_interface, version); + } else if (strcmp(interface, + zwp_pointer_constraints_v1_interface.name) == 0) { + pointer_constraints = wl_registry_bind(registry, name, + &zwp_pointer_constraints_v1_interface, version); + } +} + +static const struct wl_registry_listener registry_listener = { + .global = handle_global, + .global_remove = NULL, +}; + +int main(int argc, char **argv) { + if (argc != 4) { + goto invalid_args; + } + + bool lock; + if (strcmp(argv[1], "lock") == 0) { + lock = true; + } else if (strcmp(argv[1], "confine") == 0) { + lock = false; + } else { + goto invalid_args; + } + + enum zwp_pointer_constraints_v1_lifetime lifetime; + if (strcmp(argv[2], "oneshot") == 0) { + lifetime = ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT; + } else if (strcmp(argv[2], "persistent") == 0) { + lifetime = ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT; + } else { + goto invalid_args; + } + + if (strcmp(argv[3], "no-region") == 0) { + region_type = REGION_TYPE_NONE; + } else if (strcmp(argv[3], "disjoint-region") == 0) { + region_type = REGION_TYPE_DISJOINT; + } else if (strcmp(argv[3], "joint-region") == 0) { + region_type = REGION_TYPE_JOINT; + } + + struct wl_display *display = wl_display_connect(NULL); + + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_dispatch(display); + wl_display_roundtrip(display); + + struct wl_region *disjoint_region = wl_compositor_create_region(compositor); + wl_region_add(disjoint_region, 0, 0, 255, 256); + wl_region_add(disjoint_region, 257, 0, 255, 256); + regions[REGION_TYPE_DISJOINT] = disjoint_region; + + struct wl_region *joint_region = wl_compositor_create_region(compositor); + wl_region_add(joint_region, 0, 0, 256, 256); + wl_region_add(joint_region, 256, 0, 256, 256); + wl_region_add(joint_region, 256, 256, 256, 256); + regions[REGION_TYPE_JOINT] = joint_region; + + wlr_egl_init(&egl, EGL_PLATFORM_WAYLAND_EXT, display, NULL, + WL_SHM_FORMAT_ARGB8888); + + struct wl_surface *surface = wl_compositor_create_surface(compositor); + struct xdg_surface *xdg_surface = + xdg_wm_base_get_xdg_surface(wm_base, surface); + struct xdg_toplevel *xdg_toplevel = xdg_surface_get_toplevel(xdg_surface); + + xdg_surface_add_listener(xdg_surface, &xdg_surface_listener, NULL); + xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, NULL); + + struct wl_pointer *pointer = wl_seat_get_pointer(seat); + wl_pointer_add_listener(pointer, &pointer_listener, surface); + + if (lock) { + locked_pointer = zwp_pointer_constraints_v1_lock_pointer( + pointer_constraints, surface, pointer, + regions[region_type], lifetime); + + zwp_locked_pointer_v1_set_cursor_position_hint(locked_pointer, + wl_fixed_from_int(128), wl_fixed_from_int(128)); + } else { + confined_pointer = zwp_pointer_constraints_v1_confine_pointer( + pointer_constraints, surface, pointer, + regions[region_type], lifetime); + } + + wl_surface_commit(surface); + + egl_window = wl_egl_window_create(surface, width, height); + egl_surface = wlr_egl_create_surface(&egl, egl_window); + + wl_display_roundtrip(display); + + draw(); + + while (wl_display_dispatch(display) != -1) {} + + return EXIT_SUCCESS; + +invalid_args: + fprintf(stderr, "pointer-constraints <lock | confine> " + "<oneshot | persistent> " + "<no-region | disjoint-rejoin | joint-region>\n"); + return EXIT_FAILURE; +} diff --git a/examples/pointer.c b/examples/pointer.c new file mode 100644 index 00000000..cc58c223 --- /dev/null +++ b/examples/pointer.c @@ -0,0 +1,403 @@ +#define _POSIX_C_SOURCE 200112L +#include <assert.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <wayland-server-protocol.h> +#include <wayland-server.h> +#include <wlr/backend.h> +#include <wlr/backend/session.h> +#include <wlr/render/gles2.h> +#include <wlr/render/wlr_renderer.h> +#include <wlr/types/wlr_cursor.h> +#include <wlr/types/wlr_keyboard.h> +#include <wlr/types/wlr_list.h> +#include <wlr/types/wlr_matrix.h> +#include <wlr/types/wlr_output_layout.h> +#include <wlr/types/wlr_xcursor_manager.h> +#include <wlr/util/log.h> +#include <xkbcommon/xkbcommon.h> + +struct sample_state { + struct wl_display *display; + struct compositor_state *compositor; + struct wlr_xcursor_manager *xcursor_manager; + struct wlr_cursor *cursor; + double cur_x, cur_y; + float default_color[4]; + float clear_color[4]; + struct wlr_output_layout *layout; + struct wl_list devices; + struct timespec last_frame; + + struct wl_listener new_output; + struct wl_listener new_input; + struct wl_listener cursor_motion; + struct wl_listener cursor_motion_absolute; + struct wl_listener cursor_button; + struct wl_listener cursor_axis; + + struct wl_listener touch_motion; + struct wl_listener touch_up; + struct wl_listener touch_down; + struct wl_listener touch_cancel; + struct wl_list touch_points; + + struct wl_listener tablet_tool_axis; + struct wl_listener tablet_tool_proxmity; + struct wl_listener tablet_tool_tip; + struct wl_listener tablet_tool_button; +}; + +struct touch_point { + int32_t touch_id; + double x, y; + struct wl_list link; +}; + +struct sample_output { + struct sample_state *state; + struct wlr_output *output; + struct wl_listener frame; + struct wl_listener destroy; +}; + +struct sample_keyboard { + struct sample_state *state; + struct wlr_input_device *device; + struct wl_listener key; + struct wl_listener destroy; +}; + +static void warp_to_touch(struct sample_state *state, + struct wlr_input_device *dev) { + if (wl_list_empty(&state->touch_points)) { + return; + } + + double x = 0, y = 0; + size_t n = 0; + struct touch_point *point; + wl_list_for_each(point, &state->touch_points, link) { + x += point->x; + y += point->y; + n++; + } + x /= n; + y /= n; + wlr_cursor_warp_absolute(state->cursor, dev, x, y); +} + +void output_frame_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = wl_container_of(listener, sample_output, frame); + struct sample_state *state = sample_output->state; + struct wlr_output *wlr_output = sample_output->output; + struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); + assert(renderer); + + wlr_output_make_current(wlr_output, NULL); + wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); + wlr_renderer_clear(renderer, state->clear_color); + wlr_output_swap_buffers(wlr_output, NULL, NULL); + wlr_renderer_end(renderer); +} + +static void handle_cursor_motion(struct wl_listener *listener, void *data) { + struct sample_state *sample = + wl_container_of(listener, sample, cursor_motion); + struct wlr_event_pointer_motion *event = data; + wlr_cursor_move(sample->cursor, event->device, event->delta_x, + event->delta_y); +} + +static void handle_cursor_motion_absolute(struct wl_listener *listener, + void *data) { + struct sample_state *sample = + wl_container_of(listener, sample, cursor_motion_absolute); + struct wlr_event_pointer_motion_absolute *event = data; + + sample->cur_x = event->x; + sample->cur_y = event->y; + + wlr_cursor_warp_absolute(sample->cursor, event->device, sample->cur_x, + sample->cur_y); +} + +static void handle_cursor_button(struct wl_listener *listener, void *data) { + struct sample_state *sample = + wl_container_of(listener, sample, cursor_button); + struct wlr_event_pointer_button *event = data; + + float (*color)[4]; + if (event->state == WLR_BUTTON_RELEASED) { + color = &sample->default_color; + memcpy(&sample->clear_color, color, sizeof(*color)); + } else { + float red[4] = { 0.25f, 0.25f, 0.25f, 1 }; + red[event->button % 3] = 1; + color = &red; + memcpy(&sample->clear_color, color, sizeof(*color)); + } +} + +static void handle_cursor_axis(struct wl_listener *listener, void *data) { + struct sample_state *sample = + wl_container_of(listener, sample, cursor_axis); + struct wlr_event_pointer_axis *event = data; + + for (size_t i = 0; i < 3; ++i) { + sample->default_color[i] += event->delta > 0 ? -0.05f : 0.05f; + if (sample->default_color[i] > 1.0f) { + sample->default_color[i] = 1.0f; + } + if (sample->default_color[i] < 0.0f) { + sample->default_color[i] = 0.0f; + } + } + + memcpy(&sample->clear_color, &sample->default_color, + sizeof(sample->clear_color)); +} + +static void handle_touch_up(struct wl_listener *listener, void *data) { + struct sample_state *sample = wl_container_of(listener, sample, touch_up); + struct wlr_event_touch_up *event = data; + + struct touch_point *point, *tmp; + wl_list_for_each_safe(point, tmp, &sample->touch_points, link) { + if (point->touch_id == event->touch_id) { + wl_list_remove(&point->link); + break; + } + } + + warp_to_touch(sample, event->device); +} + +static void handle_touch_down(struct wl_listener *listener, void *data) { + struct sample_state *sample = wl_container_of(listener, sample, touch_down); + struct wlr_event_touch_down *event = data; + struct touch_point *point = calloc(1, sizeof(struct touch_point)); + point->touch_id = event->touch_id; + point->x = event->x; + point->y = event->y; + wl_list_insert(&sample->touch_points, &point->link); + + warp_to_touch(sample, event->device); +} + +static void handle_touch_motion(struct wl_listener *listener, void *data) { + struct sample_state *sample = + wl_container_of(listener, sample, touch_motion); + struct wlr_event_touch_motion *event = data; + + struct touch_point *point; + wl_list_for_each(point, &sample->touch_points, link) { + if (point->touch_id == event->touch_id) { + point->x = event->x; + point->y = event->y; + break; + } + } + + warp_to_touch(sample, event->device); +} + +static void handle_touch_cancel(struct wl_listener *listener, void *data) { + wlr_log(WLR_DEBUG, "TODO: touch cancel"); +} + +static void handle_tablet_tool_axis(struct wl_listener *listener, void *data) { + struct sample_state *sample = + wl_container_of(listener, sample, tablet_tool_axis); + struct wlr_event_tablet_tool_axis *event = data; + if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X) && + (event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { + wlr_cursor_warp_absolute(sample->cursor, + event->device, event->x, event->y); + } +} + +void keyboard_key_notify(struct wl_listener *listener, void *data) { + struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); + struct sample_state *sample = keyboard->state; + struct wlr_event_keyboard_key *event = data; + uint32_t keycode = event->keycode + 8; + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, + keycode, &syms); + for (int i = 0; i < nsyms; i++) { + xkb_keysym_t sym = syms[i]; + if (sym == XKB_KEY_Escape) { + wl_display_terminate(sample->display); + } + } +} + +void output_remove_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = wl_container_of(listener, sample_output, destroy); + struct sample_state *sample = sample_output->state; + wlr_output_layout_remove(sample->layout, sample_output->output); + wl_list_remove(&sample_output->frame.link); + wl_list_remove(&sample_output->destroy.link); + free(sample_output); +} + +void new_output_notify(struct wl_listener *listener, void *data) { + struct wlr_output *output = data; + struct sample_state *sample = wl_container_of(listener, sample, new_output); + struct sample_output *sample_output = calloc(1, sizeof(struct sample_output)); + if (!wl_list_empty(&output->modes)) { + struct wlr_output_mode *mode = wl_container_of(output->modes.prev, mode, link); + wlr_output_set_mode(output, mode); + } + sample_output->output = output; + sample_output->state = sample; + wl_signal_add(&output->events.frame, &sample_output->frame); + sample_output->frame.notify = output_frame_notify; + wl_signal_add(&output->events.destroy, &sample_output->destroy); + sample_output->destroy.notify = output_remove_notify; + wlr_output_layout_add_auto(sample->layout, sample_output->output); + + wlr_xcursor_manager_load(sample->xcursor_manager, output->scale); + wlr_xcursor_manager_set_cursor_image(sample->xcursor_manager, "left_ptr", + sample->cursor); +} + + +void keyboard_destroy_notify(struct wl_listener *listener, void *data) { + struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, destroy); + wl_list_remove(&keyboard->destroy.link); + wl_list_remove(&keyboard->key.link); + free(keyboard); +} + +void new_input_notify(struct wl_listener *listener, void *data) { + struct wlr_input_device *device = data; + struct sample_state *state = wl_container_of(listener, state, new_input); + switch (device->type) { + case WLR_INPUT_DEVICE_POINTER: + case WLR_INPUT_DEVICE_TOUCH: + case WLR_INPUT_DEVICE_TABLET_TOOL: + wlr_cursor_attach_input_device(state->cursor, device); + break; + + case WLR_INPUT_DEVICE_KEYBOARD:; + struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); + keyboard->device = device; + keyboard->state = state; + wl_signal_add(&device->events.destroy, &keyboard->destroy); + keyboard->destroy.notify = keyboard_destroy_notify; + wl_signal_add(&device->keyboard->events.key, &keyboard->key); + keyboard->key.notify = keyboard_key_notify; + struct xkb_rule_names rules = { 0 }; + rules.rules = getenv("XKB_DEFAULT_RULES"); + rules.model = getenv("XKB_DEFAULT_MODEL"); + rules.layout = getenv("XKB_DEFAULT_LAYOUT"); + rules.variant = getenv("XKB_DEFAULT_VARIANT"); + rules.options = getenv("XKB_DEFAULT_OPTIONS"); + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!context) { + wlr_log(WLR_ERROR, "Failed to create XKB context"); + exit(1); + } + struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) { + wlr_log(WLR_ERROR, "Failed to create XKB keymap"); + exit(1); + } + wlr_keyboard_set_keymap(device->keyboard, keymap); + xkb_keymap_unref(keymap); + xkb_context_unref(context); + break; + default: + break; + } +} + + +int main(int argc, char *argv[]) { + wlr_log_init(WLR_DEBUG, NULL); + struct wl_display *display = wl_display_create(); + struct sample_state state = { + .default_color = { 0.25f, 0.25f, 0.25f, 1 }, + .clear_color = { 0.25f, 0.25f, 0.25f, 1 }, + .display = display + }; + + struct wlr_backend *wlr = wlr_backend_autocreate(display, NULL); + if (!wlr) { + exit(1); + } + state.cursor = wlr_cursor_create(); + state.layout = wlr_output_layout_create(); + wlr_cursor_attach_output_layout(state.cursor, state.layout); + //wlr_cursor_map_to_region(state.cursor, state.config->cursor.mapped_box); + wl_list_init(&state.devices); + wl_list_init(&state.touch_points); + + // pointer events + wl_signal_add(&state.cursor->events.motion, &state.cursor_motion); + state.cursor_motion.notify = handle_cursor_motion; + + wl_signal_add(&state.cursor->events.motion_absolute, + &state.cursor_motion_absolute); + state.cursor_motion_absolute.notify = handle_cursor_motion_absolute; + + wl_signal_add(&state.cursor->events.button, &state.cursor_button); + state.cursor_button.notify = handle_cursor_button; + + wl_signal_add(&state.cursor->events.axis, &state.cursor_axis); + state.cursor_axis.notify = handle_cursor_axis; + + // touch events + wl_signal_add(&state.cursor->events.touch_up, &state.touch_up); + state.touch_up.notify = handle_touch_up; + + wl_signal_add(&state.cursor->events.touch_down, &state.touch_down); + state.touch_down.notify = handle_touch_down; + + wl_signal_add(&state.cursor->events.touch_motion, &state.touch_motion); + state.touch_motion.notify = handle_touch_motion; + + wl_signal_add(&state.cursor->events.touch_cancel, &state.touch_cancel); + state.touch_cancel.notify = handle_touch_cancel; + + wl_signal_add(&wlr->events.new_input, &state.new_input); + state.new_input.notify = new_input_notify; + + wl_signal_add(&wlr->events.new_output, &state.new_output); + state.new_output.notify = new_output_notify; + + // tool events + wl_signal_add(&state.cursor->events.tablet_tool_axis, + &state.tablet_tool_axis); + state.tablet_tool_axis.notify = handle_tablet_tool_axis; + + state.xcursor_manager = wlr_xcursor_manager_create("default", 24); + if (!state.xcursor_manager) { + wlr_log(WLR_ERROR, "Failed to load left_ptr cursor"); + return 1; + } + + wlr_xcursor_manager_set_cursor_image(state.xcursor_manager, "left_ptr", + state.cursor); + + clock_gettime(CLOCK_MONOTONIC, &state.last_frame); + + if (!wlr_backend_start(wlr)) { + wlr_log(WLR_ERROR, "Failed to start backend"); + wlr_backend_destroy(wlr); + exit(1); + } + wl_display_run(display); + wl_display_destroy(display); + + wlr_xcursor_manager_destroy(state.xcursor_manager); + wlr_cursor_destroy(state.cursor); + wlr_output_layout_destroy(state.layout); +} diff --git a/examples/rotation.c b/examples/rotation.c new file mode 100644 index 00000000..7cf5727b --- /dev/null +++ b/examples/rotation.c @@ -0,0 +1,277 @@ +#define _POSIX_C_SOURCE 200112L +#include <GLES2/gl2.h> +#include <getopt.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <time.h> +#include <unistd.h> +#include <wayland-server-protocol.h> +#include <wayland-server.h> +#include <wlr/backend.h> +#include <wlr/backend/session.h> +#include <wlr/render/wlr_renderer.h> +#include <wlr/types/wlr_keyboard.h> +#include <wlr/types/wlr_output.h> +#include <wlr/types/wlr_output_layout.h> +#include <wlr/types/wlr_input_device.h> +#include <wlr/types/wlr_matrix.h> +#include <wlr/util/log.h> +#include <xkbcommon/xkbcommon.h> +#include "cat.h" + +struct sample_state { + struct wl_display *display; + struct wl_listener new_output; + struct wl_listener new_input; + struct timespec last_frame; + struct wlr_renderer *renderer; + struct wlr_texture *cat_texture; + struct wl_list outputs; + enum wl_output_transform transform; +}; + +struct sample_output { + struct sample_state *sample; + struct wlr_output *output; + struct wl_listener frame; + struct wl_listener destroy; + float x_offs, y_offs; + float x_vel, y_vel; + struct wl_list link; +}; + +struct sample_keyboard { + struct sample_state *sample; + struct wlr_input_device *device; + struct wl_listener key; + struct wl_listener destroy; +}; + +static void output_frame_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = wl_container_of(listener, sample_output, frame); + struct sample_state *sample = sample_output->sample; + struct wlr_output *wlr_output = sample_output->output; + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + int32_t width, height; + wlr_output_effective_resolution(wlr_output, &width, &height); + + wlr_output_make_current(wlr_output, NULL); + wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); + wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); + + for (int y = -128 + (int)sample_output->y_offs; y < height; y += 128) { + for (int x = -128 + (int)sample_output->x_offs; x < width; x += 128) { + wlr_render_texture(sample->renderer, sample->cat_texture, + wlr_output->transform_matrix, x, y, 1.0f); + } + } + + wlr_renderer_end(sample->renderer); + wlr_output_swap_buffers(wlr_output, NULL, NULL); + + long ms = (now.tv_sec - sample->last_frame.tv_sec) * 1000 + + (now.tv_nsec - sample->last_frame.tv_nsec) / 1000000; + float seconds = ms / 1000.0f; + + sample_output->x_offs += sample_output->x_vel * seconds; + sample_output->y_offs += sample_output->y_vel * seconds; + if (sample_output->x_offs > 128) { + sample_output->x_offs = 0; + } + if (sample_output->y_offs > 128) { + sample_output->y_offs = 0; + } + sample->last_frame = now; +} + +static void update_velocities(struct sample_state *sample, + float x_diff, float y_diff) { + struct sample_output *sample_output; + wl_list_for_each(sample_output, &sample->outputs, link) { + sample_output->x_vel += x_diff; + sample_output->y_vel += y_diff; + } +} + +void output_remove_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = wl_container_of(listener, sample_output, destroy); + wl_list_remove(&sample_output->frame.link); + wl_list_remove(&sample_output->destroy.link); + free(sample_output); +} + +void new_output_notify(struct wl_listener *listener, void *data) { + struct wlr_output *output = data; + struct sample_state *sample = wl_container_of(listener, sample, new_output); + struct sample_output *sample_output = calloc(1, sizeof(struct sample_output)); + if (!wl_list_empty(&output->modes)) { + struct wlr_output_mode *mode = wl_container_of(output->modes.prev, mode, link); + wlr_output_set_mode(output, mode); + } + sample_output->x_offs = sample_output->y_offs = 0; + sample_output->x_vel = sample_output->y_vel = 128; + + wlr_output_set_transform(output, sample->transform); + sample_output->output = output; + sample_output->sample = sample; + wl_signal_add(&output->events.frame, &sample_output->frame); + sample_output->frame.notify = output_frame_notify; + wl_signal_add(&output->events.destroy, &sample_output->destroy); + sample_output->destroy.notify = output_remove_notify; + wl_list_insert(&sample->outputs, &sample_output->link); +} + +void keyboard_key_notify(struct wl_listener *listener, void *data) { + struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); + struct sample_state *sample = keyboard->sample; + struct wlr_event_keyboard_key *event = data; + uint32_t keycode = event->keycode + 8; + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, + keycode, &syms); + for (int i = 0; i < nsyms; i++) { + xkb_keysym_t sym = syms[i]; + if (sym == XKB_KEY_Escape) { + wl_display_terminate(sample->display); + } + if (event->state == WLR_KEY_PRESSED) { + switch (sym) { + case XKB_KEY_Left: + update_velocities(sample, -16, 0); + break; + case XKB_KEY_Right: + update_velocities(sample, 16, 0); + break; + case XKB_KEY_Up: + update_velocities(sample, 0, -16); + break; + case XKB_KEY_Down: + update_velocities(sample, 0, 16); + break; + } + } + } +} + +void keyboard_destroy_notify(struct wl_listener *listener, void *data) { + struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, destroy); + wl_list_remove(&keyboard->destroy.link); + wl_list_remove(&keyboard->key.link); + free(keyboard); +} + +void new_input_notify(struct wl_listener *listener, void *data) { + struct wlr_input_device *device = data; + struct sample_state *sample = wl_container_of(listener, sample, new_input); + switch (device->type) { + case WLR_INPUT_DEVICE_KEYBOARD:; + struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); + keyboard->device = device; + keyboard->sample = sample; + wl_signal_add(&device->events.destroy, &keyboard->destroy); + keyboard->destroy.notify = keyboard_destroy_notify; + wl_signal_add(&device->keyboard->events.key, &keyboard->key); + keyboard->key.notify = keyboard_key_notify; + struct xkb_rule_names rules = { 0 }; + rules.rules = getenv("XKB_DEFAULT_RULES"); + rules.model = getenv("XKB_DEFAULT_MODEL"); + rules.layout = getenv("XKB_DEFAULT_LAYOUT"); + rules.variant = getenv("XKB_DEFAULT_VARIANT"); + rules.options = getenv("XKB_DEFAULT_OPTIONS"); + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!context) { + wlr_log(WLR_ERROR, "Failed to create XKB context"); + exit(1); + } + struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) { + wlr_log(WLR_ERROR, "Failed to create XKB keymap"); + exit(1); + } + wlr_keyboard_set_keymap(device->keyboard, keymap); + xkb_keymap_unref(keymap); + xkb_context_unref(context); + break; + default: + break; + } +} + + +int main(int argc, char *argv[]) { + int c; + enum wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; + while ((c = getopt(argc, argv, "r:")) != -1) { + switch (c) { + case 'r': + if (strcmp(optarg, "90") == 0) { + transform = WL_OUTPUT_TRANSFORM_90; + } else if (strcmp(optarg, "180") == 0) { + transform = WL_OUTPUT_TRANSFORM_180; + } else if (strcmp(optarg, "270") == 0) { + transform = WL_OUTPUT_TRANSFORM_270; + } else if (strcmp(optarg, "flipped") == 0) { + transform = WL_OUTPUT_TRANSFORM_FLIPPED; + } else if (strcmp(optarg, "flipped-90") == 0) { + transform = WL_OUTPUT_TRANSFORM_FLIPPED_90; + } else if (strcmp(optarg, "flipped-180") == 0) { + transform = WL_OUTPUT_TRANSFORM_FLIPPED_180; + } else if (strcmp(optarg, "flipped-270") == 0) { + transform = WL_OUTPUT_TRANSFORM_FLIPPED_270; + } else { + wlr_log(WLR_ERROR, "got unknown transform value: %s", optarg); + } + break; + default: + break; + } + } + wlr_log_init(WLR_DEBUG, NULL); + struct wl_display *display = wl_display_create(); + struct sample_state state = { + .display = display, + .transform = transform + }; + wl_list_init(&state.outputs); + + struct wlr_backend *wlr = wlr_backend_autocreate(display, NULL); + if (!wlr) { + exit(1); + } + + wl_signal_add(&wlr->events.new_output, &state.new_output); + state.new_output.notify = new_output_notify; + wl_signal_add(&wlr->events.new_input, &state.new_input); + state.new_input.notify = new_input_notify; + clock_gettime(CLOCK_MONOTONIC, &state.last_frame); + + state.renderer = wlr_backend_get_renderer(wlr); + if (!state.renderer) { + wlr_log(WLR_ERROR, "Could not start compositor, OOM"); + wlr_backend_destroy(wlr); + exit(EXIT_FAILURE); + } + state.cat_texture = wlr_texture_from_pixels(state.renderer, + WL_SHM_FORMAT_ABGR8888, cat_tex.width * 4, cat_tex.width, cat_tex.height, + cat_tex.pixel_data); + if (!state.cat_texture) { + wlr_log(WLR_ERROR, "Could not start compositor, OOM"); + exit(EXIT_FAILURE); + } + + if (!wlr_backend_start(wlr)) { + wlr_log(WLR_ERROR, "Failed to start backend"); + wlr_backend_destroy(wlr); + exit(1); + } + wl_display_run(display); + + wlr_texture_destroy(state.cat_texture); + wl_display_destroy(display); +} diff --git a/examples/screencopy.c b/examples/screencopy.c new file mode 100644 index 00000000..82edcb9c --- /dev/null +++ b/examples/screencopy.c @@ -0,0 +1,261 @@ +/* + * Copyright © 2008 Kristian Høgsberg + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#define _POSIX_C_SOURCE 200112L +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <png.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/param.h> +#include <sys/wait.h> +#include <unistd.h> +#include <wayland-client-protocol.h> +#include "wlr-screencopy-unstable-v1-client-protocol.h" + +struct format { + enum wl_shm_format wl_format; + bool is_bgr; +}; + +static struct wl_shm *shm = NULL; +static struct zwlr_screencopy_manager_v1 *screencopy_manager = NULL; +static struct wl_output *output = NULL; + +static struct { + struct wl_buffer *wl_buffer; + void *data; + enum wl_shm_format format; + int width, height, stride; + bool y_invert; +} buffer; +bool buffer_copy_done = false; + +// wl_shm_format describes little-endian formats, libpng uses big-endian +// formats (so Wayland's ABGR is libpng's RGBA). +static const struct format formats[] = { + {WL_SHM_FORMAT_XRGB8888, true}, + {WL_SHM_FORMAT_ARGB8888, true}, + {WL_SHM_FORMAT_XBGR8888, false}, + {WL_SHM_FORMAT_ABGR8888, false}, +}; + +static struct wl_buffer *create_shm_buffer(enum wl_shm_format fmt, + int width, int height, int stride, void **data_out) { + int size = stride * height; + + const char shm_name[] = "/wlroots-screencopy"; + int fd = shm_open(shm_name, O_RDWR | O_CREAT | O_EXCL, 0); + if (fd < 0) { + fprintf(stderr, "shm_open failed\n"); + return NULL; + } + shm_unlink(shm_name); + + int ret; + while ((ret = ftruncate(fd, size)) == EINTR) { + // No-op + } + if (ret < 0) { + close(fd); + fprintf(stderr, "ftruncate failed\n"); + return NULL; + } + + void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) { + fprintf(stderr, "mmap failed: %m\n"); + close(fd); + return NULL; + } + + struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size); + close(fd); + struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0, width, height, + stride, fmt); + wl_shm_pool_destroy(pool); + + *data_out = data; + return buffer; +} + +static void frame_handle_buffer(void *data, + struct zwlr_screencopy_frame_v1 *frame, uint32_t format, + uint32_t width, uint32_t height, uint32_t stride) { + buffer.format = format; + buffer.width = width; + buffer.height = height; + buffer.stride = stride; + buffer.wl_buffer = + create_shm_buffer(format, width, height, stride, &buffer.data); + if (buffer.wl_buffer == NULL) { + fprintf(stderr, "failed to create buffer\n"); + exit(EXIT_FAILURE); + } + + zwlr_screencopy_frame_v1_copy(frame, buffer.wl_buffer); +} + +static void frame_handle_flags(void *data, + struct zwlr_screencopy_frame_v1 *frame, uint32_t flags) { + buffer.y_invert = flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT; +} + +static void frame_handle_ready(void *data, + struct zwlr_screencopy_frame_v1 *frame, uint32_t tv_sec_hi, + uint32_t tv_sec_lo, uint32_t tv_nsec) { + buffer_copy_done = true; +} + +static void frame_handle_failed(void *data, + struct zwlr_screencopy_frame_v1 *frame) { + fprintf(stderr, "failed to copy frame\n"); + exit(EXIT_FAILURE); +} + +static const struct zwlr_screencopy_frame_v1_listener frame_listener = { + .buffer = frame_handle_buffer, + .flags = frame_handle_flags, + .ready = frame_handle_ready, + .failed = frame_handle_failed, +}; + +static void handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) { + if (strcmp(interface, wl_output_interface.name) == 0 && output == NULL) { + output = wl_registry_bind(registry, name, &wl_output_interface, 1); + } else if (strcmp(interface, wl_shm_interface.name) == 0) { + shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); + } else if (strcmp(interface, + zwlr_screencopy_manager_v1_interface.name) == 0) { + screencopy_manager = wl_registry_bind(registry, name, + &zwlr_screencopy_manager_v1_interface, 1); + } +} + +static void handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) { + // Who cares? +} + +static const struct wl_registry_listener registry_listener = { + .global = handle_global, + .global_remove = handle_global_remove, +}; + +static void write_image(char *filename, enum wl_shm_format wl_fmt, int width, + int height, int stride, bool y_invert, png_bytep data) { + const struct format *fmt = NULL; + for (size_t i = 0; i < sizeof(formats) / sizeof(formats[0]); ++i) { + if (formats[i].wl_format == wl_fmt) { + fmt = &formats[i]; + break; + } + } + if (fmt == NULL) { + fprintf(stderr, "unsupported format %"PRIu32"\n", wl_fmt); + exit(EXIT_FAILURE); + } + + FILE *f = fopen(filename, "wb"); + if (f == NULL) { + fprintf(stderr, "failed to open output file\n"); + exit(EXIT_FAILURE); + } + + png_structp png = + png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + png_infop info = png_create_info_struct(png); + + png_init_io(png, f); + + png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_RGBA, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + if (fmt->is_bgr) { + png_set_bgr(png); + } + + png_write_info(png, info); + + for (size_t i = 0; i < (size_t)height; ++i) { + png_bytep row; + if (y_invert) { + row = data + (height - i - 1) * stride; + } else { + row = data + i * stride; + } + png_write_row(png, row); + } + + png_write_end(png, NULL); + + png_destroy_write_struct(&png, &info); + + fclose(f); +} + +int main(int argc, char *argv[]) { + struct wl_display * display = wl_display_connect(NULL); + if (display == NULL) { + fprintf(stderr, "failed to create display: %m\n"); + return EXIT_FAILURE; + } + + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_dispatch(display); + wl_display_roundtrip(display); + + if (shm == NULL) { + fprintf(stderr, "compositor is missing wl_shm\n"); + return EXIT_FAILURE; + } + if (screencopy_manager == NULL) { + fprintf(stderr, "compositor doesn't support wlr-screencopy-unstable-v1\n"); + return EXIT_FAILURE; + } + if (output == NULL) { + fprintf(stderr, "no output available\n"); + return EXIT_FAILURE; + } + + struct zwlr_screencopy_frame_v1 *frame = + zwlr_screencopy_manager_v1_capture_output(screencopy_manager, 0, output); + zwlr_screencopy_frame_v1_add_listener(frame, &frame_listener, NULL); + + while (!buffer_copy_done && wl_display_dispatch(display) != -1) { + // This space is intentionally left blank + } + + write_image("wayland-screenshot.png", buffer.format, buffer.width, + buffer.height, buffer.stride, buffer.y_invert, buffer.data); + wl_buffer_destroy(buffer.wl_buffer); + + return EXIT_SUCCESS; +} diff --git a/examples/screenshot.c b/examples/screenshot.c new file mode 100644 index 00000000..914f3994 --- /dev/null +++ b/examples/screenshot.c @@ -0,0 +1,237 @@ +/* + * Copyright © 2008 Kristian Høgsberg + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#define _POSIX_C_SOURCE 200112L +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/param.h> +#include <sys/wait.h> +#include <unistd.h> +#include <wayland-client.h> +#include "screenshooter-client-protocol.h" + +static struct wl_shm *shm = NULL; +static struct orbital_screenshooter *screenshooter = NULL; +static struct wl_list output_list; +static bool buffer_copy_done; + +struct screenshooter_output { + struct wl_output *output; + int width, height; + struct wl_list link; +}; + +static void output_handle_geometry(void *data, struct wl_output *wl_output, + int x, int y, int physical_width, int physical_height, int subpixel, + const char *make, const char *model, int transform) { + // No-op +} + +static void output_handle_mode(void *data, struct wl_output *wl_output, + uint32_t flags, int width, int height, int refresh) { + struct screenshooter_output *output = wl_output_get_user_data(wl_output); + + if (wl_output == output->output && (flags & WL_OUTPUT_MODE_CURRENT)) { + output->width = width; + output->height = height; + } +} + +static void output_handle_done(void *data, struct wl_output *wl_output) { + // No-op +} + +static const struct wl_output_listener output_listener = { + .geometry = output_handle_geometry, + .mode = output_handle_mode, + .done = output_handle_done, +}; + +static void screenshot_done(void *data, struct orbital_screenshot *screenshot) { + buffer_copy_done = true; +} + +static const struct orbital_screenshot_listener screenshot_listener = { + .done = screenshot_done, +}; + +static void handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) { + static struct screenshooter_output *output; + + if (strcmp(interface, "wl_output") == 0) { + output = calloc(1, sizeof(*output)); + output->output = wl_registry_bind(registry, name, &wl_output_interface, + 1); + wl_list_insert(&output_list, &output->link); + wl_output_add_listener(output->output, &output_listener, output); + } else if (strcmp(interface, "wl_shm") == 0) { + shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); + } else if (strcmp(interface, "orbital_screenshooter") == 0) { + screenshooter = wl_registry_bind(registry, name, + &orbital_screenshooter_interface, 1); + } +} + +static void handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) { + // Who cares? +} + +static const struct wl_registry_listener registry_listener = { + .global = handle_global, + .global_remove = handle_global_remove, +}; + +static struct wl_buffer *create_shm_buffer(int width, int height, + void **data_out) { + int stride = width * 4; + int size = stride * height; + + const char shm_name[] = "/wlroots-screenshot"; + int fd = shm_open(shm_name, O_RDWR | O_CREAT | O_EXCL, 0); + if (fd < 0) { + fprintf(stderr, "shm_open failed\n"); + return NULL; + } + shm_unlink(shm_name); + + int ret; + while ((ret = ftruncate(fd, size)) == EINTR) { + // No-op + } + if (ret < 0) { + close(fd); + fprintf(stderr, "ftruncate failed\n"); + return NULL; + } + + void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) { + fprintf(stderr, "mmap failed: %m\n"); + close(fd); + return NULL; + } + + struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size); + close(fd); + struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0, width, height, + stride, WL_SHM_FORMAT_XRGB8888); + wl_shm_pool_destroy(pool); + + *data_out = data; + + return buffer; +} + +static void write_image(const char *filename, int width, int height, + void *data) { + char size[10 + 1 + 10 + 2 + 1]; // int32_t are max 10 digits + sprintf(size, "%dx%d+0", width, height); + + int fd[2]; + if (pipe(fd) != 0) { + fprintf(stderr, "cannot create pipe: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + pid_t child = fork(); + if (child < 0) { + fprintf(stderr, "fork() failed\n"); + exit(EXIT_FAILURE); + } else if (child != 0) { + close(fd[0]); + if (write(fd[1], data, 4 * width * height) < 0) { + fprintf(stderr, "write() failed: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + close(fd[1]); + waitpid(child, NULL, 0); + } else { + close(fd[1]); + if (dup2(fd[0], 0) != 0) { + fprintf(stderr, "cannot dup the pipe\n"); + exit(EXIT_FAILURE); + } + close(fd[0]); + // We requested WL_SHM_FORMAT_XRGB8888 in little endian, so that's BGRA + // in big endian. + execlp("convert", "convert", "-depth", "8", "-size", size, "bgra:-", + "-alpha", "opaque", filename, NULL); + fprintf(stderr, "cannot execute convert\n"); + exit(EXIT_FAILURE); + } +} + +int main(int argc, char *argv[]) { + struct wl_display * display = wl_display_connect(NULL); + if (display == NULL) { + fprintf(stderr, "failed to create display: %m\n"); + return -1; + } + + wl_list_init(&output_list); + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_dispatch(display); + wl_display_roundtrip(display); + + if (screenshooter == NULL) { + fprintf(stderr, "display doesn't support screenshooter\n"); + return -1; + } + + int i = 0; + struct screenshooter_output *output; + wl_list_for_each(output, &output_list, link) { + void *data = NULL; + struct wl_buffer *buffer = + create_shm_buffer(output->width, output->height, &data); + if (buffer == NULL) { + return -1; + } + struct orbital_screenshot *screenshot = orbital_screenshooter_shoot( + screenshooter, output->output, buffer); + orbital_screenshot_add_listener(screenshot, &screenshot_listener, + screenshot); + buffer_copy_done = false; + while (!buffer_copy_done) { + wl_display_roundtrip(display); + } + + char filename[24 + 10]; // int32_t are max 10 digits + snprintf(filename, sizeof(filename), "wayland-screenshot-%d.png", i); + + write_image(filename, output->width, output->height, data); + wl_buffer_destroy(buffer); + ++i; + } + + return EXIT_SUCCESS; +} diff --git a/examples/simple.c b/examples/simple.c new file mode 100644 index 00000000..e1c10906 --- /dev/null +++ b/examples/simple.c @@ -0,0 +1,185 @@ +#define _POSIX_C_SOURCE 200112L +#include <GLES2/gl2.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <wayland-server.h> +#include <wlr/backend.h> +#include <wlr/backend/session.h> +#include <wlr/types/wlr_output.h> +#include <wlr/types/wlr_input_device.h> +#include <wlr/util/log.h> +#include <xkbcommon/xkbcommon.h> + +struct sample_state { + struct wl_display *display; + struct wl_listener new_output; + struct wl_listener new_input; + struct timespec last_frame; + float color[3]; + int dec; +}; + +struct sample_output { + struct sample_state *sample; + struct wlr_output *output; + struct wl_listener frame; + struct wl_listener destroy; +}; + +struct sample_keyboard { + struct sample_state *sample; + struct wlr_input_device *device; + struct wl_listener key; + struct wl_listener destroy; +}; + +void output_frame_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = + wl_container_of(listener, sample_output, frame); + struct sample_state *sample = sample_output->sample; + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + long ms = (now.tv_sec - sample->last_frame.tv_sec) * 1000 + + (now.tv_nsec - sample->last_frame.tv_nsec) / 1000000; + int inc = (sample->dec + 1) % 3; + + sample->color[inc] += ms / 2000.0f; + sample->color[sample->dec] -= ms / 2000.0f; + + if (sample->color[sample->dec] < 0.0f) { + sample->color[inc] = 1.0f; + sample->color[sample->dec] = 0.0f; + sample->dec = inc; + } + + wlr_output_make_current(sample_output->output, NULL); + + glClearColor(sample->color[0], sample->color[1], sample->color[2], 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + wlr_output_swap_buffers(sample_output->output, NULL, NULL); + sample->last_frame = now; +} + +void output_remove_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = + wl_container_of(listener, sample_output, destroy); + wlr_log(WLR_DEBUG, "Output removed"); + wl_list_remove(&sample_output->frame.link); + wl_list_remove(&sample_output->destroy.link); + free(sample_output); +} + +void new_output_notify(struct wl_listener *listener, void *data) { + struct wlr_output *output = data; + struct sample_state *sample = + wl_container_of(listener, sample, new_output); + struct sample_output *sample_output = + calloc(1, sizeof(struct sample_output)); + if (!wl_list_empty(&output->modes)) { + struct wlr_output_mode *mode = + wl_container_of(output->modes.prev, mode, link); + wlr_output_set_mode(output, mode); + } + sample_output->output = output; + sample_output->sample = sample; + wl_signal_add(&output->events.frame, &sample_output->frame); + sample_output->frame.notify = output_frame_notify; + wl_signal_add(&output->events.destroy, &sample_output->destroy); + sample_output->destroy.notify = output_remove_notify; +} + +void keyboard_key_notify(struct wl_listener *listener, void *data) { + struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); + struct sample_state *sample = keyboard->sample; + struct wlr_event_keyboard_key *event = data; + uint32_t keycode = event->keycode + 8; + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, + keycode, &syms); + for (int i = 0; i < nsyms; i++) { + xkb_keysym_t sym = syms[i]; + if (sym == XKB_KEY_Escape) { + wl_display_terminate(sample->display); + } + } +} + +void keyboard_destroy_notify(struct wl_listener *listener, void *data) { + struct sample_keyboard *keyboard = + wl_container_of(listener, keyboard, destroy); + wl_list_remove(&keyboard->destroy.link); + wl_list_remove(&keyboard->key.link); + free(keyboard); +} + +void new_input_notify(struct wl_listener *listener, void *data) { + struct wlr_input_device *device = data; + struct sample_state *sample = wl_container_of(listener, sample, new_input); + switch (device->type) { + case WLR_INPUT_DEVICE_KEYBOARD:; + struct sample_keyboard *keyboard = + calloc(1, sizeof(struct sample_keyboard)); + keyboard->device = device; + keyboard->sample = sample; + wl_signal_add(&device->events.destroy, &keyboard->destroy); + keyboard->destroy.notify = keyboard_destroy_notify; + wl_signal_add(&device->keyboard->events.key, &keyboard->key); + keyboard->key.notify = keyboard_key_notify; + struct xkb_rule_names rules = { 0 }; + rules.rules = getenv("XKB_DEFAULT_RULES"); + rules.model = getenv("XKB_DEFAULT_MODEL"); + rules.layout = getenv("XKB_DEFAULT_LAYOUT"); + rules.variant = getenv("XKB_DEFAULT_VARIANT"); + rules.options = getenv("XKB_DEFAULT_OPTIONS"); + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!context) { + wlr_log(WLR_ERROR, "Failed to create XKB context"); + exit(1); + } + struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) { + wlr_log(WLR_ERROR, "Failed to create XKB keymap"); + exit(1); + } + wlr_keyboard_set_keymap(device->keyboard, keymap); + xkb_keymap_unref(keymap); + xkb_context_unref(context); + break; + default: + break; + } +} + +int main(void) { + wlr_log_init(WLR_DEBUG, NULL); + struct wl_display *display = wl_display_create(); + struct sample_state state = { + .color = { 1.0, 0.0, 0.0 }, + .dec = 0, + .last_frame = { 0 }, + .display = display + }; + struct wlr_backend *backend = wlr_backend_autocreate(display, NULL); + if (!backend) { + exit(1); + } + wl_signal_add(&backend->events.new_output, &state.new_output); + state.new_output.notify = new_output_notify; + wl_signal_add(&backend->events.new_input, &state.new_input); + state.new_input.notify = new_input_notify; + clock_gettime(CLOCK_MONOTONIC, &state.last_frame); + + if (!wlr_backend_start(backend)) { + wlr_log(WLR_ERROR, "Failed to start backend"); + wlr_backend_destroy(backend); + exit(1); + } + wl_display_run(display); + wl_display_destroy(display); +} diff --git a/examples/tablet.c b/examples/tablet.c new file mode 100644 index 00000000..fad30d52 --- /dev/null +++ b/examples/tablet.c @@ -0,0 +1,381 @@ +#define _XOPEN_SOURCE 600 +#include <GLES2/gl2.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <wayland-server-protocol.h> +#include <wayland-server.h> +#include <wlr/backend.h> +#include <wlr/backend/session.h> +#include <wlr/render/wlr_renderer.h> +#include <wlr/types/wlr_box.h> +#include <wlr/types/wlr_matrix.h> +#include <wlr/types/wlr_output.h> +#include <wlr/types/wlr_input_device.h> +#include <wlr/types/wlr_tablet_pad.h> +#include <wlr/types/wlr_tablet_tool.h> +#include <wlr/util/log.h> +#include <xkbcommon/xkbcommon.h> + +struct sample_state { + struct wl_display *display; + struct wlr_renderer *renderer; + bool proximity, tap, button; + double distance; + double pressure; + double x, y; + double x_tilt, y_tilt; + double width_mm, height_mm; + double ring; + struct wl_list link; + float tool_color[4]; + float pad_color[4]; + struct timespec last_frame; + struct wl_listener new_output; + struct wl_listener new_input; + struct wl_list tablet_tools; + struct wl_list tablet_pads; +}; + +struct tablet_tool_state { + struct sample_state *sample; + struct wlr_input_device *device; + struct wl_listener destroy; + struct wl_listener axis; + struct wl_listener proximity; + struct wl_listener tip; + struct wl_listener button; + struct wl_list link; + void *data; +}; + +struct tablet_pad_state { + struct sample_state *sample; + struct wlr_input_device *device; + struct wl_listener destroy; + struct wl_listener button; + struct wl_listener ring; + struct wl_list link; + void *data; +}; + +struct sample_output { + struct sample_state *sample; + struct wlr_output *output; + struct wl_listener frame; + struct wl_listener destroy; +}; + +struct sample_keyboard { + struct sample_state *sample; + struct wlr_input_device *device; + struct wl_listener key; + struct wl_listener destroy; +}; + +static void output_frame_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = wl_container_of(listener, sample_output, frame); + struct sample_state *sample = sample_output->sample; + struct wlr_output *wlr_output = sample_output->output; + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + int32_t width, height; + wlr_output_effective_resolution(wlr_output, &width, &height); + + wlr_output_make_current(wlr_output, NULL); + wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); + wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); + + float distance = 0.8f * (1 - sample->distance); + float tool_color[4] = { distance, distance, distance, 1 }; + for (size_t i = 0; sample->button && i < 4; ++i) { + tool_color[i] = sample->tool_color[i]; + } + float scale = 4; + + float pad_width = sample->width_mm * scale; + float pad_height = sample->height_mm * scale; + float left = width / 2.0f - pad_width / 2.0f; + float top = height / 2.0f - pad_height / 2.0f; + const struct wlr_box box = { + .x = left, .y = top, + .width = pad_width, .height = pad_height, + }; + wlr_render_rect(sample->renderer, &box, sample->pad_color, + wlr_output->transform_matrix); + + if (sample->proximity) { + struct wlr_box box = { + .x = (sample->x * pad_width) - 8 * (sample->pressure + 1) + left, + .y = (sample->y * pad_height) - 8 * (sample->pressure + 1) + top, + .width = 16 * (sample->pressure + 1), + .height = 16 * (sample->pressure + 1), + }; + float matrix[9]; + wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, + sample->ring, wlr_output->transform_matrix); + wlr_render_quad_with_matrix(sample->renderer, tool_color, matrix); + + box.x += sample->x_tilt; + box.y += sample->y_tilt; + box.width /= 2; + box.height /= 2; + wlr_render_rect(sample->renderer, &box, tool_color, + wlr_output->transform_matrix); + } + + wlr_renderer_end(sample->renderer); + wlr_output_swap_buffers(wlr_output, NULL, NULL); + sample->last_frame = now; +} + +static void tablet_tool_axis_notify(struct wl_listener *listener, void *data) { + struct tablet_tool_state *tstate = wl_container_of(listener, tstate, axis); + struct wlr_event_tablet_tool_axis *event = data; + struct sample_state *sample = tstate->sample; + if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X)) { + sample->x = event->x; + } + if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { + sample->y = event->y; + } + if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_DISTANCE)) { + sample->distance = event->distance; + } + if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_PRESSURE)) { + sample->pressure = event->pressure; + } + if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_X)) { + sample->x_tilt = event->tilt_x; + } + if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_Y)) { + sample->y_tilt = event->tilt_y; + } +} + +static void tablet_tool_proximity_notify(struct wl_listener *listener, void *data) { + struct tablet_tool_state *tstate = wl_container_of(listener, tstate, proximity); + struct wlr_event_tablet_tool_proximity *event = data; + struct sample_state *sample = tstate->sample; + sample->proximity = event->state == WLR_TABLET_TOOL_PROXIMITY_IN; +} + +static void tablet_tool_button_notify(struct wl_listener *listener, void *data) { + struct tablet_tool_state *tstate = wl_container_of(listener, tstate, button); + struct wlr_event_tablet_tool_button *event = data; + struct sample_state *sample = tstate->sample; + if (event->state == WLR_BUTTON_RELEASED) { + sample->button = false; + } else { + sample->button = true; + for (size_t i = 0; i < 3; ++i) { + if (event->button % 3 == i) { + sample->tool_color[i] = 0; + } else { + sample->tool_color[i] = 1; + } + } + } +} + +static void tablet_pad_button_notify(struct wl_listener *listener, void *data) { + struct tablet_pad_state *pstate = wl_container_of(listener, pstate, button); + struct wlr_event_tablet_pad_button *event = data; + struct sample_state *sample = pstate->sample; + float default_color[4] = { 0.5, 0.5, 0.5, 1.0 }; + if (event->state == WLR_BUTTON_RELEASED) { + memcpy(sample->pad_color, default_color, sizeof(default_color)); + } else { + for (size_t i = 0; i < 3; ++i) { + if (event->button % 3 == i) { + sample->pad_color[i] = 0; + } else { + sample->pad_color[i] = 1; + } + } + } +} + +static void tablet_pad_ring_notify(struct wl_listener *listener, void *data) { + struct tablet_pad_state *pstate = wl_container_of(listener, pstate, ring); + struct wlr_event_tablet_pad_ring *event = data; + struct sample_state *sample = pstate->sample; + if (event->position != -1) { + sample->ring = -(event->position * (M_PI / 180.0)); + } +} + +static void tablet_tool_destroy_notify(struct wl_listener *listener, void *data) { + struct tablet_tool_state *tstate = wl_container_of(listener, tstate, destroy); + wl_list_remove(&tstate->link); + wl_list_remove(&tstate->destroy.link); + wl_list_remove(&tstate->axis.link); + wl_list_remove(&tstate->proximity.link); + wl_list_remove(&tstate->button.link); + free(tstate); +} + +static void tablet_pad_destroy_notify(struct wl_listener *listener, void *data) { + struct tablet_pad_state *pstate = wl_container_of(listener, pstate, destroy); + wl_list_remove(&pstate->link); + wl_list_remove(&pstate->destroy.link); + wl_list_remove(&pstate->ring.link); + wl_list_remove(&pstate->button.link); + free(pstate); +} + +void output_remove_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = wl_container_of(listener, sample_output, destroy); + wl_list_remove(&sample_output->frame.link); + wl_list_remove(&sample_output->destroy.link); + free(sample_output); +} + +void new_output_notify(struct wl_listener *listener, void *data) { + struct wlr_output *output = data; + struct sample_state *sample = wl_container_of(listener, sample, new_output); + struct sample_output *sample_output = calloc(1, sizeof(struct sample_output)); + if (!wl_list_empty(&output->modes)) { + struct wlr_output_mode *mode = wl_container_of(output->modes.prev, mode, link); + wlr_output_set_mode(output, mode); + } + sample_output->output = output; + sample_output->sample = sample; + wl_signal_add(&output->events.frame, &sample_output->frame); + sample_output->frame.notify = output_frame_notify; + wl_signal_add(&output->events.destroy, &sample_output->destroy); + sample_output->destroy.notify = output_remove_notify; +} + +void keyboard_key_notify(struct wl_listener *listener, void *data) { + struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); + struct sample_state *sample = keyboard->sample; + struct wlr_event_keyboard_key *event = data; + uint32_t keycode = event->keycode + 8; + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, + keycode, &syms); + for (int i = 0; i < nsyms; i++) { + xkb_keysym_t sym = syms[i]; + if (sym == XKB_KEY_Escape) { + wl_display_terminate(sample->display); + } + } +} + +void keyboard_destroy_notify(struct wl_listener *listener, void *data) { + struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, destroy); + wl_list_remove(&keyboard->destroy.link); + wl_list_remove(&keyboard->key.link); + free(keyboard); +} + +void new_input_notify(struct wl_listener *listener, void *data) { + struct wlr_input_device *device = data; + struct sample_state *sample = wl_container_of(listener, sample, new_input); + switch (device->type) { + case WLR_INPUT_DEVICE_KEYBOARD:; + struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); + keyboard->device = device; + keyboard->sample = sample; + wl_signal_add(&device->events.destroy, &keyboard->destroy); + keyboard->destroy.notify = keyboard_destroy_notify; + wl_signal_add(&device->keyboard->events.key, &keyboard->key); + keyboard->key.notify = keyboard_key_notify; + struct xkb_rule_names rules = { 0 }; + rules.rules = getenv("XKB_DEFAULT_RULES"); + rules.model = getenv("XKB_DEFAULT_MODEL"); + rules.layout = getenv("XKB_DEFAULT_LAYOUT"); + rules.variant = getenv("XKB_DEFAULT_VARIANT"); + rules.options = getenv("XKB_DEFAULT_OPTIONS"); + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!context) { + wlr_log(WLR_ERROR, "Failed to create XKB context"); + exit(1); + } + struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) { + wlr_log(WLR_ERROR, "Failed to create XKB keymap"); + exit(1); + } + wlr_keyboard_set_keymap(device->keyboard, keymap); + xkb_keymap_unref(keymap); + xkb_context_unref(context); + break; + case WLR_INPUT_DEVICE_TABLET_PAD:; + struct tablet_pad_state *pstate = calloc(sizeof(struct tablet_pad_state), 1); + pstate->device = device; + pstate->sample = sample; + pstate->destroy.notify = tablet_pad_destroy_notify; + wl_signal_add(&device->events.destroy, &pstate->destroy); + pstate->button.notify = tablet_pad_button_notify; + wl_signal_add(&device->tablet_pad->events.button, &pstate->button); + pstate->ring.notify = tablet_pad_ring_notify; + wl_signal_add(&device->tablet_pad->events.ring, &pstate->ring); + wl_list_insert(&sample->tablet_pads, &pstate->link); + break; + case WLR_INPUT_DEVICE_TABLET_TOOL: + sample->width_mm = device->width_mm == 0 ? + 20 : device->width_mm; + sample->height_mm = device->height_mm == 0 ? + 10 : device->height_mm; + + struct tablet_tool_state *tstate = calloc(sizeof(struct tablet_tool_state), 1); + tstate->device = device; + tstate->sample = sample; + tstate->destroy.notify = tablet_tool_destroy_notify; + wl_signal_add(&device->events.destroy, &tstate->destroy); + tstate->axis.notify = tablet_tool_axis_notify; + wl_signal_add(&device->tablet->events.axis, &tstate->axis); + tstate->proximity.notify = tablet_tool_proximity_notify; + wl_signal_add(&device->tablet->events.proximity, &tstate->proximity); + tstate->button.notify = tablet_tool_button_notify; + wl_signal_add(&device->tablet->events.button, &tstate->button); + wl_list_insert(&sample->tablet_tools, &tstate->link); + break; + default: + break; + } +} + + +int main(int argc, char *argv[]) { + wlr_log_init(WLR_DEBUG, NULL); + struct wl_display *display = wl_display_create(); + struct sample_state state = { + .display = display, + .tool_color = { 1, 1, 1, 1 }, + .pad_color = { 0.5, 0.5, 0.5, 1.0 } + }; + wl_list_init(&state.tablet_pads); + wl_list_init(&state.tablet_tools); + struct wlr_backend *wlr = wlr_backend_autocreate(display, NULL); + if (!wlr) { + exit(1); + } + + wl_signal_add(&wlr->events.new_output, &state.new_output); + state.new_output.notify = new_output_notify; + wl_signal_add(&wlr->events.new_input, &state.new_input); + state.new_input.notify = new_input_notify; + clock_gettime(CLOCK_MONOTONIC, &state.last_frame); + + state.renderer = wlr_backend_get_renderer(wlr); + if (!state.renderer) { + wlr_log(WLR_ERROR, "Could not start compositor, OOM"); + exit(EXIT_FAILURE); + } + if (!wlr_backend_start(wlr)) { + wlr_log(WLR_ERROR, "Failed to start backend"); + wlr_backend_destroy(wlr); + exit(1); + } + wl_display_run(display); + + wl_display_destroy(display); +} diff --git a/examples/text-input.c b/examples/text-input.c new file mode 100644 index 00000000..3ccd99a0 --- /dev/null +++ b/examples/text-input.c @@ -0,0 +1,394 @@ +#define _POSIX_C_SOURCE 200809L +#include <GLES2/gl2.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <wayland-client.h> +#include <wayland-egl.h> +#include <wlr/render/egl.h> +#include "text-input-unstable-v3-client-protocol.h" +#include "xdg-shell-client-protocol.h" + +const char usage[] = "Usage: text-input [seconds [width height]]\n\ +\n\ +Creates a xdg-toplevel using the text-input protocol.\n\ +It will be solid black when it has no text input focus, yellow when it\n\ +has focus, and red when it was notified that the focus moved away\n\ +but still didn't give up the text input ability.\n\ +\n\ +The \"seconds\" argument is optional and defines the delay between getting\n\ +notified of lost focus and releasing text input.\n\ +\n\ +The \"width\" and \"height\" arguments define the window shape.\n\ +\n\ +The console will print the internal state of the text field:\n\ +- the text in the 1st line\n\ +- \".\" under each preedit character\n\ +- \"_\" under each selected preedit character\n\ +- \"|\" at the cursor position if there are no selected characters in the\n\ +preedit.\n\ +\n\ +The cursor positions may be inaccurate, especially in presence of zero-width\n\ +characters or non-monospaced fonts.\n"; + +struct text_input_state { + char *commit; + struct { + char *text; + int32_t cursor_begin; + int32_t cursor_end; + } preedit; + struct { + uint32_t after_length; + uint32_t before_length; + } delete_surrounding; +}; + +static struct text_input_state pending = {0}; +static struct text_input_state current = {0}; +static bool entered = false; +static uint32_t serial; +static char *buffer; // text buffer +// cursor is not present, there's no way to move it outside of preedit + +static int sleeptime = 0; +static int width = 100, height = 200; +static int enabled = 0; + +static struct wl_display *display = NULL; +static struct wl_compositor *compositor = NULL; +static struct wl_seat *seat = NULL; +static struct xdg_wm_base *wm_base = NULL; +static struct zwp_text_input_manager_v3 *text_input_manager = NULL; +static struct zwp_text_input_v3 *text_input = NULL; + +struct wlr_egl egl; +struct wl_egl_window *egl_window; +struct wlr_egl_surface *egl_surface; + +static void draw(void) { + eglMakeCurrent(egl.display, egl_surface, egl_surface, egl.context); + + float color[] = {1.0, 1.0, 0.0, 1.0}; + color[0] = enabled * 1.0; + color[1] = entered * 1.0; + + glViewport(0, 0, width, height); + glClearColor(color[0], color[1], color[2], 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + eglSwapBuffers(egl.display, egl_surface); +} + +static size_t utf8_strlen(char *str) { + size_t cp_count = 0; + for (; *str != '\0'; str++) { + if ((*str & 0xc0) != 0x80) { + cp_count++; + } + } + return cp_count; +} + +static size_t utf8_offset(char *utf8_str, size_t byte_offset) { + size_t cp_count = 0; + for (char *c = utf8_str; c < utf8_str + byte_offset; c++) { + if ((*c & 0xc0) != 0x80) { + cp_count++; + } + } + return cp_count; +} + +// TODO: would be nicer to have this text display inside the window +static void show_status() { + printf("State %d:", serial); + if (!enabled) { + printf(" disabled"); + } + + char *preedit_text = current.preedit.text; + if (!preedit_text) { + preedit_text = ""; + } + + printf("\n"); + printf("%s", buffer); + printf("%s\n", preedit_text); + + // Positioning of the cursor requires UTF8 offsets to match monospaced + // glyphs + for (unsigned i = 0; i < utf8_strlen(buffer); i++) { + printf(" "); + } + char *cursor_mark = calloc(utf8_strlen(preedit_text) + 2, sizeof(char)); + for (unsigned i = 0; i < utf8_strlen(preedit_text); i++) { + cursor_mark[i] = '.'; + } + if (current.preedit.cursor_begin == -1 + && current.preedit.cursor_end == -1) { + goto end; + } + if (current.preedit.cursor_begin == -1 + || current.preedit.cursor_end == -1) { + printf("Only one cursor side is defined: %d to %d\n", + current.preedit.cursor_begin, current.preedit.cursor_end); + goto end; + } + + if ((unsigned)current.preedit.cursor_begin > strlen(preedit_text) + || (unsigned)current.preedit.cursor_begin > strlen(preedit_text)) { + printf("Cursor out of bounds\n"); + goto end; + } + + if (current.preedit.cursor_begin == current.preedit.cursor_end) { + cursor_mark[utf8_offset(preedit_text, current.preedit.cursor_begin)] + = '|'; + goto print; + } + + if (current.preedit.cursor_begin > current.preedit.cursor_end) { + printf("End cursor is before start cursor\n"); + goto end; + } + + // negative offsets already checked before + for (unsigned i = utf8_offset(preedit_text, current.preedit.cursor_begin); + i < utf8_offset(preedit_text, current.preedit.cursor_end); i++) { + cursor_mark[i] = '_'; + } +print: + printf("%s\n", cursor_mark); +end: + free(cursor_mark); +} + +static void commit(struct zwp_text_input_v3 *text_input) { + zwp_text_input_v3_commit(text_input); + serial++; +} + +static void send_status_update(struct zwp_text_input_v3 *text_input) { + zwp_text_input_v3_set_surrounding_text(text_input, buffer, strlen(buffer), strlen(buffer)); + zwp_text_input_v3_set_text_change_cause(text_input, ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_INPUT_METHOD); + commit(text_input); +} + +static void text_input_handle_enter(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + struct wl_surface *surface) { + entered = true; + zwp_text_input_v3_enable(zwp_text_input_v3); + commit(zwp_text_input_v3); + enabled = true; + draw(); + show_status(); +} + +static void text_input_handle_leave(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + struct wl_surface *surface) { + entered = false; + draw(); + wl_display_roundtrip(display); + sleep(sleeptime); + zwp_text_input_v3_disable(zwp_text_input_v3); + commit(zwp_text_input_v3); + enabled = false; + draw(); + show_status(); +} + +static void text_input_commit_string(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + const char *text) { + free(pending.commit); + pending.commit = strdup(text); +} + +static void text_input_delete_surrounding_text(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + uint32_t before_length, uint32_t after_length) { + pending.delete_surrounding.before_length = before_length; + pending.delete_surrounding.after_length = after_length; +} + +static void text_input_preedit_string(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + const char *text, int32_t cursor_begin, int32_t cursor_end) { + free(pending.preedit.text); + pending.preedit.text = strdup(text); + pending.preedit.cursor_begin = cursor_begin; + pending.preedit.cursor_end = cursor_end; +} + +static void text_input_handle_done(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + uint32_t incoming_serial) { + if (serial != incoming_serial) { + fprintf(stderr, "Received serial %d while expecting %d\n", incoming_serial, serial); + return; + } + free(current.preedit.text); + free(current.commit); + current = pending; + struct text_input_state empty = {0}; + pending = empty; + + if (current.delete_surrounding.after_length + current.delete_surrounding.before_length > 0) { + // cursor is always after committed text, after_length != 0 will never happen + unsigned delete_before = current.delete_surrounding.before_length; + if (delete_before > strlen(buffer)) { + delete_before = strlen(buffer); + } + buffer[strlen(buffer) - delete_before] = '\0'; + } + + char *commit_string = current.commit; + if (!commit_string) { + commit_string = ""; + } + char *old_buffer = buffer; + buffer = calloc(strlen(buffer) + strlen(commit_string) + 1, sizeof(char)); // realloc may fail anyway + strcpy(buffer, old_buffer); + free(old_buffer); + strcat(buffer, commit_string); + + send_status_update(zwp_text_input_v3); + show_status(); +} + +static const struct zwp_text_input_v3_listener text_input_listener = { + .enter = text_input_handle_enter, + .leave = text_input_handle_leave, + .commit_string = text_input_commit_string, + .delete_surrounding_text = text_input_delete_surrounding_text, + .preedit_string = text_input_preedit_string, + .done = text_input_handle_done, +}; + +static void xdg_surface_handle_configure(void *data, + struct xdg_surface *xdg_surface, uint32_t serial) { + xdg_surface_ack_configure(xdg_surface, serial); + wl_egl_window_resize(egl_window, width, height, 0, 0); + draw(); +} + +static const struct xdg_surface_listener xdg_surface_listener = { + .configure = xdg_surface_handle_configure, +}; + +static void xdg_toplevel_handle_configure(void *data, + struct xdg_toplevel *xdg_toplevel, int32_t w, int32_t h, + struct wl_array *states) { + width = w; + height = h; +} + +static void xdg_toplevel_handle_close(void *data, + struct xdg_toplevel *xdg_toplevel) { + exit(EXIT_SUCCESS); +} + +static const struct xdg_toplevel_listener xdg_toplevel_listener = { + .configure = xdg_toplevel_handle_configure, + .close = xdg_toplevel_handle_close, +}; + +static void handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) { + if (strcmp(interface, "wl_compositor") == 0) { + compositor = wl_registry_bind(registry, name, + &wl_compositor_interface, 1); + } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { + wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); + } else if (strcmp(interface, zwp_text_input_manager_v3_interface.name) == 0) { + text_input_manager = wl_registry_bind(registry, name, + &zwp_text_input_manager_v3_interface, 1); + } else if (strcmp(interface, wl_seat_interface.name) == 0) { + seat = wl_registry_bind(registry, name, &wl_seat_interface, version); + } +} + +static void handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) { + // who cares +} + +static const struct wl_registry_listener registry_listener = { + .global = handle_global, + .global_remove = handle_global_remove, +}; + +int main(int argc, char **argv) { + if (argc > 1) { + if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) { + printf(usage); + return 0; + } + sleeptime = atoi(argv[1]); + if (argc > 3) { + width = atoi(argv[2]); + height = atoi(argv[3]); + } + } + + buffer = calloc(1, sizeof(char)); + + display = wl_display_connect(NULL); + if (display == NULL) { + fprintf(stderr, "Failed to create display\n"); + return EXIT_FAILURE; + } + + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_dispatch(display); + wl_display_roundtrip(display); + + if (compositor == NULL) { + fprintf(stderr, "wl-compositor not available\n"); + return EXIT_FAILURE; + } + if (wm_base == NULL) { + fprintf(stderr, "xdg-shell not available\n"); + return EXIT_FAILURE; + } + if (text_input_manager == NULL) { + fprintf(stderr, "text-input not available\n"); + return EXIT_FAILURE; + } + + text_input = zwp_text_input_manager_v3_get_text_input(text_input_manager, seat); + + zwp_text_input_v3_add_listener(text_input, &text_input_listener, NULL); + + + wlr_egl_init(&egl, EGL_PLATFORM_WAYLAND_EXT, display, NULL, + WL_SHM_FORMAT_ARGB8888); + + struct wl_surface *surface = wl_compositor_create_surface(compositor); + struct xdg_surface *xdg_surface = + xdg_wm_base_get_xdg_surface(wm_base, surface); + struct xdg_toplevel *xdg_toplevel = xdg_surface_get_toplevel(xdg_surface); + + xdg_surface_add_listener(xdg_surface, &xdg_surface_listener, NULL); + xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, NULL); + + wl_surface_commit(surface); + + egl_window = wl_egl_window_create(surface, width, height); + egl_surface = wlr_egl_create_surface(&egl, egl_window); + + wl_display_roundtrip(display); + + draw(); + + while (wl_display_dispatch(display) != -1) { + // This space intentionally left blank + } + + return EXIT_SUCCESS; +} diff --git a/examples/toplevel-decoration.c b/examples/toplevel-decoration.c new file mode 100644 index 00000000..e930c417 --- /dev/null +++ b/examples/toplevel-decoration.c @@ -0,0 +1,253 @@ +#include <GLES2/gl2.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wayland-client.h> +#include <wayland-egl.h> +#include <wlr/render/egl.h> +#include "xdg-shell-client-protocol.h" +#include "xdg-decoration-unstable-v1-client-protocol.h" + +/** + * Usage: toplevel-decoration [mode] + * Creates an xdg-toplevel supporting decoration negotiation. If `mode` is + * specified, the client will prefer this decoration mode. + */ + +static int width = 500, height = 300; + +static struct wl_compositor *compositor = NULL; +static struct xdg_wm_base *wm_base = NULL; +static struct zxdg_decoration_manager_v1 *decoration_manager = NULL; + +struct wlr_egl egl; +struct wl_egl_window *egl_window; +struct wlr_egl_surface *egl_surface; + +struct zxdg_toplevel_decoration_v1 *decoration; +enum zxdg_toplevel_decoration_v1_mode client_preferred_mode, current_mode; + +static const char *get_mode_name(enum zxdg_toplevel_decoration_v1_mode mode) { + switch (mode) { + case ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE: + return "client-side decorations"; + case ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE: + return "server-side decorations"; + } + abort(); +} + +static void request_preferred_mode(void) { + enum zxdg_toplevel_decoration_v1_mode mode = client_preferred_mode; + if (mode == 0) { + printf("Requesting compositor preferred mode\n"); + zxdg_toplevel_decoration_v1_unset_mode(decoration); + return; + } + if (mode == current_mode) { + return; + } + + printf("Requesting %s\n", get_mode_name(mode)); + zxdg_toplevel_decoration_v1_set_mode(decoration, mode); +} + +static void draw(void) { + eglMakeCurrent(egl.display, egl_surface, egl_surface, egl.context); + + float color[] = {1.0, 1.0, 0.0, 1.0}; + if (current_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE) { + color[0] = 0.0; + } + + glViewport(0, 0, width, height); + glClearColor(color[0], color[1], color[2], 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + eglSwapBuffers(egl.display, egl_surface); +} + +static void xdg_surface_handle_configure(void *data, + struct xdg_surface *xdg_surface, uint32_t serial) { + xdg_surface_ack_configure(xdg_surface, serial); + wl_egl_window_resize(egl_window, width, height, 0, 0); + draw(); +} + +static const struct xdg_surface_listener xdg_surface_listener = { + .configure = xdg_surface_handle_configure, +}; + +static void xdg_toplevel_handle_configure(void *data, + struct xdg_toplevel *xdg_toplevel, int32_t w, int32_t h, + struct wl_array *states) { + width = w; + height = h; +} + +static const struct xdg_toplevel_listener xdg_toplevel_listener = { + .configure = xdg_toplevel_handle_configure, +}; + +static void decoration_handle_configure(void *data, + struct zxdg_toplevel_decoration_v1 *decoration, + enum zxdg_toplevel_decoration_v1_mode mode) { + printf("Using %s\n", get_mode_name(mode)); + current_mode = mode; +} + +static const struct zxdg_toplevel_decoration_v1_listener decoration_listener = { + .configure = decoration_handle_configure, +}; + +static void pointer_handle_enter(void *data, struct wl_pointer *pointer, + uint32_t serial, struct wl_surface *surface, + wl_fixed_t sx, wl_fixed_t sy) { + // No-op +} + +static void pointer_handle_leave(void *data, struct wl_pointer *pointer, + uint32_t serial, struct wl_surface *surface) { + // No-op +} + +static void pointer_handle_motion(void *data, struct wl_pointer *pointer, + uint32_t time, wl_fixed_t sx, wl_fixed_t sy) { + // No-op +} + +static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, uint32_t time, uint32_t button, + enum wl_pointer_button_state state) { + if (state == WL_POINTER_BUTTON_STATE_PRESSED) { + // Toggle mode + if (client_preferred_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE) { + client_preferred_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; + } else { + client_preferred_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; + } + request_preferred_mode(); + } +} + +static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, + uint32_t time, enum wl_pointer_axis axis, wl_fixed_t value) { + // No-op +} + +static const struct wl_pointer_listener pointer_listener = { + .enter = pointer_handle_enter, + .leave = pointer_handle_leave, + .motion = pointer_handle_motion, + .button = pointer_handle_button, + .axis = pointer_handle_axis, +}; + +static void seat_handle_capabilities(void *data, struct wl_seat *seat, + enum wl_seat_capability caps) { + if (caps & WL_SEAT_CAPABILITY_POINTER) { + struct wl_pointer *pointer = wl_seat_get_pointer(seat); + wl_pointer_add_listener(pointer, &pointer_listener, NULL); + } +} + +static const struct wl_seat_listener seat_listener = { + .capabilities = seat_handle_capabilities, +}; + +static void handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) { + if (strcmp(interface, wl_compositor_interface.name) == 0) { + compositor = wl_registry_bind(registry, name, &wl_compositor_interface, + 1); + } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { + wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); + } else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) { + decoration_manager = wl_registry_bind(registry, name, + &zxdg_decoration_manager_v1_interface, 1); + } else if (strcmp(interface, wl_seat_interface.name) == 0) { + struct wl_seat *seat = + wl_registry_bind(registry, name, &wl_seat_interface, 1); + wl_seat_add_listener(seat, &seat_listener, NULL); + } +} + +static void handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) { + // Who cares? +} + +static const struct wl_registry_listener registry_listener = { + .global = handle_global, + .global_remove = handle_global_remove, +}; + +int main(int argc, char **argv) { + if (argc == 2) { + char *mode = argv[1]; + if (strcmp(mode, "client") == 0) { + client_preferred_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; + } else if (strcmp(mode, "server") == 0) { + client_preferred_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; + } else { + fprintf(stderr, "Invalid decoration mode\n"); + return EXIT_FAILURE; + } + } + + struct wl_display *display = wl_display_connect(NULL); + if (display == NULL) { + fprintf(stderr, "Failed to create display\n"); + return EXIT_FAILURE; + } + + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_dispatch(display); + wl_display_roundtrip(display); + + if (compositor == NULL) { + fprintf(stderr, "wl-compositor not available\n"); + return EXIT_FAILURE; + } + if (wm_base == NULL) { + fprintf(stderr, "xdg-shell not available\n"); + return EXIT_FAILURE; + } + if (decoration_manager == NULL) { + fprintf(stderr, "xdg-decoration not available\n"); + return EXIT_FAILURE; + } + + wlr_egl_init(&egl, EGL_PLATFORM_WAYLAND_EXT, display, NULL, + WL_SHM_FORMAT_ARGB8888); + + struct wl_surface *surface = wl_compositor_create_surface(compositor); + struct xdg_surface *xdg_surface = + xdg_wm_base_get_xdg_surface(wm_base, surface); + struct xdg_toplevel *xdg_toplevel = xdg_surface_get_toplevel(xdg_surface); + decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( + decoration_manager, xdg_toplevel); + + wl_display_roundtrip(display); + request_preferred_mode(); + + xdg_surface_add_listener(xdg_surface, &xdg_surface_listener, NULL); + xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, NULL); + zxdg_toplevel_decoration_v1_add_listener(decoration, &decoration_listener, + NULL); + wl_surface_commit(surface); + + egl_window = wl_egl_window_create(surface, width, height); + egl_surface = wlr_egl_create_surface(&egl, egl_window); + + wl_display_roundtrip(display); + + draw(); + + while (wl_display_dispatch(display) != -1) { + // This space is intentionally left blank + } + + return EXIT_SUCCESS; +} diff --git a/examples/touch.c b/examples/touch.c new file mode 100644 index 00000000..9ed20a28 --- /dev/null +++ b/examples/touch.c @@ -0,0 +1,286 @@ +#define _POSIX_C_SOURCE 200112L +#include <GLES2/gl2.h> +#include <math.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <wayland-server-protocol.h> +#include <wayland-server.h> +#include <wlr/backend.h> +#include <wlr/backend/session.h> +#include <wlr/types/wlr_output.h> +#include <wlr/render/wlr_renderer.h> +#include <wlr/types/wlr_list.h> +#include <wlr/types/wlr_input_device.h> +#include <wlr/types/wlr_matrix.h> +#include <wlr/util/log.h> +#include <xkbcommon/xkbcommon.h> +#include "cat.h" + +struct sample_state { + struct wl_display *display; + struct wlr_renderer *renderer; + struct wlr_texture *cat_texture; + struct wl_list touch_points; + struct timespec last_frame; + struct wl_listener new_output; + struct wl_listener new_input; + struct wl_list touch; +}; + +struct touch_point { + int32_t touch_id; + double x, y; + struct wl_list link; +}; + +struct touch_state { + struct sample_state *sample; + struct wlr_input_device *device; + struct wl_listener destroy; + struct wl_listener down; + struct wl_listener up; + struct wl_listener motion; + struct wl_list link; + void *data; +}; + +struct sample_output { + struct sample_state *sample; + struct wlr_output *output; + struct wl_listener frame; + struct wl_listener destroy; +}; + +struct sample_keyboard { + struct sample_state *sample; + struct wlr_input_device *device; + struct wl_listener key; + struct wl_listener destroy; +}; + +static void output_frame_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = wl_container_of(listener, sample_output, frame); + struct sample_state *sample = sample_output->sample; + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + struct wlr_output *wlr_output = sample_output->output; + + int32_t width, height; + wlr_output_effective_resolution(wlr_output, &width, &height); + + wlr_output_make_current(wlr_output, NULL); + wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); + wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); + + int tex_width, tex_height; + wlr_texture_get_size(sample->cat_texture, &tex_width, &tex_height); + + struct touch_point *p; + wl_list_for_each(p, &sample->touch_points, link) { + int x = (int)(p->x * width) - tex_width / 2; + int y = (int)(p->y * height) - tex_height / 2; + wlr_render_texture(sample->renderer, sample->cat_texture, + wlr_output->transform_matrix, x, y, 1.0f); + } + + wlr_renderer_end(sample->renderer); + wlr_output_swap_buffers(wlr_output, NULL, NULL); + sample->last_frame = now; +} + +static void touch_down_notify(struct wl_listener *listener, void *data) { + struct wlr_event_touch_motion *event = data; + struct touch_state *tstate = wl_container_of(listener, tstate, down); + struct sample_state *sample = tstate->sample; + struct touch_point *point = calloc(1, sizeof(struct touch_point)); + point->touch_id = event->touch_id; + point->x = event->x; + point->y = event->y; + wl_list_insert(&sample->touch_points, &point->link); +} + +static void touch_up_notify(struct wl_listener *listener, void *data ) { + struct wlr_event_touch_up *event = data; + struct touch_state *tstate = wl_container_of(listener, tstate, up); + struct sample_state *sample = tstate->sample; + struct touch_point *point, *tmp; + wl_list_for_each_safe(point, tmp, &sample->touch_points, link) { + if (point->touch_id == event->touch_id) { + wl_list_remove(&point->link); + break; + } + } +} + +static void touch_motion_notify(struct wl_listener *listener, void *data) { + struct wlr_event_touch_motion *event = data; + struct touch_state *tstate = wl_container_of(listener, tstate, motion); + struct sample_state *sample = tstate->sample; + struct touch_point *point; + wl_list_for_each(point, &sample->touch_points, link) { + if (point->touch_id == event->touch_id) { + point->x = event->x; + point->y = event->y; + break; + } + } +} + +static void touch_destroy_notify(struct wl_listener *listener, void *data) { + struct touch_state *tstate = wl_container_of(listener, tstate, destroy); + wl_list_remove(&tstate->link); + wl_list_remove(&tstate->destroy.link); + wl_list_remove(&tstate->down.link); + wl_list_remove(&tstate->up.link); + wl_list_remove(&tstate->motion.link); + free(tstate); +} + +void output_remove_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = wl_container_of(listener, sample_output, destroy); + wl_list_remove(&sample_output->frame.link); + wl_list_remove(&sample_output->destroy.link); + free(sample_output); +} + +void new_output_notify(struct wl_listener *listener, void *data) { + struct wlr_output *output = data; + struct sample_state *sample = wl_container_of(listener, sample, new_output); + struct sample_output *sample_output = calloc(1, sizeof(struct sample_output)); + if (!wl_list_empty(&output->modes)) { + struct wlr_output_mode *mode = wl_container_of(output->modes.prev, mode, link); + wlr_output_set_mode(output, mode); + } + sample_output->output = output; + sample_output->sample = sample; + wl_signal_add(&output->events.frame, &sample_output->frame); + sample_output->frame.notify = output_frame_notify; + wl_signal_add(&output->events.destroy, &sample_output->destroy); + sample_output->destroy.notify = output_remove_notify; +} + +void keyboard_key_notify(struct wl_listener *listener, void *data) { + struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); + struct sample_state *sample = keyboard->sample; + struct wlr_event_keyboard_key *event = data; + uint32_t keycode = event->keycode + 8; + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, + keycode, &syms); + for (int i = 0; i < nsyms; i++) { + xkb_keysym_t sym = syms[i]; + if (sym == XKB_KEY_Escape) { + wl_display_terminate(sample->display); + } + } +} + +void keyboard_destroy_notify(struct wl_listener *listener, void *data) { + struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, destroy); + wl_list_remove(&keyboard->destroy.link); + wl_list_remove(&keyboard->key.link); + free(keyboard); +} + +void new_input_notify(struct wl_listener *listener, void *data) { + struct wlr_input_device *device = data; + struct sample_state *sample = wl_container_of(listener, sample, new_input); + switch (device->type) { + case WLR_INPUT_DEVICE_KEYBOARD:; + struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); + keyboard->device = device; + keyboard->sample = sample; + wl_signal_add(&device->events.destroy, &keyboard->destroy); + keyboard->destroy.notify = keyboard_destroy_notify; + wl_signal_add(&device->keyboard->events.key, &keyboard->key); + keyboard->key.notify = keyboard_key_notify; + struct xkb_rule_names rules = { 0 }; + rules.rules = getenv("XKB_DEFAULT_RULES"); + rules.model = getenv("XKB_DEFAULT_MODEL"); + rules.layout = getenv("XKB_DEFAULT_LAYOUT"); + rules.variant = getenv("XKB_DEFAULT_VARIANT"); + rules.options = getenv("XKB_DEFAULT_OPTIONS"); + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!context) { + wlr_log(WLR_ERROR, "Failed to create XKB context"); + exit(1); + } + struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) { + wlr_log(WLR_ERROR, "Failed to create XKB keymap"); + exit(1); + } + wlr_keyboard_set_keymap(device->keyboard, keymap); + xkb_keymap_unref(keymap); + xkb_context_unref(context); + break; + case WLR_INPUT_DEVICE_TOUCH:; + struct touch_state *tstate = calloc(sizeof(struct touch_state), 1); + tstate->device = device; + tstate->sample = sample; + tstate->destroy.notify = touch_destroy_notify; + wl_signal_add(&device->events.destroy, &tstate->destroy); + tstate->down.notify = touch_down_notify; + wl_signal_add(&device->touch->events.down, &tstate->down); + tstate->motion.notify = touch_motion_notify; + wl_signal_add(&device->touch->events.motion, &tstate->motion); + tstate->up.notify = touch_up_notify; + wl_signal_add(&device->touch->events.up, &tstate->up); + wl_list_insert(&sample->touch, &tstate->link); + break; + default: + break; + } +} + + +int main(int argc, char *argv[]) { + wlr_log_init(WLR_DEBUG, NULL); + struct wl_display *display = wl_display_create(); + struct sample_state state = { + .display = display + }; + wl_list_init(&state.touch_points); + wl_list_init(&state.touch); + + struct wlr_backend *wlr = wlr_backend_autocreate(display, NULL); + if (!wlr) { + exit(1); + } + + wl_signal_add(&wlr->events.new_output, &state.new_output); + state.new_output.notify = new_output_notify; + wl_signal_add(&wlr->events.new_input, &state.new_input); + state.new_input.notify = new_input_notify; + clock_gettime(CLOCK_MONOTONIC, &state.last_frame); + + + state.renderer = wlr_backend_get_renderer(wlr); + if (!state.renderer) { + wlr_log(WLR_ERROR, "Could not start compositor, OOM"); + exit(EXIT_FAILURE); + } + state.cat_texture = wlr_texture_from_pixels(state.renderer, + WL_SHM_FORMAT_ARGB8888, cat_tex.width * 4, cat_tex.width, cat_tex.height, + cat_tex.pixel_data); + if (!state.cat_texture) { + wlr_log(WLR_ERROR, "Could not start compositor, OOM"); + exit(EXIT_FAILURE); + } + + if (!wlr_backend_start(wlr)) { + wlr_log(WLR_ERROR, "Failed to start backend"); + wlr_backend_destroy(wlr); + exit(1); + } + wl_display_run(display); + + wlr_texture_destroy(state.cat_texture); + wl_display_destroy(display); +} |