From 293dbb5ad193a4ed15d735132d1f44db0d251bb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sn=C3=ADda=C5=88ov=C3=BD=20Mistr?= Date: Mon, 11 Dec 2023 16:18:43 +0100 Subject: [PATCH] =?UTF-8?q?Nahr=C3=A1t=20existuj=C3=ADc=C3=AD=20k=C3=B3d?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 3354 +++++++++++++++++ Cargo.toml | 50 + askama.toml | 2 + build.rs | 37 + .../20230710121446_create_tables.down.sql | 1 + .../20230710121446_create_tables.up.sql | 30 + src/auth.rs | 39 + src/cfg.rs | 71 + src/ctx.rs | 36 + src/db/account.rs | 117 + src/db/ban.rs | 107 + src/db/board.rs | 281 ++ src/db/cache.rs | 72 + src/db/mod.rs | 7 + src/db/models.rs | 92 + src/db/post.rs | 451 +++ src/error.rs | 233 ++ src/files.rs | 350 ++ src/filters.rs | 131 + src/lib.rs | 43 + src/main.rs | 154 + src/markup.rs | 216 ++ src/perms.rs | 85 + src/qsform.rs | 43 + src/trip.rs | 54 + src/web/actions/create_post.rs | 250 ++ src/web/actions/mod.rs | 38 + src/web/actions/report_posts.rs | 106 + src/web/actions/staff_post_actions.rs | 219 ++ src/web/actions/user_post_actions.rs | 135 + src/web/board.rs | 74 + src/web/board_catalog.rs | 46 + src/web/index.rs | 24 + src/web/login.rs | 59 + src/web/logout.rs | 13 + src/web/mod.rs | 45 + src/web/overboard.rs | 67 + src/web/overboard_catalog.rs | 30 + src/web/staff/account.rs | 28 + src/web/staff/accounts.rs | 26 + src/web/staff/actions/add_banners.rs | 55 + src/web/staff/actions/change_password.rs | 38 + src/web/staff/actions/create_account.rs | 48 + src/web/staff/actions/create_board.rs | 50 + src/web/staff/actions/delete_account.rs | 23 + src/web/staff/actions/mod.rs | 13 + src/web/staff/actions/remove_accounts.rs | 42 + src/web/staff/actions/remove_banners.rs | 50 + src/web/staff/actions/remove_bans.rs | 37 + src/web/staff/actions/remove_boards.rs | 37 + src/web/staff/actions/transfer_ownership.rs | 39 + src/web/staff/actions/update_board_config.rs | 87 + src/web/staff/actions/update_boards.rs | 57 + src/web/staff/actions/update_permissions.rs | 103 + src/web/staff/banners.rs | 46 + src/web/staff/bans.rs | 35 + src/web/staff/board_config.rs | 46 + src/web/staff/boards.rs | 38 + src/web/staff/mod.rs | 9 + src/web/staff/permissions.rs | 42 + src/web/staff/reports.rs | 23 + src/web/tcx.rs | 113 + src/web/thread.rs | 59 + static/banner.gif | Bin 0 -> 210604 bytes static/favicon.ico | Bin 0 -> 15406 bytes static/flags/ad.png | Bin 0 -> 643 bytes static/flags/ae.png | Bin 0 -> 408 bytes static/flags/af.png | Bin 0 -> 604 bytes static/flags/ag.png | Bin 0 -> 591 bytes static/flags/ai.png | Bin 0 -> 643 bytes static/flags/al.png | Bin 0 -> 600 bytes static/flags/am.png | Bin 0 -> 497 bytes static/flags/an.png | Bin 0 -> 488 bytes static/flags/ao.png | Bin 0 -> 428 bytes static/flags/ar.png | Bin 0 -> 506 bytes static/flags/as.png | Bin 0 -> 647 bytes static/flags/at.png | Bin 0 -> 403 bytes static/flags/au.png | Bin 0 -> 673 bytes static/flags/aw.png | Bin 0 -> 524 bytes static/flags/ax.png | Bin 0 -> 663 bytes static/flags/az.png | Bin 0 -> 589 bytes static/flags/ba.png | Bin 0 -> 593 bytes static/flags/bb.png | Bin 0 -> 585 bytes static/flags/bd.png | Bin 0 -> 504 bytes static/flags/be.png | Bin 0 -> 449 bytes static/flags/bf.png | Bin 0 -> 497 bytes static/flags/bg.png | Bin 0 -> 462 bytes static/flags/bh.png | Bin 0 -> 457 bytes static/flags/bi.png | Bin 0 -> 675 bytes static/flags/bj.png | Bin 0 -> 486 bytes static/flags/bm.png | Bin 0 -> 611 bytes static/flags/bn.png | Bin 0 -> 639 bytes static/flags/bo.png | Bin 0 -> 500 bytes static/flags/br.png | Bin 0 -> 593 bytes static/flags/bs.png | Bin 0 -> 526 bytes static/flags/bt.png | Bin 0 -> 631 bytes static/flags/bv.png | Bin 0 -> 512 bytes static/flags/bw.png | Bin 0 -> 443 bytes static/flags/by.png | Bin 0 -> 514 bytes static/flags/bz.png | Bin 0 -> 600 bytes static/flags/ca.png | Bin 0 -> 628 bytes static/flags/cc.png | Bin 0 -> 625 bytes static/flags/cd.png | Bin 0 -> 528 bytes static/flags/cf.png | Bin 0 -> 614 bytes static/flags/cg.png | Bin 0 -> 521 bytes static/flags/ch.png | Bin 0 -> 367 bytes static/flags/ci.png | Bin 0 -> 453 bytes static/flags/ck.png | Bin 0 -> 586 bytes static/flags/cl.png | Bin 0 -> 450 bytes static/flags/cm.png | Bin 0 -> 525 bytes static/flags/cn.png | Bin 0 -> 472 bytes static/flags/co.png | Bin 0 -> 483 bytes static/flags/cr.png | Bin 0 -> 477 bytes static/flags/cs.png | Bin 0 -> 439 bytes static/flags/cu.png | Bin 0 -> 563 bytes static/flags/cv.png | Bin 0 -> 529 bytes static/flags/cx.png | Bin 0 -> 608 bytes static/flags/cy.png | Bin 0 -> 428 bytes static/flags/cz.png | Bin 0 -> 476 bytes static/flags/de.png | Bin 0 -> 545 bytes static/flags/dj.png | Bin 0 -> 572 bytes static/flags/dk.png | Bin 0 -> 495 bytes static/flags/dm.png | Bin 0 -> 620 bytes static/flags/do.png | Bin 0 -> 508 bytes static/flags/dz.png | Bin 0 -> 582 bytes static/flags/ec.png | Bin 0 -> 500 bytes static/flags/ee.png | Bin 0 -> 429 bytes static/flags/eg.png | Bin 0 -> 465 bytes static/flags/eh.png | Bin 0 -> 508 bytes static/flags/er.png | Bin 0 -> 653 bytes static/flags/es.png | Bin 0 -> 469 bytes static/flags/et.png | Bin 0 -> 592 bytes static/flags/fam.png | Bin 0 -> 532 bytes static/flags/fi.png | Bin 0 -> 489 bytes static/flags/fj.png | Bin 0 -> 610 bytes static/flags/fk.png | Bin 0 -> 648 bytes static/flags/fm.png | Bin 0 -> 552 bytes static/flags/fo.png | Bin 0 -> 474 bytes static/flags/fr.png | Bin 0 -> 545 bytes static/flags/ga.png | Bin 0 -> 489 bytes static/flags/gb.png | Bin 0 -> 599 bytes static/flags/gd.png | Bin 0 -> 637 bytes static/flags/ge.png | Bin 0 -> 594 bytes static/flags/gf.png | Bin 0 -> 545 bytes static/flags/gh.png | Bin 0 -> 490 bytes static/flags/gi.png | Bin 0 -> 463 bytes static/flags/gl.png | Bin 0 -> 470 bytes static/flags/gm.png | Bin 0 -> 493 bytes static/flags/gn.png | Bin 0 -> 480 bytes static/flags/gp.png | Bin 0 -> 488 bytes static/flags/gq.png | Bin 0 -> 537 bytes static/flags/gr.png | Bin 0 -> 487 bytes static/flags/gs.png | Bin 0 -> 630 bytes static/flags/gt.png | Bin 0 -> 493 bytes static/flags/gu.png | Bin 0 -> 509 bytes static/flags/gw.png | Bin 0 -> 516 bytes static/flags/gy.png | Bin 0 -> 645 bytes static/flags/hk.png | Bin 0 -> 527 bytes static/flags/hm.png | Bin 0 -> 673 bytes static/flags/hn.png | Bin 0 -> 537 bytes static/flags/hr.png | Bin 0 -> 524 bytes static/flags/ht.png | Bin 0 -> 487 bytes static/flags/hu.png | Bin 0 -> 432 bytes static/flags/id.png | Bin 0 -> 430 bytes static/flags/ie.png | Bin 0 -> 481 bytes static/flags/il.png | Bin 0 -> 431 bytes static/flags/in.png | Bin 0 -> 503 bytes static/flags/io.png | Bin 0 -> 658 bytes static/flags/iq.png | Bin 0 -> 515 bytes static/flags/ir.png | Bin 0 -> 512 bytes static/flags/is.png | Bin 0 -> 532 bytes static/flags/it.png | Bin 0 -> 420 bytes static/flags/jm.png | Bin 0 -> 637 bytes static/flags/jo.png | Bin 0 -> 473 bytes static/flags/jp.png | Bin 0 -> 420 bytes static/flags/ke.png | Bin 0 -> 569 bytes static/flags/kg.png | Bin 0 -> 510 bytes static/flags/kh.png | Bin 0 -> 549 bytes static/flags/ki.png | Bin 0 -> 656 bytes static/flags/km.png | Bin 0 -> 577 bytes static/flags/kn.png | Bin 0 -> 604 bytes static/flags/kp.png | Bin 0 -> 561 bytes static/flags/kr.png | Bin 0 -> 592 bytes static/flags/kw.png | Bin 0 -> 486 bytes static/flags/ky.png | Bin 0 -> 643 bytes static/flags/kz.png | Bin 0 -> 616 bytes static/flags/la.png | Bin 0 -> 563 bytes static/flags/lb.png | Bin 0 -> 517 bytes static/flags/lc.png | Bin 0 -> 520 bytes static/flags/li.png | Bin 0 -> 537 bytes static/flags/lk.png | Bin 0 -> 627 bytes static/flags/lr.png | Bin 0 -> 466 bytes static/flags/ls.png | Bin 0 -> 628 bytes static/flags/lt.png | Bin 0 -> 508 bytes static/flags/lu.png | Bin 0 -> 481 bytes static/flags/lv.png | Bin 0 -> 465 bytes static/flags/ly.png | Bin 0 -> 419 bytes static/flags/ma.png | Bin 0 -> 432 bytes static/flags/mc.png | Bin 0 -> 380 bytes static/flags/md.png | Bin 0 -> 566 bytes static/flags/me.png | Bin 0 -> 448 bytes static/flags/mg.png | Bin 0 -> 453 bytes static/flags/mh.png | Bin 0 -> 628 bytes static/flags/mk.png | Bin 0 -> 664 bytes static/flags/ml.png | Bin 0 -> 474 bytes static/flags/mm.png | Bin 0 -> 483 bytes static/flags/mn.png | Bin 0 -> 492 bytes static/flags/mo.png | Bin 0 -> 588 bytes static/flags/mp.png | Bin 0 -> 597 bytes static/flags/mq.png | Bin 0 -> 655 bytes static/flags/mr.png | Bin 0 -> 569 bytes static/flags/ms.png | Bin 0 -> 614 bytes static/flags/mt.png | Bin 0 -> 420 bytes static/flags/mu.png | Bin 0 -> 496 bytes static/flags/mv.png | Bin 0 -> 542 bytes static/flags/mw.png | Bin 0 -> 529 bytes static/flags/mx.png | Bin 0 -> 574 bytes static/flags/my.png | Bin 0 -> 571 bytes static/flags/mz.png | Bin 0 -> 584 bytes static/flags/na.png | Bin 0 -> 647 bytes static/flags/nc.png | Bin 0 -> 591 bytes static/flags/ne.png | Bin 0 -> 537 bytes static/flags/nf.png | Bin 0 -> 602 bytes static/flags/ng.png | Bin 0 -> 482 bytes static/flags/ni.png | Bin 0 -> 508 bytes static/flags/nl.png | Bin 0 -> 453 bytes static/flags/no.png | Bin 0 -> 512 bytes static/flags/np.png | Bin 0 -> 443 bytes static/flags/nr.png | Bin 0 -> 527 bytes static/flags/nu.png | Bin 0 -> 572 bytes static/flags/nz.png | Bin 0 -> 639 bytes static/flags/om.png | Bin 0 -> 478 bytes static/flags/pa.png | Bin 0 -> 519 bytes static/flags/pe.png | Bin 0 -> 397 bytes static/flags/pf.png | Bin 0 -> 498 bytes static/flags/pg.png | Bin 0 -> 593 bytes static/flags/ph.png | Bin 0 -> 538 bytes static/flags/pk.png | Bin 0 -> 569 bytes static/flags/pl.png | Bin 0 -> 374 bytes static/flags/pm.png | Bin 0 -> 689 bytes static/flags/pn.png | Bin 0 -> 657 bytes static/flags/pr.png | Bin 0 -> 556 bytes static/flags/ps.png | Bin 0 -> 472 bytes static/flags/pt.png | Bin 0 -> 554 bytes static/flags/pw.png | Bin 0 -> 550 bytes static/flags/py.png | Bin 0 -> 473 bytes static/flags/qa.png | Bin 0 -> 450 bytes static/flags/re.png | Bin 0 -> 545 bytes static/flags/ro.png | Bin 0 -> 495 bytes static/flags/rs.png | Bin 0 -> 423 bytes static/flags/ru.png | Bin 0 -> 420 bytes static/flags/rw.png | Bin 0 -> 533 bytes static/flags/sa.png | Bin 0 -> 551 bytes static/flags/sb.png | Bin 0 -> 624 bytes static/flags/sc.png | Bin 0 -> 608 bytes static/flags/sd.png | Bin 0 -> 492 bytes static/flags/se.png | Bin 0 -> 542 bytes static/flags/sg.png | Bin 0 -> 468 bytes static/flags/sh.png | Bin 0 -> 645 bytes static/flags/si.png | Bin 0 -> 510 bytes static/flags/sj.png | Bin 0 -> 512 bytes static/flags/sk.png | Bin 0 -> 562 bytes static/flags/sl.png | Bin 0 -> 436 bytes static/flags/sm.png | Bin 0 -> 502 bytes static/flags/sn.png | Bin 0 -> 532 bytes static/flags/so.png | Bin 0 -> 527 bytes static/flags/sr.png | Bin 0 -> 513 bytes static/flags/st.png | Bin 0 -> 584 bytes static/flags/sv.png | Bin 0 -> 501 bytes static/flags/sy.png | Bin 0 -> 422 bytes static/flags/sz.png | Bin 0 -> 643 bytes static/flags/tc.png | Bin 0 -> 624 bytes static/flags/td.png | Bin 0 -> 570 bytes static/flags/tf.png | Bin 0 -> 527 bytes static/flags/tg.png | Bin 0 -> 562 bytes static/flags/th.png | Bin 0 -> 452 bytes static/flags/tj.png | Bin 0 -> 496 bytes static/flags/tk.png | Bin 0 -> 638 bytes static/flags/tl.png | Bin 0 -> 514 bytes static/flags/tm.png | Bin 0 -> 593 bytes static/flags/tn.png | Bin 0 -> 495 bytes static/flags/to.png | Bin 0 -> 426 bytes static/flags/tr.png | Bin 0 -> 492 bytes static/flags/tt.png | Bin 0 -> 617 bytes static/flags/tv.png | Bin 0 -> 536 bytes static/flags/tw.png | Bin 0 -> 465 bytes static/flags/tz.png | Bin 0 -> 642 bytes static/flags/ua.png | Bin 0 -> 446 bytes static/flags/ug.png | Bin 0 -> 531 bytes static/flags/um.png | Bin 0 -> 571 bytes static/flags/us.png | Bin 0 -> 609 bytes static/flags/uy.png | Bin 0 -> 532 bytes static/flags/uz.png | Bin 0 -> 515 bytes static/flags/va.png | Bin 0 -> 553 bytes static/flags/vc.png | Bin 0 -> 577 bytes static/flags/ve.png | Bin 0 -> 528 bytes static/flags/vg.png | Bin 0 -> 630 bytes static/flags/vi.png | Bin 0 -> 616 bytes static/flags/vn.png | Bin 0 -> 474 bytes static/flags/vu.png | Bin 0 -> 604 bytes static/flags/wf.png | Bin 0 -> 554 bytes static/flags/ws.png | Bin 0 -> 476 bytes static/flags/xx.png | Bin 0 -> 447 bytes static/flags/ye.png | Bin 0 -> 413 bytes static/flags/yt.png | Bin 0 -> 593 bytes static/flags/za.png | Bin 0 -> 642 bytes static/flags/zm.png | Bin 0 -> 500 bytes static/flags/zw.png | Bin 0 -> 574 bytes static/icons/download.png | Bin 0 -> 1166 bytes static/icons/locked.png | Bin 0 -> 881 bytes static/icons/sticky.png | Bin 0 -> 754 bytes static/spoiler.png | Bin 0 -> 2682 bytes static/style.css | 442 +++ static/themes/yotsuba-b.css | 38 + static/themes/yotsuba.css | 38 + templates/action.html | 18 + templates/banned.html | 64 + templates/base.html | 34 + templates/board.html | 50 + templates/board_catalog.html | 29 + templates/error.html | 28 + templates/index.html | 47 + templates/login.html | 24 + templates/macros/catalog-entry.html | 23 + templates/macros/pagination.html | 15 + templates/macros/post-actions.html | 188 + templates/macros/post-form.html | 87 + templates/macros/post.html | 59 + templates/macros/staff-nav.html | 18 + templates/overboard.html | 49 + templates/overboard_catalog.html | 29 + templates/staff/account.html | 68 + templates/staff/accounts.html | 57 + templates/staff/banners.html | 50 + templates/staff/bans.html | 47 + templates/staff/board-config.html | 154 + templates/staff/boards.html | 82 + templates/staff/logs.html | 30 + templates/staff/permissions.html | 135 + templates/staff/reports.html | 14 + templates/thread.html | 33 + 341 files changed, 10256 insertions(+) create mode 100755 Cargo.lock create mode 100755 Cargo.toml create mode 100644 askama.toml create mode 100755 build.rs create mode 100755 migrations/20230710121446_create_tables.down.sql create mode 100755 migrations/20230710121446_create_tables.up.sql create mode 100755 src/auth.rs create mode 100755 src/cfg.rs create mode 100755 src/ctx.rs create mode 100755 src/db/account.rs create mode 100755 src/db/ban.rs create mode 100755 src/db/board.rs create mode 100644 src/db/cache.rs create mode 100755 src/db/mod.rs create mode 100755 src/db/models.rs create mode 100755 src/db/post.rs create mode 100755 src/error.rs create mode 100755 src/files.rs create mode 100644 src/filters.rs create mode 100755 src/lib.rs create mode 100755 src/main.rs create mode 100644 src/markup.rs create mode 100755 src/perms.rs create mode 100644 src/qsform.rs create mode 100755 src/trip.rs create mode 100644 src/web/actions/create_post.rs create mode 100644 src/web/actions/mod.rs create mode 100644 src/web/actions/report_posts.rs create mode 100644 src/web/actions/staff_post_actions.rs create mode 100644 src/web/actions/user_post_actions.rs create mode 100755 src/web/board.rs create mode 100644 src/web/board_catalog.rs create mode 100755 src/web/index.rs create mode 100755 src/web/login.rs create mode 100755 src/web/logout.rs create mode 100755 src/web/mod.rs create mode 100644 src/web/overboard.rs create mode 100644 src/web/overboard_catalog.rs create mode 100755 src/web/staff/account.rs create mode 100755 src/web/staff/accounts.rs create mode 100755 src/web/staff/actions/add_banners.rs create mode 100755 src/web/staff/actions/change_password.rs create mode 100755 src/web/staff/actions/create_account.rs create mode 100755 src/web/staff/actions/create_board.rs create mode 100755 src/web/staff/actions/delete_account.rs create mode 100755 src/web/staff/actions/mod.rs create mode 100755 src/web/staff/actions/remove_accounts.rs create mode 100755 src/web/staff/actions/remove_banners.rs create mode 100755 src/web/staff/actions/remove_bans.rs create mode 100755 src/web/staff/actions/remove_boards.rs create mode 100755 src/web/staff/actions/transfer_ownership.rs create mode 100755 src/web/staff/actions/update_board_config.rs create mode 100755 src/web/staff/actions/update_boards.rs create mode 100755 src/web/staff/actions/update_permissions.rs create mode 100755 src/web/staff/banners.rs create mode 100755 src/web/staff/bans.rs create mode 100755 src/web/staff/board_config.rs create mode 100755 src/web/staff/boards.rs create mode 100755 src/web/staff/mod.rs create mode 100755 src/web/staff/permissions.rs create mode 100755 src/web/staff/reports.rs create mode 100755 src/web/tcx.rs create mode 100644 src/web/thread.rs create mode 100755 static/banner.gif create mode 100755 static/favicon.ico create mode 100755 static/flags/ad.png create mode 100755 static/flags/ae.png create mode 100755 static/flags/af.png create mode 100755 static/flags/ag.png create mode 100755 static/flags/ai.png create mode 100755 static/flags/al.png create mode 100755 static/flags/am.png create mode 100755 static/flags/an.png create mode 100755 static/flags/ao.png create mode 100755 static/flags/ar.png create mode 100755 static/flags/as.png create mode 100755 static/flags/at.png create mode 100755 static/flags/au.png create mode 100755 static/flags/aw.png create mode 100755 static/flags/ax.png create mode 100755 static/flags/az.png create mode 100755 static/flags/ba.png create mode 100755 static/flags/bb.png create mode 100755 static/flags/bd.png create mode 100755 static/flags/be.png create mode 100755 static/flags/bf.png create mode 100755 static/flags/bg.png create mode 100755 static/flags/bh.png create mode 100755 static/flags/bi.png create mode 100755 static/flags/bj.png create mode 100755 static/flags/bm.png create mode 100755 static/flags/bn.png create mode 100755 static/flags/bo.png create mode 100755 static/flags/br.png create mode 100755 static/flags/bs.png create mode 100755 static/flags/bt.png create mode 100755 static/flags/bv.png create mode 100755 static/flags/bw.png create mode 100755 static/flags/by.png create mode 100755 static/flags/bz.png create mode 100755 static/flags/ca.png create mode 100755 static/flags/cc.png create mode 100755 static/flags/cd.png create mode 100755 static/flags/cf.png create mode 100755 static/flags/cg.png create mode 100755 static/flags/ch.png create mode 100755 static/flags/ci.png create mode 100755 static/flags/ck.png create mode 100755 static/flags/cl.png create mode 100755 static/flags/cm.png create mode 100755 static/flags/cn.png create mode 100755 static/flags/co.png create mode 100755 static/flags/cr.png create mode 100755 static/flags/cs.png create mode 100755 static/flags/cu.png create mode 100755 static/flags/cv.png create mode 100755 static/flags/cx.png create mode 100755 static/flags/cy.png create mode 100755 static/flags/cz.png create mode 100755 static/flags/de.png create mode 100755 static/flags/dj.png create mode 100755 static/flags/dk.png create mode 100755 static/flags/dm.png create mode 100755 static/flags/do.png create mode 100755 static/flags/dz.png create mode 100755 static/flags/ec.png create mode 100755 static/flags/ee.png create mode 100755 static/flags/eg.png create mode 100755 static/flags/eh.png create mode 100755 static/flags/er.png create mode 100755 static/flags/es.png create mode 100755 static/flags/et.png create mode 100755 static/flags/fam.png create mode 100755 static/flags/fi.png create mode 100755 static/flags/fj.png create mode 100755 static/flags/fk.png create mode 100755 static/flags/fm.png create mode 100755 static/flags/fo.png create mode 100755 static/flags/fr.png create mode 100755 static/flags/ga.png create mode 100755 static/flags/gb.png create mode 100755 static/flags/gd.png create mode 100755 static/flags/ge.png create mode 100755 static/flags/gf.png create mode 100755 static/flags/gh.png create mode 100755 static/flags/gi.png create mode 100755 static/flags/gl.png create mode 100755 static/flags/gm.png create mode 100755 static/flags/gn.png create mode 100755 static/flags/gp.png create mode 100755 static/flags/gq.png create mode 100755 static/flags/gr.png create mode 100755 static/flags/gs.png create mode 100755 static/flags/gt.png create mode 100755 static/flags/gu.png create mode 100755 static/flags/gw.png create mode 100755 static/flags/gy.png create mode 100755 static/flags/hk.png create mode 100755 static/flags/hm.png create mode 100755 static/flags/hn.png create mode 100755 static/flags/hr.png create mode 100755 static/flags/ht.png create mode 100755 static/flags/hu.png create mode 100755 static/flags/id.png create mode 100755 static/flags/ie.png create mode 100755 static/flags/il.png create mode 100755 static/flags/in.png create mode 100755 static/flags/io.png create mode 100755 static/flags/iq.png create mode 100755 static/flags/ir.png create mode 100755 static/flags/is.png create mode 100755 static/flags/it.png create mode 100755 static/flags/jm.png create mode 100755 static/flags/jo.png create mode 100755 static/flags/jp.png create mode 100755 static/flags/ke.png create mode 100755 static/flags/kg.png create mode 100755 static/flags/kh.png create mode 100755 static/flags/ki.png create mode 100755 static/flags/km.png create mode 100755 static/flags/kn.png create mode 100755 static/flags/kp.png create mode 100755 static/flags/kr.png create mode 100755 static/flags/kw.png create mode 100755 static/flags/ky.png create mode 100755 static/flags/kz.png create mode 100755 static/flags/la.png create mode 100755 static/flags/lb.png create mode 100755 static/flags/lc.png create mode 100755 static/flags/li.png create mode 100755 static/flags/lk.png create mode 100755 static/flags/lr.png create mode 100755 static/flags/ls.png create mode 100755 static/flags/lt.png create mode 100755 static/flags/lu.png create mode 100755 static/flags/lv.png create mode 100755 static/flags/ly.png create mode 100755 static/flags/ma.png create mode 100755 static/flags/mc.png create mode 100755 static/flags/md.png create mode 100755 static/flags/me.png create mode 100755 static/flags/mg.png create mode 100755 static/flags/mh.png create mode 100755 static/flags/mk.png create mode 100755 static/flags/ml.png create mode 100755 static/flags/mm.png create mode 100755 static/flags/mn.png create mode 100755 static/flags/mo.png create mode 100755 static/flags/mp.png create mode 100755 static/flags/mq.png create mode 100755 static/flags/mr.png create mode 100755 static/flags/ms.png create mode 100755 static/flags/mt.png create mode 100755 static/flags/mu.png create mode 100755 static/flags/mv.png create mode 100755 static/flags/mw.png create mode 100755 static/flags/mx.png create mode 100755 static/flags/my.png create mode 100755 static/flags/mz.png create mode 100755 static/flags/na.png create mode 100755 static/flags/nc.png create mode 100755 static/flags/ne.png create mode 100755 static/flags/nf.png create mode 100755 static/flags/ng.png create mode 100755 static/flags/ni.png create mode 100755 static/flags/nl.png create mode 100755 static/flags/no.png create mode 100755 static/flags/np.png create mode 100755 static/flags/nr.png create mode 100755 static/flags/nu.png create mode 100755 static/flags/nz.png create mode 100755 static/flags/om.png create mode 100755 static/flags/pa.png create mode 100755 static/flags/pe.png create mode 100755 static/flags/pf.png create mode 100755 static/flags/pg.png create mode 100755 static/flags/ph.png create mode 100755 static/flags/pk.png create mode 100755 static/flags/pl.png create mode 100755 static/flags/pm.png create mode 100755 static/flags/pn.png create mode 100755 static/flags/pr.png create mode 100755 static/flags/ps.png create mode 100755 static/flags/pt.png create mode 100755 static/flags/pw.png create mode 100755 static/flags/py.png create mode 100755 static/flags/qa.png create mode 100755 static/flags/re.png create mode 100755 static/flags/ro.png create mode 100755 static/flags/rs.png create mode 100755 static/flags/ru.png create mode 100755 static/flags/rw.png create mode 100755 static/flags/sa.png create mode 100755 static/flags/sb.png create mode 100755 static/flags/sc.png create mode 100755 static/flags/sd.png create mode 100755 static/flags/se.png create mode 100755 static/flags/sg.png create mode 100755 static/flags/sh.png create mode 100755 static/flags/si.png create mode 100755 static/flags/sj.png create mode 100755 static/flags/sk.png create mode 100755 static/flags/sl.png create mode 100755 static/flags/sm.png create mode 100755 static/flags/sn.png create mode 100755 static/flags/so.png create mode 100755 static/flags/sr.png create mode 100755 static/flags/st.png create mode 100755 static/flags/sv.png create mode 100755 static/flags/sy.png create mode 100755 static/flags/sz.png create mode 100755 static/flags/tc.png create mode 100755 static/flags/td.png create mode 100755 static/flags/tf.png create mode 100755 static/flags/tg.png create mode 100755 static/flags/th.png create mode 100755 static/flags/tj.png create mode 100755 static/flags/tk.png create mode 100755 static/flags/tl.png create mode 100755 static/flags/tm.png create mode 100755 static/flags/tn.png create mode 100755 static/flags/to.png create mode 100755 static/flags/tr.png create mode 100755 static/flags/tt.png create mode 100755 static/flags/tv.png create mode 100755 static/flags/tw.png create mode 100755 static/flags/tz.png create mode 100755 static/flags/ua.png create mode 100755 static/flags/ug.png create mode 100755 static/flags/um.png create mode 100755 static/flags/us.png create mode 100755 static/flags/uy.png create mode 100755 static/flags/uz.png create mode 100755 static/flags/va.png create mode 100755 static/flags/vc.png create mode 100755 static/flags/ve.png create mode 100755 static/flags/vg.png create mode 100755 static/flags/vi.png create mode 100755 static/flags/vn.png create mode 100755 static/flags/vu.png create mode 100755 static/flags/wf.png create mode 100755 static/flags/ws.png create mode 100755 static/flags/xx.png create mode 100755 static/flags/ye.png create mode 100755 static/flags/yt.png create mode 100755 static/flags/za.png create mode 100755 static/flags/zm.png create mode 100755 static/flags/zw.png create mode 100755 static/icons/download.png create mode 100755 static/icons/locked.png create mode 100755 static/icons/sticky.png create mode 100755 static/spoiler.png create mode 100755 static/style.css create mode 100644 static/themes/yotsuba-b.css create mode 100644 static/themes/yotsuba.css create mode 100644 templates/action.html create mode 100644 templates/banned.html create mode 100755 templates/base.html create mode 100755 templates/board.html create mode 100755 templates/board_catalog.html create mode 100755 templates/error.html create mode 100755 templates/index.html create mode 100755 templates/login.html create mode 100644 templates/macros/catalog-entry.html create mode 100644 templates/macros/pagination.html create mode 100644 templates/macros/post-actions.html create mode 100644 templates/macros/post-form.html create mode 100644 templates/macros/post.html create mode 100644 templates/macros/staff-nav.html create mode 100644 templates/overboard.html create mode 100755 templates/overboard_catalog.html create mode 100755 templates/staff/account.html create mode 100755 templates/staff/accounts.html create mode 100755 templates/staff/banners.html create mode 100755 templates/staff/bans.html create mode 100755 templates/staff/board-config.html create mode 100755 templates/staff/boards.html create mode 100755 templates/staff/logs.html create mode 100755 templates/staff/permissions.html create mode 100755 templates/staff/reports.html create mode 100644 templates/thread.html diff --git a/Cargo.lock b/Cargo.lock new file mode 100755 index 0000000..599eafe --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,3354 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "actix-codec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" +dependencies = [ + "bitflags 1.3.2", + "bytes", + "futures-core", + "futures-sink", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "actix-files" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d832782fac6ca7369a70c9ee9a20554623c5e51c76e190ad151780ebea1cf689" +dependencies = [ + "actix-http", + "actix-service", + "actix-utils", + "actix-web", + "askama_escape", + "bitflags 1.3.2", + "bytes", + "derive_more", + "futures-core", + "http-range", + "log", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", +] + +[[package]] +name = "actix-http" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2079246596c18b4a33e274ae10c0e50613f4d32a4198e09c7b93771013fed74" +dependencies = [ + "actix-codec", + "actix-rt", + "actix-service", + "actix-utils", + "ahash 0.8.3", + "base64 0.21.2", + "bitflags 1.3.2", + "brotli", + "bytes", + "bytestring", + "derive_more", + "encoding_rs", + "flate2", + "futures-core", + "h2", + "http", + "httparse", + "httpdate", + "itoa", + "language-tags", + "local-channel", + "mime", + "percent-encoding", + "pin-project-lite", + "rand", + "sha1", + "smallvec", + "tokio", + "tokio-util", + "tracing", + "zstd", +] + +[[package]] +name = "actix-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" +dependencies = [ + "quote", + "syn 2.0.28", +] + +[[package]] +name = "actix-multipart" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee489e3c01eae4d1c35b03c4493f71cb40d93f66b14558feb1b1a807671cc4e" +dependencies = [ + "actix-multipart-derive", + "actix-utils", + "actix-web", + "bytes", + "derive_more", + "futures-core", + "futures-util", + "httparse", + "local-waker", + "log", + "memchr", + "mime", + "serde", + "serde_json", + "serde_plain", + "tempfile", + "tokio", +] + +[[package]] +name = "actix-multipart-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ec592f234db8a253cf80531246a4407c8a70530423eea80688a6c5a44a110e7" +dependencies = [ + "darling", + "parse-size", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "actix-router" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799" +dependencies = [ + "bytestring", + "http", + "regex", + "serde", + "tracing", +] + +[[package]] +name = "actix-rt" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15265b6b8e2347670eb363c47fc8c75208b4a4994b27192f345fcbe707804f3e" +dependencies = [ + "futures-core", + "tokio", +] + +[[package]] +name = "actix-server" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e8613a75dd50cc45f473cee3c34d59ed677c0f7b44480ce3b8247d7dc519327" +dependencies = [ + "actix-rt", + "actix-service", + "actix-utils", + "futures-core", + "futures-util", + "mio", + "num_cpus", + "socket2 0.4.9", + "tokio", + "tracing", +] + +[[package]] +name = "actix-service" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" +dependencies = [ + "futures-core", + "paste", + "pin-project-lite", +] + +[[package]] +name = "actix-utils" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" +dependencies = [ + "local-waker", + "pin-project-lite", +] + +[[package]] +name = "actix-web" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3cb42f9566ab176e1ef0b8b3a896529062b4efc6be0123046095914c4c1c96" +dependencies = [ + "actix-codec", + "actix-http", + "actix-macros", + "actix-router", + "actix-rt", + "actix-server", + "actix-service", + "actix-utils", + "actix-web-codegen", + "ahash 0.7.6", + "bytes", + "bytestring", + "cfg-if", + "cookie", + "derive_more", + "encoding_rs", + "futures-core", + "futures-util", + "http", + "itoa", + "language-tags", + "log", + "mime", + "once_cell", + "pin-project-lite", + "regex", + "serde", + "serde_json", + "serde_urlencoded", + "smallvec", + "socket2 0.4.9", + "time", + "url", +] + +[[package]] +name = "actix-web-codegen" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2262160a7ae29e3415554a3f1fc04c764b1540c116aa524683208078b7a75bc9" +dependencies = [ + "actix-router", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "addr2line" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "allocator-api2" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56fc6cf8dc8c4158eed8649f9b8b0ea1518eb62b544fe9490d66fa0b349eafe9" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c6f84b74db2535ebae81eede2f39b947dcbf01d093ae5f791e5dd414a1bf289" + +[[package]] +name = "askama" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47cbc3cf73fa8d9833727bbee4835ba5c421a0d65b72daf9a7b5d0e0f9cfb57e" +dependencies = [ + "askama_derive", + "askama_escape", + "humansize", + "num-traits", + "percent-encoding", +] + +[[package]] +name = "askama_derive" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22fbe0413545c098358e56966ff22cdd039e10215ae213cfbd65032b119fc94" +dependencies = [ + "basic-toml", + "mime", + "mime_guess", + "nom", + "proc-macro2", + "quote", + "serde", + "syn 2.0.28", +] + +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + +[[package]] +name = "async-trait" +version = "0.1.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "basic-toml" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f838d03a705d72b12389b8930bd14cacf493be1380bfb15720d4d12db5ab03ac" +dependencies = [ + "serde", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +dependencies = [ + "serde", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blowfish" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32fa6a061124e37baba002e496d203e23ba3d7b73750be82dbfbc92913048a5b" +dependencies = [ + "byteorder", + "cipher", + "opaque-debug", +] + +[[package]] +name = "brotli" +version = "3.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "bytemuck" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "bytestring" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "238e4886760d98c4f899360c834fa93e62cf7f721ac3c2da375cbdf4b8679aae" +dependencies = [ + "bytes", +] + +[[package]] +name = "captcha" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db21780337b425f968a2c3efa842eeaa4fe53d2bcb1eb27d2877460a862fb0ab" +dependencies = [ + "base64 0.13.1", + "hound", + "image", + "lodepng", + "rand", + "serde_json", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "pure-rust-locales", + "serde", + "wasm-bindgen", + "windows-targets", +] + +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +dependencies = [ + "generic-array", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "const-oid" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6340df57935414636969091153f35f68d9f00bbc8fb4a9c6054706c213e6c6bc" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cookie" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "cow-utils" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79bb3adfaf5f75d24b01aee375f7555907840fa2800e5ec8fa3b9e2031830173" + +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "der" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7ed52955ce76b1554f509074bb357d3fb8ac9b51288a65a3fd480d1dfba946" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "educe" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "079044df30bb07de7d846d41a184c4b00e66ebdac93ee459253474f3a47e50ae" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +dependencies = [ + "serde", +] + +[[package]] +name = "encoding" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec" +dependencies = [ + "encoding-index-japanese", + "encoding-index-korean", + "encoding-index-simpchinese", + "encoding-index-singlebyte", + "encoding-index-tradchinese", +] + +[[package]] +name = "encoding-index-japanese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-korean" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-simpchinese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-singlebyte" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-tradchinese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding_index_tests" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" + +[[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum-ordinalize" +version = "3.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4f76552f53cefc9a7f64987c3701b99d982f7690606fd67de1d09712fbf52f1" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "enumflags2" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c041f5090df68b32bcd905365fd51769c8b9d553fe87fde0b683534f10c01bd2" +dependencies = [ + "enumflags2_derive", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "exr" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1e481eb11a482815d3e9d618db8c42a93207134662873809335a92327440c18" +dependencies = [ + "bit_field", + "flume", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fallible_collections" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a88c69768c0a15262df21899142bc6df9b9b823546d4b4b9a7bc2d6c448ec6fd" +dependencies = [ + "hashbrown 0.13.2", +] + +[[package]] +name = "fancy-regex" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7493d4c459da9f84325ad297371a6b2b8a162800873a22e3b6b6512e61d18c05" +dependencies = [ + "bit-set", + "regex", +] + +[[package]] +name = "fastrand" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" + +[[package]] +name = "fdeflate" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "flate2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.10.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" +dependencies = [ + "futures-core", + "futures-sink", + "nanorand", + "pin-project", + "spin 0.9.8", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gif" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "h2" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 1.9.3", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "half" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" +dependencies = [ + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.3", +] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +dependencies = [ + "ahash 0.8.3", + "allocator-api2", +] + +[[package]] +name = "hashlink" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "312f66718a2d7789ffef4f4b7b213138ed9f1eb3aa1d0d82fc99f88fb3ffd26f" +dependencies = [ + "hashbrown 0.14.0", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac 0.12.1", +] + +[[package]] +name = "hmac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "hound" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d13cdbd5dbb29f9c88095bbdc2590c9cba0d0a1269b983fef6b2cdd7e9f4db1" + +[[package]] +name = "html-escape" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476" +dependencies = [ + "utf8-width", +] + +[[package]] +name = "html-minifier" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18f74036e4be1b97eaf78bcf795d55002eccf613d5c4705bf78d3b92649ab00f" +dependencies = [ + "cow-utils", + "educe", + "html-escape", + "minifier", +] + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-range" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "humansize" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" +dependencies = [ + "libm", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "iana-time-zone" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "image" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "exr", + "gif", + "jpeg-decoder", + "num-rational", + "num-traits", + "png", + "qoi", + "tiff", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + +[[package]] +name = "ipnetwork" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" +dependencies = [ + "serde", +] + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" + +[[package]] +name = "jobserver" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +dependencies = [ + "libc", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" +dependencies = [ + "rayon", +] + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "9.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "155c4d7e39ad04c172c5e3a99c434ea3b4a7ba7960b38ecd562b270b097cce09" +dependencies = [ + "base64 0.21.2", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "language-tags" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] + +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + +[[package]] +name = "libc" +version = "0.2.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" + +[[package]] +name = "libm" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" + +[[package]] +name = "libsqlite3-sys" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" + +[[package]] +name = "local-channel" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f303ec0e94c6c54447f84f3b0ef7af769858a9c4ef56ef2a986d3dcd4c3fc9c" +dependencies = [ + "futures-core", + "futures-sink", + "futures-util", + "local-waker", +] + +[[package]] +name = "local-waker" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" + +[[package]] +name = "lock_api" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "lodepng" +version = "3.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0ad39f75bbaa4b10bb6f2316543632a8046a5bcf9c785488d79720b21f044f8" +dependencies = [ + "crc32fast", + "fallible_collections", + "flate2", + "libc", + "rgb", +] + +[[package]] +name = "log" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" + +[[package]] +name = "md-5" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "md-5" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minifier" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eb022374af2f446981254e6bf9efb6e2c9e1a53176d395fca02792fd4435729" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys", +] + +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom", +] + +[[package]] +name = "nekrochan" +version = "0.1.0" +dependencies = [ + "actix-files", + "actix-multipart", + "actix-web", + "anyhow", + "askama", + "captcha", + "chrono", + "dotenv", + "encoding", + "enumflags2", + "env_logger", + "fancy-regex", + "glob", + "html-minifier", + "image", + "ipnetwork", + "jsonwebtoken", + "lazy_static", + "log", + "num-traits", + "pwhash", + "rand", + "redis", + "serde", + "serde_json", + "serde_qs", + "sha256", + "sqlx", + "thiserror", + "tokio", + "toml", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "parse-size" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "944553dd59c802559559161f9816429058b869003836120e262e8caec061b7ae" + +[[package]] +name = "paste" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" + +[[package]] +name = "pem" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3163d2912b7c3b52d651a055f2c7eec9ba5cd22d26ef75b8dd3a59980b185923" +dependencies = [ + "base64 0.21.2", + "serde", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "pin-project" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "png" +version = "0.17.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59871cc5b6cce7eaccca5a802b4173377a1c2ba90654246789a8fa2334426d11" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pure-rust-locales" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed02a829e62dc2715ceb8afb4f80e298148e1345749ceb369540fe0eb3368432" + +[[package]] +name = "pwhash" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419a3ad8fa9f9d445e69d9b185a24878ae6e6f55c96e4512f4a0e28cd3bc5c56" +dependencies = [ + "blowfish", + "byteorder", + "hmac 0.10.1", + "md-5 0.9.1", + "rand", + "sha-1", + "sha2 0.9.9", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quote" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "redis" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c580d9cbbe1d1b479e8d67cf9daf6a62c957e6846048408b80b43ac3f6af84cd" +dependencies = [ + "async-trait", + "bytes", + "combine", + "futures-util", + "itoa", + "percent-encoding", + "pin-project-lite", + "ryu", + "serde", + "serde_json", + "sha1_smol", + "socket2 0.4.9", + "tokio", + "tokio-util", + "url", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + +[[package]] +name = "rgb" +version = "0.8.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20ec2d3e3fc7a92ced357df9cebd5a10b6fb2aa1ee797bf7e9ce2f17dffc8f59" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "ring" +version = "0.17.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted", + "windows-sys", +] + +[[package]] +name = "rsa" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab43bb47d23c1a631b4b680199a45255dce26fa9ab2fa902581f624ff13e6a8" +dependencies = [ + "byteorder", + "const-oid", + "digest 0.10.7", + "num-bigint-dig", + "num-integer", + "num-iter", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac5ffa1efe7548069688cd7028f32591853cd7b5b756d41bcffd2353e4fc75b4" +dependencies = [ + "bitflags 2.3.3", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "ryu" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" + +[[package]] +name = "serde" +version = "1.0.166" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d01b7404f9d441d3ad40e6a636a7782c377d2abdbe4fa2440e2edcc2f4f10db8" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.166" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd83d6dde2b6b2d466e14d9d1acce8816dedee94f735eac6395808b3483c6d6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "serde_json" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_plain" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6018081315db179d0ce57b1fe4b62a12a0028c9cf9bbef868c9cf477b3c34ae" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_qs" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0431a35568651e363364210c91983c1da5eb29404d9f0928b67d4ebcfa7d330c" +dependencies = [ + "percent-encoding", + "serde", + "thiserror", +] + +[[package]] +name = "serde_spanned" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha-1" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha256" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a975c1bc0941703000eaf232c4d8ce188d8d5408d6344b6b2c8c6262772828" +dependencies = [ + "hex", + "sha2 0.10.7", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest 0.10.7", + "rand_core", +] + +[[package]] +name = "simd-adler32" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f" + +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" + +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlformat" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c12bc9199d1db8234678b7051747c07f517cdcf019262d1847b94ec8b1aee3e" +dependencies = [ + "itertools", + "nom", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ef53c86d2066e04f0ac6b1364f16d13d82388e2d07f11a5c71782345555761" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a22fd81e9c1ad53c562edb869ff042b215d4eadefefc4784bacfbfd19835945" +dependencies = [ + "ahash 0.8.3", + "atoi", + "byteorder", + "bytes", + "chrono", + "crc", + "crossbeam-queue", + "dotenvy", + "either", + "event-listener", + "futures-channel", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashlink", + "hex", + "indexmap 2.0.0", + "ipnetwork", + "log", + "memchr", + "once_cell", + "paste", + "percent-encoding", + "serde", + "serde_json", + "sha2 0.10.7", + "smallvec", + "sqlformat", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00bb7c096a202b8164c175614cbfb79fe0e1e0a3d50e0374526183ef2974e4a2" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 1.0.109", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d644623ab9699014e5b3cb61a040d16caa50fd477008f63f1399ae35498a58" +dependencies = [ + "dotenvy", + "either", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.7", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 1.0.109", + "tempfile", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8264c59b28b6858796acfcedc660aa4c9075cc6e4ec8eb03cdca2a3e725726db" +dependencies = [ + "atoi", + "base64 0.21.2", + "bitflags 2.3.3", + "byteorder", + "bytes", + "chrono", + "crc", + "digest 0.10.7", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac 0.12.1", + "itoa", + "log", + "md-5 0.10.5", + "memchr", + "once_cell", + "percent-encoding", + "rand", + "rsa", + "serde", + "sha1", + "sha2 0.10.7", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cab6147b81ca9213a7578f1b4c9d24c449a53953cd2222a7b5d7cd29a5c3139" +dependencies = [ + "atoi", + "base64 0.21.2", + "bitflags 2.3.3", + "byteorder", + "chrono", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "hex", + "hkdf", + "hmac 0.12.1", + "home", + "ipnetwork", + "itoa", + "log", + "md-5 0.10.5", + "memchr", + "once_cell", + "rand", + "serde", + "serde_json", + "sha1", + "sha2 0.10.7", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59fba60afa64718104b71eec6984f8779d4caffff3b30cde91a75843c7efc126" +dependencies = [ + "atoi", + "chrono", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "tracing", + "url", +] + +[[package]] +name = "stringprep" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "tiff" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d172b0f4d3fba17ba89811858b9d3d97f928aece846475bbda076ca46736211" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + +[[package]] +name = "time" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" +dependencies = [ + "itoa", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" + +[[package]] +name = "time-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +dependencies = [ + "time-core", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d3ce25f50619af8b0aec2eb23deebe84249e19e2ddd393a6e16e3300a6dadfd" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.5.3", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "tokio-stream" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ff9e3abce27ee2c9a37f9ad37238c1bdd4e789c84ba37df76aa4d528f5072cc" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap 2.0.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "tracing-core" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8-width" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.28", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "weezl" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" + +[[package]] +name = "whoami" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "winnow" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "176b6138793677221d420fd2f0aeeced263f197688b36484660da767bca2fa32" +dependencies = [ + "memchr", +] + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" + +[[package]] +name = "zstd" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "6.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.8+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100755 index 0000000..658d361 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,50 @@ +[package] +name = "nekrochan" +version = "0.1.0" +edition = "2021" + +[dependencies] +actix-files = "0.6.2" +actix-multipart = "0.6.0" +actix-web = { version = "4.3.1", features = ["cookies"] } +askama = "0.12.0" +anyhow = "1.0.71" +captcha = "0.0.9" +chrono = { version = "0.4.31", features = ["serde", "unstable-locales"] } +dotenv = "0.15.0" +enumflags2 = "0.7.7" +encoding = "0.2.33" +env_logger = "0.10.0" +fancy-regex = "0.12.0" +glob = "0.3.1" +image = "0.24.7" +ipnetwork = "0.20.0" +jsonwebtoken = "9.1.0" +lazy_static = "1.4.0" +log = "0.4.19" +num-traits = "0.2.16" +pwhash = "1.0.0" +rand = "0.8.5" +redis = { version = "0.24.0", features = ["aio", "json", "tokio-comp"] } +serde = "1.0.166" +serde_json = "1.0.100" +serde_qs = "0.12.0" +sha256 = "1.1.4" +sqlx = { version = "0.7.0", features = [ + "runtime-tokio", + "postgres", + "json", + "chrono", + "ipnetwork", +] } +thiserror = "1.0.41" +tokio = { version = "1.29.1", features = ["rt-multi-thread", "macros"] } +toml = "0.8.6" + +[build-dependencies] +anyhow = "1.0.74" +glob = "0.3.1" +html-minifier = "4.0.0" + +[profile.dev] +opt-level = 1 diff --git a/askama.toml b/askama.toml new file mode 100644 index 0000000..7c682a8 --- /dev/null +++ b/askama.toml @@ -0,0 +1,2 @@ +[general] +dirs = ["templates_min"] diff --git a/build.rs b/build.rs new file mode 100755 index 0000000..285279a --- /dev/null +++ b/build.rs @@ -0,0 +1,37 @@ +use anyhow::Error; +use glob::glob; +use html_minifier::minify; +use std::{ + fs::{read_to_string, File}, + io::Write, + process::Command, +}; + +fn main() -> Result<(), Error> { + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=migrations"); + println!("cargo:rerun-if-changed=templates"); + + Command::new("rm").args(["-rf", "templates_min"]).output()?; + + Command::new("cp") + .args(["-r", "templates", "templates_min"]) + .output()?; + + let templates = glob("templates_min/**/*.html")?; + + for path in templates { + let path = path?; + + if !path.is_file() { + continue; + } + + let html = read_to_string(&path)?; + let minified = minify(html)?.replace('\n', ""); + + File::create(path)?.write_all(minified.as_bytes())?; + } + + Ok(()) +} diff --git a/migrations/20230710121446_create_tables.down.sql b/migrations/20230710121446_create_tables.down.sql new file mode 100755 index 0000000..efacdfc --- /dev/null +++ b/migrations/20230710121446_create_tables.down.sql @@ -0,0 +1 @@ +DROP TABLE accounts, boards, bans; diff --git a/migrations/20230710121446_create_tables.up.sql b/migrations/20230710121446_create_tables.up.sql new file mode 100755 index 0000000..cccea3b --- /dev/null +++ b/migrations/20230710121446_create_tables.up.sql @@ -0,0 +1,30 @@ +CREATE TABLE accounts ( + username VARCHAR(32) NOT NULL PRIMARY KEY, + password VARCHAR(64) NOT NULL, + owner BOOLEAN NOT NULL DEFAULT false, + permissions JSONB NOT NULL DEFAULT '0'::jsonb, + created TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE boards ( + id VARCHAR(16) NOT NULL PRIMARY KEY, + name VARCHAR(32) NOT NULL, + description VARCHAR(128) NOT NULL, + banners JSONB NOT NULL, + config JSONB NOT NULL, + created TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE bans ( + id SERIAL NOT NULL PRIMARY KEY, + ip_range INET NOT NULL, + reason TEXT NOT NULL, + board VARCHAR(16) DEFAULT NULL REFERENCES boards(id), + issued_by VARCHAR(32) NOT NULL REFERENCES accounts(username), + appealable BOOLEAN NOT NULL DEFAULT true, + appeal TEXT DEFAULT NULL, + expires TIMESTAMPTZ DEFAULT NULL, + created TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +INSERT INTO accounts (username, password, owner, permissions) VALUES ('admin', '$2y$10$XcxAe19B1eWC15sfnDRyiuiNLZIhdL7PMTnTmtTfglJIz0zOpN3oa', true, '16383'::jsonb); diff --git a/src/auth.rs b/src/auth.rs new file mode 100755 index 0000000..5ced9fa --- /dev/null +++ b/src/auth.rs @@ -0,0 +1,39 @@ +use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation}; +use serde::{Deserialize, Serialize}; +use std::collections::HashSet; + +use crate::{ctx::Ctx, error::NekrochanError}; + +#[derive(Serialize, Deserialize)] +pub struct Claims { + pub sub: String, +} + +impl Claims { + pub fn new(sub: String) -> Self { + Self { sub } + } + + pub fn encode(&self, ctx: &Ctx) -> Result { + let header = Header::default(); + let key = EncodingKey::from_secret(ctx.cfg.secrets.auth_token.as_bytes()); + + let auth = encode(&header, &self, &key)?; + + Ok(auth) + } + + pub fn decode(ctx: &Ctx, auth: &str) -> Result { + let key = DecodingKey::from_secret(ctx.cfg.secrets.auth_token.as_bytes()); + + let mut validation = Validation::default(); + validation.required_spec_claims = HashSet::from_iter(["sub".to_owned()]); + validation.validate_exp = false; + + let claims = decode(auth, &key, &validation) + .map_err(|_| NekrochanError::InvalidAuthError)? + .claims; + + Ok(claims) + } +} diff --git a/src/cfg.rs b/src/cfg.rs new file mode 100755 index 0000000..5e90339 --- /dev/null +++ b/src/cfg.rs @@ -0,0 +1,71 @@ +use anyhow::Error; +use serde::{Deserialize, Serialize}; +use tokio::fs::read_to_string; + +#[derive(Deserialize, Clone)] +pub struct Cfg { + pub server: ServerCfg, + pub site: SiteCfg, + pub secrets: SecretsCfg, + pub files: FilesCfg, + pub board_defaults: BoardCfg, +} + +impl Cfg { + pub async fn load(path: &str) -> Result { + let cfg_string = read_to_string(path).await?; + let cfg: Cfg = toml::from_str(&cfg_string)?; + + Ok(cfg) + } +} + +#[derive(Deserialize, Clone)] +pub struct ServerCfg { + pub port: u16, + pub database_url: String, + pub cache_url: String, +} + +#[derive(Deserialize, Clone)] +pub struct SiteCfg { + pub name: String, + pub description: String, + pub site_banner: Option, +} + +#[derive(Deserialize, Clone)] +pub struct SecretsCfg { + pub auth_token: String, + pub secure_trip: String, + pub user_id: String, +} + +#[derive(Deserialize, Clone)] +pub struct FilesCfg { + pub videos: bool, + pub thumb_size: u32, + pub max_size_mb: usize, + pub max_height: u32, + pub max_width: u32, + pub cleanup_interval: u64, +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct BoardCfg { + pub anon_name: String, + pub page_size: i64, + pub page_count: i64, + pub file_limit: usize, + pub bump_limit: i32, + pub reply_limit: i32, + pub locked: bool, + pub user_ids: bool, + pub flags: bool, + pub thread_captcha: String, + pub reply_captcha: String, + pub require_thread_content: bool, + pub require_thread_file: bool, + pub require_reply_content: bool, + pub require_reply_file: bool, +} diff --git a/src/ctx.rs b/src/ctx.rs new file mode 100755 index 0000000..a7b74c8 --- /dev/null +++ b/src/ctx.rs @@ -0,0 +1,36 @@ +use anyhow::Error; +use redis::{aio::MultiplexedConnection, Client}; +use sqlx::PgPool; +use std::net::SocketAddr; + +use crate::cfg::Cfg; + +#[derive(Clone)] +pub struct Ctx { + pub cfg: Cfg, + db: PgPool, + cache: MultiplexedConnection, +} + +impl Ctx { + pub async fn new(cfg: Cfg) -> Result { + let db = PgPool::connect(&cfg.server.database_url).await?; + let cache = Client::open(cfg.server.cache_url.as_str())? + .get_multiplexed_async_connection() + .await?; + + Ok(Self { cfg, db, cache }) + } + + pub fn bind_addr(&self) -> SocketAddr { + SocketAddr::from(([127, 0, 0, 1], self.cfg.server.port)) + } + + pub fn db(&self) -> &PgPool { + &self.db + } + + pub fn cache(&self) -> MultiplexedConnection { + self.cache.clone() + } +} diff --git a/src/db/account.rs b/src/db/account.rs new file mode 100755 index 0000000..c6bdf2e --- /dev/null +++ b/src/db/account.rs @@ -0,0 +1,117 @@ +use redis::{AsyncCommands, JsonAsyncCommands}; +use sqlx::{query, query_as, types::Json}; + +use super::models::Account; +use crate::{ctx::Ctx, error::NekrochanError, perms::PermissionWrapper}; + +impl Account { + pub async fn create( + ctx: &Ctx, + username: String, + password: String, + ) -> Result { + let account = + query_as("INSERT INTO accounts (username, password) VALUES ($1, $2) RETURNING *") + .bind(&username) + .bind(password) + .fetch_one(ctx.db()) + .await?; + + ctx.cache() + .json_set(format!("accounts:{}", username), ".", &account) + .await?; + + Ok(account) + } + + pub async fn read(ctx: &Ctx, username: String) -> Result, NekrochanError> { + let account: Option = ctx + .cache() + .json_get(format!("accounts:{}", username), ".") + .await?; + + let account = match account { + Some(json) => Some(serde_json::from_str(&json)?), + None => None, + }; + + Ok(account) + } + + pub async fn read_all(ctx: &Ctx) -> Result, NekrochanError> { + let accounts = query_as("SELECT * FROM accounts ORDER BY owner DESC, created DESC") + .fetch_all(ctx.db()) + .await?; + + Ok(accounts) + } + + pub async fn update_password(&self, ctx: &Ctx, password: String) -> Result<(), NekrochanError> { + query("UPDATE accounts SET password = $1 WHERE username = $2") + .bind(&password) + .bind(&self.username) + .execute(ctx.db()) + .await?; + + ctx.cache() + .json_set(format!("accounts:{}", self.username), "password", &password) + .await?; + + Ok(()) + } + + pub async fn update_permissions( + &self, + ctx: &Ctx, + permissions: u64, + ) -> Result<(), NekrochanError> { + query("UPDATE accounts SET permissions = $1 WHERE username = $2") + .bind(Json(permissions)) + .bind(&self.username) + .execute(ctx.db()) + .await?; + + ctx.cache() + .json_set( + format!("accounts:{}", self.username), + "permissions", + &permissions, + ) + .await?; + + Ok(()) + } + + pub async fn update_owner(&self, ctx: &Ctx, owner: bool) -> Result<(), NekrochanError> { + query("UPDATE accounts SET owner = $1 WHERE username = $2") + .bind(owner) + .bind(&self.username) + .execute(ctx.db()) + .await?; + + ctx.cache() + .json_set(format!("accounts:{}", self.username), "owner", &owner) + .await?; + + Ok(()) + } + + pub async fn delete(&self, ctx: &Ctx) -> Result<(), NekrochanError> { + query("DELETE FROM accounts WHERE username = $1") + .bind(&self.username) + .execute(ctx.db()) + .await?; + + ctx.cache() + .del(format!("accounts:{}", self.username)) + .await?; + + Ok(()) + } +} + +impl Account { + pub fn perms(&self) -> PermissionWrapper { + PermissionWrapper::new(self.permissions.0, self.owner) + } +} diff --git a/src/db/ban.rs b/src/db/ban.rs new file mode 100755 index 0000000..0bc1f4c --- /dev/null +++ b/src/db/ban.rs @@ -0,0 +1,107 @@ +use chrono::{DateTime, Utc}; +use ipnetwork::IpNetwork; +use sqlx::{query, query_as}; +use std::{collections::HashMap, net::IpAddr}; + +use super::models::Ban; +use crate::{ctx::Ctx, error::NekrochanError}; + +impl Ban { + pub async fn create( + ctx: &Ctx, + account: String, + board: Option, + ip_range: IpNetwork, + reason: String, + appealable: bool, + expires: Option>, + ) -> Result { + let ban = query_as("INSERT INTO bans (ip_range, reason, board, issued_by, appealable, expires) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *") + .bind(ip_range) + .bind(reason) + .bind(board) + .bind(account) + .bind(appealable) + .bind(expires) + .fetch_one(ctx.db()) + .await?; + + Ok(ban) + } + + pub async fn read(ctx: &Ctx, board: String, ip: IpAddr) -> Result, NekrochanError> { + let ban = query_as("SELECT * FROM bans WHERE (expires > CURRENT_TIMESTAMP OR expires IS NULL) AND (board = $1 OR board IS NULL) AND (ip_range >> $2 OR ip_range = $2)") + .bind(board) + .bind(ip) + .fetch_optional(ctx.db()) + .await?; + + Ok(ban) + } + + pub async fn read_global(ctx: &Ctx, ip: IpNetwork) -> Result, NekrochanError> { + let ban = query_as("SELECT * FROM bans WHERE (expires > CURRENT_TIMESTAMP OR expires IS NULL) AND board IS NULL AND (ip_range >> $1 OR ip_range = $1)") + .bind(ip) + .fetch_optional(ctx.db()) + .await?; + + Ok(ban) + } + + pub async fn read_all(ctx: &Ctx) -> Result, NekrochanError> { + let bans = + query_as("SELECT * FROM bans WHERE (expires > CURRENT_TIMESTAMP OR expires IS NULL) ORDER BY created DESC") + .fetch_all(ctx.db()) + .await?; + + Ok(bans) + } + + pub async fn read_by_id(ctx: &Ctx, id: i32) -> Result, NekrochanError> { + let ban = query_as("SELECT * FROM bans WHERE id = $1") + .bind(id) + .fetch_optional(ctx.db()) + .await?; + + Ok(ban) + } + + pub async fn read_by_ip( + ctx: &Ctx, + ip: IpAddr, + ) -> Result, Ban>, NekrochanError> { + let bans: Vec = query_as("SELECT * FROM bans WHERE (expires > CURRENT_TIMESTAMP OR expires IS NULL) AND (ip_range >> $1 OR ip_range = $1)") + .bind(ip) + .fetch_all(ctx.db()) + .await?; + + let mut ban_map = HashMap::new(); + + for ban in bans.into_iter() { + let board = ban.board.clone(); + + ban_map.insert(board, ban); + } + + Ok(ban_map) + } + + pub async fn update_appeal(&self, ctx: &Ctx, appeal: String) -> Result<(), NekrochanError> { + query("UPDATE bans SET appeal = $1 WHERE id = $2") + .bind(appeal) + .bind(self.id) + .execute(ctx.db()) + .await?; + + Ok(()) + } + + pub async fn delete(&self, ctx: &Ctx) -> Result<(), NekrochanError> { + query("DELETE FROM bans WHERE id = $1") + .bind(self.id) + .execute(ctx.db()) + .await?; + + Ok(()) + } +} diff --git a/src/db/board.rs b/src/db/board.rs new file mode 100755 index 0000000..9e19396 --- /dev/null +++ b/src/db/board.rs @@ -0,0 +1,281 @@ +use captcha::{gen, Difficulty}; +use rand::{seq::SliceRandom, thread_rng}; +use redis::{cmd, AsyncCommands, JsonAsyncCommands}; +use sha256::digest; +use sqlx::{query, query_as, types::Json}; +use std::collections::HashMap; + +use super::models::{Board, File}; +use crate::{cfg::BoardCfg, ctx::Ctx, error::NekrochanError, CAPTCHA}; + +impl Board { + pub async fn create( + ctx: &Ctx, + id: String, + name: String, + description: String, + ) -> Result { + let banners = Json(Vec::::new()); + let config = Json(ctx.cfg.board_defaults.clone()); + + let board: Board = query_as("INSERT INTO boards (id, name, description, banners, config) VALUES ($1, $2, $3, $4, $5) RETURNING *") + .bind(id) + .bind(name) + .bind(description) + .bind(banners) + .bind(config) + .fetch_one(ctx.db()) + .await?; + + query(&format!( + r#"CREATE TABLE posts_{} ( + id SERIAL NOT NULL PRIMARY KEY, + board VARCHAR(16) NOT NULL DEFAULT '{}' REFERENCES boards(id), + thread INT DEFAULT NULL REFERENCES posts_{}(id), + name VARCHAR(32) NOT NULL, + user_id VARCHAR(6) NOT NULL DEFAULT '000000', + tripcode VARCHAR(12) DEFAULT NULL, + capcode VARCHAR(32) DEFAULT NULL, + email VARCHAR(256) DEFAULT NULL, + content TEXT NOT NULL, + content_nomarkup TEXT NOT NULL, + files JSONB NOT NULL, + password VARCHAR(64) DEFAULT NULL, + country VARCHAR(2) NOT NULL, + ip INET NOT NULL, + bumps INT NOT NULL DEFAULT 0, + replies INT NOT NULL DEFAULT 0, + sticky BOOLEAN NOT NULL DEFAULT false, + locked BOOLEAN NOT NULL DEFAULT false, + reported TIMESTAMPTZ DEFAULT NULL, + reports JSONB NOT NULL DEFAULT '[]'::json, + bumped TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + created TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP + )"#, + board.id, board.id, board.id + )) + .execute(ctx.db()) + .await?; + + ctx.cache() + .set(format!("board_threads:{}", board.id), 0) + .await?; + + ctx.cache().lpush("board_ids", &board.id).await?; + + ctx.cache() + .json_set(format!("boards:{}", board.id), ".", &board) + .await?; + + cmd("SORT") + .arg("board_ids") + .arg("ALPHA") + .arg("STORE") + .arg("board_ids") + .query_async(&mut ctx.cache()) + .await?; + + update_overboard(ctx, Self::read_all(ctx).await?).await?; + + Ok(board) + } + + pub async fn read(ctx: &Ctx, id: String) -> Result, NekrochanError> { + let board: Option = ctx.cache().json_get(format!("boards:{}", id), ".").await?; + + let board = match board { + Some(json) => Some(serde_json::from_str(&json)?), + None => None, + }; + + Ok(board) + } + + pub async fn read_all(ctx: &Ctx) -> Result, NekrochanError> { + let mut boards = Vec::new(); + let ids: Vec = ctx.cache().lrange("board_ids", 0, -1).await?; + + for id in ids.into_iter() { + if let Some(board) = Self::read(ctx, id).await? { + boards.push(board); + } + } + + Ok(boards) + } + + pub async fn read_all_map(ctx: &Ctx) -> Result, NekrochanError> { + let mut boards = HashMap::new(); + let ids: Vec = ctx.cache().lrange("board_ids", 0, -1).await?; + + for id in ids.into_iter() { + if let Some(board) = Self::read(ctx, id.clone()).await? { + boards.insert(id, board); + } + } + + Ok(boards) + } + + pub async fn update_name(&self, ctx: &Ctx, name: String) -> Result<(), NekrochanError> { + query("UPDATE boards SET name = $1 WHERE id = $2") + .bind(&name) + .bind(&self.id) + .execute(ctx.db()) + .await?; + + ctx.cache() + .json_set(format!("boards:{}", self.id), "name", &name) + .await?; + + Ok(()) + } + + pub async fn update_description( + &self, + ctx: &Ctx, + description: String, + ) -> Result<(), NekrochanError> { + query("UPDATE boards SET description = $1 WHERE id = $2") + .bind(&description) + .bind(&self.id) + .execute(ctx.db()) + .await?; + + ctx.cache() + .json_set(format!("boards:{}", self.id), "description", &description) + .await?; + + Ok(()) + } + + pub async fn update_banners( + &self, + ctx: &Ctx, + banners: Vec, + ) -> Result<(), NekrochanError> { + query("UPDATE boards SET banners = $1 WHERE id = $2") + .bind(Json(&banners)) + .bind(&self.id) + .execute(ctx.db()) + .await?; + + ctx.cache() + .json_set(format!("boards:{}", self.id), "banners", &banners) + .await?; + + Ok(()) + } + + pub async fn update_config(&self, ctx: &Ctx, config: BoardCfg) -> Result<(), NekrochanError> { + query("UPDATE boards SET config = $1 WHERE id = $2") + .bind(Json(&config)) + .bind(&self.id) + .execute(ctx.db()) + .await?; + + ctx.cache() + .json_set(format!("boards:{}", self.id), "config", &config) + .await?; + + Ok(()) + } + + pub async fn delete(&self, ctx: &Ctx) -> Result<(), NekrochanError> { + let boards = Self::read_all(ctx) + .await? + .into_iter() + .filter(|board| board.id != self.id) + .collect(); + + update_overboard(ctx, boards).await?; + + query(&format!("DROP TABLE posts_{}", self.id)) + .execute(ctx.db()) + .await?; + + query("DELETE FROM boards WHERE id = $1") + .bind(&self.id) + .execute(ctx.db()) + .await?; + + ctx.cache().del(format!("boards:{}", self.id)).await?; + ctx.cache().lrem("board_ids", 0, &self.id).await?; + + Ok(()) + } +} + +impl Board { + pub fn random_banner(&self) -> Option { + self.banners + .choose(&mut thread_rng()) + .map(|banner| banner.to_owned()) + } + + pub fn thread_captcha(&self) -> Option<(String, String)> { + let captcha = match self.config.thread_captcha.as_str() { + "easy" => gen(Difficulty::Easy), + "medium" => gen(Difficulty::Medium), + "hard" => gen(Difficulty::Hard), + _ => return None, + }; + + let base64 = captcha.as_base64()?; + + let board = self.id.clone(); + let difficulty = self.config.thread_captcha.clone(); + let id = digest(base64.as_bytes()); + + let key = (board, difficulty, id.clone()); + let solution = captcha.chars_as_string(); + + CAPTCHA.write().ok()?.insert(key, solution); + + Some((id, base64)) + } + + pub fn reply_captcha(&self) -> Option<(String, String)> { + let captcha = match self.config.reply_captcha.as_str() { + "easy" => gen(Difficulty::Easy), + "medium" => gen(Difficulty::Medium), + "hard" => gen(Difficulty::Hard), + _ => return None, + }; + + let base64 = captcha.as_base64()?; + + let board = self.id.clone(); + let difficulty = self.config.thread_captcha.clone(); + let id = digest(base64.as_bytes()); + + let key = (board, difficulty, id.clone()); + let solution = captcha.chars_as_string(); + + CAPTCHA.write().ok()?.insert(key, solution); + + Some((id, base64)) + } +} + +async fn update_overboard(ctx: &Ctx, boards: Vec) -> Result<(), NekrochanError> { + query("DROP VIEW IF EXISTS overboard") + .execute(ctx.db()) + .await?; + + if boards.is_empty() { + return Ok(()); + } + + let unions = boards + .into_iter() + .map(|board| format!("SELECT * FROM posts_{}", board.id)) + .collect::>() + .join(" UNION "); + + query(&format!("CREATE VIEW overboard AS {unions}")) + .execute(ctx.db()) + .await?; + + Ok(()) +} diff --git a/src/db/cache.rs b/src/db/cache.rs new file mode 100644 index 0000000..3a1f96f --- /dev/null +++ b/src/db/cache.rs @@ -0,0 +1,72 @@ +use anyhow::Error; +use redis::{cmd, AsyncCommands, JsonAsyncCommands}; +use sha256::digest; +use sqlx::query_as; + +use super::models::{Account, Board, Post}; +use crate::ctx::Ctx; + +pub async fn init_cache(ctx: &Ctx) -> Result<(), Error> { + cmd("FLUSHDB").query_async(&mut ctx.cache()).await?; + + let accounts: Vec = query_as("SELECT * FROM accounts") + .fetch_all(ctx.db()) + .await?; + + for account in accounts.iter() { + ctx.cache() + .json_set(format!("accounts:{}", account.username), ".", &account) + .await?; + } + + let boards: Vec = query_as("SELECT * FROM boards").fetch_all(ctx.db()).await?; + + for board in boards.iter() { + ctx.cache() + .json_set(format!("boards:{}", board.id), ".", board) + .await?; + + ctx.cache().lpush("board_ids", &board.id).await?; + } + + cmd("SORT") + .arg("board_ids") + .arg("ALPHA") + .arg("STORE") + .arg("board_ids") + .query_async(&mut ctx.cache()) + .await?; + + ctx.cache().set("total_threads", 0).await?; + + for board in boards.iter() { + let (thread_count,): (i64,) = query_as(&format!( + "SELECT COUNT(id) FROM posts_{} WHERE thread IS NULL", + board.id + )) + .fetch_one(ctx.db()) + .await?; + + ctx.cache().incr("total_threads", thread_count).await?; + ctx.cache() + .set(format!("board_threads:{}", board.id), thread_count) + .await?; + } + + for board in boards.iter() { + let posts = Post::read_all(ctx, board.id.clone()).await?; + + for post in posts.into_iter() { + let ip_key = format!("by_ip:{}", post.ip); + let content_key = format!("by_content:{}", digest(post.content_nomarkup)); + + let member = format!("{}/{}", post.board, post.id); + let score = post.created.timestamp_micros(); + + ctx.cache().zadd(ip_key, &member, score).await?; + ctx.cache().zadd(content_key, &member, score).await?; + } + } + + Ok(()) +} diff --git a/src/db/mod.rs b/src/db/mod.rs new file mode 100755 index 0000000..0cdd13a --- /dev/null +++ b/src/db/mod.rs @@ -0,0 +1,7 @@ +pub mod cache; +pub mod models; + +mod account; +mod ban; +mod board; +mod post; diff --git a/src/db/models.rs b/src/db/models.rs new file mode 100755 index 0000000..20664da --- /dev/null +++ b/src/db/models.rs @@ -0,0 +1,92 @@ +use std::net::IpAddr; + +use chrono::{DateTime, Utc}; +use ipnetwork::IpNetwork; +use serde::{Deserialize, Serialize}; +use sqlx::{types::Json, FromRow}; + +use crate::cfg::BoardCfg; + +#[derive(FromRow, Clone, Serialize, Deserialize)] +pub struct Account { + pub username: String, + pub password: String, + pub owner: bool, + pub permissions: Json, + pub created: DateTime, +} + +#[derive(FromRow, Serialize, Deserialize)] +pub struct Board { + pub id: String, + pub name: String, + pub description: String, + pub banners: Json>, + pub config: Json, + pub created: DateTime, +} + +#[derive(FromRow, Debug, Serialize, Deserialize, Clone)] +pub struct Ban { + pub id: i32, + pub ip_range: IpNetwork, + pub reason: String, + pub board: Option, + pub issued_by: String, + pub appealable: bool, + pub appeal: Option, + pub expires: Option>, + pub created: DateTime, +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct Report { + pub reason: String, + pub reporter_country: String, + pub reporter_ip: IpAddr, +} + +#[derive(FromRow, Serialize, Deserialize)] +pub struct LogRecord { + pub id: i32, + pub message: String, + pub created: DateTime, +} + +#[derive(FromRow, Serialize, Deserialize)] +pub struct Post { + pub id: i32, + pub board: String, + pub thread: Option, + pub name: String, + pub user_id: String, + pub tripcode: Option, + pub capcode: Option, + pub email: Option, + pub content: String, + pub content_nomarkup: String, + pub files: Json>, + pub password: String, + pub country: String, + pub ip: IpAddr, + pub bumps: i32, + pub replies: i32, + pub sticky: bool, + pub locked: bool, + pub reported: Option>, + pub reports: Json>, + pub bumped: DateTime, + pub created: DateTime, +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct File { + pub original_name: String, + pub format: String, + pub thumb_format: Option, + pub spoiler: bool, + pub width: u32, + pub height: u32, + pub timestamp: i64, + pub size: usize, +} diff --git a/src/db/post.rs b/src/db/post.rs new file mode 100755 index 0000000..efe87ba --- /dev/null +++ b/src/db/post.rs @@ -0,0 +1,451 @@ +use chrono::Utc; +use redis::AsyncCommands; +use sha256::digest; +use sqlx::{query, query_as, types::Json}; +use std::net::IpAddr; + +use super::models::{Board, File, Post, Report}; +use crate::{ctx::Ctx, error::NekrochanError}; + +impl Post { + #[allow(clippy::too_many_arguments)] + pub async fn create( + ctx: &Ctx, + board: &Board, + thread: Option, + name: String, + tripcode: Option, + capcode: Option, + email: Option, + content: String, + content_nomarkup: String, + files: Vec, + password: String, + country: String, + ip: IpAddr, + bumpy_bump: bool, + ) -> Result { + let post: Post = query_as(&format!( + r#"INSERT INTO posts_{} + (thread, name, tripcode, capcode, email, content, content_nomarkup, files, password, country, ip) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) + RETURNING *"#, board.id) + ) + .bind(thread) + .bind(name) + .bind(tripcode) + .bind(capcode) + .bind(email) + .bind(content) + .bind(content_nomarkup) + .bind(Json(files)) + .bind(password) + .bind(country) + .bind(ip) + .fetch_one(ctx.db()) + .await?; + + if let Some(thread) = thread { + query(&format!( + "UPDATE posts_{} SET replies = replies + 1 WHERE id = $1", + board.id + )) + .bind(thread) + .execute(ctx.db()) + .await?; + + if bumpy_bump { + query(&format!( + "UPDATE posts_{} SET bumps = bumps + 1, bumped = CURRENT_TIMESTAMP WHERE id = $1", + board.id + )) + .bind(thread) + .execute(ctx.db()) + .await?; + } + } else { + delete_old_threads(ctx, board).await?; + + ctx.cache().incr("total_threads", 1).await?; + ctx.cache() + .incr(format!("board_threads:{}", board.id), 1) + .await?; + } + + let ip_key = format!("by_ip:{}", ip); + let content_key = format!("by_content:{}", digest(post.content_nomarkup.as_bytes())); + let member = format!("{}/{}", board.id, post.id); + let score = post.created.timestamp_micros(); + + ctx.cache().zadd(ip_key, &member, score).await?; + ctx.cache().zadd(content_key, &member, score).await?; + + Ok(post) + } + + pub async fn create_report( + &self, + ctx: &Ctx, + reason: String, + reporter_country: String, + reporter_ip: IpAddr, + ) -> Result<(), NekrochanError> { + let mut reports = self.reports.clone(); + + reports.push(Report { + reason, + reporter_country, + reporter_ip, + }); + + query(&format!( + "UPDATE posts_{} SET reported = CURRENT_TIMESTAMP, reports = $1 WHERE id = $2", + self.board + )) + .bind(reports) + .bind(self.id) + .execute(ctx.db()) + .await?; + + Ok(()) + } + + pub async fn read(ctx: &Ctx, board: String, id: i32) -> Result, NekrochanError> { + let post = query_as("SELECT * FROM overboard WHERE board = $1 AND id = $2") + .bind(board) + .bind(id) + .fetch_optional(ctx.db()) + .await?; + + Ok(post) + } + + pub async fn read_board_page( + ctx: &Ctx, + board: &Board, + page: i64, + ) -> Result, NekrochanError> { + let posts = query_as(&format!( + r#"SELECT * FROM posts_{} + WHERE thread IS NULL + ORDER BY sticky DESC, bumped DESC + LIMIT $1 + OFFSET $2"#, + board.id + )) + .bind(board.config.0.page_size) + .bind((page - 1) * board.config.0.page_size) + .fetch_all(ctx.db()) + .await?; + + Ok(posts) + } + + pub async fn read_board_catalog(ctx: &Ctx, board: String) -> Result, NekrochanError> { + let posts = query_as(&format!( + r#"SELECT * FROM posts_{} + WHERE thread IS NULL + ORDER BY sticky DESC, bumped DESC"#, + board + )) + .fetch_all(ctx.db()) + .await?; + + Ok(posts) + } + + pub async fn read_overboard_page(ctx: &Ctx, page: i64) -> Result, NekrochanError> { + let posts = query_as( + r#"SELECT * FROM overboard + WHERE thread IS NULL + ORDER BY bumped DESC + LIMIT $1 + OFFSET $2"#, + ) + .bind(15) + .bind((page - 1) * 15) + .fetch_all(ctx.db()) + .await?; + + Ok(posts) + } + + pub async fn read_overboard_catalog(ctx: &Ctx) -> Result, NekrochanError> { + let posts = query_as( + r#"SELECT * FROM overboard + WHERE thread IS NULL + ORDER BY bumped DESC"#, + ) + .fetch_all(ctx.db()) + .await?; + + Ok(posts) + } + + pub async fn read_latest(ctx: &Ctx) -> Result, NekrochanError> { + let posts = query_as( + r#"SELECT * FROM overboard + ORDER BY created DESC + LIMIT $1"#, + ) + .bind(15) + .fetch_all(ctx.db()) + .await?; + + Ok(posts) + } + + pub async fn read_reports(ctx: &Ctx) -> Result, NekrochanError> { + let posts = query_as( + r#"SELECT * FROM overboard + WHERE reports != '[]'::jsonb + ORDER BY jsonb_array_length(reports), reported DESC"#, + ) + .fetch_all(ctx.db()) + .await?; + + Ok(posts) + } + + pub async fn read_files(ctx: &Ctx) -> Result, NekrochanError> { + let posts = query_as( + r#"SELECT * + FROM overboard + WHERE files != '[]'::jsonb + ORDER BY created DESC + LIMIT 3"#, + ) + .fetch_all(ctx.db()) + .await?; + + Ok(posts) + } + + pub async fn read_replies(&self, ctx: &Ctx) -> Result, NekrochanError> { + let replies = query_as(&format!( + "SELECT * FROM posts_{} WHERE thread = $1 ORDER BY created ASC", + self.board + )) + .bind(self.id) + .fetch_all(ctx.db()) + .await?; + + Ok(replies) + } + + pub async fn read_all(ctx: &Ctx, board: String) -> Result, NekrochanError> { + let posts = query_as(&format!("SELECT * FROM posts_{}", board)) + .fetch_all(ctx.db()) + .await?; + + Ok(posts) + } + + pub async fn update_user_id(&self, ctx: &Ctx, user_id: String) -> Result<(), NekrochanError> { + query(&format!( + "UPDATE posts_{} SET user_id = $1 WHERE id = $2", + self.board, + )) + .bind(user_id) + .bind(self.id) + .execute(ctx.db()) + .await?; + + Ok(()) + } + + pub async fn update_sticky(&self, ctx: &Ctx) -> Result<(), NekrochanError> { + query(&format!( + "UPDATE posts_{} SET sticky = NOT sticky WHERE id = $1", + self.board + )) + .bind(self.id) + .execute(ctx.db()) + .await?; + + Ok(()) + } + + pub async fn update_lock(&self, ctx: &Ctx) -> Result<(), NekrochanError> { + query(&format!( + "UPDATE posts_{} SET locked = NOT locked WHERE id = $1", + self.board + )) + .bind(self.id) + .execute(ctx.db()) + .await?; + + Ok(()) + } + + pub async fn update_content( + &self, + ctx: &Ctx, + content: String, + content_nomarkup: String, + ) -> Result<(), NekrochanError> { + query(&format!( + "UPDATE posts_{} SET content = $1, content_nomarkup = $2 WHERE id = $3", + self.board + )) + .bind(content) + .bind(&content_nomarkup) + .bind(self.id) + .execute(ctx.db()) + .await?; + + let old_key = format!("by_content:{}", digest(self.content_nomarkup.as_bytes())); + let new_key = format!("by_content:{}", digest(content_nomarkup.as_bytes())); + let member = format!("{}/{}", self.board, self.id); + let score = Utc::now().timestamp_micros(); + + ctx.cache().zrem(old_key, &member).await?; + ctx.cache().zadd(new_key, &member, score).await?; + + Ok(()) + } + + pub async fn update_spoiler(&self, ctx: &Ctx) -> Result<(), NekrochanError> { + let mut files = self.files.clone(); + + for file in files.iter_mut() { + file.spoiler = !file.spoiler; + } + + query(&format!( + "UPDATE posts_{} SET files = $1 WHERE id = $2", + self.board + )) + .bind(Json(files)) + .bind(self.id) + .execute(ctx.db()) + .await?; + + Ok(()) + } + + pub async fn delete(&self, ctx: &Ctx) -> Result<(), NekrochanError> { + let to_be_deleted: Vec = query_as(&format!( + "SELECT * FROM posts_{} WHERE id = $1 OR thread = $1", + self.board + )) + .bind(self.id) + .fetch_all(ctx.db()) + .await?; + + for post in to_be_deleted.iter() { + let id = post.id; + let url = post.post_url(); + + let live_quote = format!(">>{id}"); + let dead_quote = format!(">>{id}"); + + query(&format!( + "UPDATE posts_{} SET content = REPLACE(content, $1, $2)", + self.board + )) + .bind(live_quote) + .bind(dead_quote) + .execute(ctx.db()) + .await?; + + let ip_key = format!("by_ip:{}", post.ip); + let content_key = format!("by_content:{}", digest(post.content_nomarkup.as_bytes())); + + let member = format!("{}/{}", post.board, post.id); + + ctx.cache().zrem(ip_key, &member).await?; + ctx.cache().zrem(content_key, &member).await?; + } + + let in_list = to_be_deleted + .iter() + .map(|post| (post.id)) + .collect::>(); + + query(&format!( + "DELETE FROM posts_{} WHERE id = ANY($1)", + self.board + )) + .bind(&in_list) + .execute(ctx.db()) + .await?; + + if self.thread.is_none() { + ctx.cache().decr("total_threads", 1).await?; + ctx.cache() + .decr(format!("board_threads:{}", self.board), 1) + .await?; + } + + Ok(()) + } + + pub async fn delete_files(&self, ctx: &Ctx) -> Result<(), NekrochanError> { + for file in self.files.iter() { + file.delete().await; + } + + query(&format!( + "UPDATE posts_{} SET files = '[]'::jsonb WHERE id = $1", + self.board + )) + .bind(self.id) + .execute(ctx.db()) + .await?; + + Ok(()) + } + + pub async fn delete_reports(&self, ctx: &Ctx) -> Result<(), NekrochanError> { + query(&format!( + "UPDATE posts_{} SET reported = NULL, reports = '[]'::jsonb WHERE id = $1", + self.board + )) + .bind(self.id) + .execute(ctx.db()) + .await?; + + Ok(()) + } +} + +impl Post { + pub fn post_url(&self) -> String { + if let Some(thread) = self.thread { + format!("/boards/{}/{}#{}", self.board, thread, self.id) + } else { + format!("/boards/{}/{}#{}", self.board, self.id, self.id) + } + } + + pub fn post_url_notarget(&self) -> String { + format!("/boards/{}/{}", self.board, self.id) + } +} + +async fn delete_old_threads(ctx: &Ctx, board: &Board) -> Result<(), NekrochanError> { + let old_threads: Vec = query_as(&format!( + r#"SELECT * FROM posts_{} + WHERE thread IS NULL AND id NOT IN ( + SELECT id + FROM ( + SELECT id + FROM posts_{} + WHERE thread IS NULL + ORDER BY sticky DESC, bumped DESC + LIMIT $1 + ) catty + )"#, + board.id, board.id + )) + .bind(board.config.0.page_size * board.config.0.page_count) + .fetch_all(ctx.db()) + .await?; + + for thread in old_threads.iter() { + thread.delete(ctx).await?; + } + + Ok(()) +} diff --git a/src/error.rs b/src/error.rs new file mode 100755 index 0000000..a87dd04 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,233 @@ +use actix_web::{http::StatusCode, ResponseError}; +use log::error; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum NekrochanError { + #[error("Chyba při zpracovávání souboru '{}': {}", .0, .1)] + FileError(String, &'static str), + #[error("Uživatelské jméno musí mít 1-32 znaků.")] + UsernameFormatError, + #[error("Heslo musí mít alespoň 8 znaků.")] + PasswordFormatError, + #[error("ID musí mít 1-16 znaků.")] + IdFormatError, + #[error("Jméno nástěnky musí mít 1-32 znaků.")] + BoardNameFormatError, + #[error("Popis musí mít 1-128 znaků.")] + DescriptionFormatError, + #[error("Jméno nesmí mít více než 32 znaků.")] + PostNameFormatError, + #[error("Capcode nesmí mít více než 32 znaků.")] + CapcodeFormatError, + #[error("E-mail nesmí mít více než 256 znaků.")] + EmailFormatError, + #[error("Obsah nesmí mít více než 4000 znaků")] + ContentFormatError, + #[error("Nástěnka /{}/ neexistuje.", .0)] + BoardNotFound(String), + #[error("Účet '{}' neexistuje.", .0)] + AccountNotFound(String), + #[error("Příspěvek /{}/{} neexistuje.", .0, .1)] + PostNotFound(String, i32), + #[error("Nedostatečná oprávnění.")] + InsufficientPermissionError, + #[error("Nesprávné přihlašovací údaje.")] + IncorrectCredentialError, + #[error("Neplatná strana.")] + InvalidPageError, + #[error("Neplatný autentizační token. Vymaž soubory cookie.")] + InvalidAuthError, + #[error("Pro přístup se musíš přihlásit.")] + NotLoggedInError, + #[error("Účet vlastníka nemůže být vymazán.")] + OwnerDeletionError, + #[error("Reverzní proxy nevrátilo vyžadovanou hlavičku '{}'.", .0)] + HeaderError(&'static str), + #[error("Nástěnka /{}/ je uzamčená.", .0)] + BoardLockError(String), + #[error("Toto vlákno je uzamčené.")] + ThreadLockError, + #[error("Nelze vytvořit odpověď na odpověď.")] + ReplyReplyError, + #[error("Vlákno dosáhlo limitu odpovědí.")] + ReplyLimitError, + #[error("Příspěvek musí mít obsah.")] + NoContentError, + #[error("Příspěvek musí mít soubor.")] + NoFileError, + #[error("Příspěvek musí mít obsah nebo soubor.")] + EmptyPostError, + #[error("Na této nástěnce se musí vyplnit CAPTCHA.")] + RequiredCaptchaError, + #[error("Nesprávné řešení CAPTCHA.")] + IncorrectCaptchaError, + #[error("Tato CAPTCHA neexistuje nebo už byla vyřešena.")] + SolvedCaptchaError, + #[error("Nebyly vybrány žádné příspěvky.")] + NoPostsError, + #[error("Maximální počet souborů na této nástěnce je {}.", .0)] + FileLimitError(usize), + #[error("Nesprávné heslo pro příspěvek #{}.", .0)] + IncorrectPasswordError(i32), + // 500 + #[error("Nadnástěnka nebyla inicializována.")] + OverboardError, + #[error("Server se připojil k 41 procentům.")] + InternalError, +} + +impl From for NekrochanError { + fn from(e: askama::Error) -> Self { + error!("Internal server error: {e:#?}"); + + Self::InternalError + } +} + +impl From for NekrochanError { + fn from(e: ipnetwork::IpNetworkError) -> Self { + error!("Internal server error: {e:#?}"); + + Self::InternalError + } +} + +impl From for NekrochanError { + fn from(e: jsonwebtoken::errors::Error) -> Self { + error!("Internal server error: {e:#?}"); + + Self::InternalError + } +} + +impl From for NekrochanError { + fn from(e: pwhash::error::Error) -> Self { + error!("Internal server error: {e:#?}"); + + Self::InternalError + } +} + +impl From for NekrochanError { + fn from(e: fancy_regex::Error) -> Self { + error!("Internal server error: {e:#?}"); + + Self::InternalError + } +} + +impl From for NekrochanError { + fn from(e: redis::RedisError) -> Self { + error!("Internal server error: {e:#?}"); + + Self::InternalError + } +} + +impl From for NekrochanError { + fn from(e: serde_json::Error) -> Self { + error!("Internal server error: {e:#?}"); + + Self::InternalError + } +} + +impl From for NekrochanError { + fn from(e: serde_qs::Error) -> Self { + error!("Internal server error: {e:#?}"); + + Self::InternalError + } +} + +impl From for NekrochanError { + fn from(e: sqlx::Error) -> Self { + let overboard_err = match e.as_database_error() { + Some(e) => e.message() == "relation \"overboard\" does not exist", + None => false, + }; + + if !overboard_err { + error!("{e:#?}"); + + Self::InternalError + } else { + Self::OverboardError + } + } +} + +impl From for NekrochanError { + fn from(e: std::io::Error) -> Self { + error!("Internal server error: {e:#?}"); + + Self::InternalError + } +} + +impl From for NekrochanError { + fn from(e: std::net::AddrParseError) -> Self { + error!("Internal server error: {e:#?}"); + + Self::InternalError + } +} + +impl From> for NekrochanError { + fn from(_: std::sync::PoisonError) -> Self { + error!("CAPTCHA RwLock got poisoned or something."); + + Self::InternalError + } +} + +impl From for NekrochanError { + fn from(e: tokio::task::JoinError) -> Self { + error!("Internal server error: {e:#?}"); + + Self::InternalError + } +} + +impl ResponseError for NekrochanError { + fn status_code(&self) -> StatusCode { + match self { + NekrochanError::FileError(_, _) => StatusCode::BAD_REQUEST, + NekrochanError::UsernameFormatError => StatusCode::BAD_REQUEST, + NekrochanError::PasswordFormatError => StatusCode::BAD_REQUEST, + NekrochanError::IdFormatError => StatusCode::BAD_REQUEST, + NekrochanError::BoardNameFormatError => StatusCode::BAD_REQUEST, + NekrochanError::DescriptionFormatError => StatusCode::BAD_REQUEST, + NekrochanError::PostNameFormatError => StatusCode::BAD_REQUEST, + NekrochanError::CapcodeFormatError => StatusCode::BAD_REQUEST, + NekrochanError::EmailFormatError => StatusCode::BAD_REQUEST, + NekrochanError::ContentFormatError => StatusCode::BAD_REQUEST, + NekrochanError::BoardNotFound(_) => StatusCode::NOT_FOUND, + NekrochanError::AccountNotFound(_) => StatusCode::NOT_FOUND, + NekrochanError::PostNotFound(_, _) => StatusCode::NOT_FOUND, + NekrochanError::InsufficientPermissionError => StatusCode::FORBIDDEN, + NekrochanError::IncorrectCredentialError => StatusCode::UNAUTHORIZED, + NekrochanError::InvalidPageError => StatusCode::NOT_FOUND, + NekrochanError::InvalidAuthError => StatusCode::NOT_FOUND, + NekrochanError::NotLoggedInError => StatusCode::UNAUTHORIZED, + NekrochanError::OwnerDeletionError => StatusCode::FORBIDDEN, + NekrochanError::HeaderError(_) => StatusCode::BAD_GATEWAY, + NekrochanError::BoardLockError(_) => StatusCode::FORBIDDEN, + NekrochanError::ThreadLockError => StatusCode::FORBIDDEN, + NekrochanError::ReplyReplyError => StatusCode::BAD_REQUEST, + NekrochanError::ReplyLimitError => StatusCode::FORBIDDEN, + NekrochanError::NoContentError => StatusCode::BAD_REQUEST, + NekrochanError::NoFileError => StatusCode::BAD_REQUEST, + NekrochanError::EmptyPostError => StatusCode::BAD_REQUEST, + NekrochanError::RequiredCaptchaError => StatusCode::BAD_REQUEST, + NekrochanError::IncorrectCaptchaError => StatusCode::UNAUTHORIZED, + NekrochanError::SolvedCaptchaError => StatusCode::BAD_REQUEST, + NekrochanError::NoPostsError => StatusCode::BAD_REQUEST, + NekrochanError::FileLimitError(_) => StatusCode::BAD_REQUEST, + NekrochanError::IncorrectPasswordError(_) => StatusCode::UNAUTHORIZED, + NekrochanError::OverboardError => StatusCode::INTERNAL_SERVER_ERROR, + NekrochanError::InternalError => StatusCode::INTERNAL_SERVER_ERROR, + } + } +} diff --git a/src/files.rs b/src/files.rs new file mode 100755 index 0000000..fe5e5ef --- /dev/null +++ b/src/files.rs @@ -0,0 +1,350 @@ +use actix_multipart::form::tempfile::TempFile; +use anyhow::Error; +use chrono::Utc; +use glob::glob; +use image::io::Reader as ImageReader; +use std::{collections::HashSet, process::Command}; +use tokio::{ + fs::{remove_file, rename}, + task::spawn_blocking, +}; + +use crate::{ + cfg::Cfg, + ctx::Ctx, + db::models::{Board, File, Post}, + error::NekrochanError, +}; + +impl File { + pub async fn new( + cfg: &Cfg, + temp_file: TempFile, + spoiler: bool, + thumb: bool, + ) -> Result { + let original_name = temp_file.file_name.unwrap_or_else(|| "unknown".into()); + + let mime = temp_file + .content_type + .ok_or(NekrochanError::FileError( + original_name.clone(), + "žádný mime typ", + ))? + .to_string(); + + let (video, format) = match mime.as_str() { + "image/jpeg" => (false, "jpg"), + "image/pjpeg" => (false, "jpg"), + "image/png" => (false, "png"), + "image/bmp" => (false, "bmp"), + "image/gif" => (false, "gif"), + "image/webp" => (false, "webp"), + "image/apng" => (false, "apng"), + "video/mpeg" => (true, "mpeg"), + "video/quicktime" => (true, "mov"), + "video/mp4" => (true, "mp4"), + "video/webm" => (true, "webm"), + "video/x-matroska" => (true, "mkv"), + "video/ogg" => (true, "ogg"), + _ => { + return Err(NekrochanError::FileError( + original_name, + "nepodporovaný formát", + )) + } + }; + + if video && !cfg.files.videos { + return Err(NekrochanError::FileError( + original_name, + "videa nejsou podporovaná", + )); + } + + let size = temp_file.size; + + if size / 1_000_000 > cfg.files.max_size_mb { + return Err(NekrochanError::FileError( + original_name, + "soubor je příliš velký", + )); + } + + let timestamp = Utc::now().timestamp_micros(); + let format = format.to_owned(); + + let new_name = format!("{timestamp}.{format}"); + + let (thumb_format, thumb_name) = if thumb { + let format = if video { "png".into() } else { format.clone() }; + + (Some(format.clone()), Some(format!("{timestamp}.{format}"))) + } else { + (None, None) + }; + + rename(temp_file.file.path(), format!("/tmp/{new_name}")).await?; + + let (width, height) = if video { + process_video(cfg, original_name.clone(), new_name.clone(), thumb_name).await? + } else { + process_image(cfg, original_name.clone(), new_name.clone(), thumb_name).await? + }; + + rename(format!("/tmp/{new_name}"), format!("uploads/{new_name}")).await?; + + let file = File { + original_name, + format, + thumb_format, + spoiler, + width, + height, + timestamp, + size, + }; + + Ok(file) + } + + pub async fn delete(&self) { + remove_file(format!("./uploads/{}.{}", self.timestamp, self.format)) + .await + .ok(); + + if let Some(thumb_format) = &self.thumb_format { + remove_file(format!( + "./uploads/thumb/{}.{}", + self.timestamp, thumb_format + )) + .await + .ok(); + } + } + + pub fn file_url(&self) -> String { + format!("/uploads/{}.{}", self.timestamp, self.format) + } + + pub fn thumb_url(&self) -> String { + if self.spoiler { + "/static/spoiler.png".into() + } else if let Some(thumb_format) = &self.thumb_format { + format!("/uploads/thumb/{}.{}", self.timestamp, thumb_format) + } else { + self.file_url() + } + } +} + +async fn process_image( + cfg: &Cfg, + original_name: String, + new_name: String, + thumb_name: Option, +) -> Result<(u32, u32), NekrochanError> { + let original_name_ = original_name.clone(); + + let img = spawn_blocking(move || { + ImageReader::open(format!("/tmp/{new_name}"))? + .decode() + .map_err(|_| { + NekrochanError::FileError(original_name_, "nepodařilo se dekódovat obrázek") + }) + }) + .await??; + + let (width, height) = (img.width(), img.height()); + + if width > cfg.files.max_width || height > cfg.files.max_height { + return Err(NekrochanError::FileError( + original_name, + "rozměry obrázku jsou příliš velké", + )); + } + + let thumb_name = match thumb_name { + Some(thumb_name) => thumb_name, + None => return Ok((width, height)), + }; + + let thumb_w = if width > cfg.files.thumb_size { + cfg.files.thumb_size + } else { + width + }; + + let thumb_h = if height > cfg.files.thumb_size { + cfg.files.thumb_size + } else { + height + }; + + spawn_blocking(move || { + let thumb = img.thumbnail(thumb_w, thumb_h); + + thumb + .save(format!("./uploads/thumb/{thumb_name}")) + .map_err(|_| { + NekrochanError::FileError(original_name, "nepodařilo se vytvořit náhled obrázku") + }) + }) + .await??; + + Ok((width, height)) +} + +async fn process_video( + cfg: &Cfg, + original_name: String, + new_name: String, + thumb_name: Option, +) -> Result<(u32, u32), NekrochanError> { + let new_name_ = new_name.clone(); + + let ffprobe_out = spawn_blocking(move || { + Command::new("ffprobe") + .args([ + "-v", + "error", + "-select_streams", + "v:0", + "-show_entries", + "stream=width,height", + "-of", + "csv=s=x:p=0", + &format!("/tmp/{new_name_}"), + ]) + .output() + }) + .await??; + + if !ffprobe_out.status.success() { + return Err(NekrochanError::FileError( + original_name, + "nepodařilo se získat rozměry videa", + )); + } + + let invalid_dimensions = "ffprobe vrátil neplatné rozměry"; + + let out_string = String::from_utf8_lossy(&ffprobe_out.stdout); + + let (width, height) = out_string + .trim() + .split_once('x') + .ok_or(NekrochanError::FileError( + original_name.clone(), + invalid_dimensions, + ))?; + + let (width, height) = ( + width + .parse() + .map_err(|_| NekrochanError::FileError(original_name.clone(), invalid_dimensions))?, + height + .parse() + .map_err(|_| NekrochanError::FileError(original_name.clone(), invalid_dimensions))?, + ); + + if width > cfg.files.max_width || height > cfg.files.max_height { + return Err(NekrochanError::FileError( + original_name, + "rozměry videa jsou příliš velké", + )); + } + + let thumb_name = match thumb_name { + Some(thumb_name) => thumb_name, + None => return Ok((width, height)), + }; + + let thumb_size = cfg.files.thumb_size; + + let output = spawn_blocking(move || { + Command::new("ffmpeg") + .args([ + "-i", + &format!("/tmp/{new_name}"), + "-ss", + "00:00:00.50", + "-vframes", + "1", + "-vf", + &format!( + "scale={}", + if width > height { + format!("{thumb_size}:-2") + } else { + format!("-2:{thumb_size}") + } + ), + &format!("./uploads/thumb/{thumb_name}"), + ]) + .output() + }) + .await??; + + if !output.status.success() { + return Err(NekrochanError::FileError( + original_name, + "nepodařilo se vytvořit náhled videa", + )); + } + + Ok((width, height)) +} + +pub async fn cleanup_files(ctx: &Ctx) -> Result<(), Error> { + let mut keep = HashSet::new(); + let mut keep_thumbs = HashSet::new(); + + let boards = Board::read_all(ctx).await?; + + for board in boards.into_iter() { + for file in board.banners.0 { + keep.insert(format!("{}.{}", file.timestamp, file.format)); + } + + let posts = Post::read_all(ctx, board.id.clone()).await?; + + for post in posts.into_iter() { + for file in post.files.0 { + keep.insert(format!("{}.{}", file.timestamp, file.format)); + + if let Some(thumb_format) = file.thumb_format { + keep_thumbs.insert(format!("{}.{}", file.timestamp, thumb_format)); + } + } + } + } + + for file in glob("uploads/*.*")? { + let file = file?; + let file_name = file.file_name(); + + if let Some(file_name) = file_name { + let check = file_name.to_string_lossy().to_string(); + + if !keep.contains(&check) { + remove_file(file).await?; + } + } + } + + for file in glob("uploads/thumb/*.*")? { + let file = file?; + let file_name = file.file_name(); + + if let Some(file_name) = file_name { + let check = file_name.to_string_lossy().to_string(); + + if !keep_thumbs.contains(&check) { + remove_file(file).await?; + } + } + } + + Ok(()) +} diff --git a/src/filters.rs b/src/filters.rs new file mode 100644 index 0000000..fc7771d --- /dev/null +++ b/src/filters.rs @@ -0,0 +1,131 @@ +use chrono::{DateTime, Locale, Utc}; +use fancy_regex::{Captures, Regex}; +use lazy_static::lazy_static; +use std::{collections::HashSet, fmt::Display}; + +use crate::markup::SPOILER_REGEX; + +lazy_static! { + static ref MARKUP_QUOTE_REGEX: Regex = + Regex::new(r#">>(\d+)<\/a>"#).unwrap(); +} + +pub fn czech_humantime(time: &DateTime) -> askama::Result { + let duration = (Utc::now() - *time).abs(); + + let minutes = duration.num_minutes(); + let hours = duration.num_hours(); + let days = duration.num_days(); + let weeks = duration.num_weeks(); + let months = duration.num_days() / 30; + let years = duration.num_days() / 365; + + let mut time = "Teď".into(); + + if minutes > 0 { + time = format!( + "{} {}", + minutes, + czech_plural("minuta|minuty|minut", minutes)? + ); + } + + if hours > 0 { + time = format!("{} {}", hours, czech_plural("hodina|hodiny|hodin", hours)?); + } + + if days > 0 { + time = format!("{} {}", days, czech_plural("den|dny|dnů", days)?); + } + + if weeks > 0 { + time = format!("{} {}", weeks, czech_plural("týden|týdny|týdnů", weeks)?); + } + + if months > 0 { + time = format!( + "{} {}", + months, + czech_plural("měsíc|měsíce|měsíců", months)? + ); + } + + if years > 0 { + time = format!("{} {}", years, czech_plural("rok|roky|let", years)?); + } + + Ok(time) +} + +pub fn czech_datetime(time: &DateTime) -> askama::Result { + let time = time + .format_localized("%d.%m.%Y (%a) %H:%M:%S UTC", Locale::cs_CZ) + .to_string(); + + Ok(time) +} + +pub fn czech_plural(plurals: &str, count: impl Display) -> askama::Result { + let plurals = plurals.split('|').collect::>(); + let count = count.to_string().parse::().unwrap(); + + let one = plurals[0]; + let few = plurals[1]; + let other = plurals[2]; + + if count == 1 { + Ok(one.into()) + } else if count < 5 { + Ok(few.into()) + } else { + Ok(other.into()) + } +} + +pub fn inline_post(input: impl Display) -> askama::Result { + let input = input.to_string(); + + if input.is_empty() { + return Ok("(bez obsahu)".into()); + } + + let collapsed = input.split_whitespace().collect::>().join(" "); + let spoilered = SPOILER_REGEX + .replace_all(&collapsed, "(spoiler)") + .to_string(); + + let truncated = askama::filters::truncate(spoilered, 64)?; + + Ok(truncated) +} + +pub fn get_page(input: &usize, page_size: &i64) -> askama::Result { + let page = crate::paginate(*page_size, *input as i64); + + Ok(page) +} + +pub fn add_yous( + input: impl Display, + board: &String, + yous: &HashSet, +) -> askama::Result { + let input = input.to_string(); + + let output = MARKUP_QUOTE_REGEX.replace_all(&input, |captures: &Captures| { + let quote = &captures[0]; + let id = &captures[1]; + + format!( + "{}{}", + quote, + if yous.contains(&format!("{}/{}", board, id)) { + " (Ty)" + } else { + "" + } + ) + }); + + Ok(output.to_string()) +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100755 index 0000000..da498ec --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,43 @@ +use error::NekrochanError; +use lazy_static::lazy_static; +use std::{collections::HashMap, sync::RwLock}; + +lazy_static! { + pub static ref CAPTCHA: RwLock> = + RwLock::new(HashMap::new()); +} + +pub mod auth; +pub mod cfg; +pub mod ctx; +pub mod db; +pub mod error; +pub mod files; +pub mod filters; +pub mod markup; +pub mod perms; +pub mod qsform; +pub mod trip; +pub mod web; + +pub fn paginate(page_size: i64, count: i64) -> i64 { + count / page_size + (count % page_size).signum() +} + +pub fn check_page( + page: i64, + pages: i64, + page_limit: impl Into>, +) -> Result<(), NekrochanError> { + if page <= 0 || (page > pages && page != 1) { + return Err(NekrochanError::InvalidPageError); + } + + if let Some(page_limit) = page_limit.into() { + if page > page_limit { + return Err(NekrochanError::InvalidPageError); + } + } + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs new file mode 100755 index 0000000..257e2bb --- /dev/null +++ b/src/main.rs @@ -0,0 +1,154 @@ +use actix_files::{Files, NamedFile}; +use actix_web::{ + body::MessageBody, + dev::ServiceResponse, + get, + http::StatusCode, + middleware::{ErrorHandlerResponse, ErrorHandlers}, + post, + web::Data, + App, HttpResponse, HttpServer, ResponseError, +}; +use anyhow::Error; +use askama::Template; +use log::{error, info}; +use nekrochan::{ + cfg::Cfg, + ctx::Ctx, + db::cache::init_cache, + error::NekrochanError, + files::cleanup_files, + web::{self, template_response}, +}; +use sqlx::migrate; +use std::{env::var, time::Duration}; +use tokio::time::sleep; + +#[tokio::main] +async fn main() { + dotenv::dotenv().ok(); + env_logger::init(); + + if let Err(err) = run().await { + error!("{err:?}"); + } +} + +async fn run() -> Result<(), Error> { + let cfg_path = var("NEKROCHAN_CONFIG").unwrap_or_else(|_| "Nekrochan.toml".into()); + + let cfg = Cfg::load(&cfg_path).await?; + let ctx = Ctx::new(cfg).await?; + + migrate!().run(ctx.db()).await?; + init_cache(&ctx).await?; + + let ctx_ = ctx.clone(); + + tokio::spawn(async move { + loop { + match cleanup_files(&ctx_).await { + Ok(()) => info!("Routine file cleanup successful."), + Err(err) => error!("Routine file cleanup failed: {err:?}"), + }; + + sleep(Duration::from_secs(ctx_.cfg.files.cleanup_interval)).await; + } + }); + + let bind_addr = ctx.bind_addr(); + + HttpServer::new(move || { + App::new() + .app_data(Data::new(ctx.clone())) + .service(web::index::index) + .service(web::board::board) + .service(web::board_catalog::board_catalog) + .service(web::overboard::overboard) + .service(web::overboard_catalog::overboard_catalog) + .service(web::thread::thread) + .service(web::actions::create_post::create_post) + .service(web::actions::user_post_actions::user_post_actions) + .service(web::actions::staff_post_actions::staff_post_actions) + .service(web::actions::report_posts::report_posts) + .service(web::login::login_get) + .service(web::login::login_post) + .service(web::logout::logout) + .service(web::staff::account::account) + .service(web::staff::accounts::accounts) + .service(web::staff::boards::boards) + .service(web::staff::bans::bans) + .service(web::staff::reports::reports) + .service(web::staff::permissions::permissions) + .service(web::staff::banners::banners) + .service(web::staff::board_config::board_config) + .service(web::staff::actions::change_password::change_password) + .service(web::staff::actions::transfer_ownership::transfer_ownership) + .service(web::staff::actions::delete_account::delete_account) + .service(web::staff::actions::remove_accounts::remove_accounts) + .service(web::staff::actions::create_account::create_account) + .service(web::staff::actions::remove_boards::remove_boards) + .service(web::staff::actions::update_boards::update_boards) + .service(web::staff::actions::create_board::create_board) + .service(web::staff::actions::remove_bans::remove_bans) + .service(web::staff::actions::update_permissions::update_permissions) + .service(web::staff::actions::remove_banners::remove_banners) + .service(web::staff::actions::add_banners::add_banners) + .service(web::staff::actions::update_board_config::update_board_config) + .service(debug) + .service(favicon) + .service(Files::new("/static", "./static")) + .service(Files::new("/uploads", "./uploads").disable_content_disposition()) + .wrap(ErrorHandlers::new().default_handler(error_handler)) + }) + .bind(bind_addr)? + .run() + .await?; + + Ok(()) +} + +#[get("/favicon.ico")] +async fn favicon() -> Result { + let favicon = NamedFile::open("./static/favicon.ico")?; + + Ok(favicon) +} + +#[post("/debug")] +async fn debug(req: String) -> HttpResponse { + println!("{req}"); + + HttpResponse::new(StatusCode::OK) +} + +#[derive(Template)] +#[template(path = "error.html")] +struct ErrorTempalate { + error_code: u16, + error_message: String, +} + +fn error_handler(res: ServiceResponse) -> actix_web::Result> +where + B: MessageBody, + ::Error: ResponseError + 'static, +{ + let (req, res) = res.into_parts(); + + let error_code = res.status().as_u16(); + let error_message = match res.into_body().try_into_bytes().ok() { + Some(bytes) => String::from_utf8(bytes.to_vec()).unwrap_or_default(), + None => String::default(), + }; + + let template = ErrorTempalate { + error_code, + error_message, + }; + + let res = template_response(template)?; + let res = ServiceResponse::new(req, res).map_into_right_body(); + + Ok(ErrorHandlerResponse::Response(res)) +} diff --git a/src/markup.rs b/src/markup.rs new file mode 100644 index 0000000..64b8660 --- /dev/null +++ b/src/markup.rs @@ -0,0 +1,216 @@ +use std::collections::HashMap; + +use fancy_regex::{Captures, Regex}; +use lazy_static::lazy_static; +use sqlx::query_as; + +use crate::{ + ctx::Ctx, + db::models::Post, + error::NekrochanError, + perms::PermissionWrapper, + trip::{secure_tripcode, tripcode}, +}; + +lazy_static! { + pub static ref NAME_REGEX: Regex = + Regex::new(r"^([^#].*?)?(?:(##([^ ].*?)|#([^#].*?)))?(##( .*?)?)?$").unwrap(); + pub static ref QUOTE_REGEX: Regex = Regex::new(r">>(\d+)").unwrap(); + pub static ref GREENTEXT_REGEX: Regex = + Regex::new(r"(?m)^>((?!>\d+|>>/\w+(/\d*)?|>>#/).*)") + .unwrap(); + pub static ref ORANGETEXT_REGEX: Regex = Regex::new(r"(?m)^<(.+)").unwrap(); + pub static ref REDTEXT_REGEX: Regex = Regex::new(r"(?m)==(.+?)==").unwrap(); + pub static ref BLUETEXT_REGEX: Regex = Regex::new(r"(?m)--(.+?)--").unwrap(); + pub static ref GLOWTEXT_REGEX: Regex = Regex::new(r"(?m)\%\%(.+?)\%\%").unwrap(); + pub static ref UH_OH_TEXT_REGEX: Regex = Regex::new(r"(?m)\(\(\((.+?)\)\)\)").unwrap(); + pub static ref SPOILER_REGEX: Regex = Regex::new(r"(?m)\|\|([\s\S]+?)\|\|").unwrap(); + pub static ref URL_REGEX: Regex = + Regex::new(r"https?\://[^\s<>\[\]{}|\\^]+").unwrap(); +} + +pub fn parse_name( + ctx: &Ctx, + perms: &PermissionWrapper, + anon_name: &str, + name: &str, +) -> Result<(String, Option, Option), NekrochanError> { + let captures = match NAME_REGEX.captures(name)? { + Some(captures) => captures, + None => return Ok((anon_name.to_owned(), None, None)), + }; + + let name = match captures.get(1) { + Some(name) => { + let name = name.as_str().to_owned(); + + if name.len() > 32 { + return Err(NekrochanError::PostNameFormatError); + } + + name + } + None => anon_name.to_owned(), + }; + + let tripcode = match captures.get(2) { + Some(_) => { + let strip = captures.get(3); + let itrip = captures.get(4); + + if let Some(strip) = strip { + let trip = secure_tripcode(strip.as_str(), &ctx.cfg.secrets.secure_trip); + + Some(format!("!!{trip}")) + } else if let Some(itrip) = itrip { + let trip = tripcode(itrip.as_str()); + + Some(format!("!{trip}")) + } else { + None + } + } + None => None, + }; + + if !(perms.owner() || perms.capcodes()) { + return Ok((name, tripcode, None)); + } + + fn capcode_fallback(owner: bool) -> Option { + if owner { + Some("Admin".into()) + } else { + Some("Uklízeč".into()) + } + } + + let capcode = match captures.get(5) { + Some(_) => match captures.get(6) { + Some(capcode) => { + let capcode: String = capcode.as_str().trim().into(); + + if capcode.is_empty() { + capcode_fallback(perms.owner()) + } else { + if capcode.len() > 32 { + return Err(NekrochanError::CapcodeFormatError); + } + + Some(capcode) + } + } + None => capcode_fallback(perms.owner()), + }, + None => None, + }; + + Ok((name, tripcode, capcode)) +} + +pub async fn markup( + ctx: &Ctx, + board: &String, + op: Option, + text: &str, +) -> Result { + let text = escape_html(text); + let quoted_posts = get_quoted_posts(ctx, board, &text).await?; + + let text = QUOTE_REGEX.replace_all(&text, |captures: &Captures| { + let id_raw = &captures[1]; + let id = match id_raw.parse() { + Ok(id) => id, + Err(_) => return format!(">>{id_raw}"), + }; + + let post = quoted_posts.get(&id); + + match post { + Some(post) => format!( + ">>{}{}", + post.post_url(), + post.id, + if op == Some(post.id) { + " (OP)" + } else { + "" + } + ), + None => format!(">>{id}"), + } + }); + + let text = GREENTEXT_REGEX.replace_all(&text, ">$1"); + let text = ORANGETEXT_REGEX.replace_all(&text, "<$1"); + let text = REDTEXT_REGEX.replace_all(&text, "$1"); + let text = BLUETEXT_REGEX.replace_all(&text, "$1"); + let text = GLOWTEXT_REGEX.replace_all(&text, "$1"); + let text = SPOILER_REGEX.replace_all(&text, "$1"); + + let text = UH_OH_TEXT_REGEX.replace_all(&text, |captures: &Captures| { + format!( + "((( {} )))", + captures[1].trim() + ) + }); + + let text = URL_REGEX.replace_all(&text, |captures: &Captures| { + let url = &captures[0]; + + format!("{url}") + }); + + Ok(text.to_string()) +} + +fn escape_html(text: &str) -> String { + text.replace('&', "&") + .replace('\'', "'") + .replace('/', "/") + .replace('`', "`") + .replace('=', "=") + .replace('<', "<") + .replace('>', ">") + .replace('"', """) +} + +async fn get_quoted_posts( + ctx: &Ctx, + board: &String, + text: &str, +) -> Result, NekrochanError> { + let mut quoted_ids: Vec = Vec::new(); + + for quote in QUOTE_REGEX.captures_iter(text) { + let id_raw = "e.unwrap()[1]; + let id = match id_raw.parse() { + Ok(id) => id, + Err(_) => continue, + }; + + quoted_ids.push(id); + } + + if quoted_ids.is_empty() { + return Ok(HashMap::new()); + } + + let in_list = quoted_ids + .iter() + .map(|id| id.to_string()) + .collect::>() + .join(","); + + let quoted_posts = query_as(&format!( + "SELECT * FROM posts_{} WHERE id IN ({})", + board, in_list + )) + .fetch_all(ctx.db()) + .await? + .into_iter() + .map(|post: Post| (post.id, post)) + .collect::>(); + + Ok(quoted_posts) +} diff --git a/src/perms.rs b/src/perms.rs new file mode 100755 index 0000000..28ccb24 --- /dev/null +++ b/src/perms.rs @@ -0,0 +1,85 @@ +use enumflags2::{bitflags, BitFlags}; + +#[bitflags] +#[repr(u64)] +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum Permissions { + EditPosts, + ManagePosts, + Capcodes, + StaffLog, + Reports, + Bans, + BoardBanners, + BoardConfig, + BypassBans, + BypassBoardLock, + BypassThreadLock, + BypassCaptcha, +} + +pub struct PermissionWrapper(BitFlags, bool); + +impl PermissionWrapper { + pub fn new(perms: u64, owner: bool) -> Self { + Self(BitFlags::from_bits_truncate(perms), owner) + } +} + +impl PermissionWrapper { + pub fn integer(&self) -> u64 { + self.0.bits() + } + + pub fn owner(&self) -> bool { + self.1 + } + + pub fn edit_posts(&self) -> bool { + self.0.contains(Permissions::EditPosts) + } + + pub fn manage_posts(&self) -> bool { + self.0.contains(Permissions::ManagePosts) + } + + pub fn capcodes(&self) -> bool { + self.0.contains(Permissions::Capcodes) + } + + pub fn staff_log(&self) -> bool { + self.0.contains(Permissions::StaffLog) + } + + pub fn reports(&self) -> bool { + self.0.contains(Permissions::Reports) + } + + pub fn bans(&self) -> bool { + self.0.contains(Permissions::Bans) + } + + pub fn board_banners(&self) -> bool { + self.0.contains(Permissions::BoardBanners) + } + + pub fn board_config(&self) -> bool { + self.0.contains(Permissions::BoardConfig) + } + + pub fn bypass_bans(&self) -> bool { + self.0.contains(Permissions::BypassBans) + } + + pub fn bypass_board_lock(&self) -> bool { + self.0.contains(Permissions::BypassBoardLock) + } + + pub fn bypass_thread_lock(&self) -> bool { + self.0.contains(Permissions::BypassThreadLock) + } + + pub fn bypass_captcha(&self) -> bool { + self.0.contains(Permissions::BypassCaptcha) + } +} diff --git a/src/qsform.rs b/src/qsform.rs new file mode 100644 index 0000000..ccfaa53 --- /dev/null +++ b/src/qsform.rs @@ -0,0 +1,43 @@ +use actix_web::{dev::Payload, http::StatusCode, FromRequest, HttpRequest, ResponseError}; +use serde::Deserialize; +use serde_qs::Config; +use std::{future::Future, pin::Pin}; +use thiserror::Error; + +pub struct QsForm(pub T) +where + T: for<'de> Deserialize<'de>; + +#[derive(Debug, Error)] +pub enum QsFormError { + #[error("{}", .0)] + FutureError(#[from] actix_web::Error), + #[error("{}", .0)] + ParseError(#[from] serde_qs::Error), +} + +impl ResponseError for QsFormError { + fn status_code(&self) -> StatusCode { + StatusCode::BAD_REQUEST + } +} + +impl FromRequest for QsForm +where + T: for<'de> Deserialize<'de>, +{ + type Error = QsFormError; + type Future = Pin, Self::Error>>>>; + + fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future { + let data = String::from_request(req, payload); + + Box::pin(async move { + let data = data.await?; + let config = Config::new(10, false); + let form: T = config.deserialize_str(&data)?; + + Ok(QsForm(form)) + }) + } +} diff --git a/src/trip.rs b/src/trip.rs new file mode 100755 index 0000000..0818739 --- /dev/null +++ b/src/trip.rs @@ -0,0 +1,54 @@ +use encoding::{all::WINDOWS_31J, EncoderTrap, Encoding}; +use pwhash::{ + bcrypt::{self, BcryptSetup}, + unix::crypt, +}; + +pub fn tripcode(password: &str) -> String { + let password = WINDOWS_31J.encode(password, EncoderTrap::Replace).unwrap(); + + let salt = [password.as_ref(), "H.".as_bytes()].concat(); + let salt = &salt[1..3]; + let salt = salt + .iter() + .map(|c| match c { + 46..=122 => *c, + _ => 46, + } as char) + .map(|c| match c { + ':' => 'A', + ';' => 'B', + '<' => 'C', + '=' => 'D', + '>' => 'E', + '?' => 'F', + '@' => 'G', + '[' => 'a', + '\\' => 'b', + ']' => 'c', + '^' => 'd', + '_' => 'e', + '`' => 'f', + _ => c, + }) + .collect::(); + + let trip = crypt(password, &salt).unwrap(); + + trip[3..].to_owned() +} + +pub fn secure_tripcode(password: &str, tripcode_secret: &str) -> String { + let trip = bcrypt::hash_with( + BcryptSetup { + salt: Some(tripcode_secret), + ..Default::default() + }, + password, + ) + .unwrap(); + + let trip = &trip[trip.len() - 10..]; + + trip.into() +} diff --git a/src/web/actions/create_post.rs b/src/web/actions/create_post.rs new file mode 100644 index 0000000..3d8f7c4 --- /dev/null +++ b/src/web/actions/create_post.rs @@ -0,0 +1,250 @@ +use actix_multipart::form::{tempfile::TempFile, text::Text, MultipartForm}; +use actix_web::{ + cookie::Cookie, http::StatusCode, post, web::Data, HttpRequest, HttpResponse, + HttpResponseBuilder, +}; +use pwhash::bcrypt::hash; +use sha256::digest; + +use crate::{ + ctx::Ctx, + db::models::{Ban, Board, File, Post}, + error::NekrochanError, + markup::{markup, parse_name}, + perms::PermissionWrapper, + web::{ + ban_response, + tcx::{account_from_auth_opt, ip_from_req}, + }, + CAPTCHA, +}; + +#[derive(MultipartForm)] +pub struct PostForm { + pub board: Text, + pub thread: Option>, + pub name: Text, + pub email: Text, + pub content: Text, + #[multipart(rename = "files[]")] + pub files: Vec, + pub spoiler_files: Option>, + pub password: Text, + pub captcha_id: Option>, + pub captcha_solution: Option>, +} + +#[post("/actions/create-post")] +pub async fn create_post( + ctx: Data, + req: HttpRequest, + MultipartForm(form): MultipartForm, +) -> Result { + let perms = match account_from_auth_opt(&ctx, &req).await? { + Some(account) => account.perms(), + None => PermissionWrapper::new(0, false), + }; + + let (ip, country) = ip_from_req(&req)?; + + let board = form.board.0; + let board = Board::read(&ctx, board.clone()) + .await? + .ok_or(NekrochanError::BoardNotFound(board))?; + + if let Some(ban) = Ban::read(&ctx, board.id.clone(), ip).await? { + if !(perms.owner() || perms.bypass_bans()) { + return ban_response(&ctx, &req, ban).await; + } + } + + if board.config.0.locked && !(perms.owner() || perms.bypass_board_lock()) { + return Err(NekrochanError::BoardLockError(board.id.clone())); + } + + let mut bumpy_bump = true; + let mut noko = true; + + let thread = match form.thread { + Some(Text(thread)) => { + let thread = Post::read(&ctx, board.id.clone(), thread) + .await? + .ok_or(NekrochanError::PostNotFound(board.id.clone(), thread))?; + + if thread.thread.is_some() { + return Err(NekrochanError::ReplyReplyError); + } + + if thread.locked && !(perms.owner() || perms.bypass_thread_lock()) { + return Err(NekrochanError::ThreadLockError); + } + + if thread.replies >= board.config.0.reply_limit { + return Err(NekrochanError::ReplyLimitError); + } + + if thread.bumps >= board.config.0.bump_limit { + bumpy_bump = false; + } + + Some(thread) + } + None => None, + }; + + let difficulties = ["easy", "medium", "hard"]; + + let difficulty = if thread.is_none() { + if difficulties.contains(&board.config.0.thread_captcha.as_str()) { + Some(board.config.0.thread_captcha.clone()) + } else { + None + } + } else if difficulties.contains(&board.config.0.reply_captcha.as_str()) { + Some(board.config.0.reply_captcha.clone()) + } else { + None + }; + + if let Some(difficulty) = difficulty { + let board = board.id.clone(); + let id = form + .captcha_id + .ok_or(NekrochanError::RequiredCaptchaError)? + .0; + + let key = (board, difficulty, id); + let solution = form + .captcha_solution + .ok_or(NekrochanError::RequiredCaptchaError)?; + + let actual_solution = CAPTCHA + .write()? + .remove(&key) + .ok_or(NekrochanError::SolvedCaptchaError)?; + + if solution.trim() != actual_solution { + return Err(NekrochanError::IncorrectCaptchaError); + } + } + + let name_raw = form.name.trim(); + let (name, tripcode, capcode) = parse_name(&ctx, &perms, &board.config.0.anon_name, name_raw)?; + + let email_raw = form.email.trim(); + + let email = if !email_raw.is_empty() { + if email_raw.len() > 256 { + return Err(NekrochanError::EmailFormatError); + } + + if email_raw == "sage" || email_raw == "nonokosage" { + bumpy_bump = false; + } + + if email_raw == "nonoko" || email_raw == "nonokosage" { + noko = false; + } + + Some(email_raw.into()) + } else { + None + }; + + let content_nomarkup = form.content.0.trim().to_owned(); + + if content_nomarkup.is_empty() && (thread.is_none() && board.config.0.require_thread_content) + || (thread.is_some() && board.config.0.require_reply_content) + { + return Err(NekrochanError::NoContentError); + } + + if content_nomarkup.len() > 4000 { + return Err(NekrochanError::ContentFormatError); + } + + let content = markup( + &ctx, + &board.id, + thread.as_ref().map(|t| t.id), + &content_nomarkup, + ) + .await?; + + if form.files.len() > board.config.0.file_limit { + return Err(NekrochanError::FileLimitError(board.config.0.file_limit)); + } + + let mut files = Vec::new(); + + for file in form.files.into_iter() { + if file.size == 0 { + continue; + } + + let spoiler = form.spoiler_files.is_some(); + let file = File::new(&ctx.cfg, file, spoiler, true).await?; + + files.push(file); + } + + if content_nomarkup.is_empty() && files.is_empty() { + return Err(NekrochanError::EmptyPostError); + } + + let password_raw = form.password.trim(); + + if password_raw.len() < 8 { + return Err(NekrochanError::PasswordFormatError); + } + + let password = hash(password_raw)?; + let thread_id = thread.as_ref().map(|t| t.id); + + let post = Post::create( + &ctx, + &board, + thread_id, + name, + tripcode, + capcode, + email, + content, + content_nomarkup, + files, + password, + country, + ip, + bumpy_bump, + ) + .await?; + + let ts = thread + .as_ref() + .map(|thread| thread.created.timestamp_micros()) + .unwrap_or_else(|| post.created.timestamp_micros()); + + let hash_input = format!("{}:{}:{}", ip, ts, ctx.cfg.secrets.user_id); + let user_hash = digest(hash_input); + let user_id = user_hash[..6].to_owned(); + + post.update_user_id(&ctx, user_id).await?; + + let mut res = HttpResponseBuilder::new(StatusCode::SEE_OTHER); + + let name_cookie = Cookie::build("name", name_raw).path("/").finish(); + let password_cookie = Cookie::build("password", password_raw).path("/").finish(); + + res.cookie(name_cookie); + res.cookie(password_cookie); + + let res = if noko { + res.append_header(("Location", post.post_url().as_str())) + .finish() + } else { + res.append_header(("Location", format!("/boards/{}", post.board).as_str())) + .finish() + }; + + Ok(res) +} diff --git a/src/web/actions/mod.rs b/src/web/actions/mod.rs new file mode 100644 index 0000000..a6a58d5 --- /dev/null +++ b/src/web/actions/mod.rs @@ -0,0 +1,38 @@ +use askama::Template; + +use super::tcx::TemplateCtx; +use crate::{ctx::Ctx, db::models::Post}; + +pub mod create_post; +pub mod staff_post_actions; +pub mod report_posts; +pub mod user_post_actions; + +#[derive(Template)] +#[template(path = "action.html")] +pub struct ActionTemplate { + pub tcx: TemplateCtx, + pub response: String, +} + +pub async fn get_posts_from_ids(ctx: &Ctx, ids: Vec) -> Vec { + let mut posts = Vec::new(); + + for id in ids.into_iter() { + if let Some((board, id)) = parse_id(id) { + if let Ok(Some(post)) = Post::read(ctx, board, id).await { + posts.push(post); + } + } + } + + posts +} + +fn parse_id(id: String) -> Option<(String, i32)> { + let (board, id) = id.split_once('/')?; + let board = board.to_owned(); + let id = id.parse().ok()?; + + Some((board, id)) +} diff --git a/src/web/actions/report_posts.rs b/src/web/actions/report_posts.rs new file mode 100644 index 0000000..db4a2dc --- /dev/null +++ b/src/web/actions/report_posts.rs @@ -0,0 +1,106 @@ +use actix_web::{post, web::Data, HttpRequest, HttpResponse}; +use serde::Deserialize; +use std::fmt::Write; + +use crate::{ + ctx::Ctx, + db::models::{Ban, Board}, + error::NekrochanError, + qsform::QsForm, + web::{ + actions::{get_posts_from_ids, ActionTemplate}, + ban_response, + tcx::{ip_from_req, TemplateCtx}, + template_response, + }, +}; + +#[derive(Deserialize)] +pub struct ReportPostsForm { + #[serde(default)] + pub posts: Vec, + pub report_reason: String, +} + +#[post("/actions/report-posts")] +pub async fn report_posts( + ctx: Data, + req: HttpRequest, + QsForm(form): QsForm, +) -> Result { + let tcx = TemplateCtx::new(&ctx, &req).await?; + let (reporter_ip, reporter_country) = ip_from_req(&req)?; + let bans = Ban::read_by_ip(&ctx, reporter_ip).await?; + + if let Some(ban) = bans.get(&None) { + if !(tcx.perms.owner() || tcx.perms.bypass_bans()) { + return ban_response(&ctx, &req, ban.clone()).await; + } + } + + let boards = Board::read_all_map(&ctx).await?; + let posts = get_posts_from_ids(&ctx, form.posts).await; + + let mut response = String::new(); + let mut posts_reported = 0; + + let reason = form.report_reason.trim(); + + for post in posts.iter() { + let board = &boards[&post.board]; + + if bans.contains_key(&Some(board.id.clone())) + && !(tcx.perms.owner() || tcx.perms.bypass_bans()) + { + writeln!(&mut response, "[Chyba] Jsi zabanován z /{}/.", board.id).ok(); + continue; + } + + if board.config.0.locked && !(tcx.perms.owner() || tcx.perms.bypass_board_lock()) { + writeln!( + &mut response, + "[Chyba] {}", + NekrochanError::BoardLockError(board.id.to_owned()) + ) + .ok(); + + continue; + } + + if post + .reports + .iter() + .any(|report| report.reporter_ip == reporter_ip) + { + writeln!( + &mut response, + "[Chyba] Příspěvek #{} jsi už nahlásil.", + post.id + ) + .ok(); + continue; + } + + post.create_report( + &ctx, + reason.to_owned(), + reporter_country.clone(), + reporter_ip, + ) + .await?; + + posts_reported += 1; + } + + if posts_reported != 0 { + writeln!( + &mut response, + "[Úspěch] Nahlášeny příspěvky: {posts_reported}" + ) + .ok(); + } + + let template = ActionTemplate { tcx, response }; + + template_response(template) +} diff --git a/src/web/actions/staff_post_actions.rs b/src/web/actions/staff_post_actions.rs new file mode 100644 index 0000000..e8f9105 --- /dev/null +++ b/src/web/actions/staff_post_actions.rs @@ -0,0 +1,219 @@ +use actix_web::{post, web::Data, HttpRequest, HttpResponse}; +use chrono::{Duration, Utc}; +use ipnetwork::IpNetwork; +use serde::Deserialize; +use std::{collections::HashSet, fmt::Write}; + +use crate::{ + ctx::Ctx, + db::models::Ban, + error::NekrochanError, + qsform::QsForm, + web::{ + actions::{get_posts_from_ids, ActionTemplate}, + tcx::{account_from_auth, TemplateCtx}, + template_response, + }, +}; + +#[derive(Deserialize)] +pub struct JannyPostActionsForm { + #[serde(default)] + pub posts: Vec, + #[serde(rename = "staff_remove_posts")] + pub remove_posts: Option, + #[serde(rename = "staff_remove_files")] + pub remove_files: Option, + #[serde(rename = "staff_toggle_spoiler")] + pub toggle_spoiler: Option, + pub toggle_sticky: Option, + pub toggle_lock: Option, + pub ban_user: Option, + pub global_ban: Option, + pub unappealable_ban: Option, + pub ban_reason: Option, + pub ban_duration: Option, + pub ban_range: Option, +} + +#[post("/actions/staff-post-actions")] +pub async fn staff_post_actions( + ctx: Data, + req: HttpRequest, + QsForm(form): QsForm, +) -> Result { + let tcx = TemplateCtx::new(&ctx, &req).await?; + let account = account_from_auth(&ctx, &req).await?; + let posts = get_posts_from_ids(&ctx, form.posts).await; + + let mut response = String::new(); + + let mut posts_removed = 0; + let mut files_removed = 0; + let mut spoilers_toggled = 0; + let mut stickies_toggled = 0; + let mut locks_toggled = 0; + let mut bans_issued = 0; + + for post in posts.iter() { + if (form.remove_posts.is_some() + || form.remove_files.is_some() + || form.toggle_spoiler.is_some() + || form.toggle_sticky.is_some() + || form.toggle_lock.is_some()) + && !(account.perms().owner() || account.perms().manage_posts()) + { + writeln!( + &mut response, + "[Chyba] Nemáš oprávnění spravovat příspěvky." + ) + .ok(); + + continue; + } + + if form.remove_posts.is_some() { + post.delete(&ctx).await?; + posts_removed += 1; + } + + if form.remove_files.is_some() { + post.delete_files(&ctx).await?; + files_removed += post.files.0.len(); + } + + if form.toggle_spoiler.is_some() { + post.update_spoiler(&ctx).await?; + spoilers_toggled += post.files.0.len(); + } + + if form.toggle_sticky.is_some() { + post.update_sticky(&ctx).await?; + stickies_toggled += post.files.0.len(); + } + + if form.toggle_lock.is_some() { + post.update_lock(&ctx).await?; + locks_toggled += post.files.0.len(); + } + } + + let mut already_banned = HashSet::new(); + + for post in posts.into_iter() { + if let (Some(_), Some(ban_reason), Some(ban_duration), Some(ban_range)) = ( + form.ban_user.clone(), + form.ban_reason.clone(), + form.ban_duration, + form.ban_range.clone(), + ) { + if !(account.perms().owner() || account.perms().bans()) { + writeln!(&mut response, "[Chyba] Nemáš oprávnění vydat ban.").ok(); + continue; + } + + if already_banned.contains(&post.ip) { + continue; + } + + let account = account.username.clone(); + + let board = if form.global_ban.is_none() { + Some(post.board.clone()) + } else { + None + }; + + let prefix = if post.ip.is_ipv4() { + match ban_range.as_str() { + "ip" => 32, + "lan" => 24, + "isp" => 16, + _ => 32, + } + } else { + match ban_range.as_str() { + "ip" => 128, + "lan" => 48, + "isp" => 24, + _ => 128, + } + }; + + let ip_range = IpNetwork::new(post.ip, prefix)?; + let reason = ban_reason.trim().into(); + let appealable = form.unappealable_ban.is_none(); + + let expires = if ban_duration != 0 { + Some(Utc::now() + Duration::days(ban_duration)) + } else { + None + }; + + Ban::create(&ctx, account, board, ip_range, reason, appealable, expires).await?; + + let content_nomarkup = format!( + "{}\n\n==(UŽIVATEL BYL ZA TENTO PŘÍSPĚVEK ZABANOVÁN)==", + post.content_nomarkup + ); + + let content = format!( + "{}\n\n(UŽIVATEL BYL ZA TENTO PŘÍSPĚVEK ZABANOVÁN)", + post.content + ); + + post.update_content(&ctx, content, content_nomarkup).await?; + + already_banned.insert(post.ip); + bans_issued += 1; + } + } + + if posts_removed != 0 { + writeln!( + &mut response, + "[Úspěch] Odstraněny příspěvky: {posts_removed}" + ) + .ok(); + } + + if files_removed != 0 { + writeln!( + &mut response, + "[Úspěch] Odstraněny soubory: {files_removed}" + ) + .ok(); + } + + if spoilers_toggled != 0 { + writeln!( + &mut response, + "[Úspěch] Přepnuty spoilery: {spoilers_toggled}" + ) + .ok(); + } + + if stickies_toggled != 0 { + writeln!( + &mut response, + "[Úspěch] Připnuta/odepnuta vlákna: {stickies_toggled}" + ) + .ok(); + } + + if locks_toggled != 0 { + writeln!( + &mut response, + "[Úspěch] Zamčena/odemčena vlákna: {locks_toggled}" + ) + .ok(); + } + + if bans_issued != 0 { + writeln!(&mut response, "[Úspěch] Uděleny bany: {bans_issued}").ok(); + } + + let template = ActionTemplate { tcx, response }; + + template_response(template) +} diff --git a/src/web/actions/user_post_actions.rs b/src/web/actions/user_post_actions.rs new file mode 100644 index 0000000..83ef9e2 --- /dev/null +++ b/src/web/actions/user_post_actions.rs @@ -0,0 +1,135 @@ +use std::fmt::Write; + +use actix_web::{post, web::Data, HttpRequest, HttpResponse}; +use pwhash::bcrypt::verify; +use serde::Deserialize; + +use crate::{ + ctx::Ctx, + db::models::{Ban, Board}, + error::NekrochanError, + qsform::QsForm, + web::{ + actions::{get_posts_from_ids, ActionTemplate}, + ban_response, + tcx::{ip_from_req, TemplateCtx}, + template_response, + }, +}; + +#[derive(Deserialize)] +pub struct UserPostActionsForm { + #[serde(default)] + pub posts: Vec, + pub remove_posts: Option, + pub remove_files: Option, + pub toggle_spoiler: Option, + pub password: String, +} + +#[post("/actions/user-post-actions")] +pub async fn user_post_actions( + ctx: Data, + req: HttpRequest, + QsForm(form): QsForm, +) -> Result { + let tcx = TemplateCtx::new(&ctx, &req).await?; + let (ip, _) = ip_from_req(&req)?; + let bans = Ban::read_by_ip(&ctx, ip).await?; + + if let Some(ban) = bans.get(&None) { + if !(tcx.perms.owner() || tcx.perms.bypass_bans()) { + return ban_response(&ctx, &req, ban.clone()).await; + } + } + + let posts = get_posts_from_ids(&ctx, form.posts).await; + let boards = Board::read_all_map(&ctx).await?; + + let mut response = String::new(); + + let mut posts_removed = 0; + let mut files_removed = 0; + let mut spoilers_toggled = 0; + + for post in posts.iter() { + let board = &boards[&post.board]; + + if bans.contains_key(&Some(board.id.clone())) + && !(tcx.perms.owner() || tcx.perms.bypass_bans()) + { + writeln!(&mut response, "[Chyba] Jsi zabanován z /{}/.", board.id).ok(); + continue; + } + + if board.config.0.locked && !(tcx.perms.owner() || tcx.perms.bypass_board_lock()) { + writeln!( + &mut response, + "[Chyba] {}", + NekrochanError::BoardLockError(board.id.to_owned()) + ) + .ok(); + + continue; + } + + if !verify(&form.password, &post.password) { + writeln!( + &mut response, + "[Chyba] {}", + NekrochanError::IncorrectPasswordError(post.id) + ) + .ok(); + continue; + } + + if form.remove_posts.is_some() { + post.delete(&ctx).await?; + posts_removed += 1; + } + + if form.remove_files.is_some() { + if (post.thread.is_none() && board.config.0.require_thread_file) + || (post.thread.is_some() && board.config.0.require_reply_file) + { + writeln!(&mut response, "[Chyba] Soubor je na tomto místě potřebný.").ok(); + } else { + post.delete_files(&ctx).await?; + files_removed += post.files.0.len(); + } + } + + if form.toggle_spoiler.is_some() { + post.update_spoiler(&ctx).await?; + spoilers_toggled += post.files.0.len(); + } + } + + if posts_removed != 0 { + writeln!( + &mut response, + "[Úspěch] Odstraněny příspěvky: {posts_removed}" + ) + .ok(); + } + + if files_removed != 0 { + writeln!( + &mut response, + "[Úspěch] Odstraněny soubory: {files_removed}" + ) + .ok(); + } + + if spoilers_toggled != 0 { + writeln!( + &mut response, + "[Úspěch] Přepnuty spoilery: {spoilers_toggled}" + ) + .ok(); + } + + let template = ActionTemplate { tcx, response }; + + template_response(template) +} diff --git a/src/web/board.rs b/src/web/board.rs new file mode 100755 index 0000000..0d5d60c --- /dev/null +++ b/src/web/board.rs @@ -0,0 +1,74 @@ +use actix_web::{ + get, + web::{Data, Path, Query}, + HttpRequest, HttpResponse, +}; +use askama::Template; +use redis::AsyncCommands; +use serde::Deserialize; + +use crate::{ + check_page, + ctx::Ctx, + db::models::{Board, Post}, + error::NekrochanError, + filters, paginate, + web::{tcx::TemplateCtx, template_response}, +}; + +#[derive(Deserialize)] +pub struct BoardQuery { + page: i64, +} + +#[derive(Template)] +#[template(path = "board.html")] +struct BoardTemplate { + tcx: TemplateCtx, + board: Board, + threads: Vec<(Post, Vec)>, + page: i64, + pages: i64, +} + +#[get("/boards/{board}")] +pub async fn board( + ctx: Data, + req: HttpRequest, + path: Path, + query: Option>, +) -> Result { + let tcx = TemplateCtx::new(&ctx, &req).await?; + + let board = path.into_inner(); + let board = Board::read(&ctx, board.clone()) + .await? + .ok_or(NekrochanError::BoardNotFound(board))?; + + let count = ctx + .cache() + .get(format!("board_threads:{}", board.id)) + .await?; + let page = query.map(|q| q.page).unwrap_or(1); + let pages = paginate(board.config.0.page_size, count); + + check_page(page, pages, board.config.0.page_count)?; + + let mut threads = Vec::new(); + + for thread in Post::read_board_page(&ctx, &board, page).await?.into_iter() { + let replies = thread.read_replies(&ctx).await?; + + threads.push((thread, replies)) + } + + let template = BoardTemplate { + tcx, + board, + threads, + page, + pages, + }; + + template_response(template) +} diff --git a/src/web/board_catalog.rs b/src/web/board_catalog.rs new file mode 100644 index 0000000..1f3fb22 --- /dev/null +++ b/src/web/board_catalog.rs @@ -0,0 +1,46 @@ +use actix_web::{ + get, + web::{Data, Path}, + HttpRequest, HttpResponse, +}; +use askama::Template; + +use crate::{ + ctx::Ctx, + db::models::{Board, Post}, + error::NekrochanError, + filters, + web::{tcx::TemplateCtx, template_response}, +}; + +#[derive(Template)] +#[template(path = "board_catalog.html")] +struct BoardCatalogTemplate { + tcx: TemplateCtx, + board: Board, + threads: Vec, +} + +#[get("/boards/{board}/catalog")] +pub async fn board_catalog( + ctx: Data, + req: HttpRequest, + path: Path, +) -> Result { + let tcx = TemplateCtx::new(&ctx, &req).await?; + + let board = path.into_inner(); + let board = Board::read(&ctx, board.clone()) + .await? + .ok_or(NekrochanError::BoardNotFound(board))?; + + let threads = Post::read_board_catalog(&ctx, board.id.clone()).await?; + + let template = BoardCatalogTemplate { + tcx, + board, + threads, + }; + + template_response(template) +} diff --git a/src/web/index.rs b/src/web/index.rs new file mode 100755 index 0000000..bda31ec --- /dev/null +++ b/src/web/index.rs @@ -0,0 +1,24 @@ +use actix_web::{get, web::Data, HttpRequest, HttpResponse}; +use askama::Template; + +use super::tcx::TemplateCtx; +use crate::{ctx::Ctx, db::models::Post, error::NekrochanError, filters, web::template_response}; + +#[derive(Template)] +#[template(path = "index.html")] +struct IndexTemplate { + tcx: TemplateCtx, + posts: Vec, + files: Vec, +} + +#[get("/")] +pub async fn index(ctx: Data, req: HttpRequest) -> Result { + let tcx = TemplateCtx::new(&ctx, &req).await?; + let posts = Post::read_latest(&ctx).await.unwrap_or_else(|_| Vec::new()); + let files = Post::read_files(&ctx).await.unwrap_or_else(|_| Vec::new()); + + let template = IndexTemplate { tcx, posts, files }; + + template_response(template) +} diff --git a/src/web/login.rs b/src/web/login.rs new file mode 100755 index 0000000..3778194 --- /dev/null +++ b/src/web/login.rs @@ -0,0 +1,59 @@ +use actix_web::{ + cookie::Cookie, get, http::StatusCode, post, web::Data, HttpRequest, HttpResponse, + HttpResponseBuilder, +}; +use askama::Template; +use pwhash::bcrypt::verify; +use serde::Deserialize; + +use crate::{ + auth::Claims, + ctx::Ctx, + db::models::Account, + error::NekrochanError, + qsform::QsForm, + web::{tcx::TemplateCtx, template_response}, +}; + +#[derive(Template)] +#[template(path = "login.html")] +struct LogInTemplate { + tcx: TemplateCtx, +} + +#[get("/login")] +pub async fn login_get(ctx: Data, req: HttpRequest) -> Result { + let tcx = TemplateCtx::new(&ctx, &req).await?; + let template = LogInTemplate { tcx }; + + template_response(template) +} + +#[derive(Deserialize)] +pub struct LogInForm { + username: String, + password: String, +} + +#[post("/login")] +pub async fn login_post( + ctx: Data, + QsForm(form): QsForm, +) -> Result { + let account = Account::read(&ctx, form.username.clone()) + .await? + .ok_or(NekrochanError::IncorrectCredentialError)?; + + if !verify(form.password, &account.password) { + return Err(NekrochanError::IncorrectCredentialError); + } + + let auth = Claims::new(account.username).encode(&ctx)?; + + let res = HttpResponseBuilder::new(StatusCode::SEE_OTHER) + .append_header(("Location", "/staff/account")) + .cookie(Cookie::new("auth", auth)) + .finish(); + + Ok(res) +} diff --git a/src/web/logout.rs b/src/web/logout.rs new file mode 100755 index 0000000..f9c8d06 --- /dev/null +++ b/src/web/logout.rs @@ -0,0 +1,13 @@ +use actix_web::{cookie::Cookie, get, http::StatusCode, HttpResponse, HttpResponseBuilder}; + +#[get("/logout")] +pub async fn logout() -> HttpResponse { + let mut auth = Cookie::named("auth"); + + auth.make_removal(); + + HttpResponseBuilder::new(StatusCode::SEE_OTHER) + .append_header(("Location", "/")) + .cookie(auth) + .finish() +} diff --git a/src/web/mod.rs b/src/web/mod.rs new file mode 100755 index 0000000..9c0a270 --- /dev/null +++ b/src/web/mod.rs @@ -0,0 +1,45 @@ +use actix_web::{http::StatusCode, HttpRequest, HttpResponse, HttpResponseBuilder}; +use askama::Template; + +pub mod actions; +pub mod board; +pub mod board_catalog; +pub mod index; +pub mod login; +pub mod logout; +pub mod overboard; +pub mod overboard_catalog; +pub mod staff; +pub mod tcx; +pub mod thread; + +use self::tcx::TemplateCtx; +use crate::{ctx::Ctx, db::models::Ban, error::NekrochanError, filters}; + +#[derive(Template)] +#[template(path = "banned.html")] +struct BannedTemplate { + tcx: TemplateCtx, + ban: Ban, +} + +pub async fn ban_response( + ctx: &Ctx, + req: &HttpRequest, + ban: Ban, +) -> Result { + let tcx = TemplateCtx::new(ctx, req).await?; + + template_response(BannedTemplate { tcx, ban }) +} + +pub fn template_response(template: T) -> Result +where + T: Template, +{ + let res = HttpResponseBuilder::new(StatusCode::OK) + .append_header(("Content-Type", "text/html")) + .body(template.render()?); + + Ok(res) +} diff --git a/src/web/overboard.rs b/src/web/overboard.rs new file mode 100644 index 0000000..7bb37ae --- /dev/null +++ b/src/web/overboard.rs @@ -0,0 +1,67 @@ +use actix_web::{ + get, + web::{Data, Query}, + HttpRequest, HttpResponse, +}; +use askama::Template; +use redis::AsyncCommands; +use serde::Deserialize; +use std::collections::HashMap; + +use crate::{ + check_page, + ctx::Ctx, + db::models::{Board, Post}, + error::NekrochanError, + filters, paginate, + web::{tcx::TemplateCtx, template_response}, +}; + +#[derive(Deserialize)] +pub struct OverboardQuery { + page: i64, +} + +#[derive(Template)] +#[template(path = "overboard.html")] +struct OverboardTemplate { + tcx: TemplateCtx, + boards: HashMap, + threads: Vec<(Post, Vec)>, + page: i64, + pages: i64, +} + +#[get("/overboard")] +pub async fn overboard( + ctx: Data, + req: HttpRequest, + query: Option>, +) -> Result { + let boards = Board::read_all_map(&ctx).await?; + let tcx = TemplateCtx::new(&ctx, &req).await?; + + let count = ctx.cache().get("total_threads").await?; + let page = query.map(|q| q.page).unwrap_or(1); + let pages = paginate(15, count); + + check_page(page, pages, None)?; + + let mut threads = Vec::new(); + + for thread in Post::read_overboard_page(&ctx, page).await?.into_iter() { + let replies = thread.read_replies(&ctx).await?; + + threads.push((thread, replies)) + } + + let template = OverboardTemplate { + tcx, + boards, + threads, + page, + pages, + }; + + template_response(template) +} diff --git a/src/web/overboard_catalog.rs b/src/web/overboard_catalog.rs new file mode 100644 index 0000000..5758167 --- /dev/null +++ b/src/web/overboard_catalog.rs @@ -0,0 +1,30 @@ +use actix_web::{get, web::Data, HttpRequest, HttpResponse}; +use askama::Template; + +use crate::{ + ctx::Ctx, + db::models::Post, + error::NekrochanError, + filters, + web::{tcx::TemplateCtx, template_response}, +}; + +#[derive(Template)] +#[template(path = "overboard_catalog.html")] +struct OverboardCatalogTemplate { + tcx: TemplateCtx, + threads: Vec, +} + +#[get("/overboard/catalog")] +pub async fn overboard_catalog( + ctx: Data, + req: HttpRequest, +) -> Result { + let tcx = TemplateCtx::new(&ctx, &req).await?; + let threads = Post::read_overboard_catalog(&ctx).await?; + + let template = OverboardCatalogTemplate { tcx, threads }; + + template_response(template) +} diff --git a/src/web/staff/account.rs b/src/web/staff/account.rs new file mode 100755 index 0000000..0924bea --- /dev/null +++ b/src/web/staff/account.rs @@ -0,0 +1,28 @@ +use actix_web::{get, web::Data, HttpRequest, HttpResponse}; +use askama::Template; + +use crate::{ + ctx::Ctx, + db::models::Account, + error::NekrochanError, + web::{ + tcx::{account_from_auth, TemplateCtx}, + template_response, + }, +}; + +#[derive(Template)] +#[template(path = "staff/account.html")] +struct AccountTemplate { + tcx: TemplateCtx, + account: Account, +} + +#[get("/staff/account")] +pub async fn account(ctx: Data, req: HttpRequest) -> Result { + let tcx = TemplateCtx::new(&ctx, &req).await?; + let account = account_from_auth(&ctx, &req).await?; + let template = AccountTemplate { tcx, account }; + + template_response(template) +} diff --git a/src/web/staff/accounts.rs b/src/web/staff/accounts.rs new file mode 100755 index 0000000..0a47f57 --- /dev/null +++ b/src/web/staff/accounts.rs @@ -0,0 +1,26 @@ +use actix_web::{get, web::Data, HttpRequest, HttpResponse}; +use askama::Template; + +use crate::{ + ctx::Ctx, + db::models::Account, + error::NekrochanError, + filters, + web::{tcx::TemplateCtx, template_response}, +}; + +#[derive(Template)] +#[template(path = "staff/accounts.html")] +struct AccountsTemplate { + tcx: TemplateCtx, + accounts: Vec, +} + +#[get("/staff/accounts")] +pub async fn accounts(ctx: Data, req: HttpRequest) -> Result { + let tcx = TemplateCtx::new(&ctx, &req).await?; + let accounts = Account::read_all(&ctx).await?; + let template = AccountsTemplate { tcx, accounts }; + + template_response(template) +} diff --git a/src/web/staff/actions/add_banners.rs b/src/web/staff/actions/add_banners.rs new file mode 100755 index 0000000..7adf441 --- /dev/null +++ b/src/web/staff/actions/add_banners.rs @@ -0,0 +1,55 @@ +use actix_multipart::form::{tempfile::TempFile, text::Text, MultipartForm}; +use actix_web::{post, web::Data, HttpRequest, HttpResponse}; + +use crate::{ + ctx::Ctx, + db::models::{Board, File}, + error::NekrochanError, + web::tcx::account_from_auth, +}; + +#[derive(MultipartForm)] +pub struct AddBannersForm { + board: Text, + #[multipart(rename = "files[]")] + files: Vec, +} + +#[post("/staff/actions/add-banners")] +pub async fn add_banners( + ctx: Data, + req: HttpRequest, + MultipartForm(form): MultipartForm, +) -> Result { + let account = account_from_auth(&ctx, &req).await?; + + if !(account.perms().owner() || account.perms().board_banners()) { + return Err(NekrochanError::InsufficientPermissionError); + } + + let board = form.board.0; + let board = Board::read(&ctx, board.clone()) + .await? + .ok_or(NekrochanError::BoardNotFound(board))?; + + let mut new_banners = board.banners.0.clone(); + let added_banners = form.files; + + let mut cfg = ctx.cfg.clone(); + + cfg.files.videos = false; + + for banner in added_banners.into_iter() { + let file = File::new(&cfg, banner, false, false).await?; + + new_banners.push(file) + } + + board.update_banners(&ctx, new_banners).await?; + + let res = HttpResponse::SeeOther() + .append_header(("Location", format!("/staff/banners/{}", board.id).as_str())) + .finish(); + + Ok(res) +} diff --git a/src/web/staff/actions/change_password.rs b/src/web/staff/actions/change_password.rs new file mode 100755 index 0000000..0c7f62c --- /dev/null +++ b/src/web/staff/actions/change_password.rs @@ -0,0 +1,38 @@ +use actix_web::{post, web::Data, HttpRequest, HttpResponse}; +use pwhash::bcrypt::{hash, verify}; +use serde::Deserialize; + +use crate::{ctx::Ctx, error::NekrochanError, qsform::QsForm, web::tcx::account_from_auth}; + +#[derive(Deserialize)] +pub struct ChangePasswordForm { + old_password: String, + new_password: String, +} + +#[post("/staff/actions/change-password")] +pub async fn change_password( + ctx: Data, + req: HttpRequest, + QsForm(form): QsForm, +) -> Result { + let account = account_from_auth(&ctx, &req).await?; + + if !verify(form.old_password, &account.password) { + return Err(NekrochanError::IncorrectCredentialError); + } + + if form.new_password.len() < 8 { + return Err(NekrochanError::PasswordFormatError); + } + + let password = hash(form.new_password)?; + + account.update_password(&ctx, password).await?; + + let res = HttpResponse::SeeOther() + .append_header(("Location", "/staff/account")) + .finish(); + + Ok(res) +} diff --git a/src/web/staff/actions/create_account.rs b/src/web/staff/actions/create_account.rs new file mode 100755 index 0000000..a72c58d --- /dev/null +++ b/src/web/staff/actions/create_account.rs @@ -0,0 +1,48 @@ +use actix_web::{post, web::Data, HttpRequest, HttpResponse}; +use pwhash::bcrypt::hash; +use serde::Deserialize; + +use crate::{ + ctx::Ctx, db::models::Account, error::NekrochanError, qsform::QsForm, + web::tcx::account_from_auth, +}; + +#[derive(Deserialize)] +pub struct CreateAccountForm { + username: String, + password: String, +} + +#[post("/staff/actions/create-account")] +pub async fn create_account( + ctx: Data, + req: HttpRequest, + QsForm(form): QsForm, +) -> Result { + let account = account_from_auth(&ctx, &req).await?; + + if !account.perms().owner() { + return Err(NekrochanError::InsufficientPermissionError); + } + + let username = form.username.trim().to_owned(); + let password = form.password.trim().to_owned(); + + if username.is_empty() || username.len() > 32 { + return Err(NekrochanError::UsernameFormatError); + } + + if password.len() < 8 { + return Err(NekrochanError::PasswordFormatError); + } + + let password = hash(password)?; + + let _ = Account::create(&ctx, username, password).await?; + + let res = HttpResponse::SeeOther() + .append_header(("Location", "/staff/accounts")) + .finish(); + + Ok(res) +} diff --git a/src/web/staff/actions/create_board.rs b/src/web/staff/actions/create_board.rs new file mode 100755 index 0000000..237bc20 --- /dev/null +++ b/src/web/staff/actions/create_board.rs @@ -0,0 +1,50 @@ +use actix_web::{post, web::Data, HttpRequest, HttpResponse}; +use serde::Deserialize; + +use crate::{ + ctx::Ctx, db::models::Board, error::NekrochanError, qsform::QsForm, web::tcx::account_from_auth, +}; + +#[derive(Deserialize)] +pub struct CreateBoardForm { + id: String, + name: String, + description: String, +} + +#[post("/staff/actions/create-board")] +pub async fn create_board( + ctx: Data, + req: HttpRequest, + QsForm(form): QsForm, +) -> Result { + let account = account_from_auth(&ctx, &req).await?; + + if !account.perms().owner() { + return Err(NekrochanError::InsufficientPermissionError); + } + + let id = form.id.trim().to_owned(); + let name = form.name.trim().to_owned(); + let description = form.description.trim().to_owned(); + + if id.is_empty() || id.len() > 16 { + return Err(NekrochanError::IdFormatError); + } + + if name.is_empty() || name.len() > 32 { + return Err(NekrochanError::BoardNameFormatError); + } + + if description.is_empty() || description.len() > 128 { + return Err(NekrochanError::DescriptionFormatError); + } + + let _ = Board::create(&ctx, id, name, description).await?; + + let res = HttpResponse::SeeOther() + .append_header(("Location", "/staff/boards")) + .finish(); + + Ok(res) +} diff --git a/src/web/staff/actions/delete_account.rs b/src/web/staff/actions/delete_account.rs new file mode 100755 index 0000000..1857a9b --- /dev/null +++ b/src/web/staff/actions/delete_account.rs @@ -0,0 +1,23 @@ +use actix_web::{post, web::Data, HttpRequest, HttpResponse}; + +use crate::{ctx::Ctx, error::NekrochanError, web::tcx::account_from_auth}; + +#[post("/staff/actions/delete-account")] +pub async fn delete_account( + ctx: Data, + req: HttpRequest, +) -> Result { + let account = account_from_auth(&ctx, &req).await?; + + if account.perms().owner() { + return Err(NekrochanError::OwnerDeletionError); + } + + account.delete(&ctx).await?; + + let res = HttpResponse::SeeOther() + .append_header(("Location", "/logout")) + .finish(); + + Ok(res) +} diff --git a/src/web/staff/actions/mod.rs b/src/web/staff/actions/mod.rs new file mode 100755 index 0000000..2921538 --- /dev/null +++ b/src/web/staff/actions/mod.rs @@ -0,0 +1,13 @@ +pub mod add_banners; +pub mod change_password; +pub mod create_account; +pub mod create_board; +pub mod delete_account; +pub mod remove_accounts; +pub mod remove_banners; +pub mod remove_bans; +pub mod remove_boards; +pub mod transfer_ownership; +pub mod update_board_config; +pub mod update_boards; +pub mod update_permissions; diff --git a/src/web/staff/actions/remove_accounts.rs b/src/web/staff/actions/remove_accounts.rs new file mode 100755 index 0000000..27c2833 --- /dev/null +++ b/src/web/staff/actions/remove_accounts.rs @@ -0,0 +1,42 @@ +use actix_web::{post, web::Data, HttpRequest, HttpResponse}; +use serde::Deserialize; + +use crate::{ + ctx::Ctx, db::models::Account, error::NekrochanError, qsform::QsForm, + web::tcx::account_from_auth, +}; + +#[derive(Deserialize)] +pub struct RemoveAccountsForm { + #[serde(default)] + accounts: Vec, +} + +#[post("/staff/actions/remove-accounts")] +pub async fn remove_accounts( + ctx: Data, + req: HttpRequest, + QsForm(form): QsForm, +) -> Result { + let account = account_from_auth(&ctx, &req).await?; + + if !account.perms().owner() { + return Err(NekrochanError::InsufficientPermissionError); + } + + for account in form.accounts.into_iter() { + if let Some(account) = Account::read(&ctx, account).await? { + if account.owner { + return Err(NekrochanError::OwnerDeletionError); + } + + account.delete(&ctx).await?; + } + } + + let res = HttpResponse::SeeOther() + .append_header(("Location", "/staff/accounts")) + .finish(); + + Ok(res) +} diff --git a/src/web/staff/actions/remove_banners.rs b/src/web/staff/actions/remove_banners.rs new file mode 100755 index 0000000..b4481ef --- /dev/null +++ b/src/web/staff/actions/remove_banners.rs @@ -0,0 +1,50 @@ +use actix_web::{post, web::Data, HttpRequest, HttpResponse}; +use serde::Deserialize; + +use crate::{ + ctx::Ctx, db::models::Board, error::NekrochanError, qsform::QsForm, web::tcx::account_from_auth, +}; + +#[derive(Deserialize)] +pub struct RemoveBannersForm { + board: String, + #[serde(default)] + banners: Vec, +} + +#[post("/staff/actions/remove-banners")] +pub async fn remove_banners( + ctx: Data, + req: HttpRequest, + QsForm(form): QsForm, +) -> Result { + let account = account_from_auth(&ctx, &req).await?; + + if !(account.perms().owner() || account.perms().board_banners()) { + return Err(NekrochanError::InsufficientPermissionError); + } + + let board = form.board; + let board = Board::read(&ctx, board.clone()) + .await? + .ok_or(NekrochanError::BoardNotFound(board))?; + + let old_banners = board.banners.0.clone(); + let mut new_banners = Vec::new(); + + for (i, banner) in old_banners.into_iter().enumerate() { + if form.banners.contains(&i) { + banner.delete().await; + } else { + new_banners.push(banner); + } + } + + board.update_banners(&ctx, new_banners).await?; + + let res = HttpResponse::SeeOther() + .append_header(("Location", format!("/staff/banners/{}", board.id).as_str())) + .finish(); + + Ok(res) +} diff --git a/src/web/staff/actions/remove_bans.rs b/src/web/staff/actions/remove_bans.rs new file mode 100755 index 0000000..2025d20 --- /dev/null +++ b/src/web/staff/actions/remove_bans.rs @@ -0,0 +1,37 @@ +use actix_web::{post, web::Data, HttpRequest, HttpResponse}; +use serde::Deserialize; + +use crate::{ + ctx::Ctx, db::models::Ban, error::NekrochanError, qsform::QsForm, web::tcx::account_from_auth, +}; + +#[derive(Deserialize)] +pub struct RemoveBansForm { + #[serde(default)] + bans: Vec, +} + +#[post("/staff/actions/remove-bans")] +pub async fn remove_bans( + ctx: Data, + req: HttpRequest, + QsForm(form): QsForm, +) -> Result { + let account = account_from_auth(&ctx, &req).await?; + + if !(account.perms().owner() || account.perms().bans()) { + return Err(NekrochanError::InsufficientPermissionError); + } + + for ban in form.bans.into_iter() { + if let Some(ban) = Ban::read_by_id(&ctx, ban).await? { + ban.delete(&ctx).await?; + } + } + + let res = HttpResponse::SeeOther() + .append_header(("Location", "/staff/bans")) + .finish(); + + Ok(res) +} diff --git a/src/web/staff/actions/remove_boards.rs b/src/web/staff/actions/remove_boards.rs new file mode 100755 index 0000000..c444028 --- /dev/null +++ b/src/web/staff/actions/remove_boards.rs @@ -0,0 +1,37 @@ +use actix_web::{post, web::Data, HttpRequest, HttpResponse}; +use serde::Deserialize; + +use crate::{ + ctx::Ctx, db::models::Board, error::NekrochanError, qsform::QsForm, web::tcx::account_from_auth, +}; + +#[derive(Deserialize)] +pub struct RemoveBoardsForm { + #[serde(default)] + boards: Vec, +} + +#[post("/staff/actions/remove-boards")] +pub async fn remove_boards( + ctx: Data, + req: HttpRequest, + QsForm(form): QsForm, +) -> Result { + let account = account_from_auth(&ctx, &req).await?; + + if !account.perms().owner() { + return Err(NekrochanError::InsufficientPermissionError); + } + + for board in form.boards.into_iter() { + if let Some(board) = Board::read(&ctx, board).await? { + board.delete(&ctx).await?; + } + } + + let res = HttpResponse::SeeOther() + .append_header(("Location", "/staff/boards")) + .finish(); + + Ok(res) +} diff --git a/src/web/staff/actions/transfer_ownership.rs b/src/web/staff/actions/transfer_ownership.rs new file mode 100755 index 0000000..bbd3103 --- /dev/null +++ b/src/web/staff/actions/transfer_ownership.rs @@ -0,0 +1,39 @@ +use actix_web::{post, web::Data, HttpRequest, HttpResponse}; +use serde::Deserialize; + +use crate::{ + ctx::Ctx, db::models::Account, error::NekrochanError, qsform::QsForm, + web::tcx::account_from_auth, +}; + +#[derive(Deserialize)] +pub struct TransferOwnershipForm { + account: String, +} + +#[post("/staff/actions/transfer-ownership")] +pub async fn transfer_ownership( + ctx: Data, + req: HttpRequest, + QsForm(form): QsForm, +) -> Result { + let old_owner = account_from_auth(&ctx, &req).await?; + + if !old_owner.perms().owner() { + return Err(NekrochanError::InsufficientPermissionError); + } + + let new_owner = form.account; + let new_owner = Account::read(&ctx, new_owner.clone()) + .await? + .ok_or(NekrochanError::AccountNotFound(new_owner))?; + + old_owner.update_owner(&ctx, false).await?; + new_owner.update_owner(&ctx, true).await?; + + let res = HttpResponse::SeeOther() + .append_header(("Location", "/staff/account")) + .finish(); + + Ok(res) +} diff --git a/src/web/staff/actions/update_board_config.rs b/src/web/staff/actions/update_board_config.rs new file mode 100755 index 0000000..d4af5fd --- /dev/null +++ b/src/web/staff/actions/update_board_config.rs @@ -0,0 +1,87 @@ +use actix_web::{post, web::Data, HttpRequest, HttpResponse}; +use serde::Deserialize; + +use crate::{ + cfg::BoardCfg, ctx::Ctx, db::models::Board, error::NekrochanError, qsform::QsForm, + web::tcx::account_from_auth, +}; + +#[derive(Deserialize)] +pub struct UpdateBoardConfigForm { + board: String, + anon_name: String, + page_size: i64, + page_count: i64, + file_limit: usize, + bump_limit: i32, + reply_limit: i32, + locked: Option, + user_ids: Option, + flags: Option, + thread_captcha: String, + reply_captcha: String, + require_thread_content: Option, + require_thread_file: Option, + require_reply_content: Option, + require_reply_file: Option, +} + +#[post("/staff/actions/update-board-config")] +pub async fn update_board_config( + ctx: Data, + req: HttpRequest, + QsForm(form): QsForm, +) -> Result { + let account = account_from_auth(&ctx, &req).await?; + + if !(account.perms().owner() || account.perms().board_config()) { + return Err(NekrochanError::InsufficientPermissionError); + } + + let board = form.board; + let board = Board::read(&ctx, board.clone()) + .await? + .ok_or(NekrochanError::BoardNotFound(board))?; + + let anon_name = form.anon_name; + let page_size = form.page_size; + let page_count = form.page_count; + let file_limit = form.file_limit; + let bump_limit = form.bump_limit; + let reply_limit = form.reply_limit; + let locked = form.locked.is_some(); + let user_ids = form.user_ids.is_some(); + let flags = form.flags.is_some(); + let thread_captcha = form.thread_captcha; + let reply_captcha = form.reply_captcha; + let require_thread_content = form.require_thread_content.is_some(); + let require_thread_file = form.require_thread_file.is_some(); + let require_reply_content = form.require_reply_content.is_some(); + let require_reply_file = form.require_reply_file.is_some(); + + let config = BoardCfg { + anon_name, + page_size, + page_count, + file_limit, + bump_limit, + reply_limit, + locked, + user_ids, + flags, + thread_captcha, + reply_captcha, + require_thread_content, + require_thread_file, + require_reply_content, + require_reply_file, + }; + + board.update_config(&ctx, config).await?; + + let res = HttpResponse::SeeOther() + .append_header(("Location", "/staff/boards")) + .finish(); + + Ok(res) +} diff --git a/src/web/staff/actions/update_boards.rs b/src/web/staff/actions/update_boards.rs new file mode 100755 index 0000000..287e05c --- /dev/null +++ b/src/web/staff/actions/update_boards.rs @@ -0,0 +1,57 @@ +use actix_web::{ + post, + web::{Bytes, Data}, + HttpRequest, HttpResponse, +}; +use serde::Deserialize; +use serde_qs::Config; + +use crate::{ctx::Ctx, db::models::Board, error::NekrochanError, web::tcx::account_from_auth}; + +#[derive(Deserialize)] +pub struct UpdateBoardsForm { + #[serde(default)] + boards: Vec, + name: String, + description: String, +} + +#[post("/staff/actions/update-boards")] +pub async fn update_boards( + ctx: Data, + req: HttpRequest, + bytes: Bytes, +) -> Result { + let account = account_from_auth(&ctx, &req).await?; + + if !account.perms().owner() { + return Err(NekrochanError::InsufficientPermissionError); + } + + let config = Config::new(10, false); + let form: UpdateBoardsForm = config.deserialize_bytes(&bytes)?; + + let name = form.name.trim().to_owned(); + let description = form.description.trim().to_owned(); + + if name.is_empty() || name.len() > 32 { + return Err(NekrochanError::BoardNameFormatError); + } + + if description.is_empty() || description.len() > 128 { + return Err(NekrochanError::DescriptionFormatError); + } + + for board in form.boards.into_iter() { + if let Some(board) = Board::read(&ctx, board).await? { + board.update_name(&ctx, name.clone()).await?; + board.update_description(&ctx, description.clone()).await?; + } + } + + let res = HttpResponse::SeeOther() + .append_header(("Location", "/staff/boards")) + .finish(); + + Ok(res) +} diff --git a/src/web/staff/actions/update_permissions.rs b/src/web/staff/actions/update_permissions.rs new file mode 100755 index 0000000..28116bb --- /dev/null +++ b/src/web/staff/actions/update_permissions.rs @@ -0,0 +1,103 @@ +use actix_web::{post, web::Data, HttpRequest, HttpResponse}; +use enumflags2::BitFlags; +use serde::Deserialize; + +use crate::{ + ctx::Ctx, db::models::Account, error::NekrochanError, perms::Permissions, qsform::QsForm, + web::tcx::account_from_auth, +}; + +#[derive(Deserialize)] +pub struct UpdatePermissionsForm { + account: String, + edit_posts: Option, + manage_posts: Option, + capcodes: Option, + staff_log: Option, + reports: Option, + bans: Option, + board_banners: Option, + board_config: Option, + bypass_bans: Option, + bypass_board_lock: Option, + bypass_thread_lock: Option, + bypass_captcha: Option, +} + +#[post("/staff/actions/update-permissions")] +pub async fn update_permissions( + ctx: Data, + req: HttpRequest, + QsForm(form): QsForm, +) -> Result { + let account = account_from_auth(&ctx, &req).await?; + + if !account.perms().owner() { + return Err(NekrochanError::InsufficientPermissionError); + } + + let updated_account = form.account; + let updated_account = Account::read(&ctx, updated_account.clone()) + .await? + .ok_or(NekrochanError::AccountNotFound(updated_account))?; + + let mut permissions = BitFlags::empty(); + + if form.edit_posts.is_some() { + permissions |= Permissions::EditPosts + } + + if form.manage_posts.is_some() { + permissions |= Permissions::ManagePosts + } + + if form.capcodes.is_some() { + permissions |= Permissions::Capcodes + } + + if form.staff_log.is_some() { + permissions |= Permissions::StaffLog + } + + if form.reports.is_some() { + permissions |= Permissions::Reports + } + + if form.bans.is_some() { + permissions |= Permissions::Bans + } + + if form.board_banners.is_some() { + permissions |= Permissions::BoardBanners + } + + if form.board_config.is_some() { + permissions |= Permissions::BoardConfig + } + + if form.bypass_bans.is_some() { + permissions |= Permissions::BypassBans + } + + if form.bypass_board_lock.is_some() { + permissions |= Permissions::BypassBoardLock + } + + if form.bypass_thread_lock.is_some() { + permissions |= Permissions::BypassThreadLock + } + + if form.bypass_captcha.is_some() { + permissions |= Permissions::BypassCaptcha + } + + updated_account + .update_permissions(&ctx, permissions.bits()) + .await?; + + let res = HttpResponse::SeeOther() + .append_header(("Location", "/staff/accounts")) + .finish(); + + Ok(res) +} diff --git a/src/web/staff/banners.rs b/src/web/staff/banners.rs new file mode 100755 index 0000000..3def9b4 --- /dev/null +++ b/src/web/staff/banners.rs @@ -0,0 +1,46 @@ +use actix_web::{ + get, + web::{Data, Path}, + HttpRequest, HttpResponse, +}; +use askama::Template; + +use crate::{ + ctx::Ctx, + db::models::Board, + error::NekrochanError, + web::{ + tcx::{account_from_auth, TemplateCtx}, + template_response, + }, +}; + +#[derive(Template)] +#[template(path = "staff/banners.html")] +struct BannersTemplate { + tcx: TemplateCtx, + board: Board, +} + +#[get("/staff/banners/{board}")] +pub async fn banners( + ctx: Data, + req: HttpRequest, + board: Path, +) -> Result { + let tcx = TemplateCtx::new(&ctx, &req).await?; + let account = account_from_auth(&ctx, &req).await?; + + if !(account.perms().owner() || account.perms().board_banners()) { + return Err(NekrochanError::InsufficientPermissionError); + } + + let board = board.into_inner(); + let board = Board::read(&ctx, board.clone()) + .await? + .ok_or(NekrochanError::BoardNotFound(board))?; + + let template = BannersTemplate { tcx, board }; + + template_response(template) +} diff --git a/src/web/staff/bans.rs b/src/web/staff/bans.rs new file mode 100755 index 0000000..38c3f57 --- /dev/null +++ b/src/web/staff/bans.rs @@ -0,0 +1,35 @@ +use actix_web::{get, web::Data, HttpRequest, HttpResponse}; +use askama::Template; + +use crate::{ + ctx::Ctx, + db::models::Ban, + error::NekrochanError, + filters, + web::{ + tcx::{account_from_auth, TemplateCtx}, + template_response, + }, +}; + +#[derive(Template)] +#[template(path = "staff/bans.html")] +struct BansTemplate { + tcx: TemplateCtx, + bans: Vec, +} + +#[get("/staff/bans")] +pub async fn bans(ctx: Data, req: HttpRequest) -> Result { + let tcx = TemplateCtx::new(&ctx, &req).await?; + let account = account_from_auth(&ctx, &req).await?; + + if !(account.perms().owner() || account.perms().bans()) { + return Err(NekrochanError::InsufficientPermissionError); + } + + let bans = Ban::read_all(&ctx).await?; + let template = BansTemplate { tcx, bans }; + + template_response(template) +} diff --git a/src/web/staff/board_config.rs b/src/web/staff/board_config.rs new file mode 100755 index 0000000..5061680 --- /dev/null +++ b/src/web/staff/board_config.rs @@ -0,0 +1,46 @@ +use actix_web::{ + get, + web::{Data, Path}, + HttpRequest, HttpResponse, +}; +use askama::Template; + +use crate::{ + ctx::Ctx, + db::models::Board, + error::NekrochanError, + web::{ + tcx::{account_from_auth, TemplateCtx}, + template_response, + }, +}; + +#[derive(Template)] +#[template(path = "staff/board-config.html")] +struct BannersTemplate { + tcx: TemplateCtx, + board: Board, +} + +#[get("/staff/board-config/{board}")] +pub async fn board_config( + ctx: Data, + req: HttpRequest, + board: Path, +) -> Result { + let tcx = TemplateCtx::new(&ctx, &req).await?; + let account = account_from_auth(&ctx, &req).await?; + + if !(account.perms().owner() || account.perms().board_config()) { + return Err(NekrochanError::InsufficientPermissionError); + } + + let board = board.into_inner(); + let board = Board::read(&ctx, board.clone()) + .await? + .ok_or(NekrochanError::BoardNotFound(board))?; + + let template = BannersTemplate { tcx, board }; + + template_response(template) +} diff --git a/src/web/staff/boards.rs b/src/web/staff/boards.rs new file mode 100755 index 0000000..9038cdb --- /dev/null +++ b/src/web/staff/boards.rs @@ -0,0 +1,38 @@ +use actix_web::{get, web::Data, HttpRequest, HttpResponse}; +use askama::Template; + +use crate::{ + ctx::Ctx, + db::models::Board, + error::NekrochanError, + filters, + web::{ + tcx::{account_from_auth, TemplateCtx}, + template_response, + }, +}; + +#[derive(Template)] +#[template(path = "staff/boards.html")] +struct BoardsTemplate { + tcx: TemplateCtx, + boards: Vec, +} + +#[get("/staff/boards")] +pub async fn boards(ctx: Data, req: HttpRequest) -> Result { + let tcx = TemplateCtx::new(&ctx, &req).await?; + let account = account_from_auth(&ctx, &req).await?; + + if !(account.perms().owner() + || account.perms().board_config() + || account.perms().board_banners()) + { + return Err(NekrochanError::InsufficientPermissionError); + } + + let boards = Board::read_all(&ctx).await?; + let template = BoardsTemplate { tcx, boards }; + + template_response(template) +} diff --git a/src/web/staff/mod.rs b/src/web/staff/mod.rs new file mode 100755 index 0000000..d1425f1 --- /dev/null +++ b/src/web/staff/mod.rs @@ -0,0 +1,9 @@ +pub mod account; +pub mod accounts; +pub mod actions; +pub mod banners; +pub mod bans; +pub mod board_config; +pub mod boards; +pub mod permissions; +pub mod reports; diff --git a/src/web/staff/permissions.rs b/src/web/staff/permissions.rs new file mode 100755 index 0000000..8ef13d2 --- /dev/null +++ b/src/web/staff/permissions.rs @@ -0,0 +1,42 @@ +use actix_web::{ + get, + web::{Data, Path}, + HttpRequest, HttpResponse, +}; +use askama::Template; + +use crate::{ + ctx::Ctx, + db::models::Account, + error::NekrochanError, + web::{ + tcx::{account_from_auth, TemplateCtx}, + template_response, + }, +}; + +#[derive(Template)] +#[template(path = "staff/permissions.html")] +struct PermissionsTemplate { + tcx: TemplateCtx, + account: Account, +} + +#[get("/staff/permissions/{account}")] +pub async fn permissions( + ctx: Data, + req: HttpRequest, + path: Path, +) -> Result { + let tcx = TemplateCtx::new(&ctx, &req).await?; + let _ = account_from_auth(&ctx, &req).await?; + + let account = path.into_inner(); + let account = Account::read(&ctx, account.clone()) + .await? + .ok_or(NekrochanError::AccountNotFound(account))?; + + let template = PermissionsTemplate { tcx, account }; + + template_response(template) +} diff --git a/src/web/staff/reports.rs b/src/web/staff/reports.rs new file mode 100755 index 0000000..d6df7c7 --- /dev/null +++ b/src/web/staff/reports.rs @@ -0,0 +1,23 @@ +use actix_web::{get, web::Data, HttpRequest, HttpResponse}; +use askama::Template; + +use crate::{ + ctx::Ctx, + error::NekrochanError, + web::{tcx::TemplateCtx, template_response}, +}; + +#[allow(dead_code)] +#[derive(Template)] +#[template(path = "staff/reports.html")] +struct ReportsTemplate { + tcx: TemplateCtx, +} + +#[get("/staff/reports")] +async fn reports(ctx: Data, req: HttpRequest) -> Result { + let tcx = TemplateCtx::new(&ctx, &req).await?; + let template = ReportsTemplate { tcx }; + + template_response(template) +} diff --git a/src/web/tcx.rs b/src/web/tcx.rs new file mode 100755 index 0000000..ae9fec8 --- /dev/null +++ b/src/web/tcx.rs @@ -0,0 +1,113 @@ +use actix_web::HttpRequest; +use rand::{distributions::Alphanumeric, thread_rng, Rng}; +use redis::AsyncCommands; +use std::{ + collections::HashSet, + net::{IpAddr, Ipv4Addr}, +}; + +use crate::{ + auth::Claims, cfg::Cfg, ctx::Ctx, db::models::Account, error::NekrochanError, + perms::PermissionWrapper, +}; + +pub struct TemplateCtx { + pub cfg: Cfg, + pub boards: Vec, + pub logged_in: bool, + pub perms: PermissionWrapper, + pub name: Option, + pub password: String, + pub ip: IpAddr, + pub yous: HashSet, +} + +impl TemplateCtx { + pub async fn new(ctx: &Ctx, req: &HttpRequest) -> Result { + let cfg = ctx.cfg.to_owned(); + let boards = ctx.cache().lrange("board_ids", 0, -1).await?; + + let account = account_from_auth_opt(ctx, req).await?; + let logged_in = account.is_some(); + + let perms = match &account { + Some(account) => account.perms(), + None => PermissionWrapper::new(0, false), + }; + + let name = req.cookie("name").map(|cookie| cookie.value().into()); + let password_cookie = req.cookie("password").map(|cookie| cookie.value().into()); + + let password: String = match password_cookie { + Some(password) => password, + None => thread_rng() + .sample_iter(&Alphanumeric) + .take(8) + .map(char::from) + .collect(), + }; + + let (ip, _) = ip_from_req(req)?; + let yous = ctx.cache().zrange(format!("yous:{ip}"), 0, -1).await?; + + let tcx = Self { + cfg, + boards, + logged_in, + perms, + name, + password, + ip, + yous, + }; + + Ok(tcx) + } +} + +pub async fn account_from_auth(ctx: &Ctx, req: &HttpRequest) -> Result { + let account = account_from_auth_opt(ctx, req) + .await? + .ok_or(NekrochanError::NotLoggedInError)?; + + Ok(account) +} + +pub async fn account_from_auth_opt( + ctx: &Ctx, + req: &HttpRequest, +) -> Result, NekrochanError> { + let account = match req.cookie("auth") { + Some(auth) => { + let claims = Claims::decode(ctx, auth.value())?; + let account = Account::read(ctx, claims.sub) + .await? + .ok_or(NekrochanError::InvalidAuthError)?; + + Some(account) + } + None => None, + }; + + Ok(account) +} + +pub fn ip_from_req(req: &HttpRequest) -> Result<(IpAddr, String), NekrochanError> { + let ip = IpAddr::V4(Ipv4Addr::UNSPECIFIED); + + // let ip = req + // .headers() + // .get("X-Real-IP") + // .ok_or(NekrochanError::HeaderError("X-Real-IP"))? + // .to_str() + // .map_err(|_| NekrochanError::HeaderError("X-Real-IP"))? + // .parse::()?; + + let country = req + .headers() + .get("X-Country-Code") + .map(|hdr| hdr.to_str().unwrap_or("xx").to_ascii_lowercase()) + .unwrap_or_else(|| "xx".into()); + + Ok((ip, country)) +} diff --git a/src/web/thread.rs b/src/web/thread.rs new file mode 100644 index 0000000..5647fe9 --- /dev/null +++ b/src/web/thread.rs @@ -0,0 +1,59 @@ +use actix_web::{ + get, + http::StatusCode, + web::{Data, Path}, + HttpRequest, HttpResponse, +}; +use askama::Template; + +use crate::{ + ctx::Ctx, + db::models::{Board, Post}, + error::NekrochanError, + filters, + web::{tcx::TemplateCtx, template_response}, +}; + +#[derive(Template)] +#[template(path = "thread.html")] +struct ThreadTemplate { + tcx: TemplateCtx, + board: Board, + thread: Post, + replies: Vec, +} + +#[get("/boards/{board}/{thread}")] +pub async fn thread( + ctx: Data, + req: HttpRequest, + path: Path<(String, i32)>, +) -> Result { + let tcx = TemplateCtx::new(&ctx, &req).await?; + + let (board, id) = path.into_inner(); + let board = Board::read(&ctx, board.clone()) + .await? + .ok_or(NekrochanError::BoardNotFound(board))?; + + let thread = Post::read(&ctx, board.id.clone(), id) + .await? + .ok_or(NekrochanError::PostNotFound(board.id.clone(), id))?; + + if thread.thread.is_some() { + return Ok(HttpResponse::build(StatusCode::PERMANENT_REDIRECT) + .append_header(("Location", thread.post_url())) + .finish()); + } + + let replies = thread.read_replies(&ctx).await?; + + let template = ThreadTemplate { + tcx, + board, + thread, + replies, + }; + + template_response(template) +} diff --git a/static/banner.gif b/static/banner.gif new file mode 100755 index 0000000000000000000000000000000000000000..86d986c288f1443ae879e18cc66efd9b6c8b56ca GIT binary patch literal 210604 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

>s%H)Wc9gsnXqvwmVKii0M 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�I^*>dmSBmaYgH&1yT&C!kC`L3u4-QL3sHGGN(LeJ=jjcxa>{Ajr4 zo3bP<3A-PDPu3$@Ee(ylusp~%#=)iX21=8V+L#HAAjglRIH^z~BCssmzz;c@qK*Ad z-m5=ZhoFx+F7$>+B2jmQz6vc>yrf<|+(kD~ur1r8wd7~&qS49*1oo3rbAd+_PUq6* z$S_2O<|iU<@A;Cwd7_zuj}R*K#anxcg0qextQi~Ky5%^YWp3FM;N>JWy zHczPAO*mz5 z^3`5?De3nS83!kxa6U`xwMBLqVKvBFz%zN2yGtCBCI*bd)|spxA2o$Jj%2Dhx6Gkq_w(r)tF~50_JN7OgOVQRgX>@M%@pP zw0`dQ!^BJ8Y(P;_k^M8R+U#Bl;of>+$1t!0_xfp0Zc$*w=L?N>SRHD|WoFV9;7yZi zD*`90^ZolFCXjx9OWHgxGC->p`qIuukdP}~-)a?|Se|MO1 z&!K?Uk|#-HphE3TMz1!Wq=p&Y-PKUt|8P|w(k6q8dig`$mQd+5HQtI#anV8xH@P2C z(sd6{S#3=jFSBPNmP>B>#k%c$)nm*ewa7STSNz0lrs%ozlM!|odN^U_sp?1QfrS}5 zY6L?Ca8l!Qwgw&R%Id|JZ6H_@1~{3`e;c1x084j|7O%`R*RGQF82!0YW77jGJVZMR z*jFl2UOU{rzW*%SdEHi}FLs}tLkOaBgPFzX{)iXw*mG&(4L34bGtJssa_u_Zkg-<14}A&78A&M`DJ*K^w2t2WuyXYC?J z*+KhsXyiR65mds+u9>Ri3BooPxhj12ysTB70FH##;LYby1@y?9t*Jm&I zsT=yT>$Ju-JS3QF)g4>{+Z{`ja5QF!SdVg~rf~tvv+ivd6S_=fGx?St)6JFoGYE4T zICTyHORy&O)gyj7_roajZKJUq3!9QSsJm}1xTH# zf>zrhD~m(=Ep*O^_`0L2KxbrTkdBWS!haUQxkH5sfL-(mV<0d5b3kaKz^6K*F1u;vi92}V|M=#Pp73{Y0oZC~H-!d78D zpsl1XB#b8D&R#kT`ybqu5n*Rfd|tdRr=y zUk+`%vuAY&16fqORW}3N!^Y~fxY@;AIFARbHJTDrz_JY~)=t|=-YNoHSV%@JI!?i> z3eLE~P#cr&gU_@BCGPNdJnUB7wFR?>j5`hp;Nn@Pq7Xi3J;`PiB3%R7s~!zeRb`6Z z-U_6j5|g7q+nqtBGZ4lAJBESIo+~l~)pUtDrnNg`sYp1o2B*_pMVQqhjH9%4hZH;r zAFtD~w{{WAl$a=1CR_}JOMMpd!b~v+F5AW16b#oCIk7lN!F;nkj4mDR0S`(aE4m9u z=@|HU2y}(OwmDeaVGkAH}Q_cLjYo=!-B_ci$ueOJwJ}pwyE(T!`wVI7~Re&&43s)QrA!0WwD>_&x%2Y7~w*E?Nztuyxq`vV(0x5Smlx$kACt z#cj11S1I^FfsV&=zcWidDRNWU_!>FZnBv_*E_dIeHhfLfUWy*1;&+QP4l8yZOGk}< z!&m^gcOuLMT-5>P!860fFcdU>i@q|%H-@&xZ`oH)u9h>ZAL_yoCqGlTFEd1qCvp@J z4~4MN_0xrBL=bKu7Sby3%kkSsc8|S3sP+LpY=8=471)cbV&QzFY@eKshcZ2LWV!B7 za+99&-~!`OScUG5#4FeHf~MZJH>wj*@{hBNjdFLaBy!(`4Ar zpOy0&2+b$CL$vA|vep#7m=&L4PefsFXu`ZOGX$M3#?>m(`3zh<5$h-7Zc-FNqC;i? z5;k{(nW$$>R6T^wlpx?vTDln7JCz$F+ckN%dOeR$zs6 z@PqR3CmYOrB7e)<_AvNs7;=XTUY68rG3=*||cN z`XE_d|K5c!#+S1hYRm4my_dJeh%eUQK)NCquFc)01r$g(HOW9dd)y!Q#xu6)1_j!d zNEn9H;ietjgCq=HAQTrz(va`T=igtu7$ZW)$=d$Ax+}>>{JhOWN>pnSgFNLmF0?i2 z+GU;R_(H~2gb`c0@a*{T zuE*BswPHj%6+1}OOwUqxIo^?ZuA}lC!hm)j_N`hsdGJOY99un&KldG_R^KE2aShpB zgG|1;2`;<2*{H(}Kl;9%`6>!7f{e@0Q0LOsV%WQCaNXWaHQ6V2KN3WHj7^ zHFD@YE=8LgayzByUOA>thEBf+zId+rqD)gs#*u_u3x4HKvSdZ^$VNczZ)k0Ytl`D( zokx!MC5rnxiQFEz<0rzW?YqOHSD0qOKZcW;b7x}ZPM-A+gR!Ykb0>n?l}9-9wMj6qj8K;yT1T`f(Rg>wFL_F`i8zQ zTM=}Z?zml_q=zPKJ2hXZA(JQPQ&W8Blj9c@fQ-WMo@A7jNyl$ zNAp=I8!Enns@_M%r?9Yaps){8?@{pAw;}#KmtxQw_Py_GyZD94m%s}IYU9ksa-8FKp6(^G3laNRHNb%Sb!47Evd&oG4RV;x^5 zEh82IH$t!k5m+gL-~6!^5X?~VJEe&E3@{?&MrJLtT)OMb2tIhZJV0J93(qJ!fs<_q_HI%JO1e1^P-5=&smZrP!S-dg@|Y zL`+9n!e|V_odJ64Q}%Tw91+}n9H+!qR7{kDY6%cp7iRhpnn}m4Kl0>8qt(q2L~&~F zy5qPrWc24fC03$*TQa}f4Gub@&oA#wpgw1+?3U&nsh@MZUnTV+*pL<<>lfQ_h@ z;#!D!iL@vYwvXanH3Tr0t!ZV1f8Z5X0HGhiZi?c7@bST;W9H16R|BY>SN$F zlDm8tw?DaiDpi?lmxzT9(4Q+XK@4=oWt=zgK37_X7eCLj*@a=D>cvJh_B%9{;GnN2 zhu%N3#Uz&Q6E=R36F(kW9<p^FIX13mGT8WHG|S}fk4ZL_%|^VQV=fsSk>YiT-S z{;NfP+^<>7?9xB+b#0yo+-pvNa7UHzszhb0YJn=cT^>{~vk+!VPEDvNHyPk?wt8XBr=3$t`=SP*eTr$!;YUbzH&$*&^zM`@``V2`4{15LD zH3FAo9ulr~{RC@DNB)QD$U!Dj>;nd#2E2EA`J;-pP$f4?pR1lTUqDD6lLZ8~`*Y z5@^RS9}C}CuI%Jr-Iq#L%Rl+ke?g~~S_cb8_U*EIU+iYH1)mkza!p*_aVmXH5>o>WyX(zgTW9R)pGcWp4pXf=-MCSKmH4NA4Org5V>6Xar1$9{$}WwzYrxSzjwTTPLcsFa&u`e zzJ9v1Xz$4W%zJ=&kRHJOPu(n_mND&Dq@kDE`v%FtlrEo5>Nd0-4%8;kX8h^eLBeU} z21WZ(OM6jhY|w@ssPkIOf~*W(H|3RBM>@S9)^?bKpYb+hQvU7AwW=`pH}Zz6Hfgtv z95(aZi%V6un1tmed5iNDbS_-ioqRMx!7OvC>8E5S+{P)3gF}|ayN&}-%ubE4 zsOKIZ_Fk3qgJM%^0^gcn2x>oqJms3A#mIel{jec#^(iIT%=xS7-m_QB)c>}d=s2X0qs&k?6vc{*h(ixG*-N{MAykQ3DZMw6<5+&nnxHbF!W8ym-) z3py8LJIBG2;JktW3-ufT6lf*nx498-=sf6sMF9g2opD6wa-z+s5{U9a(t7zp?%uNH zLE`mW27~^x3)GEdb7qJJ^?rz=B{`W0{u1>Y2--Z|_3$dKh>$ghH0Q)x?MO<90`N%n zeS6t{U{1?r0{7yIWbNp6Yn|-9oSxCNXQXBUIftBk>$RgtCdot6ODSCv;fLqUJf=fO z(6Wd973`hAKc9af{$+b5ugtEvF>7jkGxN;K+KkBbS)iYM$E2*SW1ceKbj>MDr=$xj zYwjo4sFM*IjlY!+%O9kvIu~b}^4w7dNqa|RMAPlV3QT&lRM^osxM`)^;eeHsV;3~N zW#YS6stIzcA^Lk1=ibCkxp8a+5H?W~a z#QZG^eUZ_eVwutTXfQ~(q<&q!5wUgz5Okf)eRQkLTfE%um1cOvA=h^;0ODeJzzBdg z`_-!3|KlGA)1jpsg;gPJC!0)S&WKoG!lO?g+qW-vWy>pv**#VLInF&iw}J2xs|k(M zWVr#g*j=IKM$bpcRYvkylL-(*SFk${Au+# ziXw$T2Bc{&<5;UclS`=7wnFtD4C#Vw87Ym7+om(MovXY(UzKLJxEil`47Htg35|;) zs9CAApri6puwFTUww{(@?LdNQ*4>qRH{sOzt^6jB(X)R~tN<daXGqXG9#AvkEXs8)KsFZ zWcVOKSucRktLzJXb%uv6{BMi#{t&S0)dx+(pOSVb?huw|UT*TU69|JgBXBese3)0O zdDb!|`t!-~*{;*%)@fqpurFE9kFcS3S@3ch;Or?iC5q|GnA3?3emI&gu!HnyDu((= zSNDF**WP?~g!oJX8phTUcQ5o3slw;WbF|&gX7hFaAlK50r!F$an@9+H zx|Ocf<_|(Mmv`)=H6lX+SGsI&%a$y+(@`k(--_rQHTlNjB} z)m)}i+2)t8(0`&T}+vuoqj11 zXz#VBC-wRNtODPg&o0~NaLn3b9DSH@&Ndqva6CszB2oDE4|A4U&cjim$INq-jX!D?A=i3_ZwKv&YMvmmwaDe6>fctVWwzE)rv_Y=Mj`8N z0O&mXSD80?4u$jQ3a%i0w^I^H=k5+cGds#x3@zir#XA#5t+iuUWzozJB5~;=;H(V1 z+g-u;H>+E|4WTHV2(6;t`twAvwS-ggk<(dBw#3w@-*eh}_j2cs^H@IX-rO@Z&@ATZ z8p!X=^TRaXmmo1N=tJuym#RHmm#ROTu&%H?eY^Fh0p{7hnh!dVVExOOg4#5nSMo2~ zmBc{(r%f6=4O4lQ^T3N7xkGmyz2fRb)XMa>`k&S;fo()dJ}s+Bb>s!v$WazhloeuY zz&?XMbt9hVd1Qr_D!t#05^SdqLhIm1(Q3n%rjACNj#fEtyeBU@bT60?xzLMV*7wL~ z?~*~+5o<4BrE+F8x zNSWG;d<)gcFUti)Eq>Ju*R$nI^kH^!ho{Kqy3Svycs2aXoDK!@yoED|5Q|(4FtVQC zw#-Q4@~m?nH_+>P&|WYb8}`lg%m#;XO*X^~v;6#MV7}nf`T;kH_jfrKZ5AjfXF&??lgu1Ad}wC>fO*jn1}$c?=S#THp~2q zr$29#onJ!4Ay9911@mcA*@i$DerGTWOL2>RZ5@0nxLnz z06@0v7Fx2^>aH(NdLRjSH@>O=Gv3>&=;LM0H;5*+iV?^TI`{Qf@0;Oyiy|gkW83Yu z^AOr$BO>X=DfMIiPZ+PN)~8JMc`prHSn0HsEqHc|1m#jQCvhygSQCyl-?BkmKHIeU z2?O980!Ou|7TdE$f0v;ly`>?cJA$Ht>VB1%RrFE7_-+%p6|L>;<}xUkpI1ibzI z6wvUR!Zxw-s9bq7KF;I=b?oPDXw8Ku`vy#jKgo*q%8g+I^M@~gL{h}R|K3p&9;=go zBk%P;udxRg@ec{Aw=a8^yZtV-tt?t6x){`6+s*5Xg7y`gPL=(=)HJ~Sfa<5uA2_Jk z+;XR6=gRn=V>OEI9%rz<`3}ZJR&viwXI%a3_dA46`nT0U$4>h1#3p_vYRS}{9v-LP z9@5CB$2ajo766Cd;-`Gn_&qA##nR_89Z#WG4+nG+#o{=hZGCm~pwhn8sF0h6E`IY_ zXu9w1*=0~nID|IjQ6=t^ECC3pR_V6-lx{M|u&x_;_O4jCjfQBqj^BX?inG5XO#kSt zqxv|Q+_V{O{TtQi-deU!>bJ7{nr>3lOuoRjQ|$q&%Co;$+R}nn`gt_?1D1U{e|mna zk>;hhj5!?jJTJFAz3ok)dq6-yA!l9PouGC%^kU7lv*^vaeqR?LaxcgKMF2G$E!6D~ zs=Ct&KNrkdE6u*ss2AoKP zp6aXP3c#dAZd#(oIwE#Up$s|apV{hv{NYUv7a=)s+3zmoZl&W#+CWmC1zJqc1^weC zKEBzqe>S;z`QRj51cz0Y&bG$hz5y$txNh{Ly*-;BZR!m zzxzgfM=itV1a69;$y%+Wo;|bv$P=GKjXVQuvV@c-&{8I7=`NcQ0~#jutu9bwVc4=i zq3qEiS0Qq@EbOMZb=55WRbo>#`>yoQot9oa^08}i)-&G_|Jquy@<1}8o5pr{DxzNonc?`Y=jS(AWxr@_yp(m2`>qTQ!P zxB`n?GvBJ#J9^?Zc%N>>>+UX#14vIu{giow7ZX0eNj``2gi9lC69LC=CK@p@5d0?! z8vuU7fkd@I$vBv(7{KYK1bJ_Y#PuLg8pGtPrFaR{r} zHHX85&pSFLN)Cv-xnv-kPaM;5kbSMk~X?OL6zr9lja3Irhff zm}A8RQp)*7^7-%c>WI?ddEDx#FR@%GnxWwr?~7d97*2NAUZ14*B5iWr=9PaY0`LBV z4Xy4qB%wj!(b8=Cr=+G0+a^a_@9*7N9ojUZ+$q@89KrB}obmw_>+!lV#{Tvmb|K%t zcAau3T9;nizdA4;!T&w?I7$#*8;%?9?ze{@mO;J%s8gcq8#@(&qBEgAUnb(FZdp%8 zv?ey8JaccC7i28wM-!)_tR~cB^7%!Agf-iu%(o36oI6G9;=17k1Wz6f6^JBa<(xRQykx30vuame;I7>m}tqFO!VF%ii0!A)!0%^PurND6!48#e3OvEC8 zGj)BTKn55p0^tB!@5^NMT{UoT6ed+GGHRTaJRk>W{Rm?u=Gn77%qi-T5Z9T_)!qH# zSR)$k&3jh?BR1Z0*$q%8SLSYZK zsDcq4&*%Wsf{BYG@*OF!Jw^XZ&?U*h2qBof2uImaK0-kxEp^2_iYMaFe?i(PQLa)9 zB?=ck1zO+)J~)A=0y^}&IHU{X(*-fb(<@q!>MA{%n?x>X`rfH8=mHN4J#0BLK81X$c4fVZX#T0`9O z%N6HF6~gtms43odGSZof@}7E!eRpR)wP=lUqs>mr#sDQ|J4+IYLkCdbA5@@>Wk`o% zu9pazrq4^udGD`6<<^E|SQFxig3=3f9=ns_+M4m{X~xu+?K0$YCDH=M5+gh~`kz$! ze%&lLR08^mz)cx^n8m$&$%~?+^&toY0s1TshVh{~s2}=2!VCkjfnWbunBkj0PS`#^ z>64SHmojY8G*D*fy!C}p8`)NTkijXXihWV~5{90w#g{eOv3l-z8$yp-mlaFME{2TU zGb0F($Y%9eZ2DMB$Wa1aPfhQ^8AglWHigqVn^Vlo2?5o`=m(8!`wqB1Wu1C_dCU63 zR0P5=w1a)nk6H##eBusz)a9w^=P;$(A4whIOzSp}1G?ecpr2c(hYZS~wGjmld=Dq{ zEXS#{Ti*8j`u_VgB7t@HLFw5x6{>CF9sOuby!CT{WcQ?gQ)R>--CZL-+H8XyqU74^ z+o=@?HD;Ol8%FLn1(E$%eSIRiQb4=5MCg$#5vQsG58p+SD6?s&wq1N)QvO;wd6KKK zF*CY(jl}rRKR>_!{rmE+Inbbx^>5xua35k36weDWAbm z8Vhr0mVVp&aWdYa%lC1T^i(Gi%aIbxVkMF+We;v?c^DEqJ5l9-v1o{QJG$el0Y!U* z@sUpyaQ3Q!ko68;^N3PLzys!{f3Zftw-QX%m=Eprz-wXsN!i==7AFp% zz#~7NTbx|Lf&u4avF0WrIvf=gx>nD(Fty^-yCL}3g&n6h3EMam{sR7W%#T*x*`djG z(&^fk#C{u3(8856vEJ*%Gv6_N1i$W#_XS|ZemB4_=!PmbQEfyOkD6(_@Q)9Y`RC=* zfiZ77-=OV^_1lquJ8pixbuYO%c_aGm>4}3kuRo5;LEk_5{N9;Ye=0q_?raYg7v|no ztEX#a>t6j?K`?rGCV417;?|l(2b}tE;6A-l`(D8XT@&R@jeEoOL+B$))T0wRIGd*m z_0Z>`{=1jyH%i4jz~)`N!#19ZJpJZSOFi?2a-|{{ig=XaF%`PJCKMj9Z*BdX`jl zFnULsEL#~w`x>EpM6xNlFt-UO%eHzo{-)@mWNDA9Skp!*FyFUM7?}6YR$CbOwn=5H9zF)4 z)*KP|=j8f73i)Mczu&@=sEp&p`sr`f07#V~y%|+TE6qsF#DN`ZM&9Em92o5(ED129APm^N~$hA~(mY8w!k5FYD^(opMVP^&9Ft5f7O~ z0J}sS(A(BHWnC{oqYW$z5#z(U6``Qe4nd&fL)-BVyF?RfJerE^X-#Lm<7$9mIQ!M* zYt!5m=3tlx`5HmM_UezZrqpu}O^fWT&iY#toD4bqNfy14V{BHn?nQy*JjjL;--bb` zh+U*W+}+m4V3nt(uPz7pv~m1Om1V`>Tp{;fAy-&7ysw+9ZZ95wNa2TJreFJbWO`{3`+@;{|Y zoM->H9^xV8DzhEv&_ek06NA`PmGBn6I+|mOev0O|E+o6+^by65G(2cZU=vIngdHVQ4JyIItGcm&AQ8QY z>hLaN3p2l0GZ@!nbYHj1k3`ovaO@mnPSLhk(}@@^4@mF)qqV-UcZtg!M#CBsF!;@C z$6zs7zHrRPavHmpwhciMoy+QI7e~#P$SjQ;9NxR>2X*u?8sbG%y@M=M={(&(1sLxcwUg_1#2%msv+goQd<%Tdo} zafz1ZT89e#ZB*|nOZ|?kA4LUPrO6N!ZZE!G(r=^k^F=u;TJ&QjNE_j=c$c^-0 zaS}1tjGZ#Q($HUrMCLRrdN6;@EMpixBGNLD*qIS?(-e3-rxqfzAd2=IK=4GE0um%8D8dmkuHG#rV$SM?fX|vGsv=QYIZ3dMHBZ zRSk$r6GJb8h9*(U4TwrN6cGe9Aqh>;Pz5Q5CSVOkMQou+M^gN02mY7>O<_TQYeL3+#8*$GE|F$%u!{sY*iwivw!7 zb{3dH#VC28UxvYk3}h%Z$ApEyGZF|ZRIJ#^+CcXFE<_R)3u~-)K-e_^u0;rl>{2l? zx@}xa+~|Sh5K&=)q)o{Qm9b4&Ie$DhKm4!6iVR^V!!cGky{aw(3+Xt+j`ZsF1dMdY zjK@yjX5%WD=`bKxi`OkZ7k8hlR(2mCUPr2i#4 zFH(7VVsw!JZOA~enYrFF9Blb|{3^RlXkEp`wzJTcA`Es3)zpD+l7c}Lt_BNR$RNH9 zLkgJrJ?lOOfY+iWeDY^ z3NS7Zwnl`lr-K#}l!gSgOyvfN@g__)UG@LmVluVLoGfLc71w}-ac z0K(eCyc&J~A*O;iGZ#ki?$lsXX}Ika7!ty0^%cI{hgTm6Orat)vN%CuMA(8hBnC4n zDBJ%WadJUb0p6K{Hx*z4se&pAdM{G}UiYk`!%^6ZwGtdG$uprN@}&8ieT8s%wFD}c z^S~$}=qM?>0OeSTN^05oFeb`Ygz^!gR?$)A5;Pu(gWI-jHa{=l{ zg;n%ch^%9xVH??+jS3GU!<8V(rP#&wB7+#teRijbC6t_94(vhcj|K!ympp$`cYhCvjtTayQ4 zD*h52Yzn&Dj@bhdI8tH;ggvQ+-6$m;qT|=Vd#?2Clk)q5>Sb8IhFEyXHKAZa_SMP1 zU>EX}Lj`FTW_zuq-0jc_4y^%31pJ%o53^CV4mMTHTn&6_yo?q_=URy|2e%bPi4T{? z)$#G(DNKZhtT9BS@4Cb-=s>_=QN08oBPm?bAEcyAtbp*}e9#rL@)<^%trV@$r>H@} z^@__>ft>YlcbM7uT#aB!N6b-?7ir*YR?&)1gv%Jdw4=$ZAIhPpp)?6PQgEjT{_)1G zV&Yyx*lY@TEgoG*BQozbUKPw+SJHi~NghlCgINcId^dNAkj~o`oPHi3ywu{zD$;&{_j*uhB`ksA z&^$p&FO*&-2@0eBSHx?l`t@w25-c-!jK$k01IO?Bee6c{o2Fn?d}~U7jhP?2@Dp? z@fIx61)<1-g0b6_ubAj_kBNcVFL2}hlH^;6RNNzu4i$=-CYAVF!nT2a0xlsa3ONw0X|0pOA;|RU_=P$ z9$}rII90OWiDe~HM290iCvl!{Pp#HLg$kMivwI@#V(&5ItEv!?D}bWVS>uagDD3p$>8wN2`iF6&>zlH{KYB!=Q2WTi5seA8vWwhbHcd| zKEJy?-bRySF{jAx7$;EG0+xhu=u3 zD+w2r9E~UKb0WboS%nyM{C&AjzzJ$ki?j!ABv=I+)brw6iui&J6QQb;o~v_n|7r9P z++Bs+rV>o1fVeH<{1DJj?m&FEM|5M+DmcWcs}t_uu&15CIay7&Za->0T+G4qr9o9v zbg7I8OBgGt_^&$Mw%A7FcOZWP2cx_QBk^M$;1IRW1e*3|T}(T3W`v0iqY`l9165Ki z972VSa>*3j$9q>bm?cJ3MA0M;jtF-Nlxz^uva5V;32I!M%@gV?O2TIRPBBj&o2hN~t zXowKTjK4kMsO&Zqz#uN+g;tYWWQ}XD+}cfz{UL~PvPYbMfckakar-PNT(u&Bo7%Ggn|D@p8uDk-2S29C(5d3(+R$)ja@cf8KVTLRhR|1CB4Uf6s z9@xUe{G!$%po;$bUI|1TQHXA0a_VX5+R}S|OcX{kp9mSkaZ!Wvr)q3K=Q>4=hOGh4 z^jI8Slf!)#R)=eRV(}7VM@5E0giJAM5MohM2*)k|^r45i!>82#_cMv^LMkO#-l4Pv*%_<|`xd9kfRNnWmHQ8)Df< z`t=erEx}H)zrDm5h@PcMfn|lm8c$|TR^HRPp4+{Dv1Id;^OpZX+Bn5mQMBO@Dk4Wp zDyPrK618FjV95sVs9Xl$(m`V@?Nh(hlbuggk=_vk@Hm5}T+-eng@S0Rf4LCSM3_YJ>|uCqMMsSn0A&E4w`uGRDJvAHr*FG^K#I5cMl$vV6_!9I6X_zF z%@90R63wPb{&~wv?I2&2+XJ%BJFt6-o5bw*Z%ob&rcW4}*hJ^OJ@ z-*Gk8lmgR`FrJ4qHpk*9h*#~mc)4fqB@i+4dnYN$)%FK11YnK$pGwKRp&MR*)mw+Z zjQZeMun3jG0&rB!2?vX%2%FqoDd<9_pBoH!6j8uq zQY%IK#y9eJ?3d@j3#-eu>D&;AXiq`5NI#pb0Qve~R{Zm^=*05CYV7X~<}Ctj`w>~F zgj8_q)&UW6c=H%uZ)=?3$eSAc4gjeqJfx%a6HqqxQRAdJqqR)D6$b-}iga6+G=$<+ z5_HB%(|yY1$N^XoL#Bu~mjAzYY%AT@z|*gZvOWbUcTZDmOx0CwNhhd{j0~SBd;A?8}H{=Y_UDYBsw1f;`oMMrG}0fP1siC{Ru=@ zg&7i!PjXfrdL2B|q2pXtkR5)rF5`1G^4W^wbW@t5t8Jqc}b< zas^HVL>o3yky1DupM>|~J4C&x%u_m3R(4?Hk*d53&Gl;&V#Wjr)E!Fp-#F)}82wtJ zf>5T4*`UVj=PGANZ@DdGyFtt9tpMZvU}db$7NQH`HU3;vp{)U~fyP}`sHCDYxW>U; z7^^VfKiQ({6?Y}p$jj~&(kdjRN#dsOTfVbza~ipA6<+DOQfADh9iD9GXT~s{ zkXyzLZM?M41R6aUX6Ney`+s*0Qi54Kl&?Mqj0Y#Kyw}hBp7tsoI5m!T zB$IcRVkvGkm5?*13aK`JQl63CWH02t+E~k|5N_B$t=4hrGvGEqhhz>89yE?evyb6K z0jR+&Q^6?uEUNk_s&b7f!*QmV;Z=9o{yv9>sDkyfpjQ|*YF``Z@8A>^^2TM&N;_e3 zS|BIT+?=MmQfT1UfZMO5BzYv2oLPYTVP-ChD_( z64noLw}lP=wD+$%ZnR@3Mt8r>D1RsE|zoaK*Dx6gFVYmBV zm87}GDOMnr1DpRLn6f_Ny363&GH}9CF3CI`o+~t6_u5~L{!Gk&915aRho8=NRWESZTH|jjx4W1^N*!^O6R(fr74x*q zEchuOiE~E3*%0-Hw zwBFM^Ebz-h1OZ-;^Q3C+S;NY^Sm11{ zfTEy^P4*R>kdWO(T+d`6;!d$9own9Fa4gQ{!losmFqKW#@wq`QD%Ts_zwXY-u31;e z+2Z-;Mx+AHFZID}@pJWNfNdVtrG0n?(Uf}mux_q+icbqoogeZvmG)m)eRXr3TZ>7( z&kXX!SO(?(AClE^Cq_AKpZ`qgL|9p`Q?osEy=_9gl5_`2UVKVC7P`WM6@4w-x;xYT z%D6&NHOWAr(fz66AK#ITzh93iA&ORn{FPmc*atFjtHhorfDd74ATd&XN4~_)=$ZV{ zpMpkm$~nJvFhoITd$urX$cQT^-sGM%Ref7a?B(ErZgibj6u-+fp<>dQglgm-J_jjSu_e#|0OP?c8D-&VUSdNJ@TWi z$(hjgC#g)tb$_2i>o$wM^~+FlCfVs!fyIR{{=plGgSIs4UHzH6;MAXHWgsl8AfAniC4`x~q2--5ql^_dH^h{`dTuwEr*6d!+Rhd_J9D0f4La`%_rRq6kM`OG(6ob0uQhJ5h4@W#50f@_ z9f6wZ|Lly_x$yQr%W8Wokmq!kwkQvw+ufCJy7n`yFYA-SyQv}0sv%T9Q}yOf%RTh4 zxFLWAn&9Z{fV?^j<-p=?@3~!Bmvw`rECeZ~>q_ZvR`5taK8jjJI$E%O!=EQb$VGhF zGj*E9vD4rC%b$L+O?|e1WsTw?lfKt^xYo=Q@;?5-RRmY?(Wn}irEYDNKYf&K(;e?3)#v;V zG_+~`wwdL6#pg(3&9g-FeyC?{%GHgIk9HTkR)-QL4@{MkxkX)6mhmi}44kCmX`fv!9 z6Y2oC2P@ER0a_OgQHJ{A$ERtFH7SsTvG*uHTi)Oc=fJ8mNVI1M$mhl$@M~9BMTrf!OY6h{0yILHNIxnkfrWT%iggs zIfVy}-5ksX=ReszvSM4hvXSiLSSpat94iPJulmxhlmQf@N0j|`rr32_J@T)l=S=1gV8u^d)p^koOVGCm? z2TI%=*^@PPY)#onHKVvN>#+5iK@@euvK2L8JT+N)ZU{Y+vE9E~GHHpfLJL};dLNW% zV$x$;K6!U4@b{@(Aw@yZw8Q?xN|uw`-i_V$pPv2VUC!Rr{4hY&H))x{{$TI1MC5GE zQ2sR$FslZhbM`NPH#mmdydsyl&G>?r1Z^PXLG)WMjQsWI>Xkhnzr#W)L(<7WSc65KTnz>n<|4Lizgyws z2YCcnN)&yai%{ZPG~30YAvmjY@R9=?Tnc=G_6n<+seo%4vaYW>{pCJ++8rY(%Bo1EoO`h~JJ1JptsdIEa~vM}bs*|EJti;#kerf{~6Y#@vu zT4gOZUKVekn+h)_eeJpZLC6JxdFI|R_@Jqhc4*KG$+<$@m(ydRe93P9)@*Cq_Vi9187c4qW0s?U1aewZ&T^k+x!e~kYk=dKIs1IA;j~$zOc&@%he89V`;$c$@7jgE% zQn?SfEFSdqb8w5;mjNccpGFBEj6N0#-P;qB9yeeRq5EakSIqQ-qM-ETZ zN*21xnIlU_M3VXR;jy2tx~-zW`RaT)OlmJc1el{?o-7d-g3ysw&U`B>Hb9K<%N<7s zT5D1ZqOw-q-aEE63#}_bYu%D#{9z^vRt`&}lM7Mfq{XMY{H@P0qn?ZV)IcX8H&}u; zFZ_=N`wQ-{lJg3NjnXCgt;@p|b(7{<=oH4o)hT>vEZ;=TH-Wh^7Sev9 z`7>umLib|(|HKr`!o^jd=Q1*q&DDp|IT+28mgU!@0~R>JZCkG!51^ntqa(4|v+%YF z&s&W0htt3^^j|C_mE8!;@V+0|;zxd>rzY@ZL?2fN@nWM$8LVMI{zs=3^6AU5SyO0O z`?`FSlURgfokj#m_|A+M1y?Z5H`Qj=4?b{p5Uot*cr;Yli@EM{ zF&MSHtKbX&f5aWyJPT#dUd(vOT|JFnyNq1R;Ca%JZ;Mg>=V0j@#&-;btG>3T5N&Ud z3O@oyQHpl2dY-8UZs_1u+{$0gK-b*mtro@Y&dg&-QJGJ6XNBkLLuL@kiU_I+ATnqXo$DLhf(dhelqYc*=y&**BkAZDi-2* z-$F(8VVr&b$Lp~Z;+Lcwgq+TkZ}hd^5M?Mgd(_$vw37gEt&TryP!w9ocb0Me#Jn|< zC9@;186Dis%czyIJlm!G6o_}c+I#O2&|?Xi_@5(>2Pg4*ZG{N2ykI@NJICg(rr_JY zfl+XcmE43Ea#GAuu*YuVVp3K;=plVimnFLZA8chv7vSA0O40m>celR9$1kBj3y^zY zY)|%n>Q-`gJ>N_AdUy2)`Z70QIreXPGHj8vrR05@&!a)8)jk|s8gB~@G^Jq!J02d_ z07C_PLdAP3m(kx3?kX3g9Fk!Tfy6a5UbF=D>s-ogJs4HU^Ba5n7dfBKddZ;VuiGs9 zLHhqPsQ^sq{R;p%IRN5xeMG_mE)JV#sbV#Mq9El{pGBVK|0VQlltax58pcF%G!>*4 zy#wj{>)FX*&m+_w6P4qJ68(@^A4Rf+x%+klZJW^2@coOa7N4^2!q5Vchk+Uu1%wPs zbfdBB-kuBnmx^|Z6ZJIBQ=zDc{oP&wbOBN}b-|CojE1j$AO+*}8 z*Y2e-F`YO=)W5CwuBP2?_>!uo!?n6}DW<^@y!5DupZYj!?|SCP-Io^^B%J2{{c|5u z&nU>{MOzXd?El-b`~8#Q?dqpChu9A|?~rGpCPd!fFPYRPLERy z91fry23%Rqf7NuG4m;J32VrmZ%E=Oh`Gkc znGCUxlJAT}pELX^&$K2t2x|%BTswng%4rh~DI4ZZu;7;;`Qe9#gFGk(2R;R=Do4x( z?@ia^7n>3y7-H1n5S8&dYY*|(omb5 zvo7PZ(GgC0UvPcrLDN}p#kDUYDXVrEkFS}`9OSOn?Fh8A+?$c6iB3Tyi?>e54fOh6 zY<`SC?Wq|uJeIFK5#8(gyyIbFt1}z0t2P zgxT*7yXQ<$}%JyvLSM!qO}KdgDe{=*@k`S5yY*ZJ(Ej(EqbA7?eU zV3hX$`Eu`NWH;Q%X$mqV@zR42l;3@Mwd#;uexf2( zU+!G%GbG9@4vtugq7gh+%q-f6Jm(yOk|HjB>#3l1oW|{n<`|bVQT|DmX(zW|mR zFz9Bep-@Or4paRW(xzHN*;?>hQ$_yno$8rHsUfm!P*2_xE~j`zC`&vwZY8&6zs@FD z5(3fs=cosa10U^gG&(cl5m;=N#Z?XU!K}>= z538io#r3A)5#fc<t0Fw`&l!>7rfLt{tg#UOisO72If!Qb;U3#GOR<6@tWw2nT6pmEoQf~Y zO|0i3-9yycDwZE;Z>xhUY#p$?Rqo~zx@`F$D44pg~g zSwWt39XG=)zaDixBoFSw=s?{=FIK5_4_a{K}ox#E7eHi6`a-R}m%cW}e~! zW$kxN)%BYx9fhbBv(yc$@=L(KaQ?AU_nxQEBHB}pOmu|(?jqq8m#w<%3{w$Xez({( z(A{xKQqNHlC1#x{PabiT*AzJ1tXjovNbtMYY4zQHa?xSP^aDg7IzQFnNZs}9QhDCP zUMmj?hb?|nI$c&!+Vd7odT3A4TEBuL!b7Oo>mI zYFpkB?5$2PhQ_$)?S~0#jSV$CaGpvX^t|nbPrb8ViqThvTsje{tS$i*4sy6QJT|gj zJYFu}tcs|ldt@g3*rf7ANcFUXMYv_MMvBm_!&}N% z#v$+9Nd}CgpaR7+uBs*#Gy|5jv%JmJZCgnfn9F)I82RZXRcD&5Wupmvyh zn441aRfdHG6T#rn0bQa6JsSB|kF)a8b-r>>Wg5ov6_P$y>xKTz^3NzE#&rAR#y2FDEQ zHFN5apx1X<9{H#xgz#Y$YzqX!-OeC7k_LyZ=qcj$xnK7xG*A(v$Fkp^OxeOjYl!f* z0vIlXdqS8NHlEUE@~KHHbj)0P3aPJONl|n#fRS=Rma|}wv}9oqo?Jd2_|+2@E_4t9fz}*5*z5qAOG3D5SBEe z6|2;QCeLoTiLwwRHF?3!9O6iOseQT>M)y?yi=gKKTC1ly=sC3ctOkx z6(FDZG7wVyWna`B3;Ud2RR`XhD5)49l(B%~Rgei{Izq|QmzV9h; z*aANOL`sI$T5SANYU|d^AgoQ3htr6!05q&1x+vhpB(y|2o_xh>iGc*87fvFWn>Oyp z?t=J62^hF0>OldOeh6}@qzE=XQ-G_bw}p0+raDQ+^>VT}HcU*)zS#iZj*TbA1 zCZ#qV#;Qt~nLRr@yXlxGS=fPz-7uk7C{Y}Nh;@Ew4>8u|fnqwWoPrcbWbsYDiY>mx zv6pSZOyQJ00)Glsm!+smEPRj<-9&B8qmxGHq?^>Uu)wN`)%|%}RmySv zkW^m$_4Og+elQ%q1lz$^tXlOj1(!<*D-kv}zN`8T{+JZ3W8-q!qCBX3jEb+IlVFi} z9!>P+b$l|Uc#|fYaKHtQVP3J$*|2hRL`XY!k2+o9O7_<4{U>*eaUQ@0t@ccVhZsJD z8DXFCmu0RFCuPE3E+%P!iu0#pZ?ewT(TOFJ=D)(hu~A-mCu%26V;?41^DREf3fC(T zn9zs^oJj3V{1=PXJfI_q+61c~bBal0%nQNWFYObRx@;qwUoMW(IVGS%v@0hYDVSV3 zMovamUcTHe#MeoSxspri>`Q(UOf?msyZypbK*=zXR7X#NDUOG72k@;IswrW2&B+$m zN&Md;Y|K5@E~vXc5$ooNy%|oD(W}y_|AA95k__W;5du7gs1#aUQL!x}AxyzT2tLxe zylH2rh;nLdUwYm8^CJS>K{0v&>K>tcDYI*vu$owhv|?gPnWP~IQwWg;m`S1AFV#tKVNBrFdctbzrLW;I?AGC&tzx z*FV5oz;2DJC$pilQ|6cl6XHx6G0?JGE@R_h?;BTu&tL+03Kq6`;l+TNXaE+j!ARb| zy0efD>HrIJxp=ZmjGLzM=5@~gdz=^zD4ilI{ga5VW+4eIfJno)(D1Lr@Y%Gp(K2Ky zg|r8IUX|A46@6t}W@p(bYg(8D8wE?LczfZ*=N!UO2w4e*VP(cd*#uUG<5BQ6EMz6~ z06PJlBf^&7(-u#qCt3(Y#o6aN&=nNyxoUI<4MBh`@NA%qGzo)Z-*S=1g&7$%q&Js8O&#uL5eoWQzcAHi><3 z8db4hjz30&#F?0n*n-`@M7L42Kb6!%V`~lq7%D-D1^DbTCehd=HURgLTw&G-A|x?q zK;O*TT#3?4%rs3HBSMBbpD2`o85C?#&}<9Eq>_e5_hFQv$t^+qDG+-8J897iOwK-i zOs4pvWcM($z+t=ua=dzH{}`TWjFB3v$tDg>1DY#2N;JGH1iG^EIg~1w_>*u!d5c2Q zzf$~%@p#zA>PSP|N#kK?b~RF@?7fB}U-Oyo343`~?tMgI7^&}|ZhlLmP=K=lNN&PC<>KO5pX^lKLc$TM1m zXf`Tcj7<^X6lHUj%-f+~7gw*s-ld1)L_nGV!=z;I$}XK2SC>Hd833{JedFB?sZkQ# zaVF{p9kaawAW$DfH}I!da$Kp;y6W$=Fi|ODd=!K_xzKDG&;t{i-IAGzTQ4%n(kd!G z8zS&wF_=F>N%Sa<@?x(da%ne`F2~3@lD1tAh+xUH_urpM=r3zCN2jt%&lZ6@*^3px zBwn&;pzv(39=d2Hr+CG@n#kZ9HaEb&^WU>G2Ozxo8#ba*7{x5^uLZkUNNgt zXBPCRZ{s%*TqztZgyslm)_b4RTp)e^t^^l{8<tL zI9ZBZm1W}$=)=nid3EwOV!cRqOpHqrrypCN`sO4j3L+Z*`Dd-m>z-A})lU!x$@>ff z@VRV4g?7uoXRB>~KJ(e~#xzsm>EYa{;x`N?76*{Jrsm$Pm_M)k%C#y* zQc%JWb4B+bzCH-E+6O1W7`S*=wE-~!Z2QX z*(P*wo_%mz$CFpPU%||u+=XzIjSUlErr%EhAD6W3U>+}|Xu#KB-z#L8^X8{7R8`d0rwn^sQQ5T%TFb@B zIopoSM4h-p5=%CgTOt4K6D~)BMzhS+4Rwp&iY0X6ZEpbZ&_*V--qCmM#_h{ z{TbRITB$tP0{8Mcl-CzHPkzrqMM)N~d?ZJAbQW%9nQIUVt`_24te2vT$>iBV?M265 zQm#h6d*B+)HRd0i8_c7bmEio?vnI9P9j&$JI(!WBEqbAHpY>f?gQPvJOu0bSI?b23 zO3eju-Pjvj9&hp|WX5_W+PsOKhcbqqm6HkGo2O+RHG{r(nXGYm1`g3eq-YvCHIM*ZL5mybgUU;-HX;ZOs+rT#3zgBzI&`_3` z9q4j-*rM>1&*yqxy~gm)&(847&W|w&AM8lcQU<%CwUbLvAf~Jdnmd}GBRnj8q-rkY z`<7sV-`LhBwV4egZ|*biG*>W^aL6PF+rAh1B&y&a?zGTdh-%DK;n?>^HV?DiiN*$k zYeuKqP8Wo1x}+8Q+sm5G=AO%ns)6l3I`oX5`7ur>;1A>aVT*PfN*u?nLJ znqX!OfO1|`eP**w{nI+Cb*|xmhbbq2YpN^OM=QUi@(kz#gu4eKHEM^~Q=Z_OQVniZ z8gxA1RO>0Nv(f1o$*|c~X~U>qy%KuCZKd5t9Nv{l}$x;HTeF#!@m)Ty% zF6*CKRS?7WdM$uUPNQ-*^9lf@akL7fu-2_tRIawoRcCo zhpAd@Dv#*FLmKn~XrV6#iu|JE=4nCD8^e26qr9h#1LE6jJgi;rfbi^zoiE|7A|ML< z)NGAJ9mAS-aCtHoD8H8Ey4qW==C!NW1ecG?!-`rBDaEHe>hP7@CxVWlbm6~Q!Xa}v zalO*8Nb_hG&y?DP4Ugif{go9>Qa}_k2?Nl;6tKp!hcs%jd)v=DN43ou^(ukQ_Pbp* zifvK4dk+R{-d{!8y!YIcwQzVmgHgq5T_s{{3Ua z{14PoBaM&wzLgb*on!f?Q+LM5N6c|kqA9a&X3WQWkRtihbA7Fmo(YRFV!>7Uo!)FW-O zAfQ1!Y&!+HVaTuLM;I4pt2-HkMsc`8Qma9J41ULoiR&!R&hI&&x&@g(+CXqAs{d}oTXb|)N&>|&}dzgH{tNewdGuN zcSJLKCS&n>pso~=f~wTD?wO-{eIgw9L5BwJ!wnSMpvJSzsG95D$;L-gWB*ue%7g9% zk&zf`ToFQL&gN2}^guK*Ht>+di7(u_tnwgu{~7n)D}W=9wD0w4fGbpJ_`Y3z*0_#c-Y-ORa=AnT zHDcD5y|eb+RsW#XoZ&?z#06JPL3ZoSM=!R0dcUW@DNF6hEpzik;AuQ&WmTD(@usWq zQp*f=uKqTpsO{q(Cm0N`WEQa)X-~H4#QJ$M0#eoN#-_J>KI*YZD?$CW$mlAz^QM?;qQt76t`!aH`v z6My;;rH8Lw&^h+ai9-<%=0{fd^CfrxU8z?GyI8m zvcCftbGIbW6`@JLu@t{CjA6w*+!HD~pI+s>1(P%w3 z&WbWgRkW>EC71Vhs05a1R+D>GzUc4JRY0)-crE6;!+u;FjH?&m?oveB{CM2z<5ImC zp66IPUs~Raq+0E^0}?F(G{yTf8`1Ld%n^B4&DI~PYxm!@O4tZwfp7?x|C^k_?d89% zF*f&vFF$^0_;JF3Pxy&I)>*$Pud#5@QCP^Itq-L5qV0PEg|0(vMB;WfddV7Xe+t=g z5^Xi+<~X*sZ;U%-9QN+ker7R+zDnWs@WJ^dRi_&s$re)FB*o71rRb=;aczU}vdvvNWh;fTQ>z9>!{&I*t?2^M& z-2TzJ3NCt%RD-8b6T~7R>B0n zFM6dotI>qj#S%?Sa4)y_j?T?H7sEjUbo-@UAd<{gn=5b8_RY@$ppGlAeiy9u;cHLd zG2;h;U*x`LtO5PAL60g?1{ZJ+Ot#F9jTW-aeb&SVYMYhLtnm!?asnPbUyDoL>?fHC zc^C8w9jqLuqkyyx-*k7whP$DC0m$WG9RKc6;btW40Q3O#MOS(p*`d`dH9i9KwB9KOVvhFgSVM%_5BkVzBY77GWYOmPlMd?@bDVTIczbGU!&Cm&r6vJJkf$(}1aFdHV=6y<*ZWypPb((MeBHA*tJ zs_;G|lwH?0lem&?L%Dr;fsxZN`^65S1l?~sFdItup}h!=O%6H5+?IbKs7*Pqv+co# zIp6kc^N$`qh&ZtAV5E;v4!?HA!!^lZ#)gM4GuUm{3T3e0k}{5B@%vr`2X@@-{~C1l zLgDroYcHRfY5o%~4!9dijtJcueEI6_kFA6-@}pspu9y%px*<4>;(P2YuDSP4xghrmZ>fNXtB76Mzg~0zq*n9movA2!algXq92oR8}p@(WvKtR;cAyNW@gdzqML`02*lJ$wIv93;$VX82y~TI+FvVp1m< z4MZX7&!yDq(Ve#;rDO@`xz+H~8sF)>Ab#8B_`}?%m`$T4G~l1#@yg$R;f)dXUw{{D z{w`D9LrU*{T@!~&dH!D#^S$pwl!$LmFO8JlirF{y5mFik-;RhhU{Jy)({zGafRT0evRX!Bmzy18{Ri9d#xOVsEGBC{)mlp&BYE3!yz)$dExH z5l#3t+*R{&MhAGe`Wfl>HZL!GY_R|8%B)4mTp@%Zy`C-OVRD|E;O^eJ3%8ESN?3`O z@dXSxS}HTMc7O~;t+p^$$1JeAFnux708$PGo)A1tn)QuE;aHG|oad|LC)5e!uvWpM z0{4^`MqlrZ%~jxbM6JH|A`-^jn4PwDLQWk7=Y|8;B3<^sxZq1xuixySoEVmc3|17b zk_)`*guYy4980)dE@bI}t1iX{n5_!mH2SCSh3}36FRIW2cIJtBVKV+I*=3fCz&rn0 z%wo9UtKWuabMyC*&Z8%M>kvp+9s@3di-aEEkVzLOoux^uhNJO%vndWe4l;BqQ{azv zz`?!n9<&t}l{Y$xTGZQyopb*BV|Mj%6itNMEESsRp*nx?VI&b2NEvO~usdQ?VZ+Ts zQ&Vhf5wLUclakhb#SxZC-D+rnTw;i%A8 z%w6>j;Vg#KnQu<)TDOJ@xpQl0eCnTF?sJx;W^6>Q6cq$~LwLxA79!!%+XAL5dU~~h zk;QZ6@SNznmkp2}qL;qXg{F-#ya*$I^J%L8i2)s8!m=)@T^kkTTCiz=XC{FRrM$&k z_aH4-WIRXEG!o_yw`67LK&f!0Sm*&;2vq{O3){YRb zrE>TlB98Sa3>gs^#nMv3mfoQ9*#K;L2LT4*93h zEOZ1NwKiq%szY}pRj|j&D(D-SmH(dg4F*sS;{wv?yRS#52pv=czaFmhe&i|`u^r`e zv-#@|eX+Xm=H%f5rcw}e9X|Twt&#I@s()Q$EDWVXK0T>18gEZ-{22B3hAnUxxDIk2 zh1LPcEu%c;)fo6cpWtYiS=TzLfv7a#Qvy;~ zvY3%L*?r<>Ev@7i!ued=1i~~r=R@(GA?vI zILZ2pVPSUeRhY=n*GrH4<{ltPxtIJ4dBOJfS<7W!OdB%);nl3qZyKi`*v2(%s3!9R`Fj4` zf~YHJW1GZ?aiJt5+=tt;&#Q2|(6>s}dWm3WpA0_-s_%u>%dxe*fVgRCbb4#58 zhGtU$$<(;+<&4kLUH8Kd8DuDUgNECN2E4Z~XB6V~eTPgfY&2cT8^fCB{Q={W`zBSj zXFFdHSv4x0HX5&S?$ouZIF-N^RQY_u1oU=48l%FoM@xcH#sG}_NkE1qS?58~&eX19 zfhFYntsTTtI3rd%V^udyOC(+q$eF;-K<$I{F>gEPStzC@rM!6r*U_LkroXtvt|hR& z(eBf>s_F)am9+MfL;a>Qns?M83-!8g!(Po50FJ!?L*<6uwN3TjB; z+*GPjX2i@5Nx;IK&}+=Uk*V_=1{(PlaJ9bZ!BZ`$t6TDq(3eA*o3wf&YV_XHs2kPK z$b^b&w?eaiONBlypR-Er(T}qJheji_)uTizQOXs2$Q(YM94`4jrn-;b7y(=?mC0_-Y!B6ZKl zl}|{d?fQl~ExBKRKL0KCs>%I5!+06}B(^GCXiC1byM)dLtF6RcM2h>ln+C&AO)Ic@ ze6GcU&@$1HtCkZ=3FZ#*T9D^j#40z_1xUj^Q)1-MLR#F)F~OjiB1Q_qltedLv}9HF zI?JPprA-F-e$d1+loI7SoEg#KHnP=zb)I(M?Jnxd1_`Ks1lyvs(~7jpj$fcP!=2F^ zY#0qUz>-Zgew>>Lr#m*}zZb4i-$B=;pAQT{JLIhk@LHOh*o@}dh&D(ZLbrsl*w05m3yu`%K;6U z%3xwnrKQ)v(ht^uA$IlfEf+V2_iKhgsS;d=0l(O%cl)}Zj`RqMa0_Zhv0>Yf zBOr+jsJos@(0C#pJUpP5&|MR-NI?XX6VCeS(CyMxh3~Sh^R1}d82$CrceUie@3#y) zien9{fzPh%TRZ`bipR8FJRPl`9oe243k0U^04jvs9k!aWt$uW^BXVIsc_o)MzyHz+ zXL_@Zqm901VWaC< zZ1m->Nw8i)zPgfvU801lX@G_}WrXoqBG(^j1l%?GOX#*MwP^6MnZ)AmnSNY}drU0l zqG;v$l_M-oEM%S_SVB%X(_m0wnU}!&t&Gq%a!s0zxHQG0=-bLfK1)3&aRH>48YMEs zBBtjY!#0jJ1iyt*pR+Go26%Z$C@oL~mKp|_CUcLE8^c_k#ZynzxRh&{uUQgmXNoI$S?v6K4#K_U znevp}b%u|)bi2gb#9IQ(rwXBE!)LqZ{9^QD&LJjo0JKqfQU_>7L0e}vmn*6{n%k<5 zFjG^abMfk5gw7FUFKrQR03E?3*f4PlglYh?Wb=Zlv8ZEM(`6lLXL0?;>jBHfw&Sg(E|zLa9@mU51@=quq8Z-2sbI5o!F zdzad>XYu7&VbW8Iz+4GvCO@X@B+7A)G_O03OZ)LcSX4+E0L@gO<~uP&$M!?y059iF zxy4KD_|Y4=NFy!=6BKZ_l%waXmBz&yc$|RZ*^t?-UrEbLVM8KJTDtTXYD$&3qX7eY zFG&Sq9?A{-MhEpnfJ4jDHmRkGhK?jZ<6>2EoC)>rhEmz#jy4KHxgd?ODhxURrJ?VKElAonbH5@roQvP1Oo$gV-U?VXXj9{Ax^w{YKiC+ef&H z^D?fM)<=-;gMiYr7W5O(li!jX4u#@`YPySboMx$s)-DNOFHu>b#cYNy1b7xAC22i7 z*ia;khx!0i2li6b!g_p3EqBbm#%*_KEcfn!Aq@b8y?zxE)P#y0q2T_HngcSrEeHpd zs0bRUBLkPXX4}ZqjwAIoJW523!J}&Dq0q zL|D7{&m*o{O5u`Gw4VwJB@s4}bSk*GZVqho6T$f8X8Ni+3RuX-^5;SRsA~g9m{H4H zBied_lsU95zm-J@44j`V5i|4 znhxw}3Q3BJZVi?;K9{5f+U=iLj!3`Xo(LyAGMA+X6w!G$?%*Ol~tvI`f zI&l=#-M%~U8yP+yi-VgODqPc|63wC^B50^cn5+PVf0(GZl>AA(hTMI%Et!~c8BP_L z5*h~UBJ0T6)a%>OdtpeG)a0i;9?M3YXCfj2aU>I!T?bk-!Km!&uxOCjRqnO87L-%nqV_7;bH+D?`;G+09`u@7gVtqlpTvN zmLN;H)rY!T(XViM^we=SB36!WhLJu+S~43NQlj<-5?OLg8I$;M3<|wcf9oR3OhUBf zW?yqdInt}F6~q{PbD~7*s0$>^Ktoz;YdZuR`9!Ld&6E^BIx>lg&XYj>6zqr`#gH^- zG6rk#)27SY%7MZ}x6R*Zl#SMrdb7R0KCM?)O-0n{E?dfgTZ`$t>XgfL(tVr3{pAmuo_YNqR$4UEN!ku^-*AkY-VUhKI0T_aOb{K6gEPs0pIPT3!8 zC&i$ick(i~XX>b+v5N@UAxDZqyo|vzyNi#(UqFT$hdaC^G>m;(m9z}P;3y572^{}B zT4KSGWM4+Oi_>^xm{59NA|17chItW#?O=C=Cj2E}*99rijGyGA3bdQ}f`FYm_+Rsq zLlsL>5S`mECen%Ct5C2s)K7VF1km~Q{gOa-E;tqkzg6w$Zelu~8Ke+1$02wS|T1 zTa^i8m3!HkCVBCI<3pj%6%*XjlT>UataW2<$$$xa8GsQ3>U11gMP4M* zaYQ=Cg*Fmug6KEE>$roVdrqhQ(g>%aUei%KqEp|y6G^6V@A|X6 zuqy*obR+yTMy~w=&{(jJgpFpRYF6c&-W-4}v@jq1UppeSA7XyI z2~%7e%9}(P`r4@p3@~H~1M9Q{xHZCv&izLk)J2NyT^)HjKuhuXL3S>i1m4~Jvz{CO3s%QnU#djZ zD~SyXuElm~)EIW1ajKC7wIBfvfHO^!lRFg?v;zP^^$-^K-EFwzNk`D_FwA~jJRn|? zgIk-a7(?5)u)r7!%KcRTA2tq6=T@nJ5~(Ol>p-ZZS}W&fUM3=4@8Zr=`=h2X-SYhA zb`)+W0l?{4sR&*_HPG})GH`D)ieE*7vOuD!PDG%OHp_8RAWwc{s#d>l%#skhM!55v zMxMM)bYR2bzCNbrR1x(_tL$LgVlQ^X_uM6z_UpejxWAM1HXa{(k8)Q*yI=_}4ZrK$ z1nju`S$ppf1=`>_d9d@5T3zd!|KQdXZVWAbe)*BL5;a68c2kh*l8w`)kHS1L%l^;Y z=E-@`N*eJ|ktY=GtmxO%_f(ipW1ci7oKxWDI>21}%=#a=4CRe`b}z|X(bb#{5U^fN@hKSJj{y6n_`M+!W}Z%tWqj?gJOwd^^^8dL^L^0E^(P+F2T zFosdS4x2&1dci;nrbCA9wubO3^5~04s{>HX=Kb?=tMzpWsjf{LSaAiNTU>Xi?6fFM z6T;`?>zS|6Y;Ye3r?>0$WIz)v%F9>N`PP__bl}*jlOT(UJ^cQ)--iMM^QEZg;01e3 z2?w?Q8i1qYnz%Emmm~=UsFtqSX@`FHJKj*9K zvtMlLdU0?9%ga&US$t(G5}_jjOy}%gs5MB?}*xmclMZNH2z!T+Xw&LCyIgPDsqU%NzBgH`BgLjEGD6K*ysgH ze%Jyka~bNE7_mzEJT&avAIiU;q}ym|iO7}T3Sc*+0O@RiNW)!!KYBo>BDf13f$45% zM4EVSyljZwM5KxlfF@L6M1qU8zpOA!lG{>)@$WRoVNWDVotmXdMRg=QIvAfa9VuC2 z;|NlGj)u=MYV0+3u?H=Ub^OA+vc6mR-G|>jDdttySke{w7nq5F_yYl`R#t*yD}jD>W%d)dv`n!6J>d^nk;dS3fbr-}U#FV+F3i4gpB;D%8DKN=2O18`$B81eUf< zQdo;((*m0-v=seDKD)g@)4y4Wn3(-}$op!(FvaREHGr#5`_YqH{7*~+zg){TOy;-z zPdQ(EIj#H!nz%yFJxb*FSR56wb}Ud^S`>>V{1b7j=QJEPq$Kz5O_UYiAs2r8)bH+! zn=4*XsYyMm5z{lLOZG6DlwhdhJA#Su7B=}h$(4%;0?WOK*1go`n+J72AFk9V*x#uP zp?w5|&8A6(`umvl8Optk@e1~|G#?RpB zpd|Kwg0|T3KJRT!j}U8$Ct}@GTFk$%7`=j`Hv6dOXtI?ORzUR|it+k7zK6hPQuiEy zy=n3Gt5M@1?$i=Une2Q3Umy zWM}-Ielbxu1ojT@qMMu{u2>|21-g8d%Kw$C%lzPk&srtdKXG!PODufhtri?oE?2KJ zsZ?q%iQ~>}^RDCZjwbEuR~E+ZB4JIA(|%c&uDo`0g2-;wI4Y4BS`eS zS#4rpTG0@vHoVgZ48B&_zvsrLJ3v9wF0QSJXg(J`dT=eN{95xno0zj<#jV`V2`|Z@ zF#gY;8O?t_%6{9r;@zaLl8Bz`-i_^^X?RbizQaK+ik-&?ES{bI)09(gxbxdFwaZ@b zSi0A$^Aa@s=uIYzY+292stHngi(*Akr9)%NnN8n4W4!*Y)H?jk0=bI5c{xa34R*a$ zE9e<`Bm}TUr*~$N%0-y@8ly#(IrR%%t4R$o#Tx+;pJ7-;ujS&60~08|tqFs}!$6iK zxGdvI@DR4Om8GoPP&H_v#|F&p*$AxOFrw>H;R6a+YyHvN$sYH?Ll*$_<|m%-&eseb zoWD(CU!A(MbUzZ8>X4JJXfO(58{B!kle{BKjv%rD!LJh;e*%C$mbM?Xl|f1M7P&!} zip`g{knrA~;BXDXxw90!X5qqOZ?F6PNx=BR(C-GERFL@|2~%Ye0UiipDh}%c>ZQTWWk( zyl|K^GjMAwI)cmSH+9ut8#+y_*Ya-ioL=Qrazb;RXX%XEcymRidFS@g^oM;t^GhD4 z1q3eD0;g}^kkd#iwR)ORF_291CWY?IoFSnXe3o>VdLhsf`d4B_ID-iwYFm)yV)H|> zawSq^kap)`qJT4f)A9&)#V2+?*2ukLvmNKh_`zDuZm&zQbFy>*eax3^iR zuo750;`gw?9*Ioy^<1$_adn5Ky`Z;Q9+#V96_=A*>t1B-wG@LCq|9OpbG;|-`?%i68kl zqqT(Nc#-JJ_2GlYBst1qK6l9Qi{vx_hgW9bP_YllF5#cXrD1GCtR73+Ub?c>)02zX zSZVZ|)@ntg-7rn>f3VzmR;`b6qKz^_B)=<;Lxwzp^_9E`a#|<5%0geC8Bzs#VkydZ z>wd*Z0VO~04@HG}QuQ#kYx_>J7KmuBU!T)w8MxQBZ14jMyXdOA


(l$UGiv6hh< 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%0AV>DvD?2%1Ow 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 QG}r^cxQ!uvMNJ(`-Mf-7Ko=+*zVn5ZHc_5 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

)N*;|$|3DH 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 literal 0 HcmV?d00001 diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100755 index 0000000000000000000000000000000000000000..6c1d1332c3a71147fd916de90e5fe147bea299ef GIT binary patch literal 15406 zcmeGi2UJv7c0`YoXc7yEL8SLOGn4@|MPpXi5*8zgi6WMmM9n6aXcQ}U!9o*}UX>!f zR}qjVg2vvvF-F&2H)gZD(YyCPeB?9EfQ;hVlf#@d=l%cwd-vXV-+i|}k*J5Lr>K8_ z5w`lGFMEkZP9l*=U%%zue1J$4g?(c2lkcV?QH`cZWR7ES3eITh$423A__2G?*}o+3 zh#v>W=ejok1Wr{K!Kw1X@Bf46!MXk>xHR5wgTpqVc#`~l4u`kSb=SeZ=zDM|J`N70 zr@*D*W-E+gD|cA&`I6itVXjB-wtl1evYIPkw8kH-!ZN^iZyA_u4h8$XCZy#CI96V` zgmZiF`PAAbS1xjCxb+|UE<1DuBpJ0}x+M&TdCrB`r7mFY9}kwhQ;~*SAWl0pPdJx9 zTkJ`dIaObJM0_w>wF9IGW73C{!OP1F^kl=qGIT#k@|((Vd>h<+KDAEOmw#mRS6u?9 zigPeMp$LL=>tR%E4tqD-78NHPFaPX#@LU?rcRF|x91olayVOdM;hs2@oB-mHRZO0@ z{2bxCIJ@y%$BGN^PRVg_ODP4%gmT=2lOWD$zDGY`%J=lD`^ zk4OWX=wh%B&42}g;qd3mbD%YCO#EX1+1K{{!E)oD zdbKY(xsP~2>y=es0_WOm?AgBHXw*}K6?7PGiPd$gx_pITa5xU-XPS+I7eQY$gJJKH@P59%N{%3690C)NSqIl>au+eX5R4VoAABj$97^0H(f?pfT2+`77q=cl7Mp zvlTa|LvzAMp!?Md<`WRTD4%=r8+w7A{;Am)9{p9we}YT=pgw6*IqZ&%hK!61NK8zG z)2C0v`0?XG=T8%vejq-PJeh0`bMG|fClk;&c__qBz88PDiOC1Im@GI@To2Wib@0=j zyYTJCtsqS-Zs9qe2g{HYu#U-{rYe3(c3lp~N3Bq|(6a>PafELoc!pKO``h<}G^LX1 zMH)-{WwLQMXnTEw-nVK$n}njJLj3%h&J^h&^PO>kdj!rkSD7zFHiCR(KF%(w{4ruy zR}H&Jq_@KFT@H&{`@)l8mr{$eU5S488L-_~)~fTxY1Lp8SH%2i8q0jj$n5K?;(ju( zpX|`(-w2*_?G3O^I>gq7=NW0J0R0sqs1NS2K1pUHo{t37Pj#pVT5P37@V@Hj#4oZ* zC_ha2Ekg6q|Gx@e>80ScJp`6#m4JI{IodSjLDgln0p;w>QJg@$u}iLnH)pNt)VWtg z>yYW*!G=E3p#9l;a4b0qUIn$VDl8h7#A3`4o(H-McY>i$6nq$)1)KLoz`Ce-@F;3z zJQ+H7^FBo|JJV<68$OopWkeC^E%nDeKLj?3XaoF{Su8{`ge3hCmxg%2!)oi0q9`Tp`8=7m>b$V6rLZabL*? z9mNz%P`2&1+h5f{_=SJcZT1D^pB-WLmcEgHY3S_>+SBKu93DK{7K-X`mQlG|g}7UA zA%64^NgvaBAX_2y|4cT7e6BjiwlfDz@YF@Vwy_2B^a$TE&i_qhV4&3&%JaRM?ucC` zT%Qo1@R`P#2ki@ZK5PnS_b}TLzXfB)M?!r3ndCv7S$Dx`eefKd{gjWd5TXj5n(ou= zEW^^**d~-F*ritG+3YQivj|CAImmsgBZ5TR#{821I6(aPf*MMuSqyw(KE|A zpg%iTO;5Xe8QM-VNs|!lA6ssp``0-WC=noK{7xvbi1g zQ>=&k%VI04naD8LCQhva>xe9{+LO-mLDtcEn2R~hVs08Qtci34pT65BmR?1gUr|Ii z?|T+Fs*VxHtptPR8*$%Un|{ylwFlcQaBnTAQ(4>Id{w?tJ&R2GrtClpnYKA z?FU0Xp3U+Ax+0}hz)#k>j(cKZ~xJZ4a=#qy-YXKT#K*(Dvo z9Mmr;Zs)15H*did2?FGpY<++Jo$~jZcf!?_;qPn3Y z)?f*@T}oxaOg>(v^X>aMB@Dl&X4pZJ)YqA%U4LYCp zScA}X9SNc*x!@kXdO;r@eRy+{Cpcx+GMT5mG36yNm)2&_oolZ@G+H0xiNvZJH}=%< zoNtPG&RQ-{#80Bp7HcAO=13mM7L)u^U0~p-2}rvSScPXY|H5jV8}v|9dn%8uhU>8y zI}wH-IDipx_=I(%Url$!72>$pI1SI; zYHIe=_x7D`x3}zPPPee7T=>BECbF|j>!I46E!M84PMr#_uC6d<%orFsawKcr+}xl~ zpFV62TBt`&w}yk^ifydcLwdkAxuRL)lP}u!byQqW56pQh)U6~hq(`{kAYCNGGw8iD z2(q)Y;pWYoaQpUcIDY&%Jb3T`Hf-1cAAURqOctzSIdMAQ26*miz9g&Rtf^m|fr>P? zI}PuED9n>d$tTVJ-KV58LTeh4Tn6FsDRATZEx32@9-KOL1|I(W5cVb|!>7CB!3y_{ z_L1^@dJEUK+#e}uzGM|sX4EbrDt@#I&ngwl4Syz|nd-d!oqQas!B7ow?8Zd!3r>TW z-MO$QAQN_kXTZ4iL5z0te`pTX(rEqK)8~VATz-U9^>nHwQBGS{-PUGd zjQ$&bU($;31wRa$wd6I_&u!{{M3*%0doT;g08_tYFx{36R?(&Ci=AM8GudG-bEID= zZgwa>!QxQz=lJ?*&FEMEVi}t5^@7P3g6oC#iU6de)i0u2r16%-R^3UmVVhVE<^gGV zZz~+{4CJ?-4Wi$^=mf4a27Qh?l&#BnUkrU6+$%Y%x@`WwG+ zzF9?2_p0ggDs;|J9{KK#(D<2XvvthOG zHi*y8g|PfmFjyIaKIj=%Gq#RH9|wI6+9Q%3k}G<4uEV&$<~j_Xw(JTL-X&+3Go-i0 zc$5C4XPq}(AB(eQiM=&hi6Ae?h?}oAYsE2S3#1GxYfj_8QOw!}Hx~jE|%-v5k>3fI5z;ScIaMf;% z)sKNVFa=yUg@OHsFfiK^i*>?iFjyW4bT`q^2mPG2p)lSr5@s!31JNn4!h?< zzBRK6*xDsm;C<9IkfhbYTPp)#>Y}yq4(eBS*AdUQ#^l9!UlF@gt*EPiniwOs+A&k~ zgEhu`uy}AN-Vu_Z|4HlPXGGXiUd0?^G4fL}#sf>NJ?npm_ik2%KJF*;C{wqbpxf2N z6MV~E$xWOt^4sn3z5|bAsh{X~zkBaGd5W6%koVNF&FAgf8;mWIm)5X{b+gFlIA!4O>gBk$;+hQczJ*(-V;2bi1*Y-{v_p^ zSsfq!ACe)Wo9-5Ie}av}KD=L8s^vbd!#mC|cztT-L5ZtTcPNa>l&wp?AJ_HBJSb@+ z($=MROVQc~3?Hp)mtNB#FAwrGDto7S(xPM627Tb^pa}lU=o>P9-rJaOI3tt^W%LUB zu}<&^@BB9EEL=zTU{uZVypSbo&R%G28J5z|RIQAbg)>ia}mOl2sN*}v_-5luVKsN`vInd34ZVvo$IPgE7#{$j( literal 0 HcmV?d00001 diff --git a/static/flags/ad.png b/static/flags/ad.png new file mode 100755 index 0000000000000000000000000000000000000000..625ca84f9ec596848d4b967b5556fda897ca7183 GIT binary patch literal 643 zcmV-}0(||6P)S}{rU-#^xW|9%5S{`_G8k=zVG=|5luWB>#JF#yj01oZa& zTu&JQ008~}|NQ&{0055x0sR95`v3p?1_t~7{`v!N`v3d-{`&g=`T6amqXIBA$0h)T zKokWRkpoMx|Go@O4FvhR>O1p+i7`B6t^3)y2dJ<#?4I?d4x-E}Az98Z`2`TmzkmP! z{`(J9{pauh-+zJD{JOYLhW+QSzkh#x`Y&wke*WLjpZ~u9`2XuCr@{^OJ|MkZb_UGR@Z=V>fB*iaq<8P{*B}2u-uMnu#J~U$KrBDL0bT$1_irEqiZcM6WEF7g<|*+% zzkjHi-TwRc=f7_t9|K*?`1?07lmG&V<)V$@{}>pUYZ(~+fDw@M3(WY1!T<=sp}f-o0K!lJ3<>Jc!&VtMslE3ph2^H3FGe(F z4|^}slF1@l1Nxc}^5hjjU=0la|37)k@b@neJ^1|l@87?_{{z(l6@kcKe}Db@_Y267 z<&g#201!YdV6*>2R0EZ*bYA%%2Vi7me5m>mAb?naPGtnD20MY__n-f`0mzg8{s9CK z*hzmtW)s%H$oS{aAAkS?JLxaT`2W9u;n%DD1Q-B%#%TuGpFSS|0000&5HW|5#c7{r(N){s9YCi84$~U|{$Glm>AD0*K|^yLU}ZO+eP) ze;~;4`#0mCzs$dX{r~-&?f370zkUTM{{OB1_1E8DKmYz*JbN)f0I>i8Q1#1Kum1f0 z{pZggpt}FRe*ORX>;JEx|9}4c_w(m__W!pfKK=atLxM{ZXbC_7vHbh@@9*EgK-ECy zzkh)Y{?EYhFEQc&-#`EN9{7Lq7*OE*@9)2U|NQmmC(vO40VtezBLF}U2%?OI(TG)& zJC>!~;SYmN-)zb6gc(7A-^Q(#z0vHb9!CJ#T#ii{@&pjek8j`pfX)5|H00+GpnLvt za{MtfWBC4qk%R63j~{=2{QLgr`wyTb*amx2hce{;{QL3a|BhWh#6A5bKmf5of*%NgdVm^$Zuo!gI_LQd|G=96g51yWl0Agf71rLE? q3XWqq@&Lw?Iyk0*94-cc00RK~MQKxxUU$F%0000= z`}|7!`YQYT5C8xIh~*yx1DgQ1_jkSr_QgN{Gn)!7=zkRT=l(yS{y%^Jd$>%yrP!)vVq~xpZ~xA{{HjZ>hB|)Z~OQoBLBm{yCqA0{k;C`&+mV~|1$jj15^wU zKukakbkF}kzkmk({q_6zmUTZaUWBOraqa5!?(V-pgMR}R{04?0&`AIR#PSE^hrdi> z;*7t4gLVFSJ$J5DTibsorq@%ai5h7B2l^1G@*gM=fUW@uAjYc<48V{DX@ijvE(11_ dg@FMezyQzuBHsGv+i3s*002ovPDHLkV1jTADB=JB literal 0 HcmV?d00001 diff --git a/static/flags/ai.png b/static/flags/ai.png new file mode 100755 index 0000000000000000000000000000000000000000..74ed29d92616c86757d3c0ec04378301c8f591b4 GIT binary patch literal 643 zcmV-}0(||6P)ocPy#thD++(+#W%SS0Qvp^`1%0+_yGC)0QUL-|M&m^ z`T_tk0M7pe&iDc7fh@K74M*k&0{8f*88BG;;GY6ve?;&4{{Q>_{{8&^`u+g@|Ns5} z|C?Nv0*Gb#mu+n4z6ZW~#qjy_|6ji&ZeIEMk16oyzH)i@Pk$MNxLARR?a#kwpMS72 zF)}cG2M8dRUN*~81wCz%$A2$f`_IL|A|w6j^RHtc7{2`lYG-KkQ{(*knSqh%3kzr7 zs%s1kKL7#%F#yj00-^B^D;pD^^AqC)4C(?1m>@q26ceiU4*2{4`u_d~@vQ*ykp&A1 z3h$o${r~^~`vQo?Pm-bY@cm79zVQG5%l!B6)Riap%L`bGemnT<@2|iAfl64!%YWS~ z`p0YY_dig_cYpw5WYAmG*lPLk!;jy8|NZ#~MF0Q%{rCG1ko^Di`(Fhkd3F{?py0c9Vg{{gA~^#>F<|Nj5KapBR^@Bf~CXSi|t;lF=C z8-4)<5DUX^V9+rDCI3RuUy#}V{s46X!}R~}@4ug&fA|+@;n!b(1zCZ900KKMX({{sIILBZE*UQbc|SngJt$+`m9Kz!<;5 dBm+Qz0RWL%NC2%sdjkLf002ovPDHLkV1lARHI@JX literal 0 HcmV?d00001 diff --git a/static/flags/al.png b/static/flags/al.png new file mode 100755 index 0000000000000000000000000000000000000000..92354cb6e257be2cade71cb825027ce8d9efc06d GIT binary patch literal 600 zcmV-e0;m0nP)PbXFRCwBA zyv)hK@{fUmi2(>${xJOc&A`II@PmN?BKC`c;SU)710$d~Kmf4-r6niy16BY3`}g0! ze=L9h&Uybegp-Ns@87v^zGQMU|NZla@z1Y+zkdVKmFbHB0*HkH4F0@)&iwE1;&GRLuzkX(OGXMMa``@o$|Ni_2x(y(Jn3#TnHT?el|IhC;U%pHK`}6Df z@2@|9J^lXU=Z~KvfBzi*^!4A*U;lv`e*Fge3Lt=(82$q_`~m9z|ND;$!(WEqze~6o ze}X|JFO$H(U+VvX#{c{avi3L7@c;n?3L&6l7=Hix`}emN<6i~#|7+iUWBL8-&##}m zKKx5zXJr5LA80nvkwCM6egFs{po9Y?& zL6B;olm7ns#=rm&Kp-3b{RIXY(1{??Ha=$NKfkS+|9@us$Mfg+93j@fzkY#y2y!;i z&kO(o1PWH5>zPHwn7|>;0Mz;WPl13iP!Y(WKYy4&4hBXMSPugOKmaiw2gk!dq!|4J mj$lZE0R~eis zC&uN{cDQ8`!@ZNLOqwtoG6nhzPx}SV-d6yzFfcIz75{(rngJyDkKrFw8iaoThHCr$ zo8k9wMhS^O3=9AP!~%5B|9}4(ASQtkLN$m1CV&5705X362095KfLKJhW;OjWdGY7l zzrX*$DuLu*pcFC#NdEr)SL!$SY=)lz0mSm_*B_u)|AM4JP)(}33zy1Lc&_o7? zKL7y)bkd){fBym<_v`mxpbeRs`+WRVot-5A{r$IX$CJFg13u{3eX_{0R++j zR}GCkSy{&4zk!krKoTg(2n-k?g31B}5JW!NMq0d0000q< zM7LZb@rX?|r)2RP-+aO3(7q?c3+$-Vv0E)PxM3SDV%@s`#GkZvw_x^WBa~uq3^l}t zWdf(j(=(>^SgETc#5#EZT(4ObRkfxbzP9G;yza0;Ygc8-_*?EP(ca#`l6-Z6D0{tL zQ4|~MCSi!9Q9YkW=V$ix#EqZ!rc?eWA0TwdVID+3aqrYUXUhCI)Ad5!(cP!BhhW$Ayb2&r8kK!bz*2`~UE W(Ndrek0Jg50000NL7TW{{R0! zJP>i}(MpzaSkj z=eqvqa`^|6{{QbQRQ11q3~Vg_kG}Z}5I`(hw}ncX8D4$|h64jUK>or*=^r$dfI%n0 z$3MKz;!F0w91GjkkV%_X`@4 wKR^hm`X5LwD9*v?4;TUC6Bz$&3;+QJ0QLcJ=WT{TU;qFB07*qoM6N<$f>3bX%K!iX literal 0 HcmV?d00001 diff --git a/static/flags/as.png b/static/flags/as.png new file mode 100755 index 0000000000000000000000000000000000000000..32f30e4ce4eedd22d4f09c4f3a46c52dd064f113 GIT binary patch literal 647 zcmV;20(kw2P);Rmc0RI30 z|Nj5|{Q>>`0R8>{{QLs@`vM01^D6+%Ap+Y10Qw3Sr3ED)s=c}b05Jg0{{#dC0RR60 z)z$y}`~dv>0Q&p?0Q>ne0Khr|#}EMN1`-ttJvaFq6VTDg`OMJS*4F}vg#m0fQ1$QM z42u6QTCg3Kt8+Li1J#Y_zUd>4Lw{URe1tEjLbKmY(S0M7pd(g2qsJ0|z;{R`~d z`n<6E*3bb41p*Zr{{R344LkeqyaMyV01O!W0PZ0+TjlEQ0st`p&i?@b0Q{Gi0m{n% z`T6-B``1JQx+4kM0{rp_FfRy7P6Qq%_1|&<`|JPx`Uew8u)+%h2+ zdiAI7xt}_}e|$CmbI9$2>u h*D)|iF)#oG7yty8`q2#I8zBGy002ovPDHLkV1j5VEF}N{ literal 0 HcmV?d00001 diff --git a/static/flags/at.png b/static/flags/at.png new file mode 100755 index 0000000000000000000000000000000000000000..0f15f34f2883c4b4360fc871d7105309f1533282 GIT binary patch literal 403 zcmV;E0c`$>P)@|4`Xj5kLT%`al?B=W5I`&prl$WjwHQRjfmQ&G0jUOA z@&|Dug_Rm`2Y251|$~)1M2@@6mI}!8O6olw6y^Q z5X--d7nzS8`+x5q12kBmVFD!~j6c5_fMKno0(1^Q0I>i=is|LjXX40RRttS6cG0UZ?;7002ovPDHLkV1fxUnjZiF literal 0 HcmV?d00001 diff --git a/static/flags/au.png b/static/flags/au.png new file mode 100755 index 0000000000000000000000000000000000000000..a01389a745d51e16b01a9dc0a707572564a17625 GIT binary patch literal 673 zcmV;S0$%-zP)>fJ3En$GhGS>sbE%%m3$AD)q?8M9y>88-}kR7#RKlk!P~Y_PLuF7~U~3`~nC7 zF#yj00ZUDdpLsm{7ajP|&HwoK0Usg|6%f4L_{`Mi{rvv-`ukf=Ed&Gs-sA7L!Q7*a zj{*QO0M7pb%?Sw^g@yy{>ihEY{`vU@3=8@G0rvO$i3mOL`~mv-`W+b$Mmr&io5dg< z5v!7q0*L95jt`TzK8Kd(Utv)OSp_aLv){6ccV+Z`{Q2+asKUU&aO3`Kpz6wW8wp`< z28M3{0mSqnB#A*-c*8%1=RD#sSOwMznKA3=e&iEzwo{cA=PgXK`2OQ}gqId83!|%* zA_Kz@fB*n70M7pdECCwp4H&@R`1|(w-}M5x*74i)0}%fAt;XafA{48))#>Z>?CD#}*e}Ret0tl$#*RMZ7}Jl7Z|M45`5*URzH9L z{rmSnPy;{!u>dsyO%meg+00000NkvXX Hu0mjfN{&}S literal 0 HcmV?d00001 diff --git a/static/flags/aw.png b/static/flags/aw.png new file mode 100755 index 0000000000000000000000000000000000000000..a3579c2d621069c8128d7cf16440d5e45a3ab3cd GIT binary patch literal 524 zcmV+n0`vWeP)^}0h@W9fA9JOn#opKkr#VO<{LPm{QLg}EdH3Vb1Zzpp zqiZ+XNBm%5{`ViKi{bCTe}Dh~2a+HyfB%6Q|9}7eKVjxEfB<6Q<6r}-{{7;G=hB{; zLB+p+|Ni^;|DXT={s75;AoBO$f4@PDf8sps4FCQC1Q64wUw^h*hy4HZXO3U)@85qw zD*pci8U|DWQu_BVi2MUWKoOv;00M{w=;|*lY_o%kegGx^{`&*A{SSok_usF-P)oof z|A86+0*K|;FQAM6fB*FtoEI&bZG5mq328#as{}<$F zWDQ{Ffz1MH001phxCBNdC_2H6U$AI~GQbEJqg*Ti0R{kQ(yH?TRrCY^ O0000^@RCwBA zRL|V|7QjV)*ul;Rlceqc6W0{`~_8AeMg& z|LUXE8U8c=`}dziv6P|mEu%JjM}pqh@65md|Ni~w->=_)fBgZXe?Nc!ot?WGAOHX{ z0M7pe`uG9>{{ZXo`u+d?{`u+u=j#9V2j%Sc^797z|N8p+{rLO+`TP9&`u!FW2mk>3 z0#G;xDFDDQ2vg|)-@5Zw?JVTrAxNs~5&|AZ;5uWfQ`vUsMGm`>aGWoI7=P|oW>%~E z|Kk8dq@aG@HzdsB>fj@shYzX-a%=q<(frSYmfLIv5{HbzQ${~M_P_y6C&m>3uU0*DFd0+8#0#Gk)^|NLQBRAyCBeB9H+Wn{=Mr@*PJ_ZKV< zB>w@GFfafF5Ks>TBP0ZV{bBt5_ve*sKkwd`OiO#eX6=u=cfX!E#rX3NBT(umNC7Yu z0Ro8S7X#4ce?Xr63$phg)Bk64X8r&5``_O`AFf^jc>p5y?+^38KVKLa00M}`wU!~x z=I_1Fe}Df4D*yZI@1I|PfBgnRptt`0`2{iqMpRNPo|?TW>MPOFW(r1_!xlT-yep5|G*@e%^SFxf#DC32@n7=0M7pe00011 zNe=7o{FIuhzQ(sjF~t7>`T+s_0sj00{`>*}`~Uy^|Ni?^Z7Tcx|FW0O0tlpm;s5{T z+df{s^E1rDZN;v4VP>0|8GkY`{`&t1s2YfV{r~st=KUYCl59Xr00M{!Xv@F<41fPH zoWA^R$>xvtF5yd$xc~X{7o-}f=ig7DY9RXc``_>1K-c{N2q2&ahQEIq{`~z1RCDs; zw*~7zIJ!sAKj8J}&!7K)enC|K{|nUc|Mwq|27mwp*#K1f8;Jh=2byv8+}GKw-@AGz z%-rMu^XK3HKtBLA{Qvdq*I%FsKn(x^1k&&qY(LP_Uw?q)|3jz0PF?=a(?4bU?qHzN z5I+E=z&88?2q2IKpz*){`~&I%+VJc5-=Dw#?LYB#!lHLRL7BZ8-NZ5x*TXaKmf6TZ20qEQj`^F;~x-W z05U+*fBxNj@_W(7kJ(ujGnWgh$g%(Z2hso#K#U9wI~hQ+`3Dk_7z`j1tL#*2FTcgW f@C+EF009O7>dRn2w6d?H00000NkvXXu0mjfueTzu literal 0 HcmV?d00001 diff --git a/static/flags/bb.png b/static/flags/bb.png new file mode 100755 index 0000000000000000000000000000000000000000..0df19c71d20d7fdc06e1cba01028983439b2bdae GIT binary patch literal 585 zcmV-P0=E5$P) zj51&U|NhG$_=oZTA7 z0mJ{l|Ns2{|Nr-Y#^3*c{=WU_!>_-;fvROCxPdkR1P~M0Xa=C_KR`47{sXG+pY!Yf zqu=)*{%)W0>;M0szkdJy_507SKYxDz`3KYh5I`&-cY{^``2$3Z|NsB`^ZWO@y}$qd z{r%_nFQBC$4Is{6hz5WF0@(mI8^j0N`~Tl>LzQ1Ye}a&q>MtPo*RQ`|OMu4x1!@2Y zAfSdne}TsT{`c$8-(P?J0c~)w`~?J`zx?#Dg*yp^z&88=2q2IKpt(TRKniTbum8-y z1bBWi0e#F0wgIH{FVJ|Pxj-8L0tgsNfByUdJMs7b-@h3^8h-!E3i%CU{QCW$1*GB6 ze~`2PfHeF82q2&aU>N+96yg32bmdP5238q{|Gydk0=52OVEN6!@<&OA7Z~7wL16>b z@DCt>7#SFn85mf=5eY;LZ#OUe_l@D-2Zn#Y82<4v{9|E|jkRQ8_`$&N0jL_N03g5s XX0T^_9W~6o00000NkvXXu0mjfXpthO literal 0 HcmV?d00001 diff --git a/static/flags/bd.png b/static/flags/bd.png new file mode 100755 index 0000000000000000000000000000000000000000..076a8bf87c0cedcce47099c6b74b59f2c9d1dbce GIT binary patch literal 504 zcmVCcfPV}OzZe+)fYC1)`hmpw%>WR9L@~Dk00x0r!@5ksR;+hV0>ZLfIcBS@orh;x zv}95za5W)x_7^}bV3YqpdH?h;NZnuSC%?V#{+0gl`~RQckJx{&l>NO~;@7XgzkdJz zEh{VwR0LSuiyWGR{aKQ z00-R5+27mwp+3@G@Um)kt zzdstU{yWl9SIB_0ft3II3)BD*KrA2|{``^Tm;4PDy`=a1tTre>fEI#8 u{{2z<2NVVaum*qtVq}m+iAaI~Aiw~?reC_kVQV=60000gsB+3J~Dn`pdxgmx19A{hgns>oXkhsL8>j&wfIu2Rsv+R_ zAB5T1GyoL?1Q1BWpFe+p|Nf1n;TJ-~Kd@?uhChFRHUI<=#0HS!U%!8$YJib28yLY( z0tg_G2B7i3e*FSj@aq@44gY_`jRywQ69xu=0D?FP=vyd&x*M*V6|CV8P{Uu4OBfgc z0tjNmA4y3`us8lPG6H?}8%zRafgb(Cp!5f*6oP{xAq} rF#LPR@IoIX4%E%Yz;K6w0U*EtuUcjA`-_J300000NkvXXu0mjf+>pV; literal 0 HcmV?d00001 diff --git a/static/flags/bf.png b/static/flags/bf.png new file mode 100755 index 0000000000000000000000000000000000000000..ab5ce8fe1237a18d6809a5570024eb108cb14a3e GIT binary patch literal 497 zcmV@|4`Xj5kLT%`al?B=W5I`(ov;U*021-Lr1*!W5(gW7O z@cTDV13&<=05Ky_HBiN$KMcQt819e>gHP`g_|Np;&&;0(C^$RHS>olZ*Q41X9v27}ar6#W9}0h{^{OajIK0?h(y z_zOe~zZd`lhy{p$|NA4!EeST}?;nUxkP49VfMx;1;V%&U|N9rH;SU2q05LM8GXV8K n(H~UyA0);fa6B_H00bBSQ>$p&WfB*UmB!B(-`wPhZ^#?@C^U5EbbPyl_g=3Hc01Sh${{P9=HB%4| z34*<3-m=C?^;L%miR{xQv2*hU;8+Y&0Dxf-W~KjsusWFAC4@j0#9_j;X5z6SjRhH> zd}sd(7FPhVFdSi!*Zj@;_Sc`kfByUdk|3A-`STmZ_yb~qxIp9o{E-p)bLt=iKmf7) z+|Ix(`{&<1pm88mK&}8g1WG~}e||Ik`OB#Cw~m1UAb?na(Zlrn4}+v6P!1@{@CT$5 z&-#|8y{IY2iKmf5omHz(^qAp)ym^JhN+jk7Vet{H$(Z8=>|AV=V zva&!M00M{!p&AHub^kXuF^G#pRQ&(-8^nMkpk@XJfB<6o_wOIv5C1P;X6Wwu|KUB< zc%X*g2-OTg#J~U$KumBafq;(A|A`a+OH08N{X($;=pP0KfB<5Fs|GR7oM!0i{{QYB zSm|$=!=N@Wf}I2qKuka<{f7YtBjf)QCj1u{`~UM7nrdKh0c`*VF+c!8{Q&j%sZ;-Z zd;dRshENS5{{S`og~Sg)05QIL^-54s5b7kL(8GuS8yfz9{>%Ui`+q-vfW*P*^_43C z0mK4S`s2qBh&}(NP5W0_$$%QQ@R)`GfB*vkck5Jby^kNv00000NkvXXu0mjfy0pt~ literal 0 HcmV?d00001 diff --git a/static/flags/bi.png b/static/flags/bi.png new file mode 100755 index 0000000000000000000000000000000000000000..5cc2e30cfc47452d5bef949628e955a522d59e50 GIT binary patch literal 675 zcmV;U0$lxxP)$wbBBJ zMTk#;k4<3e#ePFE;{?TciOx=-NpIdg`t|#dcz^$YFqm+of7AU<7UGr+0t^5F#PsJM z(2)${Jd)SmT+KY5@!|h>po)L5-!r~>3uJux|0`&Jz~QGy6a*CiGyVtq1|Wc#zWw|0 z_y6C2|NnAvaR2)A>-NX%|3Ci{R?!hvH~jzU``ypCK7Rkq&&~h)FDNvCApj5nF#yj0 z0_X_*{{Q{_|NQXv@Av-qBMmR$teo!O*6-%u-J+8r3n~2s`s?uP{Qmp>{`~+900M{! zNC9;}eE(3IS9-C{62AZc<>Jx>%af}0@?r&05Jg0 z{{#T;0Os`NWh`ko4>SM%|Kw(60099Kad7|t0qcf^`tR-^sIP`Fhru7lkI#w#>Hq?W zkzqQ+@08y_|9v}t;{CEE%)%nTc=-MC@P)7S@!~g$((Ud|+28Q224FCZIGXF0FQ1zcbfB*dX_lJRr z;s3wCNa|2D02KoSAbE^!0Dxf-mZ69ApkCb5fP^9ydGO$cm6w`kGj(t#`M{tFlLo%j z*4%mm2&CaJSn02SzkrtfWBLcO;r%bLy5Gnoqrh)qC;VKmZT`F#yj00W%wG zw4zx17##T6*Z=hN0Tvey7!|wG?K;V)0{r{_`}_X<{Qmp<|NQ*_`}@YSvI2-@&cAgG z*R?p0?_>V(@&EVlEP?{x|1esA`||VNU68t8zyJRJ_3zg&hTp&0WMzR?0R#}s1|E|% zRV}tRkH6o2#3;(nsVMXI-pgBmh17ms`TzTu!pfBl%*_9R;OEbWDJei#0R#}sGpDd$ z96Spi@~bn7G5z{~^_!ZLy2#s;5B~o8&G`G*|6f0Ap0WS=_rFd2C(ubi4FCZEF#yj0 z1a!1=2e0}MwgDi3SU@2S4mePl{012eQ4J-3 z|Mm`933BS6zyJRJ1;ztF0D(08|NVzmQWB*4&)@%$um=Y`lmy1W-@hDx{{qQh3=9AP x#JH7#;TJ3-|G=X54_FW_j)5c_0|P*S0RT0dOSD~(4;cUe002ovPDHLkV1hfJDkcB` literal 0 HcmV?d00001 diff --git a/static/flags/bn.png b/static/flags/bn.png new file mode 100755 index 0000000000000000000000000000000000000000..8fb09849e9b5712e9cdd8a2c25035da201535cf5 GIT binary patch literal 639 zcmV-_0)YLAP)8n_8%|dG+hlCr-g% z|9<~wU<9iE{r}%DMphZ1Jpcj3%*DZBWo-@72DFWlk(-gj@!ngb-$#D&C_i9e{QvLY zw|{?r|NHlgiHY~?^IHG`05Jg0{{(k=dF}7->+9=cXlNG}79t%T{rC3_t(pA#`tSX# z4jKOh|NsB|;rr`({{a5__y7Wk5omBxQSrlv5B>nb??0VZ8qCZrpS+?}gatn>o%-+B zPl=+||6st##PspQ2Y>)#{Cu5(QJ~_^?faD-pMV;E|7MwLubjQ@B-gLso$mVYgECpU zxpfp2fEt*XnBKpC4-fz`0M7pb@zVeZ8g>5r-~k2r`Sbhd;{WmN02I(80QmHEv)Ik{ z>H7Nm`}_MdF)?FhWi>T50*LYBMFw`s0-y$le?J(QfB$Fr_2c8e-`_!j`0PG|ckZ*_ zzkY$-`sc5Tips@{7Xbo@1sGC5IYwrQfB%2{|MTZR!ygX*-%McG4cZmTY ZzyK0(F$K@T-Dv;-002ovPDHLkV1la=J3;^e literal 0 HcmV?d00001 diff --git a/static/flags/bo.png b/static/flags/bo.png new file mode 100755 index 0000000000000000000000000000000000000000..ce7ba522aa7e948d581478432643c230eed1a658 GIT binary patch literal 500 zcmV^3LvnC{|x`%yaFl$ss8ha0V@6XKS=c-5cwO(_{}IL0ki=i zfLOjo{AE-9^-mn=h(G`Tfz|!{{r?|W+uz?{^yeR#!Nm9NlRN`J0I_^YV&Ikj@%Q)F z|Ns9m{0FN3^Z!3k!*8HnFvf4N5xas50L!z?-wXsAPk7$ ze<1l+iQ((fPYeJ7#KQ200VpKFA^{3Nph^G!{9^b86oDW}(Ek1R7ZiL9e}Ret0*H}e qBRB&8AR!3%7c6cef(%d+Aiw~vBYd|xMihYn0000j-HAXl7XJGjM{~r+i{r~sxzrQwG-&h#_Y&p;L z=ieV7_s^f-zyJOD{rC5(+EoAn1k&)I;s3Kw&;LT?{{2}P{Pq8T&j0^^J4?LvUd;UK z&+k8ffB*XXONL(tXahh1fi?X94^$0Q>Z$uRRO)Y4)uapmB!2(-ul(c1=C+V!kAF`) z$PCo;`_FHns{jIs3Fu;wy-Z(c2YwAz{&V4aXk?bejFO*Op&u`@i~PecqBpL@DIoojb8mb+WHGK%fG2>)a3=iVf_~v+`s?*1;!`?Kmai^I3i*ZIYtpN f{g(k500bBS@Ns{bTs^2gCr95H^s6Fo1}O2_S$Nfl}4;<}o-r{^R8Q_xtzX z|Nnu?|Ni^;2gm@D3=F@4EC#P1& zzuV{ie)#0qf2Lnh)j(~3VeG$ufPMl9Aczeh3x56n#l!R`HRQLfpFjVwfkN;%I39k( zVgne^e?jDThF>oL0*Hk{T6(^^8pGqq44*zhqZ1OZzkZ>_F(mFeH~<0+0A4S6=>Lb* QN&o-=07*qoM6N<$f&=*Yr2qf` literal 0 HcmV?d00001 diff --git a/static/flags/bt.png b/static/flags/bt.png new file mode 100755 index 0000000000000000000000000000000000000000..1d512dfff42db1ea3e7c59fa7dd69319e789ee12 GIT binary patch literal 631 zcmV--0*L*IP)?&DC3JV7l?ccjcgB=Qq4l4w|Q;eOZ4z|IjsEI`#PYSloM|AFHF zfy)2>XZQ=$@t;lU|F1tRzpnmg{PUOLH{-8A|F{4CvUU?d0I>k|0TuuM^_1cNUy$nm zzZn?*{^!*ACzSEy$NyhHzB0Wn`TXRU=!%=n%Ci4h82|!^32gR%glZtk^6USnb00o@ z{`LDW>%U)&BK_|-y-75RkKVi&O=|xC<=6keK+72b0*D2q;Xlai|Ns9mF#h@fM(h;aV>^!x1-zNu02XV-n@ zm3imZ@&EI0hChG)|NZlafdL?Zn1I0yH26P<=DUx29QQsc%}izF;QV-S-hYOl|1V4z zX|a-<=Kf#g*Z)7i{{y|szyJ_HEKEEM|C#>$KmJzoZa)M2-~Wm-e7Cl+vi)L|kY`}} z&A$F20RV*|BkB*O Rz6SsR002ovPDHLkV1m;fPLlut literal 0 HcmV?d00001 diff --git a/static/flags/bv.png b/static/flags/bv.png new file mode 100755 index 0000000000000000000000000000000000000000..160b6b5b79db15e623fa55e5774e5d160b933180 GIT binary patch literal 512 zcmV+b0{{JqP)O=a{vExMP2%`MCSoB^FIcLe_%lf;|~%E5I`(IQNh}3Ao>6Q|DFUXMn*>AqQd`w z|1kXd^B;tM|Njjl{{hM0zwd6?1Q0+hV1xeud-4=Wy?p-%sO`^#2S61Jzk!N?s)6X& zzhA%p|N6}=D+{y%Ab`Lc{sL9~1=0UN4*CD*7s%9KAf+JHKs~=eB-8KTKvw|-5R1&; zzd&a|ob(5%^Z$Q=wHy9p13+aOpFRNu5F>N&`Tk_-7w>=n{RejQzkfh&Kn{rf10?_b z{tFTZibx5v&dxav5I~H7|Ney-|DWN1$%1FyagzUW0464;_wU~W1Q5$TW@eGxtUvee z3vAf*8|igK9~@*rr66bh|NrkNM8z+V zAV?>O@ek;bKfu6d00k6 zPW&$KB`I@TtA?2x@Q~7pdcWi#1>DDZ2>MuG0I@IumHuaV^&7|soAMvT0IK){RtF@1 zgH;3B;_Qq-34j1%{P^)BFE1~|NkA(gBv!!4$aw$$eSiRB1ga=2D|__l(H|iA4T2Ex z>lc`SQ9x2&UjE?0g8%`<0`lvhzd$}*14J4{IhY2@0~G@V5J82%q9;EBlXu0U&@_82I`BfBC|Yn~P8llm?myQ3_K18=`^X_ivyEfB<6p_xd%%#*GZ! z-C&_V5IGPDK|g;X*gypg3;+Sd!XPTj0Q7fK5>&$Y{sHB| zjK9DB00sa3QR4q|tc?L6fSCSm+3>HW`NxbYpP7GsX8sK%KS9yYPfWi)GJ)AFzdp14 z{>t>1fsFwmfLQ*Ci!yxq#8guv=_mQ;-(Rp{AoSPbXFRCwBA z{KboB21 z`ppP*BG3|`!vO*asNvt=e_;3gWsp&PA@E<2jYs6ilRy6-zmSku5?~OOP=5aV@4sI_ zSN#QP00zQ!JD>SpAKYgR_QStF|9~F;2M|Ck zz%U1e+FyoWe;B_0VVclq;}vp_kNy3hKMWrj7*{kqJbMcaQ;_Pve;I)x1Q0+h46j}> zeiN4E1lkA+>|e|*mzJsW^M3)l^W_^hf&c&c`Mv->`48yHFF-%s0|+3-*GLfwiRNz% m3}3(u4lrUsie?}H2rvLBbQv(L;??y40000e`b1WGV} ze#gbd^&bp=ef-GykAYc$@BhDltSqdeSy?RXJpcawy+5fJAb?mHcsPJ&{d@EF@4HtJ z)qno||1xd*zaM|Ot4f#|8A1AQ-~Pubz$7IBv;-i4SQvovfB*ge{fFVtAE4aNE7yPi z`^Eg=5yP(^Ur(Q5`TLjM%#`8#_rHuB|9}1hItd_vSpNO`#qjs<|KGp=|NIHm@MXqK z79K7}ZvOwQ9Df%s{`~lX*xI%KzW-!k{Lc96Cr|@G0I@Lq`0?-epMSr9|NHeD?&umBG}6iH(DSogJte zDERNk_kV0Zng09%Itd_vSb&=T{rt@+B*66dJ0my{fpNkvBm!jpV_;xnVgd@XDk?Dx zh=IJyzyJ_HjJJUrz)|>#fr0nRl^;KTz#|yK`2G9$BS%LzureS32rvK^u`=B;c)+&+ O0000Vbu`-)NXk-Y`p?2$B#e1 z{(buQ`}e;;zyJNd_UF(2w_nb@VUiUP2igD-Kuin_BL6vl`zgIQV*mR8|8G|2U!T7I zn`-)Ow$bxne}9LGfB5z5*XcJ*K(;aeSD>o^0st`p&i@1e@&c~g4N@7~{}B9V!5sbp z`j|K8<@Nq-&kt=P>@pAZ`T7Q#;RiPl^j;kSgdzX}05Jg0{{#R8=f>y-z~LG0`u_d< z{QLg=2?6_k)DH^)`=sFo8YTUi-v;{r`o8J{6Wj>^)c^vB2^cJY|Nnmc_5b@He}DY@ z_51JdufKoSslWR1>-W9)3`r;XfsXn0`_Fc($H!lT!V@5Xn1Igu{qOIuf50&L{qg7D z?|*(LofMGa_%_k-*{}b_0g?9mMSwvE)Bq4bEIr*1})*zF_+U)&LMdEMOb{Nb-vOh6FrNC(tkd{&4;N%g_D$&)>g> z0^hO}m?z%iIsOJ1mka;_#K>R{i_RZNQ42x8VJSe8f#Ern2@qfa%&RHCyvg>Q00000 LNkvXXu0mjf=TkSf literal 0 HcmV?d00001 diff --git a/static/flags/cd.png b/static/flags/cd.png new file mode 100755 index 0000000000000000000000000000000000000000..5e489424884d2ec9e429f70d69af00edf242a077 GIT binary patch literal 528 zcmV+r0`L8aP)JkPqeYl28iLgD=0{><0$P44T5yOrT$dE?(KkwMFdoG^-J zGv9P)Kk|i5`lcNgUUAbboca5{hI)v&h!9!~`Yg)Ld}$VwYqqXn@gVLi>3LSVGm1W? z3qnDJAk6chH(u7f~FohUBCxfQDx8?5BQsCcprAnfVhO SHC~zk0000@|NZ~|iEi8i zh~?j3h8^dV0y&$fY|i?}`2XK;hJSzm|G$6#|L@;V)&KqZ3sU;$?>`_ZF38C6g#jRd z7@s_ODJ3Nev=9gw8UKSQhX4P)z5oCE{eQ>y|1j|H-+x9%#`EXT0R#{W1H*5i5@u$g zs{agN2m-%;fixfipeaCQpFe*F2q2cU!)f`}`5%6M06O*WzrTN({{8*;CkCkD_wPBk z=llWket~@P=ieVecEOTuB>(}$vTge|RYlbYUmpDW_v_E!KfnL|{{8n?G|>28zowm@ z_UrGj-+zAtrGTUoztWctUjPD#h2amw@BhDn5OHz(52cFPg zot=T34qlT?57Mzkg5?0ssOG0Ftp>paW8OyZ`_I07*qoM6N<$f+2k} AjsO4v literal 0 HcmV?d00001 diff --git a/static/flags/cg.png b/static/flags/cg.png new file mode 100755 index 0000000000000000000000000000000000000000..a859792ef32a02b41503b5ab5f216191af397e02 GIT binary patch literal 521 zcmV+k0`~ohP)i@P`2b{=v9^Ktp0uZ001fLMSM)r!?%mH+B91 z=ii?+(ckX8zrd=&8g~5t-|*}I50LQ;KzRlRfB=Hn08;wv->)Q*Kc0LLgTdsU-~VfV z{r~#=|1XdRMzE6r0tlo5X#B6gzhXrG`18Y*0!g6iieLY~Kvgqz}`W zLWO>Z3Lv@r7+CdZpiy8Ae}EeP0z(_<2Y>)#Vfe-1#`njMUlORAfdMG=o8iiD#%aG9 z#Q!h|feZ$rzkeYJ=p=vuV)VVru?7U|?FE@Zm|i>fBlzF zc~M_qKf%h=bAcoS;}NE7f8|yFe%B9?;;8%o@BeG_!|(4qhyo=(h-XBmKHXpc{~y!A z`THH3fsDVeudko)ARzm9UL&JI!+~uEM*rBES1=kd6zV%LH0J*N$gIQAc0y}k9qTFv z4h1oVG?rB#zNY^8{QUp5wE>>R#S4NZQd1i@F)*?OF@6y}@zmk^!Gr7L9asuAf!ae1 z{{CbBBH^Az=(+fAb?mHzA!MjRs*H~|NF=I z{~td;@BjZG-hUVsqZ#w(|L@=b|NQ>{d(*K^00G3pzycQk`jp|{UxvSb;p*Vv_V?Sr z{{Q;@@3$6WKrBG#F*5vR z`2XiW&+Xo6{KsbP_-SF+DJF`pL$*;0gaz z7NKVhyo`U;4*0+SK#>rfFFfafF5DUYXKh;r+@n*scPQUy6`!63S zGXn!71H*qtMn-04W+o=4|487=moEST#KiEAA;m(3;Xgy1iO{3BKc9a12~-UM7^Z`) z1qdLZI~bN-c=z}J|D88K{QmR*&tHcBxB*ZDKmf5Ya0q<-!`is-{h$8~f7m(x{QZSX zH3Jv`1P}|uy*o^wIGI2G`1kie)4zYe_&EQ6|NftW0ohon1}3I|Z{7d|5aVBMp0ssVo0Ek~;W>Z#0SJsA+2j`G% zv|UVeYYs-#Sn6_J90h1VosR?LBU7{U1rQ6+R0f9sPrg3=`~UA>#=n0a|7Q67_y6zT zP{j57|G!`V{{zu)Mn+knB>(|98e;E17s>tTLaMG-~Y>h{r`!g0jL-tfS4HmF#P%V_xIo5zyJLP zk|2W%e*G8w^1X|KC618W{eAoCFX+EI literal 0 HcmV?d00001 diff --git a/static/flags/cn.png b/static/flags/cn.png new file mode 100755 index 0000000000000000000000000000000000000000..89144146219e6fbec7eaa89e1bf4b073d299569e GIT binary patch literal 472 zcmV;}0Vn>6P)$bmtfBa_T{rmsVufH!rO2O)W0!b+P{TrwO zAb?mv&i(NBbu;G`sX*)cv$d*%>MiL-(QdhpkjakVmyu%k;sfcNRj;yhJaxT5MTg0u5&QfH8#Bf O0000XbC_7v4G9~kE;3? z$h?1GrT>4y7{3|*{r>Zd0U&@_82$jY{AFPH^Plk#hy=QU5o|Ds0oDLyFn~2M0QE2c z1P~*G;PKK9g@-SH{rUU<_aC4k|G@~v`1Kn|{`&=C|M{yZ!G37cNq_)iVfexD=MNA8 zh5p0Hf4_c1v;p<}|Ak}_F!%rh2&CcXZ-(!`82&@8$XA^gF6?xq}zd#y5N`WeVBbyB+frxZH0- literal 0 HcmV?d00001 diff --git a/static/flags/cs.png b/static/flags/cs.png new file mode 100755 index 0000000000000000000000000000000000000000..8254790ca72f98d9e79d94bdfcb8839b1fd434ad GIT binary patch literal 439 zcmV;o0Z9IdP)|s3jQ%L{DG0k=ogG+0SLgMnA-pV!aytqt1(q3VU5g2cTadE%W~lnu`}m; z-504zOD10s2K8+~RqF^K7O;8$o;>*sR0>r0`!|sM`x~eNg#P~i_4n8BzrTI~MgGdl z@-i@d0|+1%Q&SyHO(9WHu7Cgk{{@--A8b6x2B1zb1BygNIks=N00WJ{7y^0)%zz1kWJN^&bany+5X-;o*O`wU`+x5q12BMq=+`e0f-vAB ze||Ik`OBc90(3J#0I>iAmFf2%21!Yv97q%>_xm>^i2a8FLV}HlAfRG^0AlbRVNjfdgKH->)<41fMG{Q1Z53yA)}NHF>VM86o=*Z=~EMTLRklg;&|8vY-+ zh5rBh|L@=bKM?ZoKOp1JpMQV<{rmmr|L=eQfFkpA_5cJB<7Wm2?&_*f&z|!oCH%Iq zVPN&@1^xa7gnxhi`TP6#zh6KNfByZH;9_972M|CY z4S#m*VEXjw_teQhfB)LctFzlGTKpda#8eRa1F`|=V+j!s1_l{`0AhU0z`&K2_5c3; z?|=UACdB;@3Hy%?Ffai9!1(6P8-M@;JL%7#4}bn}Wu*W1^8Nqk|9@zxfJk8Yg2Rge z5=!5G`~e6c79IwMkAMHSMfCl8%kXF6O^EHl82Alg`~}6s-@pI={`>#;Kf}J}IRF8~ zc$$I1RCFdZQi0L={}0epF!T#d{sWT?V3G+SzyRi{Q|!NXWpDrh002ovPDHLkV1m+z B7Bv6> literal 0 HcmV?d00001 diff --git a/static/flags/cv.png b/static/flags/cv.png new file mode 100755 index 0000000000000000000000000000000000000000..a63f7eaf63c028615b2ded5878b5e14a7dbe962f GIT binary patch literal 529 zcmV+s0`C2ZP)*82p^=00=`tlmIeOf&y&dk@6oT z&CV8YCOfMzZ7b-;WHc4ffO0*K`UGc#9pHKW{n=1`s=Y4`sB0UGuD|F2(+4xFrs{6A+r|Fh*S$P>SRGs(%l z+O-QHfEa)O{tdAK=ovi517(5A-n@AO5I`)f0sl(Vm><0RZzq2;(QtLuuFT6X6;y@p zb-8u)9gSFj-3}5^z@SqUX4qfA01!aT3<}j|#!Osn3@^V(zxysO&hx#~ZN`f)vS*$d zpLlA?$HBnM&cM&k$j1o^^oKjY0t65vgZ)>ehy*ei5K#*ZyWju7F%Ll?01#jRixNU5 T4U6zw00000NkvXXu0mjf>cZT~ literal 0 HcmV?d00001 diff --git a/static/flags/cx.png b/static/flags/cx.png new file mode 100755 index 0000000000000000000000000000000000000000..48e31adbf4cc0074f40e95f87c1f103b91fe270e GIT binary patch literal 608 zcmV-m0-ybfP)Uz~~Q*L}q{yKmai^Fs!d`Rbj9@@=xl~KZbvQ|NZ^*|L@=bfBpc` zKOp-38^rz{DEepVv)`L`Yyt=%76t}3hHqR?<~aN{I`!9n&u`}MKs~?z|Ni|Cihlk3 z1w?Q7fI4M?HUI<=3&<7!82Y{{Q;@?^mDN?|=V) z{r~^ll=rtu5CcE}F#**BRkyY(adR>Mc_H{~T5^XRV~oVFSgBv#s=t2z{grn0SJIVV z|Ni~D^5u8)5(a<(0%_pmV<{@S{pr)+Nt0E6|KyV7{&xHKulY}Z0S*2Ic2cIyuhSoY z&3*a@=p=vu0%~ALNs$10lZEA9e*W!WzkWV{%9A7hYlh}ewm<)V{rd@2{rBIm&Idr} z{RV0P2mmnv&i?}d08{q%2kh+oUtbt0DGA2L@2{yn^Xv%Q%_4hjZ2Q{KfBuh*0fWjOcoPYi>{Qk`ejtlm`TPy!Q@c0|K1n4Ay00P>u ul!4(JQe+}W>@P40kp+Sq42=5$0t^6?P(4CrvcmZQ0000s1`2Y9I{~ve$KWO@Yukru?KTxgz{s9CK3*7Y} zZC_6Qf4TJkuQ&gHzW)Di+kXz$|9k=eg(Cm|XMz~|=g%L20Ahjo4`KiVr|y5|U;qEV z`p@?NKb!P_9;^R?@o<+hfSm*oKp+h;f&YIQ*bg)L>I;A4WVP82*P-nR{;Wu@%{Vvyu7@~4txIf`R>OD+-01E zIfRil07L2S-Mat*#Q65@TRuKMWMi;}EJy%|ff@h;2;_%%@7_UT@edf{0+7H22rvMY Ws9gjvbyTka0000? z0048MLcfb{@Lpld*gfdL?Z zSQvhRtN^J#x6%GQNHxSfxHgc;AD{-1tAIKH0tl!9q}uD*5!1Kl8Kk6va!f$;fJ%WL z`2Cv^NdEc54D$xi27mx!VfgXqT8ME7!~2)OPy-`SXu#NiAkhzFFflLy1Q-A_8F>@M S6G{sJ0000h<6BFn%a z@b8~2SoNP@zd$;E{sbbRuHQd?{QCI=sNwhbA3*&Qe}GP900=;09NYi^fU@pUdVa9*13;+Sd!tjgXKhXQEMobL97(p6<{RLvMGBN!7 j!N9=G@a-1^K!5=NcXWu!7_DDe00000NkvXXu0mjfeQx^H literal 0 HcmV?d00001 diff --git a/static/flags/dj.png b/static/flags/dj.png new file mode 100755 index 0000000000000000000000000000000000000000..582af364f8a9cb680628beae33cc9a2dbe0559f4 GIT binary patch literal 572 zcmV-C0>k}@P);we;9uK`S<6~zaM{qBL9B<0yBR7V`E_e2q4D) z|Nnpa!Ep64!{fLA8NdLj;oraifB*mg`;Xx-kn#6Fhzn-q&in!pKrBENJRA&WD*ySo z7*5@0`26EP69WTC_22)0z>5C-g{l_hVFa245I`UeKudt6h7^Mc@BgDW81BCO4-x~L z`sXhc{R3+I%fRsKA3y*x{R6rHsA1>M|6jifb2E4w{z{xB{`~z5CPC;Y7bk|9<`c2PXgjR$^CT@Hzz$KrBEfF#?VC z^aSdB^z+g5SJMxCJOGqNsQwQkfr0#&=?~CJ009Kjz|71H^!MIRd#Ajb^76;aUyQ$y z%m(TN#spBq-#`C>zGeUjAdrR+|30kwu=eoBL!3-pGMq9%bs!`E|ACMovw

4;Zk2 z8GbPU1Q5%#7t@Nb6*GKbU;u{yA29j{CVzn$|6qa)V3LCYAiw~8(_SNKujRx50000< KMNUMnLSTY(1rd4x literal 0 HcmV?d00001 diff --git a/static/flags/dk.png b/static/flags/dk.png new file mode 100755 index 0000000000000000000000000000000000000000..e2993d3c59ae78855f777c158a6aae6c1fb5c843 GIT binary patch literal 495 zcmVh!ZNvLM`<}kPiIA3?K?Zl!VJuS0ABN12uI2v;s z000mK68GQM4oDR3?|C6;zBc4LR82Q1eETXSa+3nD0Ad8%4|Ml`Fn}2U{~ypshW{9V zk%{T!hYtV&#KHiVV*o?2zW>+&Bgm+K00G4EikX==E9>w5`yf~S`o*<00G4K6dZ++hy)_Bw{QPEdi2K7 l5H1Kw2asrHVqgFWFaQRwS@oh;XP^K8002ovPDHLkV1foV*8Tth literal 0 HcmV?d00001 diff --git a/static/flags/dm.png b/static/flags/dm.png new file mode 100755 index 0000000000000000000000000000000000000000..5fbffcba3cb0f20016c9717614127b89db4c9664 GIT binary patch literal 620 zcmV-y0+aoTP)yt}{r~U(pZ|aU z{rk@#!dhJXj+vP`D&$&!2yPR?Jud5I`&tqo00z_V3?cpb$_)%#~li z5Bw?p&G@T5&5h~tB<;UIJ-`3_mgbQL+5iwhOdtm^{QZlh+Tg>NcGo{qR#UR9ewx4g zlzHy^uRp(j{rmOj?;oHBfB*n70M7pb{ow!s5r+W$=Kufw0RQ~_o$a1N^GPoTT-yiw z&XGVBSbe$r0&xrf|M~#~9P-zx0st`p&i?@b004Y@cH`sX`~3X;`}>j`1PlZ1WGkKd zF1~FN+w&9T}cJeJULy4V8r?0tNHM6WN&<2126ppbC05A-~q$vMCOd&N)3^rn&3WaiZo>@dB zxpL5=L>h@#UjVT%{Q39iA58Ths0J3s|NohoLF&Lt!8(8c18V>XAjZFc|1vT%{s#lF z^Kb%2CZ>-cJ^%y|<6Q;@;r#qR4;}z*|Nr|B$h_ab1b6QI%fu2>dIV_O?>~RRu82tM4=f|&Ke}8;oX5+eBw}y?G6)5=s|Nnnr@aNATAPEpaEN{Mj=m^OD z&%p5S|G&Tg{{H#<7bL;LEGj9<&cFmz{_j5mJbLs9Ab?m{m{|TZ{D1lB9Z2clKfnI{ z`ThHs^2c9)q;CF`l>Eoa3N#g>nv07INCE^93jWH3lKe}28-VENu!{qxMpm&svFOiawo%#4hT5U&FS z5Yzu(KY%Xz`RDh~-yl6N|NT~b@qz9A2lm1$Hf43G`D-AmnZXVNY5)izCWas1fbRMA z8?52ykLBVV-&q+tkKFpbbOC=r`2SzOfQo=l0_p*hfB*gk2q2IKpzD7Eo%H+Hk6%A8 za57|Q3rv;f;d1r)FDv_xg9F*eKs^8f#KQ37)2~0jMR){${rwHH2k3S7pO3`Z{#jf7 z{|`16Y&=9YkOT-IMh0&|hF9+yelRe6V}O#tcxPkSx96}BCoe=1&?OKCkOT-Y05IoG U$(*n^qyPW_07*qoM6N<$f?|9Y@c;k- literal 0 HcmV?d00001 diff --git a/static/flags/ec.png b/static/flags/ec.png new file mode 100755 index 0000000000000000000000000000000000000000..0caa0b1e785295d003869330fc4e073dce07e7f6 GIT binary patch literal 500 zcmV1sCzZm}g`N!}J$oTi?|G$4gL7*^D3`7C}Kmf5Y{CmeN)&f@km*M|^ zrvE_l-~a!AA&BAspa1{=fXIJ9!9O2vbOQts3j+fX{b%^|8m0my0Yd-4N`WN9@BjaR z=no^SIM8~400P%s(0a|A0FHhM?*o#se9Q zEZ;b|7ytr@MWm#zEz$bb`!9d~{{Q>$@1MW_!07MqKOpw+zkh)g(B$8L|49h*Ov!x= z5I`*NZ%IAX?Fbu$UUAQCA3`wxix_2=I& zAouq_SzðCcuS!~%52Kai0?gF&VORsRAR2~rJG2PFT1^!)w@)C_d-AAkU2Vc75Z z*R<@y`9z1vevIh)-p7{p`5C+7f|6l;f1_&?! X)GmJPc-xs)00000NkvXXu0mjfGFPrC literal 0 HcmV?d00001 diff --git a/static/flags/eg.png b/static/flags/eg.png new file mode 100755 index 0000000000000000000000000000000000000000..8a3f7a10b5757b006948ea4436fb242d02dc9a4e GIT binary patch literal 465 zcmV;?0WSWDP)LAHVtk{r`=k{y)(2e*gi*sIRYISXlV_^=qKp{(!;n-+xj9 zUjemETFMXP0$m6sfwJP_;%#kh009JYeOg-Dy?gh5gTXH_fG|KLm<2Qhs6|CZ<>JMQ z009IFR-loRl9E6vpeV=!FaTTi8)D~Q7yv2;2q2OXK!5=N{?|@pNV(X=00000NkvXX Hu0mjfG@sA` literal 0 HcmV?d00001 diff --git a/static/flags/eh.png b/static/flags/eh.png new file mode 100755 index 0000000000000000000000000000000000000000..90a1195b47a6f12c70d06cb0bd0e4ea88d7bfb03 GIT binary patch literal 508 zcmV`hKmn*~pz%QT=MPXRKmaj;?1ifa0xhloNlE|L zuK&--1mwx?-uoV+`qwW8u#*4+i1F_GyFwg7fByafIr{%Uh)$p>Ae%w(|Nq~=m~|`# z{`_H7QhIal96$iEC^sml1*F~kc<(nb4FCQ91q_kDz!3TkBLDsd`Sky<|4qNomi`s~ z`xoeVfB<3v8uI)9A4wibp!A=AfB%5B0nwj-e?TNKsQ>@@`|oeijK3Q@{{o!^5I~F! y*$fQd7#Mzm(H|HCnf(WhfND7yc3x%x2rvM-AWsdQI)rrq0000&(jx%j7OGE_~DVuFcQkgj@33fJv($pjj zgoNxWFM>pG#K4X+%S_Ys!f>f$mib36%ekHNec$;y5njB{!+Y`YzVGwA&4mTVh%ikU z03gD2Hn&LPeNu%hDG7PUvzrphs|^(-as$IIo1LmPya%Hc0Qn*6qc4XX3oKoa+Z)_XBQk8 znPA)XelBh#6J<)fj|w>7X+~Yun^@Bp4$+N z6L8rb{%QnJN{fql*fJH1L*2YjUlB~CXS&&LY)1V3h&68|x1_5-(4l3HUgs~3JvLXI z$_D=zL{dTnq9RK`-w~w|sCYqqA;@OoAE0!{9Gi+cF%zA>5*8OAiXWs z!A~!@Tb_6WJ;mn(q~>CYJ~Oq(|Mc`miY)G1d$)?S_lf*=dz3nd-8+hwz5w#U=!7L- z+Ve0W8Werm#o=KvYxRVVNtM9!poHk%m;Y{gxKdXC|Y{ fc0^aUlspXz7vm>S7OoCUZUIwXLGJ6E%Z+~lY(hhH literal 0 HcmV?d00001 diff --git a/static/flags/es.png b/static/flags/es.png new file mode 100755 index 0000000000000000000000000000000000000000..c2de2d7111e3cb59cf6511dd2ab045e824bdb43e GIT binary patch literal 469 zcmV;`0V@89P)@|4`Xj5kLT%`al?B=W5I`&pe;NKW0^Ri&h`xRJ_x;0v zUa?=y?0^3M|NZ~}FE9c#{{3cP{Qd6}13&;Vf!z&M{pZWqKYu4MFm$tgedF}w=P#IQ z7-9gT-$11R0mKA$(qEu4%ok$*y!^wMRm*x;`R7|k6yu?K{s8?55I{^|9{?Tjhec2I zv+6&FhFWG_BbNVc|Ns94tNRJp!0`V!Py;{!F#$2enB#XZaohg-5%Tlk#oa&nzQW9g zl0Y{D4gK?n0U&@Fe=;yIr=|V7caH%YEYL84k`Tt9-wc2LGODP&y?7BIfLMT@X8Qey zK~fSFpuiXa$^kk7RCwBA zWQbH``0|MX0{;DB`1Ob3-!Fz=zZw28fY1*HhF@R=VQ?@21P}|ur+3w` z_wT=dfByab`{x&s{PXYspTB>919^Y{{Qd`I{N9v10U&@_7=ExZ{APUe{`KE~Al1MB z{rb!Jhml3<_uqeCzux)%bv7|NkFAvw@aK@N+YWG5`bsF#yj00sZ{|0ReUZ0OJ4u`~d&_lgxzd z_7grGtKje;)ax=32IqJ>VE_O6|Nr{|0Uz@6!2*a0?AgCSJ_s@V{`!jztXlEUzkg2h zOW%AK0ILQg2A~)NKmdU>0L=y=29PKt(~s@sMWK)O87MU|4G0ImPt*+y7s`{{I1L_{;G9FVHyv z0R+;(^!pEkq$JpwzYKqVGyVRp{reTr#sB4{{{Q&{G@Ah!GGGK$3=lw!Ux87Egcwk{ eXi`7`5MTfy3O%OUuKb?>0000SU^I57#IKohy|#uQJDd#=|98& zUrgMLRb~JG{$u$2m+|*M=0AU#{`@s%|H#1h=ih%I`g`z86F>lpk-UOTf}FCMD80)oDIYC+&q4vMR0s0&DpH|L=c>-#`S^3sJ`m zRPz_88i@Y=|MmYr*an6_AO0`^1P}|uzkh%JGXi;k8UFtPIt#4m|G)nbm0000FP2AE)Ir2{}>qlLBSs|`Qg(SfB<4)VqlOE;Q=cD|Nnn$ zna02W|Nj1E&`=Tpav_4q;M$#E00G4E4{SI@`q`VGKvVzz{r4XmU}R+c_2(Zz0I~c7 zs`v*r?Dty(;z&PFFXX zRA5t=4x{1SIibD)Vqy6A2V^D4P_SySA|L?j2ip1XFA)9%V~_%1r~w2J3=}{2Oiu1 f7(RXZ0uW#T>&I!FfdIJb00000NkvXXu0mjfj-u42 literal 0 HcmV?d00001 diff --git a/static/flags/fj.png b/static/flags/fj.png new file mode 100755 index 0000000000000000000000000000000000000000..cee998892eb316c3293ef2d52afec9218bdbbc03 GIT binary patch literal 610 zcmV-o0-gPdP)2C05Lr?a%1G+Sb3M_ z-f!*)-&mJ@lxC7weD@!u;s2li|9<}wjr{Zf&o8mqKR`Cn4*&rGF#yj01QaSLwCD}R z0w(ww8v*|PzTN}jB`Pj8{QK|!{{8;|gOCLd|L9jy6{oELG6Dcq@B)aDq496GGsCmb z5T7wXTnzN$?|=Wl{r{i6vr6{G)xV#={AXc)t!L+QBoiQjSb+Zc`=1dU2n>I~p8E|B z6OfY_{`1$ji1Pn`9_T5yZrhJfj0}g~00a;V(9A!7nZZWFG{8az7^c++|9dI@cmDl* z!Nvb)UorrL86bdIfbsI1fk}{;;V;BV|AE?oY(}v2K-{x07*6Kx`SfB<4-V2A|A=r2_C101z~ iU~vp#0R6xN5MThlzdwv9U#bcK0000}CO1*!he@c;k+ zfB*mg{rg{#hxPwIh8G{d0|o#7{Raep|AEAFCm#U_AQp((@4x;AD*Xo({rB(3@4q1y z(m>63@(hzyJPYWMEi%>@iRTXyxzU zAo>qT2S^W413&<={Q1WKlmMyz`(Hzv@8AD_R~~+N^7b200Z@m&0zc4{Q@7rNwftxJ z^$Q??fEu9g1Db8CAq;fMkDq@pJa`8*&sI~^TtyHla^%`8uswf)HUI<=3()%@Pl0^! zf8Ui?K|l%XeRX{Qd(n@juAHz(D*15I`UefB!>$cK-hRUqIf!|Kj}Y zKt+#Ue>r^ZHOMRf{y`i940V72V*2%m0pg)Q5O4ka4>U8*PAAEH2(%ZZ;ol#C0AiF(UW*)& q3=s4Oj6m#vP&UxAe?ZIt5MTgFMVEBke8_SD0000BE0lK=nzFYgc)d0A2*B+AFf z2joHok-@WP&j1351!6Wt`q9fjf1W;g`1ALFY=DuG5oiNI0I|ST{|2JJ|Ni~?`|A$_ zRt*pr0t5gt0M7pe4IJopi4@}M{rvp?{Qds``}+I+|3-D|`uqR;{Qmm<|NHy?`uqO- z{Qn;q1i_Qs0*LV@1A}N|@t-FT{{IC^{`vn0sPGp^)o&2vABgb_!eEtCyu9%!Kmf6* zGhfda5_|CT&#%8A#S0%rhKer*8VNG{57cZ3sU*g7is3Rq0I|G(Bf-nd3vr@r@vHy8 ze*OIQ@9-oMOb-A(eJ@7=Ab?mP;SCW2x*O<#U%#>Y7zqCS`2!F@APw*!ml9!S{vjhP z$_zA&0R;fLP(1(v#Q5^%OL#2G%0Af7VC%@R_vTF*lgG%);U`26kn-@hOg zU%!6+4+cOs(0HIde9xZz`}Onxub&LUB0x(30+2WcIRJn#2ut|?gWYu1Cf+!-K%B8# zdf?1WA}#uZ8oj7u>$I1i0Al&`=O0k%-@icgAIJnM0xA6maSq6BK-ECw|NZ*S`0Lj% z1_pot6puj;05Ax`F!=umqj7^frO?t|3^&I1kxUq9yECc+jQpY84SWH_0#pxl$?v~F z@*hy-KN0|X07U)z`4{NpU%#2aHUI<=%a31wK(7Du52Oc(|3O^?R1IN+RRjI-n*kVB z3=9AP#PZ|EACPLGJ%9cJNh|>9B%spYzZw7h1%?tp0I_@ndg9MNE>313@6R75NcceF zkr51-#U+7;F#`Sf7i0rK0I_`g_NQ&Zk)EZ(2O=d>QH$KN3zEi7S9u{+2K>GX4ds`2QcM z=+A$K-~a!^(JwH9Fn%*K{{Cdb01!YdV9)*qi~a#?`wdg{8%Z^Y!NB>w;@|&31~6!UgVU(k2*|8J(R-+sudaynhucHbwAMTnor{mwqO^w7JHzaBsT z{O^B8RYf5+LvDs&KmRKVd78=o{`1#HTiEo_OolaGleS)G+IQ#sUI`b*pv<`1zCJ=H0jd{{2S>p`ri%{LsXJ%FbMS z$#S`6f|?OG!^Jxczkf6Q`UNF{l0Sd`ad7zm>({^EzyAS6{{CgrkluOb3l1A>ZU2~A zK+FZ=zkmP!`TOVhpFbzBzFaPmD2$N3;+$pK?>zdet`f0002ovPDHLkV1gy;I?Vt8 literal 0 HcmV?d00001 diff --git a/static/flags/gd.png b/static/flags/gd.png new file mode 100755 index 0000000000000000000000000000000000000000..9ab57f5489bb9ebb6450cb27f4efe0cfb466144e GIT binary patch literal 637 zcmV-@0)qXCP)@|2i2MUNJEAGBA`g{QJZ3ub1IpEW7h{~Z4K zJ3#Qa=Q1XS-;5h0el2+U>(Te$zyAID&HDTIKad810Ad2W{jW5`@9y)AKr^5J{4Kqa z;cw*UKQW)B)-pW&@%z{RUqB7N{{H&&_Ycr?fB*vd;rG8kGw%JlqX`uK!_D~nn&&T_ z*-Q+-7;nUX=6mt$`7e;3-;BTi{QC{m01!YRC;j>JdmqEEKMa4Icz%Tm{+4F_^}h({ z_1{sye%WyRp84|E^4Gur0Kxx1e;6150*D2Oe>41%=Kmef^V^IA7&yOx!2%AYU;o*D z%dq`!;`!w)_PhDb-(PS30!;@9Adn3rpZ_$9NHVegX88Y?;V;N+#{WPzFy?-P;*ar< zJ?CFrnZE^h{{CWM00h;Fvzl@K2fHp9I6dqaaxb00=Mu XLcuQ~?TP?t00000NkvXXu0mjf`7udf literal 0 HcmV?d00001 diff --git a/static/flags/ge.png b/static/flags/ge.png new file mode 100755 index 0000000000000000000000000000000000000000..728d97078df1d07241ae605dff2f2cac463be72e GIT binary patch literal 594 zcmV-Y0^8x|9^h-OG^F+g7@$L?BC01YQ`Wbb?43;K=s|G$6#bNnb!1Cx>Qe>QfY2m>?Izi&U8 z1o&Rm*8l_%%a6%3nS?}u4*37)&;Q?l7=Q-<`}?1Z>;KQLY|KmGQ@ZWEch0Jnt zUmm{%2p|@g=ujpTGX@n^21dqzKYxO4`1a@2NuYivJ4XgKw*UYBFf%g!{qd7YP>5~& zE`R_4F#yj00OjT7{QUg;`}^~|xBB|}`T6Q!vcs262Lz;t$n|1+qbnVARhhy8{z5C(*C%JTg?tEV3%;s64O@&5h$(1-*>2%Ak`A87BFlP7^( gh&l)WvH=1N0MfQja}g1cO8@`>07*qoM6N<$g4hNuZ2$lO literal 0 HcmV?d00001 diff --git a/static/flags/gf.png b/static/flags/gf.png new file mode 100755 index 0000000000000000000000000000000000000000..8332c4ec23c853944c29b02d7b32a88033f48a71 GIT binary patch literal 545 zcmV++0^a?JP)lgG%);U`26kn-@hOg zU%!6+4+cOs(0HIde9xZz`}Onxub&LUB0x(30+2WcIRJn#2ut|?gWYu1Cf+!-K%B8# zdf?1WA}#uZ8oj7u>$I1i0Al&`=O0k%-@icgAIJnM0xA6maSq6BK-ECw|NZ*S`0Lj% z1_pot6puj;05Ax`F!=umqj7^frO?t|3^&I1kxUq9yECc+jQpY84SWH_0#pxl$?v~F z@*hy-KN0|X07U)z`4{NpU%#2aHUI<=%a31wK(7Du52Oc(|3O^?R1IN+RRjI-n*kVB z3=9AP#PZ|EACPLGJ%9cJNh|>9B%spYzZw7h1%?tp0I_@ndg9MNE>313@6R75NcceF zkr51-#U+7;F#`Sf7i0rK0I_`g_NQ&ZRCwBA z{Lg>@|4`Xj5kLT%`al?B=W5I`(ov;U*021*0XgD3^5{teN< z@cTDV13&-@;@|`T5QYI@3O)ok?1DO<2trehc#kXh!0Z4iC6of!=I9L4Jz5Qk(jP`l zJOKo8(qFLXAF#IH8`u5XwDI@PAHNy@|4L4RsD^0x1N0+605O4m05bkR14QCiMDQ;; z>0h$aKjWi;+@CNFzZm}i25JBZAQt8_hOB_!_dovn^Y72^zrTL{{r&6TuiuWpfB*e$ zwD}j1{Ph<^0%eu?|D0`P00`k|9}4iHT+`$2p~p=WCoxfpgkZGj{YEt g{DC2GLI4Ob02tU}a;hkw5&!@I07*qoM6N<$g4!w08~^|S literal 0 HcmV?d00001 diff --git a/static/flags/gi.png b/static/flags/gi.png new file mode 100755 index 0000000000000000000000000000000000000000..e76797f62fedcbfca8c83c51951680d6a6e9081f GIT binary patch literal 463 zcmV;=0WkiFP)VoB37QQ+R{;bN6GSUi z+kb{HA3p-oUOth}-@kwP{0U71P%%INK{Y@H82)oDp3V0Dt?T`39Pi$;RTl%zL?{P4 z2_S%&kW~Z0x6qjPzkeV9`s>}VU!Q7P|1&Wm)PrpR2q2b!5Hle5FfeebsWZ)5spT9vc*+3O2}Iw&|Nr{sqx*C2&8&?7c>c4n{QvVC zD9-TjFQbI?+i42`0*K|`>)%Y*uQL4o{r~rGhChE9{`~$Pz`@Ka$@uLpb; literal 0 HcmV?d00001 diff --git a/static/flags/gl.png b/static/flags/gl.png new file mode 100755 index 0000000000000000000000000000000000000000..ef12a73bf9628ff5a67b81bd980d9c5d2b2c0f05 GIT binary patch literal 470 zcmV;{0V)28P)J{teTOL@z0+>00G1VRSiT77W_YWkm2*^|KGm- zfAHXcOY8ruSJ7+$Itd_vn4oTd_U!+mLkz$F{Qvdq|L@-*^6S_C%a&nk00990)`(*=-xesBS%qG0|gf?f~#iu^9N|j9|i`10Ac}ZUz>% literal 0 HcmV?d00001 diff --git a/static/flags/gm.png b/static/flags/gm.png new file mode 100755 index 0000000000000000000000000000000000000000..0720b667aff506d7892c5c301af04e6bbf932751 GIT binary patch literal 493 zcmVwRhhvIeu00_fCKU~B)yH$s9sXS^B!W{?M(W&}hPbMwO z;*cg65E@7haJ!!XVgYOW|Le(9kkY?@fpY);{sqc`6amR!K*q2CzkUI^Y_hUI(*XjA zMdSH%VNp?r|Ns620Z1T|}fB<6Q zlw#oF`Oo_sVk+2%KTsoq3?TP6gz@)3Ki_`_=6?VI#CZSdeQ9y&f57m8xf%uh13`xW zAjrhTbmsgSfB<4-$Y)3kNW1sx-tWJ^f#}!YUqA$5fJva>FJQR-`S({vK;>fVMSuWe z0mcW=Ig;FxKxv@ppTFP`1*!N0BL9M&0|dYz`1hCL7Xv^5F*2kxF#KQuvOqEU3km&! jiTr^fV1zR<00bBS-TrJ5MX@2w00000NkvXXu0mjfGz`_@ literal 0 HcmV?d00001 diff --git a/static/flags/gn.png b/static/flags/gn.png new file mode 100755 index 0000000000000000000000000000000000000000..ea660b01faefde01ad2527a6abcf7d1a5c1b0526 GIT binary patch literal 480 zcmV<60U!Q}P)@|A6>41A`El{SSoRd}EL3@|NdrR`1}9=ZwUJP z@AvHwzkdDu1yn7|BMY<#Ab?oFX8(t({tZ$6>;L~hU=2XVuU~(E|N0Bk07O6y00G1T zbT=bV^`Afg|NLS2{ReI~M8m&-NE-fuGynt;*hzmtW+Q3%1=j#1fvO=I{`~y|)Bq4b zU?=?r84r{KY4``%041R|`~%zYhXEjfz)k`h|LYgXRlk0r+3@c_)IERx{rUUv4^RU@ z0D&|xgN*;p0Mzyy>QQ8EKn=iP{qyfH5CNS85I`UeOuzpyNJ@hA{P_#yFfjaPWc&?| zr{By>f0X$D{QV0G@4r9|{}=!Qi18~pg5ikaD#Jf9Xfy-Svu_Nh0nj)GNi#731Q-A_ W8E1tdJ(&;y0000P)fLk0D%}*I7ff3uKv?i+N*~ULWZ>4 zW5%k%a3T{@*`z6pma6eF$JtK+F@C*&o=d^t|Ns9GOCXH@*Z?CVuP#7nB5Y|1kmu|NQ^=?>FP0zrYX%2q2aZH;)P`n*#-K1r9WbfYOYN z??RUX1P~*`M}`*mir*mb{sxCVG>rbhqT(MY2L1y54rHu+wi6(L7#SX-$0bVa{(;3h egu%oB5MTiLH(5{VMZMqv0000u-`~Ig{`~p> z=MRwl_xtx>F!}G#@4vq{&D;bKKrBFA+{}CzK0Nsg1pog2{{I_D14*DX1pWH^3y6RW zSzcL&Zwvqd#Pa7K10w^wlkmIISh(4kI3GTJhN2$mzJLD! z0*D0|DC|s(0(}1j8UFtJ4HA_S5@P=M@9)2VV#30}-~k05FvNkXnV5ck`2-L^EDTKl zn1259n3DG7^QXUm{{H**3#f!E|`n6Mz6>fhdBj29g(UfB*aM-=Dw#|NaG$fByXc1LXhxFC@THKjjKQ05P&# zA9gbr+SsEBRPB^?1!&T?30hEBFhHFGv5AR^>DH}B00G4E=NHV45I6k$@0N4rAH*g9 z{zDN+_&*OP%Y{RC0Ro8e#fvv0A_7PTA~XKMG0?q08}8kE2oOLl>koag&}IJi^WT4% zN&g{c!yE%t3}J9_Fdy0V1t5S}4xV|TB*XjR%dfvcU;YDm6wdeu;Q~GU4JP)J`S$qz^!f=A3G?{>83*rF;63vB|NHv-`~3j>`uzF%_#GV;x3_Tu z05Jg0{{&$2KZ#9J4f5RdzRdzC6Ae5p=(o+T{uB7y^ZNSwN=h$cVmJ#62-nx+ob%l!TKAE1V~I16T$|E1+i#l`u&y!03t z7ytqQF#yj01Tv_Ick58z;rzG}_y7F-%)*RRAv1X@1^f8;`}+eA4+yBm#PKA>w6y_L zQ&a!|00ICp0M7peY0>I$KneW(?7rp&{QCm?`vUdU)NRiG`uYI-`}gbY@;Dai8vP{| z4h7uY=>Px#0*Hx$0pxvffc*LW3+PFp{}_J#0ty11^n2!vLjod>mX_Jy|Cz2{eHy3% zAb?mH7=HZ$2N_TWSP@V&gaITO7A`uvc=2f<_uIFxDk_pd4FCZI)bI_+mz3lOl7E0f z{^u`PGlT&Y`3GeD{rm6lUtS;y)Bq4bz=+dkVE6#Ehk@Y-82x6z3jhKP0OI&0DF;s+ Q-T(jq07*qoM6N<$f)`^cRsaA1 literal 0 HcmV?d00001 diff --git a/static/flags/gt.png b/static/flags/gt.png new file mode 100755 index 0000000000000000000000000000000000000000..c43a70d36424b66f1627216ad988cd23a4be9285 GIT binary patch literal 493 zcmV|9}7f|M~m>&%ghRD!%{(5DNnfNcHoNKp}=7 ze;EG#|IZ9j4hBF)cVB@t{Qmo2T96TF4?qC109^ty;2+Qi2B0xObN{1)Uw^{8{`KJ4gZ0H zP(J{D2s9NSfWR7{27t^!x8NVhN&g{E`Ueb#e*ggla?+pwj3Cv27=VUhwE^V&zaVoN z82$hR5DUYve}Dck14V%vK+Z)23?LgAK*7ZT@-zbjKmf4-BkT7+CNVw+pd~+kF)%WM zL>VCz0|PT7gS-eZm>Gd?16jcE4PH%g~!@=<9&!2x_@aEGW jS9>vVD)6R*AQp(xFW-Wt{{mJ2|NHk};Jc-)O#kPzME?5A`1{ZQ-#|To{!0im{$XGM z2p}eq*?*y`{{RjC%V7Pj<(}hvo^Z>=hrJ-xK=d0#0&M^~2_S%&fR6tAp8=>2$p8C? z0q7F5H=q9h`}OesIT^OczkdG%sRkpU6i@>|0I@Lq1-k@j0La}yZU2}V|JX_T{{Q!% z>EEtDfBydd!vuBJUq+w?fB<6o2X+#W53~WS;s2M<|9d72Yseq)`11cZJHs!aS-+wF z1}X*!ASNLG{ST%Ze}QTk7ytqY@{}>p)on&BOV)*xm;om>72$%sP!HhqD7ytr@1teTu4J7{m`^Wh2AGglm{~UiA z82u;s5_9PZ|FH1)~3de={)r1*?FgUtsi`kx>?C4?qC1 zfX)8@|LZe*d2K>lZN0{{I4*^b@QIr~;(tA5`a`e}Ddhy$ldQAPvkwr9kh3`~WiS7Zcc2 zh-#qDKOj^7{QC<;3||-k0tlpm>GvN7NlB2NKYyjTe{-?^h8PLd@aHekus?tQg2Ee! zfN=^CK#X6(5e!Gd)(i|h;JEn(j5jcXFhHq*fkB7?Aiw}&uW^ngBcx#f0000J&k9ol;AaCAG*Vvs6lsG2f+AJUecp&K4&zS7@MzJZZ+RCHJO2~-cn~)8*ZB# z%#~(Seaqctb3On>xdArM!+zLfe2=iS%3k1HK82I)yo62#|&;D2*%o~N(LQ$HrxFU=@<#wgQDty7s|5?>qxBTrc>UoBZ!}1le z#)a`Pq~$aEPO=D0fO80I7h5SSMqU=q48*j9Qb*%7#+Pi|ervSf?0bSFwKsAPn1FO| zKH_&kh#AJmvOUSnl~!1AmcaNJM5awz`0DF46>zWZuCh$z(7uBp0to4w2iu-uj zV9oc#M;CkJ!OT_8;~(;r&Cw`0K3r=(%@VWyiIA#;S}+n)^}q>|)QZ|IaYyyY!;frq z6mATysX~aM!z!n$rJ$=27fpoIr3iB{q|Gr32uDRa3PcNj==OQGHve|07^1DbtUgzuEQ=j%rDF literal 0 HcmV?d00001 diff --git a/static/flags/hk.png b/static/flags/hk.png new file mode 100755 index 0000000000000000000000000000000000000000..d5c380ca9d84d30674f05b95c2f645b500626c07 GIT binary patch literal 527 zcmV+q0`UEbP)00;JD`K-EmLvOuK( z0R&e6?>|)a-@i;iz|8zVIqAQ;I)|_@BNM~FU%wy-s0ZjAfB<3vx(uZH&mV?Ae;64V zIcsYEzkmP#{)7J;N}0Ju0muUq%~ z^Jl0Zz)k`PASO^y0(FCg{s2v4J zf4+RlSW)rg;lp2_Kl2?q^5yYkpazCNzyJOD%k=jzP%%INf#Tuc?>~%^l1w0DfWH6z z1E^V4lvz;l%d1x`a&jQQ{ROE8h7C|LKmaj5WMKG(8n4KVKd5of#=rm&U;y%qJ?5>3 RVzdAN002ovPDHLkV1mTk^F06n literal 0 HcmV?d00001 diff --git a/static/flags/hm.png b/static/flags/hm.png new file mode 100755 index 0000000000000000000000000000000000000000..a01389a745d51e16b01a9dc0a707572564a17625 GIT binary patch literal 673 zcmV;S0$%-zP)>fJ3En$GhGS>sbE%%m3$AD)q?8M9y>88-}kR7#RKlk!P~Y_PLuF7~U~3`~nC7 zF#yj00ZUDdpLsm{7ajP|&HwoK0Usg|6%f4L_{`Mi{rvv-`ukf=Ed&Gs-sA7L!Q7*a zj{*QO0M7pb%?Sw^g@yy{>ihEY{`vU@3=8@G0rvO$i3mOL`~mv-`W+b$Mmr&io5dg< z5v!7q0*L95jt`TzK8Kd(Utv)OSp_aLv){6ccV+Z`{Q2+asKUU&aO3`Kpz6wW8wp`< z28M3{0mSqnB#A*-c*8%1=RD#sSOwMznKA3=e&iEzwo{cA=PgXK`2OQ}gqId83!|%* zA_Kz@fB*n70M7pdECCwp4H&@R`1|(w-}M5x*74i)0}%fAt;XafA{48))#>Z>?CD#}*e}Ret0tl$#*RMZ7}Jl7Z|M45`5*URzH9L z{rmSnPy;{!u>dsyO%meg+00000NkvXX Hu0mjfN{&}S literal 0 HcmV?d00001 diff --git a/static/flags/hn.png b/static/flags/hn.png new file mode 100755 index 0000000000000000000000000000000000000000..96f838859fd2aed975f5f4134050fdbc0486ce1e GIT binary patch literal 537 zcmV+!0_OdRP)yNpn^YtfB*U? zE6K^g@B<)#SlTBTcsfda`|@_0R#{e$UZ3l|Ic6l=B#}T zWCl5lg}RFY8S^$g{qgfJOdc2ve*glAv3c@IFK6|y-~NDH^$#cn3{a5k!L9^_5>O@B z$^W^zSlTD;0tg^R28Q0WdbfK|zW)9V43odV{`~*->+kR1AO=tbO#T4}-G3E1?u#4x z0Ro5x7#++k42m+GppXWk{}2W^;6Y*k7i(1vOT1`b$6{=&w9#5#oJ b00=Mu*}Zhb7k&Za00000NkvXXu0mjfKokPk literal 0 HcmV?d00001 diff --git a/static/flags/hr.png b/static/flags/hr.png new file mode 100755 index 0000000000000000000000000000000000000000..696b515460ddb670acb7e9de4438aaf21fc5fb77 GIT binary patch literal 524 zcmV+n0`vWeP)@|4`Xj5kLU3fF!G{fyDoR{}_Q36Vv~H|Ns5{^Z)NZrr*Dqe*gae=g)r_`DNuw zfB*t(VEF(4$y0{Ee}M=nS{mB(NB;kxJOBSE{F_{n`2Y8>|G$0##TjK~fi?gH5EIz! z|8Uj6|NiY-l-<0|OxA@1MWlzkmOI;leLR z$De1;{4g{7^y$;LZ{NOt{rct07a;lk`E!5(f@%OM1_PkhC8`eE9egqWbga z&p;hdpFRZ$Adm)#>fe8W4*Ct02B|hR1*-n0rS<;(dx&bFRY1n$$BzL5h>;=uaC^Mc z(+@v?|NZ~x@4w%F|9yUZW7+yTpo@LH>e(bUfFghX{rmIxzpNnpimU?w0mQ=a>kp9s z8>AGffmuv7DrFgv!3yU7{`2q8f1ngFoPlxn4AoS-S!;e2821p2q{((sbfB+=MK@k8U5Cg$|VB~~? z2XKWZk_lAZtGhi{|56nPieMKY$Bq=4KgZ0muK;2JYWn}5;nka8K-GUCa!{rJenZIL z|9<}gF~mh#ftCOS5DU<%|Ns8~1)2?0{RgZLWF&|Ls)lL+iU2hL1Q5&LKMX(>AUTM^ zNU9+S#0FXN@8@rz^Zx+^5DWL07wmsTIe-5EX@IBzTJ`52%kO`z5F362$-h7b*KaNc zh6exv#P}EJiR%3Sk01R1^NZmZ(C**=fB*Xb3rzn04HN{CU^bJS()(Sf00M~R4FdxY z(0f3MKYtkh0!g5OAQFsz{e$TF`x|H}%fCO*7#IKo2o$W~FaxWA8VofRr202h8w1#j zz=!|{Ah3qte;CCj89_$={rBfLBSbS$5J>(7`GW}-*g)q41Q6q6a2)=FMdm+9l%onl dL?8elzyJ+{hsuy4pm6{I002ovPDHLkV1hP90PyYjz{{0J*12TXlP$`i71!VmC|LYf!%PK1iv=Z0I@Lq zVgLrRB#$I8Q2qeT`3KSlX8!?(3s3+U9e@9T1Mx3N13&;VGFUSJ^?=Y13Wr{r~&-|6d^ahvDC! z|G)qK`}^nrA0Ybu|2K$nd)6X=0AgWa1{?O`IRi-PU$8V7{r&w9sOb0ae<0Pr|Nr{M zEF}%J0U&@_82&N|Y=e#y>zg27mx!0Xgp5*S}vr z{r~fq0csvl>92pk!P<5VDfB!NI2#TFQ3lKnzfB%Al=06ZHfFW+c#KiRe{d<4_V)^&)A0s0pNIe5S)eu>r zF8~6F38(?TQZ#J<0R*xEXct5e0}KG|WIzExE=U%r7$AT^8h-rv@ecwRzz_$3Xaxu` Y0RLik?wUgPu>b%707*qoM6N<$f;0ZTz5oCK literal 0 HcmV?d00001 diff --git a/static/flags/ie.png b/static/flags/ie.png new file mode 100755 index 0000000000000000000000000000000000000000..26baa31e182ddd14106e67de1ac092a7da8e4899 GIT binary patch literal 481 zcmV<70UrK|P)1Ab?mHSU}=WzCQi??=KL1`SXRBmG?g! zeExSVgb4YXfjasA0Ybs`#&c5^XvcLUqDM3{{9AP00d^^H2e48-+%sM)d02u=%hct8G!N( z3;+QH((o5-_OE}xfO;@2_y=+i*h!3FCjkTyNW*WSt$#tPfB*dj3@CIxKqoQ$2DuvO z1O^6x00KJ+r1UogVe!Ksu!etsL5P6?Ab?navG)7lA4zUWkT?GPWdcP410y3N0|YR! zFo-FE!v&-P=p=vuVq_>~VE6=zV^DnmVAx)=U5ZNz6vaS)0m(NHWW2-wfs+9Q00bBS XO2cxg3=*#z00000NkvXXu0mjf|9Z^l literal 0 HcmV?d00001 diff --git a/static/flags/il.png b/static/flags/il.png new file mode 100755 index 0000000000000000000000000000000000000000..2ca772d0b79b255872cde2fb29060bbbbad950f2 GIT binary patch literal 431 zcmV;g0Z{&lP)WlqUuh`uiUU82D1+EBLb>EWz|Nj3k zj6%@>aVJ0ku|Ql5RsEk~{?`9D9{=ZO{V&1vKX2lHHJSgJ0SFC1p8y096I?Y|?05b{XcgblKTHZ zfByjpAQrd=h&?HOAa>`R|6Hv9XB30N3RxDY7$AV4en1PH(j<7uAT&Tc4G=&q@-F{c z8i9e$01Rv(35=ybe;NM%WdxES!M~uG0dj%y@b5pvikg1_0mOLw_HE>d#AF}?ph|!M Z0{|%qc@l5wel7q2002ovPDHLkV1m6PxaI%= literal 0 HcmV?d00001 diff --git a/static/flags/in.png b/static/flags/in.png new file mode 100755 index 0000000000000000000000000000000000000000..e4d7e81a98d705da8d7054e77e7d311805659678 GIT binary patch literal 503 zcmVl^KlW*80IEmzVa(K3*_6 zG7fg0I9Zj&0woGah`r_&Kwu3FK=xChQigwjfh>?7kc!_h@)sEWW@MKI+5iwhEdRtz z89B8WSj7JS|MwrL=l|b3uZ7Osk^B4auaUxSRgtG4v;Y11_x}$gi|9Y8?EnG9`1|i) zCPv2p|ADsrhuF4k`@Nr^zUpfTpS$xp!A}Wj4A3Yb2~_s}<0pUsVqyY2p8>1`g1&zJ zsVvR4Yya)fUw{4wtNss>0tLxGfB<5GmnRH!zxweH8<(Mq0N7e&^ba6_ z7#WHgIs!VLeti1p-=9B!fB*jb=l8$ge}LrQ-#`%%`S%Y9{re-sFSERHIY0ohF#KVF z2*K4Ml>Ykz*ZJq)UtlmW{9*tIAQm77@e!0?Mfa}mS!7%=x2KmY(S z0M7pbTSu9imq`K?75n7n_u%3MB_szB3#hl|A07@E6$<6-<>30S5egmg@cSkZL+Ix9 z0st`p&i@3O7{&wE8wU3C1oia^`T7CwI=ckcau@Q71iA1L?!*;{7^Nm*&$?GLJd|NjPb3=0E0KfCb4 z#nAu(05Jg0{{-+tQ26`)!^rI-{P_e371QGlF%9qW_x;Sb;QRdk{r*xJJ*zy?_rWgu z&$=$1lYjzR(%pFe+p|Ni$IOoG{eTR0XemVUia$~;LXXZeDO z0096o0M7peXKyl1N+90g@dyY5ARP|N&gc{s2^<#+#>?j*9u48*^A9U5-*(6(kqBPq zC^|QM0*Gbi#3NFYyicBf1{wyk;Wx-spzFb0kX0fvuWZ`CzyHEKd)}3G%ew&r05Jg0 z{{dZPvvzMc=Kqyj=IHYZ2nGGUe(f)J7ZwZK+v5TV s=!a5B6v9X#`iH^&14cjw13-WQ0BQ>oQ(TIK+W-In07*qoM6N<$f`&OQ@|4`Xj5kLT%`al?B=W5P+gNxB&nJfgpGfTOih;e`=>T z5jZ8;?_>v5xi(~iU^udv!6f5$jpNVh2O?$m1OPDr&i?@Y{r&#_{`vm=wBfh>{Qda+ z{Pz3$!R5rm=Ee2+`0e-d?)LGV)1LD5^!4@i=jZ1F2;wA$U5|F$_;B;f&rf1p(qbG! zCte(9VPa-y5lGpbZn4ZFhzcT9$vfdqmuG z@j$ZG>u9())mkwqmYHSd7eFi*FJ3%$?AX0~_kM%HFED^GKqQ#;=g)7T_f%9=fX)F3 zAdr)QMoCIaf{X{6{|BNG$o>N%f#5F;02KoS5XlH2zyJ$0KZ{``H1_}i002ovPDHLk FV1nFR>VE(L literal 0 HcmV?d00001 diff --git a/static/flags/ir.png b/static/flags/ir.png new file mode 100755 index 0000000000000000000000000000000000000000..c5fd136aee534ecb59914e336cad18d18ead2a4a GIT binary patch literal 512 zcmV+b0{{JqP)r;gUH{1e{Y(x2_S%2fSMQ?7@vH7`tSc=xS~J*|Ni>>`_JFszyAFKs{8d9NdA)L zm1AIH00;mv0M7pew_3Ln1`-ek5ajjb8VVZW^Whu|9pCfc910uY_2L}~8{YEX9t$4Z z@!Kj9D)d(L0*LYN-@lBEj6f&-|Nox>4F7-s`Ty{t|Ns8~x3>Pz!S){pfXY67`UDU_ zOc38f#US*GW&hv2{?Eqpf6;>f$N=n5fB<4bR}BO)G5?=F{eR-b|HMQT_5c3^H2?$< zb1geNgNn-kGiMln{`!CM;{TsNL8PAke-;*?JV+Z*eYOvhv$==KunT1sF?AKYlWZiGf7_{AKv_o8k9wMiBcC z1B3*kzkfmK*Ds)AfB<6r3XWMgVnF4hNdW;sfB^vU;z%SnI0)(h00004s{hykP}!$Xp8x`g@iqg4NJaUd z$B+Mm%>4cD_iu*Zzrl=O|9^qF|9<`Y547mdFIIVlOMCYL1Q5sui18rvfj0Ph3vJwt z)dnUeruXmP0|XEYv&@95W{1bGfWG{@sKWZ+FOVO6s`df7U=M&0& zKrFzJ{`2=AL>j0Rra@ocD)4hB}-f* zN`mv#O3D+9QW+dm@{>{(JaZG%Q-e|yQz{EjrrIztFq(O~IEGZ*N=lh=;=qSyMwWku z27eMOW_|f0uQeek^e_9g7KH|eq{JVG0^UaP2Jy4}|L^JL_3uCblfVD@mnS9t`~UCn z|MT(+KT|KOfz%~1cG~~^_2vEk{SFNQ?Cjg~|NsBWy<%2im{vp^YdeS=hk-Cyo6U`Hgs{l4FR(w#{P`G0;a3G2@YSmzI~fu(ZE1> L{an^LB{Ts58L6#6 literal 0 HcmV?d00001 diff --git a/static/flags/jm.png b/static/flags/jm.png new file mode 100755 index 0000000000000000000000000000000000000000..7be119e03d203695325568174b72522124bb2f12 GIT binary patch literal 637 zcmV-@0)qXCP){QLU}0{l%6`#}@@_VD{9F|q;xF#yj01gpgWJ+A*m zGUYZW{T>4SpXmF{^Zon(`}_X;`}_MY3j1pm`Wy}V&B*(tydCWT00ICp0M7pd0000m zGd#J&@cQ@tG$8vu6a54J`qTCN{{H)06Z&u*`VIU0o2UAMn)~_v4c^|~0*D2u;qTwS zKYspMz5CDEtAAp>e+Mf5)@1$t_wR2Fu3uNK{_0!&`}CDxK-+|V{{|`s2p}dP{`2SW zZ!oxe=XdSY-}fK=Qse!l!T0O_!(X}WAk`4?=MOLh7ytr@32Xz9{pZ*3U(#Z~DiVIl zOa8j^;n%JAKjo!$j^Xni)Y$z6WB&k?3JlvV7}WR}00ImE Xyv9Bjb9W)}00000NkvXXu0mjf@Xt#6 literal 0 HcmV?d00001 diff --git a/static/flags/jo.png b/static/flags/jo.png new file mode 100755 index 0000000000000000000000000000000000000000..11bd4972b6d5f134045d4e8ce134601ea9b5654f GIT binary patch literal 473 zcmV;~0Ve*5P)M00|Ni~>`!`VeZ#eh`f&K#;fdS|pfB*tJ>FU-06DIsWc#z@uumAs9{`&>~&q~MQB#;&cfB*tH z31sk|Jq+K!KjiuK-^&B5YLK~LCjkTy3s3{|pFco7yH$Tr@L>D>cm1y|D}MvS>F@7f ze}Db{_vg<)5c|)+zsmedM_Y~p1Q1BWd$vDo!X?isvq}Pk|KA^w>VH5L!1(y{_x~TD z9$-NK{r~sxzrPHB7ytr@v6F$JJdlAwh=Ji34E;f3{DCq4fk_4ifB*vkxQ1J~H9>i| P00000NkvXXu0mjf0T$ba literal 0 HcmV?d00001 diff --git a/static/flags/jp.png b/static/flags/jp.png new file mode 100755 index 0000000000000000000000000000000000000000..325fbad3ffd3075a4a84d8d898ad26ef7d3e0d56 GIT binary patch literal 420 zcmV;V0bBlwP)9whYk?f=!Q|Ns8||JN@lTD;`{R1ZWk|EGa3dAO8ObDh3E3Cb;oH_5X#1 z|NHy@|M?558b}5Q|Cf`4hZv9q2p|@?lb|{i68>{>{ol0lx`{mi O0000=G`P)0NEt6k^VGA)9E1hT9ocRoN>wSfaWv)?-raRm?)Slj<6Po6w} z{P+i;{`~nD6~!ec29@~tkBNo($fnHz0mS%{fq}QS{_m4#|Ns2?|K~SQUHy-* z`HU>AfB)8feAoK(-@hL}|Nr_0bQ_Dj+^xMk00K}f2RQ&hFc1JYLgN3=lsJ)M+p3uR zWC5ydAM*!ly4H1hsiEFvIU^1)HH_GYz!QMsIYt5i1c4ZMLC4DfztdU-q)WGxxg;|L zi3%uAJ2fm~N8&I2%AdL;`{4^9#;e!&D=C-&Lk8;9|NlO`c*HPy9@C${KeOWnB;`P2 zATRu9VP-jSWFD-S8kh{*zoh2aO#pT8A2W0o(w3 z|5bef!~)j#|KF3RAf-U``!@sYUq;#A42-}3UHtv;%kTfcfBpOQ3nmTE<|1vNq z0ns0zZx{dq2xP;5h!=kY&G_~A;V*`-zy9<8Vi5ZI|I4p`PkusG11$kMn1KNxfWUtE z{TpHc!>?a|&i!W8{>5bQ`~TnHf3N=fz5nHq%!z>% literal 0 HcmV?d00001 diff --git a/static/flags/kh.png b/static/flags/kh.png new file mode 100755 index 0000000000000000000000000000000000000000..30f6bb1b9b6c5bf355f67a17531fa73beafa6639 GIT binary patch literal 549 zcmV+=0^0qFP)P;@arD~1pHxO_zPr1&>t9y%wPZrAQpyS3=Ms1K-T|%K*j%o>i_=z2W0&D^Y8ax zhQELQ{rLl7|Ns5_-|C4+00M}Gf#D0s|6k8u{RAokD*W^JKSaeZAp18+HBcQ8{rdA) zTAYJ{;SE3lu^j&CtN66?*W<_k{(=kvTJiVSPc{h&pyuy)ZZrJ(`}gOM|G$0#rP$=; zY#H_d1P~L*>3>1SGXDMzbOE=49-9EaM0J&9T`emwH;=g~P!Ocy*DnU30tNVGcpOKXK;IXGH`G*aB%Pig@_cF{AXeP^XnG~{rU5QfdL?ZSim;?VE{Sy z7c(ax6CWR+s|%BWAkauYPfsQR0VXz9sPSMM00M{!7+@fO0fqklmFn#S3Nf;>{s#gU z7DjgV{|pRrOO`MKef9?wUO?vn1P~(w!@{x_lZQ{f0d@UhVEX<0FF08K{sNMJKnNIa zzrX(mdR{@6d*A9+009Ja65pra?7SkZU^!3-{)PrTC`>`Y0b%_6|LHH#J`sQb0@|>a n0T_AEh(trkF%3aX009O7j5IT?Rho+J00000NkvXXu0mjf2r}#E literal 0 HcmV?d00001 diff --git a/static/flags/ki.png b/static/flags/ki.png new file mode 100755 index 0000000000000000000000000000000000000000..2dcce4b33ffe1f40d490cb1a2e03efe22ea56155 GIT binary patch literal 656 zcmV;B0&o3^P)8t@U|NsC0_uv12fBrK4XN%za&+zB_ z{P)aXfBpaa=ii?{|9}7d|NHmt1seeZhy|?e|DWei8UFwK|L5=jKYtkh{P{kK2}m(L z`||tm?|;94|Ns5#-_IY+QnEm+00M{!r2OxHhJR4iK=k+TZ>A77)*#lue}Db^^$Tb= zko*TE|NI8J3LpSOb8Z9x2m%4nC$a{*Gqe90@enzQH`ta%tA$7d{Sv5iP&~x@8dMF~ z(;dfh&fyCHF#yj00oRR-9sTeJMNR(n^YxvS3U`G57YhIQc>VqR{rPSM@(uBDU=5F+ z{|5&5hj_*A{sI6o0M7pbe|x2IYDAmA_)R$v7XIy^!u#*~18PtP{r&xWnDPVw`hiji zey{rM^8J)$5m8%@0*JA9=57`qRaXnayHCFDJ@r1pR}vUfQ&&Fu_xE3Vu+-%{U$!58 zQy3!)avcufO?mzv0@a%gl z1HS+N7!IC&H?5`#AOHX{0M7pb00(zPR4BWp;5AJa{{8^XwcY>#`eSh{`1tyzm&^bF q{8L{tuE6I1;oe7AG|b!z0t^7P6ga05`yJ%~00001r;P)}L!W`0l>rF;|7So3KrTcC!ho;=0*Gbf0S0@;YBwbYEs=i=3_$ev|Np-X41fOr z{{tp}0~v7g%iT=?0mQ<{9!@# z-(SD~{`vL)_wRqdfBpaan?+XX#@15+0mRIp%kY{1qrJR?xs-YLhQhSVzk_f6;`sgh z57Tc3#$ODKzZsZ*F#y?2e^`Y0-&}tV5I|5HD)yDjz7nmS1pU~~aVF#A6wD&YtO00ImETIDprOD_2B P00000NkvXXu0mjfKOhx^ literal 0 HcmV?d00001 diff --git a/static/flags/kn.png b/static/flags/kn.png new file mode 100755 index 0000000000000000000000000000000000000000..febd5b486f3f90056637b23caa26d838fbadd7d0 GIT binary patch literal 604 zcmV-i0;BzjP)h(K@ANy8uaQvQ^_nWcs z*Z-GL)eL_?t_B7*Kmf7KbznHW;LqhtK<$TZ9ej=*TGLweOZn#S|EVB#AOzI#2dDw) z)4xDJ00a;t5ND<*{rU5ogY7p9)8EGU->gS|Gwk>cG!LX2Y%nmu8NlfEl`8-N#0ZOI q248)K1w0H4M?n#d6+r+%fB^s&Q!OA|2rzyC0000Cs@aq@DuRlQczuzDZ5@KTj2q4CTH~*`MftCON|DS>3-+w6c z9|(gO{~7-O`v>9vKX&5_Kmaj*WME|P@B8=S6~kYUnG7sU|G#_z>G}QV|KC3#^7rq5 ze}4b}^_xjb^7)+E00G1Tlwy4KiiwGVIVgltUY_yi&tI!o|Jl8p;n#15-@icU*KbCk z6Mz3^`1ON{fdL?ZnEnBs@%JyYzyH5mxBfr4|7*t%=AfYeY;6C2{Q{!DKY#uG1wwy- z+}}Xm3;+QH(!lWNFN3HElfM4XRjZk-tp4-xFo=l!{|(XrbkBdVP9XXJ&!0aG3;+Sd z1adCWtuJ2w-n@w=AmGpT?F`?)|9k%Y-_M^QML&N+RfBB+Dh3E3pdT0*fp#rf!j_o$ zUs8faP3>oG?f*A#7{O)(oeuE;(0C>wVqgFWAQqr4|9E)*J$m%5y#o|bz~KAxm4S=v zKP&4$usU!k0b}RSKS4oYgaHH)%c-;9wWL`3={r0|OreK!5=N4TMk7RCwBA z{P_JV0}}Z6?;n_iu%H+Q{s1vR05Jij`8c?M=-GouSI=K${m;n9!7aeW#m~(x$j!^i z%zXLG*~fS9it_V|2?zl-00a;V#NgMjUvJ&I^~3uQB4T37ii-d5-u?gQ&wmw_XD?o^ zUAsm=P*7M%NJdr`Xazt3fo%By|Nn;%AAbM-ZD?YwEG7BBxA%WR!T-FR|8><0Vxn$d zUT@yKdH&)BP#Mq$fB<3y`hl076R7Rgt5;mSyo`Gea7>-}|M%}Nf0%y${3VbO@hKwm zAWK?W z+TGp#<;$01Vv<1pdP-ancZ!Qkd3bmLHK?nrgX5I}Ab=R3zkQ1wk#LIP517FKVgLC9 eRt>}e0R{ktF&Q^6#MUGL0000@P)xg`upqGzh6Lx zERQVE2><~E((v!!|G%IA{@M07EI*V_ln=0RjjdN{oM|h)7EO z{{7?6U#34`ML_iD4-=RKMg|km5|FijfgS(|AV#2u+YAh13=HqUkqe1m1{eb(!T=Kl c0)PMm0G()MDW>>^I{*Lx07*qoM6N<$g4p`a`Tzg` literal 0 HcmV?d00001 diff --git a/static/flags/ky.png b/static/flags/ky.png new file mode 100755 index 0000000000000000000000000000000000000000..15c5f8e4775b2b68e0360c1f4ff1f37e61611276 GIT binary patch literal 643 zcmV-}0(||6P)0{QUt82Kj15^L?rd`uqE`oNxjFF#yj0 z1e^fI2i-9Q(8&Vs@%;Dq2on+Z{QuwM00sm0@b~}!1OzrH#hk+X+Tt}E6bb+U_yPbi z0M7pcvI;2tA|wYPA^Z*x0300&EGqR875n@A_WS?(`uvdQq*oFTSt1&p=b-!h{Qv;{ z0st`p&i?}PGCBeX39IA)-~tZg`v#`;6$Tz2`uqI%`ThF(|NnA-^wR?L!uSAshx_~g z0000205Jg0{{tif814-hz}E2g`1#%M`@GEN)${-9=jr|Z1Nim(?*qH%B39iMC&AR2 z>ggNf+PVUWW##cF5^jI~{P}h24a1+`jKBZ?zJB$|uU|aB82|la`WF`1`0wBUe?VZ- zRnf8uXahh1u`n?Z4sYX?@pO{;x_8g;0tl$# z2T+})81L`j|Nel$KOpz_zrTNegN!(Tli}h6pb7teeq#K~3=Aa(fB<4-V9 d!wLWb3;+YKCC*ol*cJc)002ovPDHLkV1loTFLeL_ literal 0 HcmV?d00001 diff --git a/static/flags/kz.png b/static/flags/kz.png new file mode 100755 index 0000000000000000000000000000000000000000..45a8c887424cff6eb0471f5a1535139b965e241e GIT binary patch literal 616 zcmV-u0+;=XP)g01!ZoKn?Fz`<^k#?O_Q1 z`=8<8e}=z6_5c2{{QvRuAM+0emcRf01JR%V|9}7gKjGLHfB<4)U|@L0AiL;yFw=jq zasNSbGXHKG{NMlfpWxpAK41Q^gEaj6FV4=$@arEy05LIu!2gi{Gync$`1$|;-~a#q z|NCw7f0xa__4fbPn*ZDO{onuJ|3JnA^#F|o2q31v4F4ql-&_7K9cVD)|KCjiesKSP ztM&iLe}uy71TZ z|DRv){|H?Bqoe!x=x?wkfBu3(0w91`fMN3Vzue;gQUCt^|MZVr;{RRU{|DCmOS=6} z@%2BU5C8a_|1a6~&;1YB8$b;J0mKBvKpP_e^#OhS_CN2(f86)~DtrE)Yx94t!v9OT z|MTDe69TJd_zQH>zdry01PrBrQvYt3|7!q-C@@&>{!_XBPnqZ6E6@K61pYml`M2uu ze+NdW22lI}1Q5_kK)3wPV4bt}e=;a?{xkdrMUmL?|7pP3c>kYY0b~&4U$AjN34j1% zWLW#P{SRLy(>r)v0s|Y${(}_LK*N79FfcIy1Q-CnX{(%t#68R664G@6GIJN-*24NrwB3rW+v!ydOp^Ef6{n_)(btIFVjHa=pdp6)} zz^!@$h^2tpKUmc4)64h&|Ni?2LVth#{QKwk-@kwU{{Q=j;qSk{fBpc`pWlD@C4}l3 zHUR_xF#yj01d}3g9TFqw{rUX<|NZ>{`TG464+L38761SLpR(uO=J){s0Q&s>`~3bJ z6bIb^kphT`;m^O{e;I!LWBmP>@yDNkj7*H>@iN-VTtHNrD96Ue^ySz8pMMxZ=pRTg zKmaiT)&Bj@@b3@E4ZnZ>72sjw}n?8s2>T{qV)lKMV{%|NQ?241(YPff@h;hz00Cp!a_N2HF7% zr}y9gR8D)C;wJ_Sx5=xYz5MWpi4mv-=yjk&KmiL7K#aZ&_9^w5@1DH=3l15e)xUl~ z-0=7B?|)4HL4sh3f5LL21siGr0*GY=!$H*K#ZR;BJ~dv8zS`wDeeIR3;>1y|KC3hK=RLTAp0Mf zWcc&@%EC-|_DIyI;S5 zZoa(f#*3@};Q;9GfBygi2&4h78pxV*WHQhn|Nk-k{`>pa-{0-~I{v`b{|EZ(4?qC1 zz%@X;G0|`0)6dV-R;K{9rJ5v|%9;KB_nVP{8R7~c2@pVx*BKb3t8)H6dH@UxP=NgY z{qNULVEFv`^^@@rIK+N~gX`}f7I~!;+fM-m5DPFa{(t+%C?E(7W+q^;{`t)a3di3} zzd^yz010JK%>4cT^&8LzfB<5=h#HaqkRlk)Wq^@D01#jR5K~0vg#SK#00000NkvXX Hu0mjf%Ubyh literal 0 HcmV?d00001 diff --git a/static/flags/lc.png b/static/flags/lc.png new file mode 100755 index 0000000000000000000000000000000000000000..a47d065541b0d998da832e1981b479097a9b36aa GIT binary patch literal 520 zcmV+j0{8uiP)#-NSZgwz{Qh@GSmETWyIzrrS!pkkqDDw`CEYY|A1Dxfxke?UP9EWUlaZ{K@! zXYTRdfWyFioqIm+xW_M=V(hYvbO?~5ZHkEt37xh?rY1@PqM%`P+i2w@_wXJJO#nzA zheNt~+w1B3H|fqGMx=x!lms6SMy;uqQ4R``NH&49%B_cditsDHI6DHXLNubec}E0~ zb8dy|txA`rTkZMN{rCM3FV`MqlfuwZrz$X1)+?ntF|UvTkD3M?FxSaem74ag}Vzy5sA+`s~GjvDl6>(E?=UGu{=w?r5#MJIwhn?GrT#s zeRSo}v&#TUmcjL&mxEF>2%EIxN+SI=O=izlM$T5JH;yv-C%^zTfK|9CLa`qJ0000< KMNUMnLSTZ|5$YcR literal 0 HcmV?d00001 diff --git a/static/flags/li.png b/static/flags/li.png new file mode 100755 index 0000000000000000000000000000000000000000..6469909c013eb9b752ca001694620a229f5792c7 GIT binary patch literal 537 zcmV+!0_OdRP)sI{|q~>>TZ2$qp!tjsj_dmuxH+6SkQv+K1^Dpafp!@&+{r#8W&u@@le*a|z zk$)I|{ss9HAb?mjKkZQc#wYOgBhb-*|NQ;?=l9<~e?U(E{r5MB3DgSYf*4|4g1Z=I z0R#}sfv@v<-|;cLeDMG8um8XQ{Qv#?|LOa4L zz5|hefaLFgf557NB#8Tm`R|`M3=9AP!~zPVKOloaN+E`UP5lQo8*B+s^WVQre?jpA z5I`*dz#16EB$cmd~05Jg0{{#R40Cvt10RRAw z`u+d`{`)-+^5ON`yb$y0|Ni^@{rvm=`~3g>{0I^G8ZGb(2;2e)q~Yi9|KETAVEFqN zi2na)xwe&yo%hS1uZ%yx{Q;WF%<}W+mp@!0-yWP|m)B$h2q2(_|NnsK|6hiGKudoE zUGn9{-`6*oEmQ72y~rUb^YQPmzn@?Idwh=T>wA{p3V#3shzY3p@87?_|NZ&@_cy~| zpmRZP`1kJ@JI^@8AFa{s9OeCZO+ts{j1?4b<=-Nd5zA z`2GL?FD{9%H@9*#{QvEce@o8hC9n7wpg7QIfB<3vS^!iHvfyK-U8V5ZH#le}4S|yXQB^Nt}W|`Q?5-JjKDn&hY;a$Df~n9-WqyG5z}b zHWMS`AAkU20!9tv|KD6JO#c`e|FbePFfi-*z4`Hxjg_16|9{rM|5*PsvHt$a@%k1I zzvO#v;hz8j#Q5o)BT__yf)$AVfxHBa6HpujodJ?%_y>%AV59*A7yy`5b5c`Z!JhyC N002ovPDHLkV1l?nIh6na literal 0 HcmV?d00001 diff --git a/static/flags/lr.png b/static/flags/lr.png new file mode 100755 index 0000000000000000000000000000000000000000..89a5bc7e70711575c1ee3b83cc2be7f0e1fb29c5 GIT binary patch literal 466 zcmV;@0WJQCP)2Y|A4{o z-@kwT`t|eY&mTX2eEM}Kp+i!_T03wQQEla((gZiC0cs^;{c3|jAkj>009Kl@aN){ zC);;k0UG-E&);Xo*&wq)roznr3pD=Ezu&)DC1p;}S_BY4jKAN$W)>8Nm;toyKW@Ot z#Ps&Y4S)b*xg;zq)7SR<*)x!NAa?^@4{|ZkY%l|8FPQu15397y$%U%{0*LYZ>zAxx z8}J(slm+_X#f@tK0mO1iR9wET{^!#tU}GSb{Q3uSG}s1+e?a74b~(9Y%Qpf95aZY9 zPuWDo(ENa58%O|%pI^NU5I`*FB&GkLM&}>Ys6}P~0YHEO0B+J}4VS0Fk^lez07*qo IM6N<$g3a05u>b%7 literal 0 HcmV?d00001 diff --git a/static/flags/ls.png b/static/flags/ls.png new file mode 100755 index 0000000000000000000000000000000000000000..33fdef101f74e38e2422bb85dc8a31bbf1da326b GIT binary patch literal 628 zcmV-)0*n2LP)NT^udI6UX~&u_xA`izWBNXkIq%g^6Y%Pu{8|3yZC zlYxl^Ab?nacHcU-^!@XD|Nj5|`r(zVwkHE4BV6^xC+~{3+xxCp=yQ1PA~B|JUd6PoU1p;PCnS`uh0!`Wt}y4#)fi z@&Nb%0tn=Xmv@c{N@*}KFh0M&kIP1>YRmQG4?lbdn);9N*SEXB6{h}Te)Ie9Zy;d! z#Q+chF#yj01pfa18Ye&*C_n-K{_XVnU82h1@caA!0{i;;`V*Y{7}WX#^!xhz{Qms? z{`>&^00Ic4fsvW@|G$6Ruf6C#{P_EiKfi$f`+Dz}{FL7;Z+`vz4fMjFe?Sd?fe5Gp zAb>y`UVr&E@!c&!7K){sO`Ozkh)melY+9 z5KGUl3lpbYV0iHf6xF}JF{n*t;A3C_dhHtn&^!?O1t$N2Nj?UE00RIWZBXJNY9>Gc O0000 zKY#!H`S<7dzuzGA_xCRl`Rmu;Um!M^l;`6=xPSp5fLIuQF#P%V7sv;y25A5(1xW+7 z{Q_w~Xakza@Pz>&fLMUe`uqRSpZ|Y=>VQIE8-4+ehiC(l5cdDyKm=3_5I`(zTN!l! z|Nj0Es0O49Xx6_!5M^MM5b`fj@gGk4KbtNx00a<=83P0Vn?HYFf{Xx4|Nr&tKga?w z11|FC_y0eCSvdcCFfafF5XlYnMRN&=-B{`>{W0U03nA0WvHB!TYz`r< y{$OAL2q4DW;E4VQBmbdt8IZ(*2pDGo0R{jiB6maa(%qQ=0000! literal 0 HcmV?d00001 diff --git a/static/flags/lu.png b/static/flags/lu.png new file mode 100755 index 0000000000000000000000000000000000000000..4cabba98ae70837922beadc41453b5f848f03854 GIT binary patch literal 481 zcmV<70UrK|P)?-#?r-wgj45C|ZESQtLMVW?~Zs{a4) zALIXj41fOq2a1uNeOQW%&E= z|DQh$fB%40fEE4z10q3;-;ClCKpOx8h=su~@}N>;ErcnO|V^hXG82+5i4Q+5aFU0|N&GK!5=N X;lz1sunOP500000NkvXXu0mjf*7env literal 0 HcmV?d00001 diff --git a/static/flags/lv.png b/static/flags/lv.png new file mode 100755 index 0000000000000000000000000000000000000000..49b69981085ff54568907cd51a56a1e5d8b01ada GIT binary patch literal 465 zcmV;?0WSWDP)TuF);jrk;v#5jAUY900)zv`N|Ns31p}&9s{rUUv@1OsF{`>=? z-@pHYNg(_0@82^wZ2|}&78a1v|Gz$Y3Q`J0Kshi8lm?N%fQ(=Ne*FS+xn*U6mIDM3 z3(!4({{8=rtQsf{G!?8Agn$gN2Dab7KQS->1Q6rPlP7uPKoY|E^ZWmwzrbJwx)~sVSb)*-|Mwp*NlCCVfB*i0>4ZfB zFhYR-gakS;`Tzomv6O+~6D%TsAw}vh)M$o8KMw-~K!5=Nd?C`~#DJkl4QvBtQTT<=hAW5C&pkLRXaMS_oX@ePCublh%7`S0>4^BHJ{X z&jSWU1bzAnAdrUt4F8|~c=q?-U!ZD;3Wy>I`UNEa{sJFg8g4-`_wR00IcC z0c`wlknw+DNZ2$-$7NDlT|NlUo0ap!i1F~k2r~my1Y5)izkcK~h z{{rRU9);Krw*=%9uq;py&^Z7B1lI8X4~o-~jQ<6)85pKOHYf~%iU9%$qyZ=)&LIKv z04P8aRsoF!DgoLL3cdee4gVMb0*H~J5hWs_B!uw~i3^Ex1_pot0|0+0kn{N-xWWJc N002ovPDHLkV1lkWn<4-J literal 0 HcmV?d00001 diff --git a/static/flags/ma.png b/static/flags/ma.png new file mode 100755 index 0000000000000000000000000000000000000000..f386770280b92a96a02b13032e056c3adfebfa18 GIT binary patch literal 432 zcmV;h0Z;ykP)@|4`Xj5kLT%`al?B=W5I`(ov;U*0{`Ko0*gOW1x?dnY zU=0kve*-lD1P}`lGXhluRs8wG@Eb_}{{H{>S-s!?{`@vR^^5K2FR(pO4M5WY0*DFZ zqCZG(`2G8?)UU4`zrJw%x*-cw4MBhY08Ix7Ah47E{sH^x7s!U+ztwL3`tbkv-#@=J zum1jzWCJ7ENdN%^b`n?!@|4`Xj5kLT%`al?B=W5I`(ov;U*021*0XgD3^5{teN< z@cTDV13&<=05Ky_HBiN$KMcQtBo?#b8i1w)1P}`YD=UMn?0*)P|9^oV_=9jUlG7n1 zgOt?2g9iZui1GF7*Fr)<|ABx33~>V{CZ_AxuLA@S%fEmBAbhajaRP`eP%%INfiyrk z1T_G`pFe*90tjjYTn_{=GBPrt03a7C3lKmc4KH52_yY$2zyM+rgbiXafFO_o^aD@| aAix0StzUbk+v2SN0000M*00(~<{@!wBU}0eR!0_)M!#^$%c|o1wA4mpD0t66HlA)zv9Z3HD2a;wKuKxf3 zKLhV?#{Ykr|9@us&njQ==l`GI|Ns8^_xsQFIm-b82&94GKf}}4zyJRI4@Cd}JZ511 zyk#BtzrVk|eZKww|NG~I-~WGu5Q~)bF9rsH0Ad2#1T-6>`p@704FCVWdiqyE_S>%? zzn?t&`v3p0|G$6zgQ7n`R{;bN6VP4%{xkdmsRoGvjXbc2Q*ib#i+$e?>}LD_@7KRy zzyJOE_4n5=pu>QE00u!g^X8F}1){Re7)$pq2>GzRP>hz5WF0{Q`{ z7%1`&WXbP;Kox)fFb41M1d2p!76A1_RfAN3oCFX+Kn)0M$tdvjY9_8yH^9QVjn@nfZP*{rmI(|3?O9b~d@cVAX$tK?&3V z5I~F!3@gDg2t{v?r~d;6^$&1NgV7;ZP#i-L5C8-i0C2iwRaxXp%>V!Z07*qoM6N<$ Eg62#MXaE2J literal 0 HcmV?d00001 diff --git a/static/flags/me.png b/static/flags/me.png new file mode 100755 index 0000000000000000000000000000000000000000..ac7253558ab939481a85cc06dcc4d73503afb9f0 GIT binary patch literal 448 zcmV;x0YCnUP)l$FJ^m&#tWvBA4C(n)b76qu^ z3TjKJi*u=MzAs;^(tHqT@6cZ|8AHxz+0T%zR}I9mkc`8faCz48MN^H2?$<3((yN)j;^`52o304M1f80R+|X9}Iwu*X+N)@cjDs2c+lU z?_dAGBv9wyKfl@e{~Tjr001}1@4rADVDj%Tpgtwu-=}^u z00a=o2DtG+^6#HtKYxRyQB?o^{pa7Gzs!FaUNHa!5W-0i5^f%h1nT_t=O0kRUm#-m z!vGLKP#fTS#5u+P{rv~@0nkXGhChFS;q~V)5d8o97pUPE13&;VK7Rc89~k`k^9M+( vx2Q8b0Y@nl1JFDW`UNKcfk_?)fB*vkB(P&2-J7g<00000NkvXXu0mjfGX%sy literal 0 HcmV?d00001 diff --git a/static/flags/mh.png b/static/flags/mh.png new file mode 100755 index 0000000000000000000000000000000000000000..fb523a8c39d40401b9abcfb144a73cbb2d76b286 GIT binary patch literal 628 zcmV-)0*n2LP)qpJCu1p{#SASZ=3QjbPhlO05Jg0{{#T~{M_a8tGL(@4F<^6===Qr`uzX+`vVjI z>RSuFND|!tCprH%UjG&-`Tqfgkh}r_F#yj01OWa1_W1j+!`}P+|NQ*@_xS<*{r*D) z#ao8o+xY#_%t@QS?0~yfBW+Wj{_zyJQv%*f2f%)|)v=^uaq0&4j6{l|Ybrbh`TZ`2ITPyN!~wBya;Q+wXO z|N8qsP{n^H7N*~zApZOB??0dhfB*t%@KJoPW~Y4ZyXB%oU++J<@%!g5F#%3te)iws z==lAQ0jwGr+CT&T00a=DyL0x5XB;1||6pKv0FF^K^bd&vjBEyg00RK!=O6aq+V@KU O0000p}y_ZxVsQQo9l8qD!tQ%&&F2zEbEdU-v3mY$p-gb*;wwp?LFG<9EeNpZLj7Q z>zeacpNZ>XJG@0bcmXcALo;Ad(L@#C92p0~G#aM!FfF0T7^YIJVVFaIl|0gRpSyF_ z@0dgJ{oT}qqUk#4;-a-U9Fej5EJ`tIE9)E!qDfL@GEq>vEDI}q@P8EmenIHxu!*Cc zLK?@%1j7u0A`mPlm`kyT;5daWs;EH!+LV0IWO0Zyj4+sHxRqia#e9ki#cu?^6YQn9 zOfZ8&4uw%r9nR_}FG?tJ1sBpnAsdGMh7pA$Mlm3ABvgz9aj&GrxaT8{1^YB+UzPEM zQQ5*0;(QnblJRNh>E*%16wccXl466KPu9Lk=M%$}%9~Z3xs9na6KbZ+^U;AoQ+JVg=BO3kgY$Vuu?iP6r(sQV=EH;Iwf|hcN2Nd zPl_EfW;$kS3zh=H4ojC&X!7Bd!`~OdX{VxLp z5dC3f{KL%rhe`hT|Cm4jfB*jf2Sk3^vlaWpqpU2@27mx!VE|eEAE^2d5dHlPWd8sE>;L~hU=6?i|N8~f1J=Os z`!`SnKmdWv|I6_A575egAcQa*n+Bj_fB<3vdK75(@4vtQ{Do`yh0yRHtQw*LD9^wE z5I`Uef5B$|`u7W{2T22%M6!Vq>?D8y0%`dD|M#!IAl1MB{`!Yz!@u8fUYwuxex*z#9GlH2{4I3~mO10Ac~g+V6jVB)KI)-uUyEi4o|t-;5vX%A}^sE-TCS?;peW@7xO)zGwLT z>;Lb2Aa%cf{|B;v0lB{!Wo3aj00dxJ4sHN|VGstA{YR$4C2D_2_!cBcz(8l;%*ju; z_5-pDt^fjRVEX=(;rPk#zkV}({q}dw+K<0~Gco-B2UY|%8?FIpIzRw{{P+Lo&pY>j zzJB!i)2Bb*-v4F%#qjU=2Y>(qX<+*Ohe1*jY|LMVKOmiqU?UkIBoO`m3qe4|00G4K6*VFmu*EK13J3rK Z3;;9iRuWt9^;rM_002ovPDHLkV1h$@)rkNA literal 0 HcmV?d00001 diff --git a/static/flags/mn.png b/static/flags/mn.png new file mode 100755 index 0000000000000000000000000000000000000000..9396355db45a8ee040c790782209868acaad4b85 GIT binary patch literal 492 zcmV@{}>pU8D26lh`@M2^zAEy;6E4#hyVhJ1te8n&0xjw|I|OmAOC9q@qGTx`1kMs zKYtki{9$JJ&B6L7=Kt^CKt7QCvS|}Q0D(0y{Qoccl;O=^hIfA-|M~k7Bn3tPfBpOS z`}Y4|zknP@Sy`YB00G1VQttboLEtY##9yH3?>`J++5f+PL6rRiQNLgu1_potVgX{t z{eKx$|NOuHhk@zOpC3@OA=>```VZI207MK7009KDfg$woe}>=xgMa@Q`TZMV99$1f z=+7UZ=>P!)^22||KmS$!{Ac;a@cR$YT8L7JY6c`57{N{g2q3VN{s9Bw7X!l|paf9r z=TC&I7$7zP9Rm!dKY#u(FaQJ)NCWfVKmVWoW?%y` zm}dTA_#*kA1?Z>0QqoLZAnySq0pv->KTM2<4My5DUW>hHBSpkmCRUfavf4zkmMxWn=;={POe9 zpZ~vq|NHajABg<@_xGlmn*aic1*nOE;s2AbPk~B-;NSn>+$?|p{{I~>&N%tu*Drs5 zfBO0B*Z*HY)v`RYKsx~fhzW>+Cjb5S_s>6&>Le+qufKnBv&bF%YWVBlABO)w3uGC7 z{rLq%Ks`WL0R#{e(EPs)fB*akI^_5N|9=)g|N8#t9~WuY61}otf4Tqs`!(tD7m$X( zzkdG%X#fZyCZKPCW&?Et`7z=QS^~DI8Yx-=nhgK{7whGvYgWDg!B8&G1k~{7FHk81 zKmY(S0M7pd06qXVA~x>%?)v`v$?y7WENVL!I|c#<=Jn<;5-<%03=swpg4MkH|N9RH z59P$=0*D2u3CIB%01Ag+CC5rQSvY_G`T70NcNRvLcR${}{{9+hIZ*cRKadRo0R++j zv0Gk5I)>DQ+oULEUYSww-@{VeP#&z`*?j4i%tcfB<3v#u_k;CAlSmszIWE zes6rZ@!!9HKqG(r{Q)GE1e8GG4GeUkhF=T-0mR5q%E0gm7LmVTk@^EErhg$tKMw;y afB^u%K|axUkwLit0000IqP)p`2X)eQ1zd`|Kz0p8A$%R z`bTZnZKVTj3KfeK`2Ky*5B&e@&)?sFfZ#7s13&;VG5q=W=RZg_5SU54z5Mv&imk%` z|FW?#NF2HHZpKX|PKHOnfBpIO`|qDW|9~0*0*DFdzkh#$Hv9ux`j_+Xe->2}ZC)XM zHV0!dKPS0Ur}$Y}|Nr_6wBa96o`K;HKmdVl_zUt7(16dMgtTSeTz>rQ?Z?ko?mjsC zklD%d+V79-zd^=BZ2$-$7GT%`Z2%eY=kMmT9MVkp=Y%mFes6g9+4CZ|=Y~?>`*tz_ z9Sja7kOqJN0yzojravHW{k?SeQ|&okK5=fKkARLe6n%c?uEf?;0ubZ>f;9XA2p|@Q zU%!CHiwJW41sn7GB}e}J|9v$?qW1mmH(Bw2pdk4RbO%twKY##YWMEE2jz}>2 jgG53Y5Cqh~01#jRFwa04;J&RL00000NkvXXu0mjf4K^ZQ literal 0 HcmV?d00001 diff --git a/static/flags/mq.png b/static/flags/mq.png new file mode 100755 index 0000000000000000000000000000000000000000..010143b3867f21e7791b8254e806b325c13b2895 GIT binary patch literal 655 zcmV;A0&x9_P)$g8u&g1qF5h0Q6aJN-{1Mbz`Ie0O|k$ z{sM@ZfzzR@(T$Ir&B098+eukMUeMl2+1^x^fq~&CAE%jZ{^O4ipMU-bgNM&P{`mQajg9%ivrm#DT>t+4XJGgP z5I`&pzyAFG^Do#{Ra%^vg_(hwneqG2-w+MozW@IH=Wj)-86P+6=Wo9l8G*Kb0|+3- z*{jc+=}JF+`H7W<>HmKQUT#*P1{)(8poaY?9|3*x^4(W97N$Rc|4EDS&R=&5Ab=SE z{{73y$Ox4F`Rgyx2o@H`|EK_{=f}^#%*+g|tSlctd;ka_mU(L~nd(ak@UpY9GCq0n z(2rN05Jg0{{a96b$W_S@ACL(Rxa}M z`G=gy|Nj54lTiQv|3YG^`}+MH7z}h_G^4TA+~V=RqI&{}iQ&&bpkF?J{dw&CQ*JI+ z5dlsHn4|vw{rBhJzZb8+p1k+fF;B_XE! z42<9q0s8Xa-+!garV_&3Uw`~!Vgv;%KmY+HvKbgYfiyF)F);jMVE6!x-Ip&{0DU4U p=>-f&1_my$6wo1$fFwYG0RX)13*@;vt7rfK002ovPDHLkV1lt{Hh%yB literal 0 HcmV?d00001 diff --git a/static/flags/mr.png b/static/flags/mr.png new file mode 100755 index 0000000000000000000000000000000000000000..319546b100864f32c26f29b54b87fe1aee73af21 GIT binary patch literal 569 zcmV-90>=G`P)rBb0vs`uywH-=91j zzd+y*NDt6q00G1Vbl+cwzkmM!`SbO+m+YTk|9<^u`R%^_m*bXSzgT|#{QE0P`4>nh zQ2ZZA13&;V0loO=-(MgHX#3gMzn3`u{`KzHucyC$Kl}CT<*&8wzt6n|ss8o%*Pp+C zfTjZk5DUl#p#T2<`NjV0^vyqym4EMy|26&E??3;3WoiC?{O#A4)4zWSfZPMI0U&@t z8bCe+8UPFj-d`E(e|zZv%GLeN@c(z$rC;+8f>rHtN0D&|BIS>OtI{AOC zx$tZGDUcCBkzc|7XAeyp!)#=hy@sHz%Z8Nmi!G71?uGb{rk^vkcEsO8W!D1Ad0T=%Vj%gtVfB*vk>3V2g53(}_00000NkvXX Hu0mjfpCtxQ literal 0 HcmV?d00001 diff --git a/static/flags/ms.png b/static/flags/ms.png new file mode 100755 index 0000000000000000000000000000000000000000..d4cbb433d8f9fe49f06585dc46ee15593e3e621c GIT binary patch literal 614 zcmV-s0-61ZP)w!6%f1G{My^>{rmp(`~Up={s8&+{Qm#<{R63-jRF8M0M7pe zp74|h+7SfEy9M#{{`U3;5)b(M0y+2j#`QMv`vWF8IQ;$o{QUp?{QmLR&;S7V0*Gk~ zkHv3!H5OU9Kb*Y(q-ELEH9vC;U*%N({+r?VuV26a{F4-VqagC^H&EN}zd$De1Q633 zj~FHafsLPJA96}RV-#A)X~v?X^MOAye@1K9u&05Jg0{{zeC zH7h(V@9+2F_Xpti2mAc}=j!&)<^S{h0sZ;_Q7ob~2($C-{v8Cq(%>lF*}4LV2^e-j zV}AbzqQAd@=ogUu2Vs2v^{02G<;{1(|2aQ(EV23Z2N=G800M{wXv^O}|A7VrH9+)$ z7=NG)mcRcxm)QV402KN07wDuv009Kl@CPU%A;t|Pff9c}I{*Fo2PXf3L>PYm|M&kd z6T{yxzy1Ri0|XEw14AS%MzNxQNDQDd27mwq0OfZ^Ej7^!+W-In07*qoM6N<$g6Gg9 AMF0Q* literal 0 HcmV?d00001 diff --git a/static/flags/mt.png b/static/flags/mt.png new file mode 100755 index 0000000000000000000000000000000000000000..00af94871de66cd0fbf0ca8e46dc436d66e2f713 GIT binary patch literal 420 zcmV;V0bBlwP)Io>l+&W2PtRx|M&0z2M_*#`0)SN z@BhDl{r~j~sG3n$7H9)N0I@K!uxMy#e*W?mp&AJO{R1fisrv=e1J=Os`!`SnKmf7) z1AD;K%nYO&458rnZ>;h=xCZfJy-Z2&4h30>ylo1|%C8 z!A=4QAQtS#|N9SD2R9xVP=6R000Ic%Boqz*|DhQF2dLpM!{5I^H2?v`f~*=Iag5B& z3^Fndyu3hzLFn&a2m+c75I`Us-n@D94+enNf~Z%o__l08i(?1?2rvLmwOi|Xk;8TX O0000wT1SlAdCl&Y)$gVg>5qW^#Y{{Qp$|KC6V{`~n5M8AIn z$$wxH$UeVm6F>m5>|$VWV&MJy|4IE<4N06-W9 zfN4+=|Nq*iiwn$Q2C&jbT&$=TD3oCSlHOGFpRx(;BY;>KBo9alsWSh04>T2o{{H<9 zq`@}){__Va_~#GM1}QP2gACgN0*LYNU!Z^U|NnpRpWzq7|3Cl#|Nj5~7gmyqN$LIj zQvdWzhA$B4g=Z%5I`U&fgJtk z_g|1x{{H;?U6oxK=&at?J**6@V8K5Oe}Dh~1#%?NbbtT?*#Hy-y7l+}Kff9N{$pgg z_WK6Ie}+7v0!uEdpa1{-Wc>4s0pu$NunhnK1op#kuysJ&8U8Z;`FH#0jm^LQ>Tv2E z__*)izhD3U{sq|pR0FmFAb=oF`osMFS8?ijP~d>v`s?4X6Tl#928Ghke_*>=zWoA* zI8ZS_0I~c5+3<%^Qj!Z4rNibE_6+kRtZU3J46>yw zfWS`r^B2emYGC;Nhw;yEHn21ZK^Q<1%m5k+3<-b$0%`dF7h*inus>j>Kov-;VIf zD*pWek$*v<0SxiK|NjEzfQkVEh>@X`f#DO--wX`DVCWAL;}4AS4@`0~00bBSj-y@M TF2~k{00000NkvXXu0mjf^ET$> literal 0 HcmV?d00001 diff --git a/static/flags/mx.png b/static/flags/mx.png new file mode 100755 index 0000000000000000000000000000000000000000..5bc58ab3e3552b74d990d28a0f500e9eb6209dfe GIT binary patch literal 574 zcmV-E0>S->P)LFc1LT4cKmY-iGBrkbGB7ay`}g

Nzrc?B z!}RAj&|v@p#KiFL&)@$*g@6D2{reke@BjagZ=QH_|HA5tt#{7v1Ul>guV4Ru|Ni&u z_rKqNfHnXG5DUYvUm)ZE{sF26>H%tC6A=5t#K$G4Eg-G_A87rbKVS#^0WyF#00a;d z1Ca3#WHt~1jRI=eclPL04k1AU{avRH{sTG*Y{UOQAO!R;KmY+XFaVtnvEdic(+vNe zOr8IIc?-17*~$Z`|L?Eg|G`fB4^+g!01!YxCouq>54Pd=FQ6a({TC7tjr5F#2GXxz z|3N{=01TJ^fBykB00a<7!|#88#Ce2)8ovGh$;ikEv=>5x7)(s8a literal 0 HcmV?d00001 diff --git a/static/flags/my.png b/static/flags/my.png new file mode 100755 index 0000000000000000000000000000000000000000..9034cbab2c02704b65fba6ecc4a7a1c1d053b6c5 GIT binary patch literal 571 zcmV-B0>u4^P)Z-xKO+5@Bcl`=5c~|G$6#Vc^TNX8-{JF#yj01a@w+002>mTdm0Dxpa1{C#)An)W@eTA0)PNwiNI_f1h_u_DTrb&+z}xv;{Wj zFGj0Cgf$G002ov JPDHLkV1gu%1+M@A literal 0 HcmV?d00001 diff --git a/static/flags/mz.png b/static/flags/mz.png new file mode 100755 index 0000000000000000000000000000000000000000..76405e063d43f2f3b5b9cae4f76d9f1c73cea25b GIT binary patch literal 584 zcmV-O0=NB%P)d!0?ZO;SY>NM!#Sr3j;s^4&s;y01$=&U~zyG1R{bN8&$-J2AZUB z{O~2s*67}BSLujJh!l{(TM_&V!SLx<0I@JIFetqFAHVYHe9OP56#xDPD){#oDEIpx z82$bI>))?me}4fPvfQ#j8vp_bq~ZU+|9p&pvv&RstuJJil>ZL~|9}umff)b({bONa zxh{1bAb?oDF)-ZV`m5;k=ljw>l6BpeezVN}{rlPPKR~N~|N8X{NCKH4>bI<%?516t z00M{!=o3jd#=5m)yzyNB8Nca#eH--U&Fe3(f#?+keR}os(@P+F`}Hl*IRF8~0t}ng zTmN>%etWlrgX7)b6MtD}{$cp_8-#v?7>pqD50GU3{f7;x0U&@Fe=;yIS7rUbaG!zu z&%cJ+j{>}Z{{3SByBg&1|Nj_3~Dr2e;Gh>zZrofD5`!lF#Z7{ z2B7#~hM#}`y~Cfd!0!j9&~4{}>qlfDw=_GI6Spo7yiaSL1(R34j0qF#yj00RRApetkm@ z3-<^I`04Bn_xS?+{Qmv@{`~y?GBy}bOB@O2-v*J4|MK+z`}_2=vH}QbDjOT??*y+^ z9PHma=D0k1DE9l$Z%$6;=mbqObq>D1hX4By|NHgp|L;GHwRPtz;{gH)sDXiz;U6Qz zZ)V2dKoY20MNK$ASA+NcQ;z)f|Igq2|MmO7w9@DL!aL%O?v>U60R+_W>(dw3rWqbw zY+vs`7YYhj_p}$}TRP+a`c40T|N0L!J1pWwjPJac>kgmX!|;RwAb@}x{`~&)@5xJE z5fO>bZXLnj?>WlS|KEEGbn$;~p|4%Vx0QJ+&gI^Ic|%b^5f~5v0R*z)@87>RPSSB9 z(mdPNGA>^D|K~4|Gn`ysXGCuKcCvq8=a*k!egj?m?>8{m00Ic8fvd1cUx@iTXM5HE z^H)FyGjo2eEq-FG+;YA1)Puvn7=8hj{`vO@7;-=x00M~R?)3!82NxK-n*V?K1yZeJ z{HiGaByR2;1J+usHUNMy48Q{FH!M8N)Pwp9Y)wTFo81A^+}-HTA|tp~ zO4-IyLWKVGUAVv#KrFzpU^vb8&*4vW%&*_Sfp-5+Oa#jR{(FIy5oqwQKVTa`BqPut z3=9AP#KLU;d%N^MnR|>Uj{MoN{TEQv&!4|iQhqnS=35v13ux)DKYxDz{qyJVA7#|2T literal 0 HcmV?d00001 diff --git a/static/flags/ne.png b/static/flags/ne.png new file mode 100755 index 0000000000000000000000000000000000000000..d85f424f38da0678471ef4b3dc697675118bc7e0 GIT binary patch literal 537 zcmV+!0_OdRP)pTI(!tjlO;rIXl@1HV&)cpmDGW-GR z`3+L^2aNvy`v2$G|KGnEMPz|W00M~d>&=s#l8OvKbwEpiHvESG2>tK>|GyyO9|$ut zvpzk42q1u17-V!9I61+pfvQ08|BZwH@16Yr=jVTUlmA*S|6zcEk@1g`6+i&7`~&$E zYA%%V^7j8zTmS$3{hyirzos*?2B2bq00L=%yMh7Y5+V8jy0-s+|NJkm_8$o_f}Hjb zAb?n|yt|^zto-ZmuYW+t0)q+&<<KJ>BgrQT zRQ>1Q-#;J~AoS`6pHRCwBA zU~p!DquG0BzkdJv^XJbWKYo1u_VxSs@1MSW+P$@#L70Jomw|zm0SEvBhy{qNbE|>m zzkmO1v}^=;1(+C_zx@3C{m*wPUMbGM98Q`}5v}3B|NZ&>_xGmUO#lG|(!jv*|H=EO zfB*gc{`33)|Nj{n|Mza|{r>BFYe?(AfB!%K_3?Y%L>Z^l>!7{V2qIffI$#e zz5f4~?wt{_jNwA=k=tvV8m;04hxH1ClNsp|jaD0d_yUND;Sa;#|9^ps{`~n3bQJ?5 z!?D}Pp1*tk?A@~oJ0>vvX8@W7)C|%C)&LMdARGSt{R`y$`S<5P0|@TEy!-p_?>~S2 z1lj|1A`hhCuT1`^U1^@yK06yzfAV)~#?EnA(07*qoM6N<$f^cITh5!Hn literal 0 HcmV?d00001 diff --git a/static/flags/ng.png b/static/flags/ng.png new file mode 100755 index 0000000000000000000000000000000000000000..3eea2e020756c41abf81f765659a864c174f89db GIT binary patch literal 482 zcmV<80UiE{P)E-@kt#fq(zr{dlL|rVbPb$^K$sU||3VAQpx%4ArjH z5b1ya|A`BUvomopF#HDspdkBi_LzW}KMcQr|NHa%@9#}BHvt3?3s4hK`pMU)fB*dj z0+88E|KR{Ac>Ck+U;lpn{`Xs!M;2%gKmf4-G0FZ zKmdWv|I6_A&;LJv{(%shYM_N64Szv401;3FKmf4-Jp?oxsQb@fum%PU8~*%)I0>i# zs2CuCKpOsn%?64Bg>X9QKhy?*00Lh)xZD#`v33$e!wuw~|G$AI0?h>~ z1_&UqlR!#;Ll9OQ{s1-n2ZahyF+c#Z0Amdp#**BUAaDHn%gD$G3dPzV3};X@Gl13bFaQJ? Y0MmSSAW;3b&Hw-a07*qoM6N<$g7#LQDb&XuwlP!fzJKM z`1`}(|Np-K;|B=>MS!;cWf13KY+LvSAb?md?)rCHn)&`aU^p;VI>1V00D#b-){yc34R8!1Sqb680000@|4`Xj5kLTv#?55wQzKoX38|NjLffBpXj6#2y{D-E;(Ab?mHL=FGT z$TP6>fK>na1GWK({(upf0nrSU5*Gz(00%w4e}91F-@gjtJbOE500a;V!?RECzy5mt@dro_q~YJM-#~SLe}OeX zNT7y4|NilCvNABd0|+1%hF>6clER!2lYo}|1|zVkK=SXOfB*mf{rC6ZKVbL)odgg- vjKFAPVE6?_e~=h|kVO7~qZmRm0R$KTYszPUy89K;00000NkvXXu0mjfB$dbi literal 0 HcmV?d00001 diff --git a/static/flags/no.png b/static/flags/no.png new file mode 100755 index 0000000000000000000000000000000000000000..160b6b5b79db15e623fa55e5774e5d160b933180 GIT binary patch literal 512 zcmV+b0{{JqP)O=a{vExMP2%`MCSoB^FIcLe_%lf;|~%E5I`(IQNh}3Ao>6Q|DFUXMn*>AqQd`w z|1kXd^B;tM|Njjl{{hM0zwd6?1Q0+hV1xeud-4=Wy?p-%sO`^#2S61Jzk!N?s)6X& zzhA%p|N6}=D+{y%Ab`Lc{sL9~1=0UN4*CD*7s%9KAf+JHKs~=eB-8KTKvw|-5R1&; zzd&a|ob(5%^Z$Q=wHy9p13+aOpFRNu5F>N&`Tk_-7w>=n{RejQzkfh&Kn{rf10?_b z{tFTZibx5v&dxav5I~H7|Ney-|DWN1$%1FyagzUW0464;_wU~W1Q5$TW@eGxtUvee z3vAf*8|igK9~@*rr66bh|NrkNM8z+V zAV?>O@ek;bKfu6d00KAO>U2WB)$@6+CBT{3ok>^7H@y{~6FRKmalQ{r8#S z4^Xx6Je&%q%J2@E@iKAb=Rv<(vO+e^|@#56B5{*~0Mg z>UitA{$OPI`~Tk`F#7!u z%=q{3H<BYX7n!%ts-g52=?&#%8AHvnDo=g*(t zU{@(f3Lcro01!Y-3_uV4{%5PNloM>zp5gQNALI8Qf4=|z|KsPsAHV+n`1$wy&wt;4 zfzU5-=mP{0FqD1)U3&iJ)0b~Q-+l7x$B&=CVSxxV`w!S3U{3%6(9;Y60R+_W0~jFx z85t(6Ir{$dcL`zMKcF!E2U7}WK$QOlX#fZyMg|5;)aZo7D4hMD0TloQ7ytwk}@P)zKX@%&%DST%gMqDF&nJ<9}^SM9e)7=i1G97Xij+!pc8>s z0}TKw06GH{9{>J;c@WiqflO8wrXNp!0t65X1H*raF>uuoM}q1_&UQ zzyE+PV}l7nR6|1@Xe}f}K_mmn5Fh~%KtLN9K+(a>4Du5*FzA2|{m;zE0Q4slD+}03 zKxJTefLQ+k0*D1@+|Oq}Kt_TL2e}yHXa<;L{(_vY&wh05Jg0 z{{*4}t^?F62l4F%@9_Wk_yrLV`1}4n_xiEzG57obO$p>A_3H5V5SZl@9UBk;0Q>>~ zF#yj00jE58tx;oDUfVAO7ZA^g)(IQ}Y8G-;ZB^s|2r!a55}@Ef&J{K=uDyPxdE3 z4FCZEF#yj011R$m=m{0X((d>7`QGgNy~*X%==~K4{m|+BO$p;F|LeE!5zX@o6aMwK z|0Cnry8?)1@m-dDW`RF^3@85Z{`vj)H~*iTuYX^D_V?HC|LG63e*OOQ`}ZH9+h%{4 zR^kLX2_S%&fc^l6#;?EsK&pTL{q^hL&)-1T|AVLlN&WsC!*d@f`}fa3pay^dVgYLS z^XKpHUw?lCNw6Z2x?f-t$o}(Zg7`(je_wy{{yg~C5U2qlfPfml0Rvc4oChck)CmlD zkWL^2sNoMV9{$c|wex0wa`2z{-@pGE82$nT5F-OaFayIEq`3SAj@n=l%a5DE9w9oI(Q6o;?Ey zAdrT?A3yTg*!;YE_t&FGSk*xQBO~LVKYsuMhzTgoEGG70+cq{OrGLMF<5CR)KqmnN z5F^kJDrIFqfoA{t^Z)mszkh!J|NR@N^WQHZ-f!>?ZqK&!y&{zFIzP0wn(b{R37FH0BS}Z;-(ZzkW0R z`o;JgO8$qifBy!003d+C8bA*C^$+NzU%!${e*gOW>-S%fvmgwhvw&=%Tb23#oNZ?S z2p~`>{R0^fayL*XP!U2MkOb-c1#;`ZzkmMzW%$Pc5I_(c{;*0)g6#S8SB49$^)FDx zACSQydx0wd{{073{+Hno13&;Vu4Mp{AoLGRCWbOF`~tJSfrb9TxDaUu27mwq0KDvZ UcsT?Vy#N3J07*qoM6N<$f`X&bC;$Ke literal 0 HcmV?d00001 diff --git a/static/flags/pa.png b/static/flags/pa.png new file mode 100755 index 0000000000000000000000000000000000000000..9b2ee9a780955566cc7dc2f59ce175f32d3731a0 GIT binary patch literal 519 zcmV+i0{H!jP)|lVPPN>g8sl5Km-s#EI@faK0YA%?%RKmGG2!N|AD;!zX}Teef|3X z_wWCI{=muCn>GOi5DUcMXP^GBIsf;|&;M~|Oj3M||NsC0d;h_|&!7JP`u*?sum8V( z0aY`}$^xwd2q2IKptK|}gRT_Am!FIf)j$AI2PS_*H2ec11_potVu8EfUYUvEKf`}G z`1lE^`X5*+Sm$r%-@k!200a<=Rv$}~=bu-f|Ns5_|IfewfBrH6Nrpdvs+^pde*a>f6qSrfAZn~Z?Fa+2||AuS*t4lqXH%-ra!^K00G3r z@ax~7e+)2nAoSxWko^y??$?YNza~t8coi7j009Kl08{<<|1U847wF+XP}P60U;n*# z@9*{N{$9Nb{(u|?WHSN*&{SqkP0pSkP;|=6L&63i zfEXEE-vV95@Z%rDuRkCLl>P7efnPxL{(%8d!yj-G00Mvj0{}mHT?%@XEt>!U002ov JPDHLkV1lK4=}rIu literal 0 HcmV?d00001 diff --git a/static/flags/pe.png b/static/flags/pe.png new file mode 100755 index 0000000000000000000000000000000000000000..62a04977fb2b29b96d01ffef3b88b6bf2ff05862 GIT binary patch literal 397 zcmV;80doF{P)@|A6@UbB2E)`X3x9D*gjYK@dOyv49j-R|ARv|Nb!om5Pi12buAo@&A8j1_q}8 z|NqCt{Qv#?|DQiV^2?@8009Kn!0`Y7lcx-S{{qo}h;n3b`}Y4|zksS4Wo3aj00a;V z*zEsM)xUqEs|Es~YOn@|-@kzx00M{wh#7&Zfj0j6!|?mhe@uX+0cadR0D+zK=P$&S z1T_5l12i2VfWS`r`v>f&U-&gJf}I2qKwu{UjsNuvF#Z0+ASnqp<}V}$85tQ7(W#^a2}2+PDh3E3#;-`R r2#VqJ=b;e{^dbb<+Crtk03g5s0zF}bJ8sS=00000NkvXXu0mjfKVzU% literal 0 HcmV?d00001 diff --git a/static/flags/pf.png b/static/flags/pf.png new file mode 100755 index 0000000000000000000000000000000000000000..771a0f652254b4e891fc73910aab38967864da54 GIT binary patch literal 498 zcmV3lobsI zohi_A`bB&J!~)dH$ngL7lczwX3_#UDxxarw>LBRX?|;94{rmL`$Yzn1{l&ll5I~Ht zU%nI;6$RPw9|VBf|1(_vbYnFmA3K-0+yDOt{~_StKSoBzkDopP1Q63dnCt(82%zd$ zpFb}6I_2!oo##J&nDhVtbEpQW0tSEpVuGrMivIupee<8UpWZS`Uj1hH_v_am-&g;K z1CTfW0R#{WvT7jw$rQ2Wy6P|4+kZd)xq2}(*g=aGrk)Yxu73al#Db(Bq?4D0-N;b? z5G()RfB&pB<@s4TkY)e;`2!F@EcYcO{->q=ymt>64xqsK^^5b@FIO-F$h{9?`~e2* zUv?FhqZcm%1P~}#|Nj2NBq_=8`#0mCzd$+0-@loGnqiRuWPl>)F9-k?0|XG`aR!E8 ou!#JF#Q1|6-w+1S#{dBa0Kx%7Vg$%BF8}}l07*qoM6N<$g2}Akn*aa+ literal 0 HcmV?d00001 diff --git a/static/flags/pg.png b/static/flags/pg.png new file mode 100755 index 0000000000000000000000000000000000000000..10d6233496c10e52ead975c5a504459fad68ffb8 GIT binary patch literal 593 zcmV-X0Hv=@BjaQ|F{1AU+wpQ{$Kys{`!CTH>0fVKL!SX0Ad1a`1cQJ=-<7ptZmH9SAnX3 z{Q_yQ`~BbL*ME+m|K)!Dcl`DLKS&U$0U&@t8vg$M`{&P}#F!W*N5{%vzvln`{r&f^ z{||ospYrSf)?fc0{rZ3A*Z(w-2B2bq00L=XVPVP4%$zZO`i8aZ($dmav$E#>{B`Z@ zum6{R{h$5&|A}A!9e(}a_zUO_pbY>4IGm#s06-9cg3a4XeYH!D;D>_*`V5R3;NTtr z%*@^Mq=>M$LXVh`5jChqDeaf800L?F_U+sH_3M8E<^KOyQ&ao$p literal 0 HcmV?d00001 diff --git a/static/flags/ph.png b/static/flags/ph.png new file mode 100755 index 0000000000000000000000000000000000000000..b89e15935d9daf25173f89a36d8111824fda5db5 GIT binary patch literal 538 zcmV+#0_FXQP)N~0_Y@w0Al+04@f;`V3_{@|8#9F=K6XQ9UY*azdwKd1Cc)=8bAo50U&@_7#Kb? zFg*PK|H1$NTnr5Nxw#FRn^&xvtbK0f`#-;cuKxpc)t_H~fDExeq6ZmH0|XFI1NZ;` zGXMXp{AUnj_^>}zDz4B$`$1}#7U0X2MOU=aELU!7sY=Kr&1{QvMCSsj$|2dLpM12Fg)7ytqY zsKMy}yX6c^FZ@4woIyZ63`(G)I*8l(j07*qoM6N<$f~Z~XumAu6 literal 0 HcmV?d00001 diff --git a/static/flags/pk.png b/static/flags/pk.png new file mode 100755 index 0000000000000000000000000000000000000000..e9df70ca4d63a979e6bcea2399263c081ce5eaeb GIT binary patch literal 569 zcmV-90>=G`P)`{xe>ko^7oADI06=l8$gn`UeR2p|@S@&Et-|M&0Ts{jIsi2(+HrUEqpC9EW^)CAOaJl^^9-%lBC8BHP081)#ChQGgo zHUI<=3(zGH+B`^Tu)Z%{q{PpYS&%;j+KluCr=pK*_e;5D)h=t+bKO_wx|Lu6N(?HnJ zN6`lu;-7zgR^V0GaA(7wCwqWF2h;!%KrH_l5Kj8_?>EpHKuhXR);;uSzaAK9KY#yZW@T0p zQ2G1+FVF^n0AhUp{`o&J`0?k5YKbbt8;l4>j(9ExfB*vkhsr>Vq>*li00000NkvXX Hu0mjfu=^7c literal 0 HcmV?d00001 diff --git a/static/flags/pl.png b/static/flags/pl.png new file mode 100755 index 0000000000000000000000000000000000000000..d413d010b5b097c4e0a4604eba86dad79567ed16 GIT binary patch literal 374 zcmV-+0g3*JP)Ab?mv3iQ8Nu5A{|6C_|Nk>HFfjc`0biay0|+1% z2B@O{$c+Ek03##gzdwHf0*Hl3)etG5lK=vU1?W~rxN0!OqXDP`Ab?mH`1u+7`u;zA z_W#cxhChG)!_n{G|9=A+zrl>(AX#bYe+w4^1Q6Is4VEzI_51&? zUm!LT$@u9L&^Z7B1a=Zw2xL66B2?87%l|Mi00a<712fnG3~)u5+Wr7F{AKw27w8;- z00L=X`u&GNQW9*;Uxq&*os3{386YGO{rw9;K*az7#P}5)xp2gQ%0-g`0)PMm0MPYZ UsK>Njp#T5?07*qoM6N<$g4HXSwg3PC literal 0 HcmV?d00001 diff --git a/static/flags/pm.png b/static/flags/pm.png new file mode 100755 index 0000000000000000000000000000000000000000..ba91d2c7a0de26e554979f6351d42a1a4e22de3b GIT binary patch literal 689 zcmV;i0#5yjP)#D@XkmAv!xDMMW8-mEZ&mK%|%B2@pa*J{pUD?(_ahBqlG}*TVt; zF#yj00{;H~{{a8``T70x^5Ww5-{JLFN2dS#-{Io#@$TjE?&8zZ_V@JO>E`A8`2YX_ z`~rx{;oS`3$G61pUY_{!-0$E2{{CbX;QPSJ^3BEStfg-V`n;-q6+;t+Xyw zOy)sS^8$#8OF-b~@87@v{bTs||L?z_Zq~=&zGIaZd&b4_{m<{;|Ns5^`sL5xKflEU zUjXHSP67x3F#yj01nBVe84eEr00I90|NZ{}FelkBB-0BC^O2xB85HWz)f)HsDi#s! zMLEolpK<^Iq5=Rh0M7pb=>Px;h=2d#;^FNBZtPGJ5bKP1n*{>+?(qio_5k|){tF25 z`1Sjqtv%A&PR-7P0st`p&i?}b008M5=kFQg|M&R&{r=?U4x6PnhWa{`B$w z?CApk{rU?E^8f<&008;|hy@rKe}6M^a>=kt2+9et{QJXr>zQ5ua`W#$8JQS={rbi5 z^Ctr{)6XBj7@3%V17i>%fEb@MFnj<<;{gVSbOv{z8Q{qN1r~!u@ISB;HgNQF0R$KT X>6#2<48ze<00000NkvXXu0mjf$fQr4 literal 0 HcmV?d00001 diff --git a/static/flags/pn.png b/static/flags/pn.png new file mode 100755 index 0000000000000000000000000000000000000000..aa9344f575bc92f4c1a5043e6e7d0a8b239daa64 GIT binary patch literal 657 zcmV;C0&e|@P)$VEDzr@CQtS7ytnPF#yj0 z0a0(~eP|Fd7x&oU`XvhO+V>M05dgm54eRCe)!y3s`vCp^_5Az)`uqj_{QRhrlmY-T z0M7pd#W4OILofm6?eh2PFCO>E*7Xbx0@lgN z0st`p&i?}F01o{F1pxvB0QdR->g@pe`}O_>?Enew{R9F2_ajBO3l7@{2K78Gz9u`z z008^~05Jg0{{!Vds4FN77!dx<`5YAi^1B#F4D8&$5I)oT72fOU?&Jm;1k~m5*82ws z?b$fe$;$!&F#yj01PbEP9OVUy$0!>9?*iHF&;9=9{2wXIjNS}D{P+g={1WdM4-6DF z>gCe?_5uI^`T_tk0M7per>)2uHb&;=(#87${QNQl(a`kw{Py}Y1nctu{`UwC>ihis z2n-DS{QU(1_5c9-0*DC|aR2`P{`;Tl?{DV6zkmJy$H?%Xjq&fFKfk|zXRCbma58?r#f z00G1Tv;`<3F2eQa&)+|P|NZ&>@AqGj(m#Ly0)zk56?XydpHmj-@bfY4J_0oTA3y*x rGBBhgM-@1KAF z|M~a-&+mVKfs8*8^zZj?AObQ@tXl^VK#U9w|7)um9zFT5!1JoGnu}M2{r|uJ|AC@F z;y(;9F@d=M{=L6-3m|})KsNsS&&$bh^PO0375Ag3EPt6;7?_!X=sz3*^#j#0Gyh{@ z0SF+Vlm3Z`F-Ar(?BDbM+y#c5od5B%>y$nn=KcNZ|L>nr$AC#T8JS}%RsaMLPy>UR z34^BAe{Qb-hmSD)`~82~jewZHH;sOtVgB{~2T_Lx z^M7~ue_6TzObGu%0nl7VM#g8?t^ouP$PYjMFazDG!uzbThlgL98zlelKgeJZ;~z*Z zSPxJG!?$k$0R+;(`ulr=6P)M00|Ni~>`!`VeZ#eh`fLE8Q){QmQQ=eGY$|NqCtU}^v=1iBd@fS3^8`SJ7r@8ADF ze*C{^(f_{w|JZZ@y#o+HED**2KY#i6{~yEeU;qEJ{Pzp|pOucqNnlF=0*DFdB%s0n ze*I+l{{11(um4^iSXF}z{SS2YKY#!N`GNV*AE2Jys=p_Au>JnK{@0e3zk%WO_xG>A zzkdJw^XDIk{pa6bWqzfjEk^+Y2&CaX+n+VzlIN6JC4s^J?+-}zKcEU=eEj+Q{|`_P zFrfeb|NHmfUxq&n00G3<$-qz^$iN`P!0-!({va{_z!?9)Bm)CLfB^vHpj0t%_B3$- O0000op82)aAGO;3n0AgYI#891D4N?IF|Ns4E{L7&Dm*MXp#y@|U|NLS4 z{rmr)KmTFmmra`h0*Hly38?u0llM=#nEx6H|J4!x{U`A6pVzdvv{Rd?JIrI9L zs`Fos+0`Q4a^C}Q0+k5A1KaQ$>Lf<6lK=vUh2aka(D+|}f9<^YM_B9kC$A?0Z|}3+ z`ptao7t>dSY6f5^0o~2O01!YR8-T_G^}PA>yZ7X8cHUpx=KlJ_{+sC?ST#h$AD{+c zSpNn30U&@_7``$5{_{tYU-I{#-$2g*Lz_YNHw#c5FVJd`!65YaF9ZRd1Q0-s48{x$ s?-&?Px# literal 0 HcmV?d00001 diff --git a/static/flags/pw.png b/static/flags/pw.png new file mode 100755 index 0000000000000000000000000000000000000000..6178b254a5dd2d91eeaa2a2adf124b6dba0af27f GIT binary patch literal 550 zcmV+>0@?kEP)~nkZ zGRMDC%7~XK0S0Tx8Wd7-QG59jKr9SQAk|O4{{Q=*0jSzY^rW5C9>)KFc0aM(`^fh9 z|Np=Kfe=u&EDs~YzkdJ$!~!z=-~YcrJO42FE6xsAYGq`2_Mbt_P-yG_e|4Mhx&31J z|LZSE!|%TgKvw|-5ED@OU$BE2n0|Z9O=M(v1mpqrFfl%gR9?uy{Oi{rkOq*RfB%6# z1PCA|pp${Bfd()#{N!P|4fj41<69Aq$E=K>;Tryc4F(7xpbZRv|AD;q^*8I6-->Vz zfB*5n`o{nM2Peo6f5F}W+3*h_fS7<7;^vxc*?8?`g7w0kCk@cHxaHDByoH$n$~K0fYN5BQR!wAqjL2Kmai^lz(OTgcO%Q oK%!9YKcr{|u^AZn7ytqc0H_5zuk@Q*SpWb407*qoM6N<$f;OS^T>t<8 literal 0 HcmV?d00001 diff --git a/static/flags/py.png b/static/flags/py.png new file mode 100755 index 0000000000000000000000000000000000000000..cb8723c06408828ce68a932ff472daabecc64139 GIT binary patch literal 473 zcmV;~0Ve*5P)@|4`Xj5kLT%`al?B=W5I`&pU%&omV`KRD53KJ$2txq_ zg7fbmh|k3I@68*40Al&@kBy(1nSq%Zss!k?M~{APS@-YvZ#JJG201x|0gQ}qez5@r z5EI0wa6>`h%cteq@9Mue|Ns2{KQdro`19u4 z9*F+^0|+3-w;#WAv9bOIX#?r_2Xj8qX@CF21pWab0}C_Lljko10*H}8@M3d^)Z>@G zf!6*0!vH4#gGo5!|DS*V{{HzdC&9L6!fAj26p=v+03Zy*=I{f8|9_}7o838uP_pBd z=z9{Sra^iHOE|+IC{ z-`~G~{{ZRVfB*dX11A6d`CYbrEkFRVK#Yg0UeQ$d`q2ZhA|Uz&)bIy{egR1#X&Imb zfB<4bR{ihazwp{dkXn!mkfPsU#_wMs1hfID1|Wb~;Esc6TU=EJGWFLlunkbN!Q9_} zL0)432p}e)sSwo=4bd$f5a~a^fBpd(3|0LbOac`E1P}{Q!+)sq|NsB}pI=e{a>g%& z)4?|U{s;0mNCQ9sG5v!Z57O~Jp}QY!5N0Be0)lgG%);U`26kn-@hOg zU%!6+4+cOs(0HIde9xZz`}Onxub&LUB0x(30+2WcIRJn#2ut|?gWYu1Cf+!-K%B8# zdf?1WA}#uZ8oj7u>$I1i0Al&`=O0k%-@icgAIJnM0xA6maSq6BK-ECw|NZ*S`0Lj% z1_pot6puj;05Ax`F!=umqj7^frO?t|3^&I1kxUq9yECc+jQpY84SWH_0#pxl$?v~F z@*hy-KN0|X07U)z`4{NpU%#2aHUI<=%a31wK(7Du52Oc(|3O^?R1IN+RRjI-n*kVB z3=9AP#PZ|EACPLGJ%9cJNh|>9B%spYzZw7h1%?tp0I_@ndg9MNE>313@6R75NcceF zkr51-#U+7;F#`Sf7i0rK0I_`g_NQ&Zji7_t0d_@@ozArL?Su`s;*Q{AKpRQ~TD44PX+*q00taD0I@Lq1k(S2nt`tR{g)9*1H=ZfhCe_Je;NM%1^NLXfPkU&2dGq1gcanC zzsyWb(hLmW7#V^70~+_6f#nZ_(jSmgFakOWAb=Pd7`8Gn`~pjZT=;x%FbfOAzdzu3 l1(F{a{)I#17yR-T)##NTdjqb^wzQ(`1@?t)Ix4MUXz556teM9A7Ic zq_@itH|pv>q+zrjZJ^Hx5bj=fD{5McI3ol<@^-l_@~tZGV7p>1CU&qG~{YccyC-q z$8~P)6sG{nMmQy85K$E6L33rja$x-b9$ literal 0 HcmV?d00001 diff --git a/static/flags/ru.png b/static/flags/ru.png new file mode 100755 index 0000000000000000000000000000000000000000..47da4214fd9edb383687c1d4f84fe8b42a51ceb2 GIT binary patch literal 420 zcmV;V0bBlwP)X|NRSO0LlM<{-BURBqYRGSojej zfLOL~|EH_V_~;P>Nc10*D0|Jxss< zFi1)Q<$$6LU}rIc*dU*QNFV}+9T))>0|XG`SD?F)5CbX~O$rDA0t^5@iDe$xIAIn5 O0000N_~0!B1ZtR02zJmAl3i>|Nr}+@!x-t zvcLa8?7#n*fB$3p|L;$z$Rx)9zm`4EX`B2HAb?mPX21FhQ~^@@2dMNf!=L~E|NQ+A zWdHd6KUK1c=hsc9f8Rnyezh^=0R#{e(Ek5GMIci_s{j0D`2GL?@4p}ozrlKzzsUIh zhw0@n(cNzYfer%*AeP_1{{8vS`0Fp&84w#lmi+$#)ARI~X!Y&+KyeWsW`<9n00M~d z^G^m==F0#79{mS71ZX;t`~_q%fY`tPf!Mzw;*3o4FJA8j2p|?NkT1UdXZrG=;TOYy zh@M|qNhT&CJ~jq`0Ac}pl#vl6#K7 zFA)9u_3syi0VMzY2QmHtx&Qtu@&7&0&HxaAAvs6^7=(cU7?W7&6Z-$piRe`dyDK`^ zN$WO$zWL=wEu!PO?Vu9@iVSM&8cWvf2p~p=WCn&G3_$lI&>tl77dYY}Tp)vm0U*Et X__=7oxWDB`00000NkvXXu0mjfV`BRN literal 0 HcmV?d00001 diff --git a/static/flags/sa.png b/static/flags/sa.png new file mode 100755 index 0000000000000000000000000000000000000000..b4641c7e8b0dd79aafaa73babdb525d3d2dc6a8e GIT binary patch literal 551 zcmV+?0@(eDP)4!1u&@QJ10&`rk^HbMk8Ee|uIe&H zS+;4$DbWCt7$DsBz5oJg0IGiW@flDZ69W^F_wDDmUw?kFvatRB^XvPsAO9KtfBpI8 z%a6}8Lb5=`00G1TbjJVx|9}4ZVWnuJEUfzZ$EVZx<$*voWzTGcp~$d(=+V{_?X+ z3y#kPS_RYq5I`UeU<=TsD9Bk~@o?qi&=DPd(?v86a{(`&&3I*E&g8|Wo?Sn;v*0j086Wc~d66UYT>00&^E24DBZ$$%)DV9SRUYEY{Wn z85tspN%!Z^Q&_X+!-^Gee*b1;`1hkUW~HJ2(d(c7|`w2)m##KhU^#|s1eh2YzMVW-Z(;)C{QJl7?-Rp6DTaSP8U8UK5I_L2Ffe?nu66~hU^Xzg zV`^IR|NmbGhChsd{xGln!xZ`Z|DQkqe?!SHn>GOi5KsdU{eSZ0I}_6%bMu4$|G#2j z_zP0e_xu0e-~WI8{{Q>e|6jj=B8;-KKpOx8hy`TyKZd`5nT(9?%F2RO|M~TQ@}K{E zz)C@?e?v4d{QeEp01!YxcLP=bXJGj0<#nFn|DXSVfvSK1-v%}nhwkOu|GvKejg0<-0ptJwK&1cy1oE`H<`Z?5M+~$7{9gq& zn~(3mv&(;P@Bi|05T(EW{(k!9>4UEid{_Ab1OPDr&i@1e0Q5gX)c>UW0I2)_6d3&w~i*%}NQ0G05Jg0{{#gAwk6j%|K36Wcrx-Z zDBuV5-R-~I;@8;l*yr}=_xShx{`~y_{Td7!{r>#`1^@zxvDKIVAJ?B1c2ZXvZZlkB uU;qZ}2Vg*eW0eWa_yywvNgf7(00RJ0?>)A@UfIF`0000`tbb&P~tyW8d(D~GxMiUp8x`gh2bB=pZ|ZjUUI!&{yK1G;4d%$ zIuA;MS%3cg{`2Rrii*m`ix&X`h=t(`1IH^)u0vdsLXv;@{sQG7;18Jf2Mqqg05F6A i0*HaZmVqPy5MTgGElxU<64PS<0000a|fPuet^$h(7pHv_{jfB<3vn*8q{15ov!pR5qo|Ns4BVf^v!57RHO zo?l?}`yWs<(7C?=0*LYNK?X*pGKOD3v;Q#s|MUOfZxH$qCjb2cBQWFtZ$@_cPkRpn z1P}|u9|n-AAQdnT|9?TXAyk7H4FCQBl>h_~&`AvcLF)bhMS(&{8jwh^2qVzve;5D) zh>=0RIIAq+{+o}$pxEl(3%2T)`P!1-fBt~{@Pp~sA7J?W`}60ovKZgl)=2;X#KQ37 z&mWM7{{H^+4`$e}UqIEMAo>Rk|KALM|1kdh!vsX^3=B^I0*D0|DL|!?{M^6*VPKPH z00z{*-?BnHps)wJ`QKllIe-8D1EGJQNCgNWMh3}bctpOPvlbWzK!=K^+cJPc;};D5 g19O2S13-WQ0NlBGh$rR(5C8xG07*qoM6N<$f_QiWUjP6A literal 0 HcmV?d00001 diff --git a/static/flags/sg.png b/static/flags/sg.png new file mode 100755 index 0000000000000000000000000000000000000000..dd34d6121073fffcb2fcb5b9402b3e6361cded35 GIT binary patch literal 468 zcmV;_0W1EAP)dtOYis{Le*Dj#JuDs`KNc)tl9OYUmifJZ zA4uJ=-~WIA`uFP>kj*SB3$z3vfIu4l|NYA>FaP8D^M5;ba1<8<4f|GC2UPm+H&ER# zkRGsxe?Y{*01!YRC;dKnkj2`X)zkCW_8s5b+Wvn23^5y|0jv~A0#!5q{{4%A0U&@_ zfL8pya^=_l{r?#l8F+XY{;)G~as30ko(ZTFY%s&0Ka9WsFiJ`S6$1niy`;Hnv5 zfRT}r0R;fL{~@sn5I`&p|Ni}W_wFAQ`~gBVzyJ~jk&qMs5MThRyiZo6SsHx+0000< KMNUMnLSTY6dB!#X literal 0 HcmV?d00001 diff --git a/static/flags/sh.png b/static/flags/sh.png new file mode 100755 index 0000000000000000000000000000000000000000..4b1d2a29107be96413eb86e64a75ac7a3ba5793d GIT binary patch literal 645 zcmYL{Z%9*77>Cd9?woAXO+#E-F%m^1b0Xy*Qky9{B^@hJqB6}jOKKPc70u1CS|Ug( z7>SA^1`5-}4+VvY=3G*k2%(8O!OWTIn!4?td(P>GANugV4?p-l@2B^fCONIbD;IAODX_{rV|BCn_NC>%qlWoHrzH=l|0Y^Rhgkwr%>N3 z(d)FjlCqjgyY4&yRH!;rb)|Z-v~HjxIkvar`*JLyzxBc-B?Ix`3*qGz4q3JAd`#LY+Xw^k(ph!n`d2H7`aI`Eh(LrOLs%9g zj93;8ws%s88WHkIqXqnSf?YSjh=@dF-}4L7dS0HFB@iNj8OY*&4>%Dn8t&*i)aXz6 zSX_wQ?~e=9UcwhrAtAf8XLVoTbE5+<^|-KK=D&>)yX6u!zrPCrbEr|4Yi(XyIGTQI zFEDsraAY{)DhUd*DN;Q?!uSxvkoT|31dF#>2L0DGeRcNZNehm>xm~}-9q?gtV@Qz` zv-lB19|m}3LHcg92}TUOb+%v(0bnUhB(5rQI9?ZY)h~Hw=%2Au&~WB@t;^kVE@F0Y z%=8f1ZN}R1MniiNxkJ!a;3!XFerfimE2A;1XJChGXJ=)MAVRubE8WFo1T(1Cmhdfa ztzC{Qms6asjkstFkFp5L#maeek84Y+NtW^Wf=SRytjpC1=BCX4NH^VxnQ`+YXocAv zR?lKskkKZN7D>{S3>4;4+gPYYq0_5iq@jsB^}M0yMT0|p`lM;R_dwbVrBg^4RRbsq Y$WB%-43-yHbAJTXS^1gPjGK@C0`m$%7XSbN literal 0 HcmV?d00001 diff --git a/static/flags/si.png b/static/flags/si.png new file mode 100755 index 0000000000000000000000000000000000000000..bb1476ff5fe8e0d3af4fc6bd11e513d95fd9cccd GIT binary patch literal 510 zcmVm9@#;PEzrU@Gx(rNA|FHo^Mn<3|00G3vEO>ZAhtlWIf1*N!=PZ8p<;&lH z{~7-L`S<7dzu$lU0~x=8==VP$LqeQ==EOq)0mSn6{g=m2e$<)X`O9Zpu5&$Np~P9Kn=gZ0kf<1I-4a zUtk1c`~{K>fBu3(0U&^Y8d(1RW7^4V^6LZG89>!QBmXe{`pfY9FT=0Dj8O6)!|#7g zK*az7#L~(TO=a{vExMP2%`MCSoB^FIcLe_%lf;|~%E5I`(IQNh}3Ao>6Q|DFUXMn*>AqQd`w z|1kXd^B;tM|Njjl{{hM0zwd6?1Q0+hV1xeud-4=Wy?p-%sO`^#2S61Jzk!N?s)6X& zzhA%p|N6}=D+{y%Ab`Lc{sL9~1=0UN4*CD*7s%9KAf+JHKs~=eB-8KTKvw|-5R1&; zzd&a|ob(5%^Z$Q=wHy9p13+aOpFRNu5F>N&`Tk_-7w>=n{RejQzkfh&Kn{rf10?_b z{tFTZibx5v&dxav5I~H7|Ney-|DWN1$%1FyagzUW0464;_wU~W1Q5$TW@eGxtUvee z3vAf*8|igK9~@*rr66bh|NrkNM8z+V zAV?>O@ek;bKfu6d002F*|Nr~{=Pyu%qcHbB24G}l{PX7zKmY(S0M7peLS*D^UKK~y z+6(XH|9gD^r>6bY*OZ>+`2GX^{Qmv@{`~#_{QUm>{r(dW1b1xK0st`p&i@3&%J4-( z6Giy=|7vRh4-WrbUHx`??d0*<@CX3>{QLa=`~Cm?`~Ld;{u~zu0R89!i0SVi2B1U! z{r&fU#+3gbKmA|6l!@v8=U+^J{{8>`mjUR&KfnL~{sUtC1qTg400I5L26X!4i0my} zo;{uZo#CfPX{7DT1DwDAf(-fnkMZ|^ra%9I0mS$d6bftr0mQhUfkCOfiE zM%HqlKU{maemr>kAILSo!3gZ8-+$N@WcKe}3J^dnRtyZx@9+FOdynDWy$P0%j62V; zZC)?>`}hA}zy1SB2;@n0006p>>h67sJD!pI8@uK6+#GPW%ce@CEFZM znTD)%K!F4J_qpc@AQp(ZPk%rA2T{TB=kLG2fBygZ4O9eD_xsnsUl6u5yEM=SfB<5# z6|+@gR}o|u1R4pn+XF1YrQf2oylS zAbS3(sBkhcTmc9mV6grHN=r(zLW3F{=D&YK84x>x_WT70A}|U80*H};VI?9O(a}F7 e1_Utx1Q-B;QgQb4eH!Wj0000PEol7!5I{@}e;EG$`~Mq){{FvoV+so& z6Zek;JYV*``O13q$!wq?2!V|I&+z9TKmf4-@!$W9Km&lr1Ie!(IeUNcyZo#F`{&0p z?&{CqnEw9%50U)~((nf$fIu4l{AK07*qoM6N<$g2hARp#T5? literal 0 HcmV?d00001 diff --git a/static/flags/sn.png b/static/flags/sn.png new file mode 100755 index 0000000000000000000000000000000000000000..eabb71db4e8275a5bfb7b1b8f3a8374d50da95db GIT binary patch literal 532 zcmV+v0_**WP)6{xSen|M~Ox&!2yPfTn)={d@hr-#`EU4p90fz>J~+=oo+i0%`d3@9*!wzk#ZO z2WQUEDXOGe*gO;$t?-?1~^z5 zels!xNuY7SApXOk^arFAjDSu82p~p=WCoxfknArIdOZOgs+`19}IpFa%0{xSUi1L7diFBr+f01$veIX40Tgn<}np4MoMn3N`o$god9 zrkzn;+j{#q5F}xeh49xZuI$05IKi0v3Lq917Le*!UxBJYN`Vr8|1$jj50VD5fvSOw z-(ZF~46zx($8#~-kUKOh9u19TNY0I~dG z`1hBA5y<}g_y4cI3}({*g*gAq^Z#dL_#dnH|JmpNJMaAe2etv|3x;0|00G4G>kr86 zzYquf`+xk=e@^EAQat}9xc>97{@;He<|?3qzo3u+2q2a}APrzwf*tnl_y6c6m z5?7266~G|=0}2mdsDK;{bP_-SF*1~XW%vY(NDyK`u#uw~6h{mUJPZH<1^~BhckWKq{Jk|L6Yw|Nrm*vcLXk{sL#*k)f0!)jRF?KX6FHLLC_7zyJOQ#RJf}AnqSv4E_E0 z_d>^cfB<4-C}v>z1dGUDNRj#r9OZBkNc8hC00bBS^Nnc?6(4BA00000NkvXXu0mjf DM=x{`~^7feaw| z@9%GBrr%pd7ytr@3Fu&;D>$G0;d%9&ckUlP_FsJLznOpkI<);49~%fU|NOOg<1c>p zU%YI;<@gu?0tjRS1JJ?0e*b^_hvDg;|Nnpg`SWY#%HJzjff!!CzZWj}wP?w&U%!5b zMg95nhXEjfKpOu4{R2W=zZm2}8km@V1qJfIu3a z^ZvQT`ny}__wU`%Fad@Sg!~P3A(#OSI%WR9r+OFw0*K`e1H&7RKZ`vj#ee<&!}=E_ z2M*0Ye}N7Llfc;c2aF@2)L(`#3;+SdxR!w-xR`AxVx?>``QKoX4p z{r>$=Qj`^FFF*h>?mzuiS(feBuYdplGyMPm{~rVab^il$89+1;fd$yvm=2wM1rR`t zfB*hvWMl+7=|4yZ16bGpcem@l{$rO?srZisfXY67`UDU_ED+y9gdmKw*T0{<`x@v9 zlkZkl}Tegi}1FC>)y z`~`;fe+5al?K4jS1P}|@5C%z67NEr6KmWj?{{J^f1u*QH|Ne!BH7L;kfnp0FfEXE= rk23safJY>Z`~zeELt=n*00bBSq*!cC{}>3t00000NkvXXu0mjfg_GrH literal 0 HcmV?d00001 diff --git a/static/flags/sy.png b/static/flags/sy.png new file mode 100755 index 0000000000000000000000000000000000000000..f5ce30dcb79b443ebc1615fe4889cc26e2d762b1 GIT binary patch literal 422 zcmV;X0a^ZuP)@|4`Xj5kLT%`al?B=W5I`)SK7Qoo3V-qKd5l^# zgv$taFhBq?zJ2?apPwJU>mjm?jEr~g+yMw6Mj$IKE$!aDd%wZp7Z^YoAQH^_^XK=U zKYvwJR4!h;2oOM^VEz63kEEm|Pzoptl!JgjVAdZn_zMF-#Q*_BG6D!N0MDLEDh$KY Qwg3PC07*qoM6N<$f z|Nj36M1Mf!|33`>e*gaqWCO|HKwFtO#a&sZ0t5gt0M7pel4t!zdFAutyc%F2ByLSib7d z-@iY8{9s{WsjaVha_-{UlG^LGvEO)A^**!$6$1ni3ljqaFhGRYPy6$qf&JG{kKey{ z|N8ae_ixs}{}``bdDhkT?#VOp#VvoBm>H#|fo1~)5aY*A1~#Xrf1jTKgW~`H-wePI z{Ri~aZw6pM{r$!84-_k)u=@Ltg1)Cf2{xiF#iKZ95W~`fDE7~ z|1pDN1{?_>vH!pR*Zxoe2p~qo;+=0k{eVOy5dHe~@Bg1a48OqWACLsaJOfY!7)!uZ dz{3I%U;rfUVNTmRI(Yy9002ovPDHLkV1m_xKPvzL literal 0 HcmV?d00001 diff --git a/static/flags/tc.png b/static/flags/tc.png new file mode 100755 index 0000000000000000000000000000000000000000..8fc1156bec3389e54d3c5bb8339901773a881e68 GIT binary patch literal 624 zcmV-$0+0QPP)Mt z2Fbqp@bUfi_XiXZ_x%As_WHU2H1hfc9TM^w3-JC0{^0Bg`~MgK0Qv%mWs{6kqN+Cc z+b3Uc-enXLWmi^s_2~6APR{Qy8GilxQ)j#p({t5y7`^LQ4&lw9Z0Ra5^`SSP!?%<&3?fU!$2L%N9{QCa@0Qv%mW$D2m zA^~iFet$Uihac>@UpF6ozx?O#ufL4HfBpRUndtzp5U;>@#TUPR{|1KG4}bt-0)`aO z`@jDF|MM3p^6S^{zdwKf{q+mXVfa4fgq7?27ZxvH%|34Sm*EEk!#{ukVgYLS^A{)$ z3^fq>3urc&4I=;kz4MwgW4X`2zkh%J`Om=vauPrQ0X6*k{pY`=2p7%A_P)?P zUwuVdAkKe=-@h3}_C6p$AOxEwQo+UIeHT5%mg3lYGL;@HP(LjqG0$?6F}(Ht8A z0K*^*BsuTDFa|;zm9Mc;PRcq|KMMBO%8|{GkrU*a2x&r-3HS3`xnqW1|R~39RolBu`vAj19S<{HjoWK z4L}tj8-Qm20eTwfuYbROLyY(bwgDi3SQvf*HG+%>>H*pSauQI_zkmNAP67ugNCPlf z{{97O00g6G8FFbZ~XHln?_bqJeH^V)*lb;YTJ&0)m(r7ytqc06HRil3NF`RsaA107*qo IM6N<$g5!7R+W-In literal 0 HcmV?d00001 diff --git a/static/flags/tf.png b/static/flags/tf.png new file mode 100755 index 0000000000000000000000000000000000000000..80529a4361941e01d1def5d581bf2847cf99fef6 GIT binary patch literal 527 zcmV+q0`UEbP)KfiwinSYl|od6I(APxT+{=azr6>87_{|pZw{QvzM zh#vfW|M&NwU%!FG-`~IfN=xzq?EwhD!Wi2C0Dv&)|Bp?Zs+hPi0R-LQn75%cY-O8s zAPsw;Q!9X27=Hcx_y6DDzyCn0!4P6RP{Xg^fBpb%_yyDhbQs7f8-Qku33L4cS@IvK z8OZ(n2kOgTzyGb@ek0IRW9ouaN6$P0x*s5bfH4)06qlIj4>;1{Yyp4(0|4dQTo>gF RMrQy3002ovPDHLkV1fdR=hFZH literal 0 HcmV?d00001 diff --git a/static/flags/tg.png b/static/flags/tg.png new file mode 100755 index 0000000000000000000000000000000000000000..3aa00ad4dface0a9c23744ab451cec0443f187bf GIT binary patch literal 562 zcmV-20?qx2P)@|6mN}b_RwI3=Dr@=ogG+VE_mq7La^(HIVqv%*^=nCj$%1|9}7Uoj(8m`RC6+ zAo~61@1NiQe*Xrt|Nh=Ea}z)Sfi-Y&{FjhmFg0aZxaj}$=L~=U)(L)O`TP6-zu*7= z1Ib@N^zYwqCU)6YF9v`BVgi}{>lcH)J%gU!|J)p)>i@rg^Kt&>WCWsLoQyxgk29dnvBpN5vQb0*LYVQ3gi&tp7jnGyMMp z@*mKbe}4Uk_!#8f-w;8De}5R+mEP<>2M|CkH{LKvi2wQh{WmZi827ytqc0C8?ZF&p#S!~g&Q07*qoM6N<$g49|K A6951J literal 0 HcmV?d00001 diff --git a/static/flags/th.png b/static/flags/th.png new file mode 100755 index 0000000000000000000000000000000000000000..dd8ba91719ba641502bc7ffda16c25dc71b2066c GIT binary patch literal 452 zcmV;#0XzPQP)@|4`Xj5kLTn#2^O%5QJf({+!S7KyMr1NSdb0?wsyYS6cNVdko7wub89?$EL;)x)00Ic8;m6; z*ldXL$Yz5{poPB}7`^}m5DPc2nu@9r4=+1782$pC1a=$HjDKJ@i17#P6G=(#Q>V-T z0*LYF&!5c9%>VxV!xcCX0F(uW(%ZLh0Ro8SA3Hl!NeKhQjeq|#{05SL7=Ql;MhF4{ ujRQ&nZP~jQAb=RZqDCa1IEDa#00RK>mSUL#9?hx%0000(5Af|u+{y|g&!S9Ft%(8imf-XR*|Ns8{XO&`< ztN44b9;zJZ^?&~W0*LYB$B#TbJpUo){|D*(`>^x>w|gKB?9z<#wQ%E^n3(S0zYh>V zEO6uD3`W^f29Wmu3`mZF`w$?27#UO<(rVJ~y}I}N&+p%VfB*XP3y6U1Uw^?QNbuL6 zzrX+d{i`Cbal7Zfib@b53s27mx! mU=U|u;Adc9XCM*)1Q-C-v^a{iiydVE0000+lNu{Qmp=|FW6D0*D1<1Ovm9m%kYQ|7p*Yo3ikU z7~kiESLFZv{{Q#iA0zqwf4<*Xu-*CD8$MYncA&8U0mQ`ckKy0n|9}7f|MB&2MbDkQ z1j{KKBL!IA2(Z7F;(zkuBe#mo9TT;SzkoLU{s(jwKmai@{QdX$=kGt?etVi7(p9*e z(|o73K&5wiaQBkXEB9so{`tH8jIplb^d$ZPi5h|uLD4*o5RnOS|{Qd{@Cr~j!0D)}y0}8T#$FHit{lE#dc*g~k_utsL zxj&Wpto`+k?f2h5mv;mM4gK>M6!-uE1hnA~P_?8O+wWh(`!4wX{Cn2j=z=is`~Uxb zzx=@K_DcEUJ7IZAUZAu8{sn~+Kmai^Fsw$4O9qB73=GeJhA}V*Ffg!yW&gnt6F`6g Y0QOrYft$MNbN~PV07*qoM6N<$f;FEW z@b~ZkKS1)&|37~i{`~p>`}cn&^2?@800G1T)Nta$zvt>t<757@uK4@^{4bCmpb7~3 z1tfp{|Md&VW|Wov$G`v(Kp+kO{{26+>+jbuf7A2+upj>Wf7$Q%RxoV1$N0e}Fas1Q1BW)@@rKJa|xATBWA`D>(WW1JFHv zzy7cP0k+{MTm!^O009K@!>LoJmn~avX#S_9;5YZ-KmTX``u`YaHjD&?*dJiPF#rS* zNW;&cKP?=87yABYZ~OCq-%n(9P{tpi22h9t6$1niNQ1e-pD1xDrvBdy@BT2zfI@>2 zY$OAO1fsuxAqeOsfB<52Wnfst00RHO2+qJn5C9Nh04p0wT74^6IRF3v07*qoM6N<$ Ef~oTCkN^Mx literal 0 HcmV?d00001 diff --git a/static/flags/tm.png b/static/flags/tm.png new file mode 100755 index 0000000000000000000000000000000000000000..828020ecd0f6fc73348373c9e7a235fdced09de7 GIT binary patch literal 593 zcmV-X0VKiqu&g@GZ_kb&V31Gky(*8`UselaloV1SZ886W^4001!n&i@1e004Y* zk0R&!|NaLC5DIk$@CyeC@AU9ebDYiJ)zswL{Qdm<{`>p<{rmm%TMiuO{1voVt6d+$)WVk%^O){nwx0zkdJv^%rQ#Z=eQ%0Ac}Z`19}Y zkI%oqe*ekA`2WvehFzDBOo*xZ{rB(cQ`_&qdGhP`Z=jyvAOx}jAb?nae){+CFDvWc zZ(siLa{c@D=g;LQw^HX+sY@u`d-M3!$G1SGAWQ!Ifj9{ufLMTG0<_`#=U?|Ye)D|< z8pH7G?=PVA*@stt1I-4xpA0e#40jk9 f${7d%fB*vk3(!F(w2U8u00000NkvXXu0mjf+94t7 literal 0 HcmV?d00001 diff --git a/static/flags/tn.png b/static/flags/tn.png new file mode 100755 index 0000000000000000000000000000000000000000..183cdd3dc98c6957bde83f375a431e543a3ce9e4 GIT binary patch literal 495 zcmV@|4`Xj5kLT%gT|L_r@28Q3iff@h;hzaCwplYy<4FCT9KXmB7 zhQ|Nt)Bg(#gN*m^{Qvt8$Of<_K(zn?!~}BDpT8hi0uj&>pxItt|NHv>A2{&e(C|Mm zFGw7s;m;qS=>P!)((wQ9AF!W(0sZ}7M&|#9_5TYB{zpfHZ20g2t^wjCfB*tH2_nSs z8?4R7=Kq6S{f9wP5^T(0hI#XVIvK%6GC)WrB}fdh6SO{nUiXv3iAlW}aH!uJM5J&?vILH{_iZHeP0c!XQ3PuJ7 zfB*t%VEX-sK~fTI%wL8-Af1e0BN-qh5dHlNK|sX-0mS$fH6j^sMDRaYQUC}r0RA0L U-~OCsp8x;=07*qoM6N<$f)6&Rz5oCK literal 0 HcmV?d00001 diff --git a/static/flags/tr.png b/static/flags/tr.png new file mode 100755 index 0000000000000000000000000000000000000000..be32f77e9910c0896c1ee8e7ed4f0edf815a517e GIT binary patch literal 492 zcmV@|4`Xj5kLT%yy% zCxE~j7#aURc>+`lQtjr(@bBOM9XtMi`UFz<>-YcPzyAOF1!ObI$^vZw2q2J#|6qeb zs-vSBOie-Rl$HN?bb!_U0_g#3VEFwTr~x2=m_Y6Zss`GqsL0^t^nd#F|4B*zH*EO- z_3QuT%m4H6g6)A?0#pkSKujPf{rCwIb#eU5`( z{s2t}2q2J#|9}60{Pg58FvR|AYlEDjruP5RC6KEgJ^H_IA4CJhNdN)F0>q49OBog~ z{?Etvzo-c07$As@{Qu?4|3!FoS~(Xu$ujuK&Ki|5;f$7pYF;Nfxh(xqFs zZUMDjzjMbfEbRY>5C0Dx`v3aP|JSeozj_5kj66I)?%V+g05Jg0{{w&k0RJ5w0P^!X zSy|WJ-R9=z(aMV97z{4myy=pj4$^bx3|zy{hYtY)h`Ao9!QA5iyLbPuTmkB_PfP?Vee~$j z!-o&gUAyj)n+wu&>J&%=KmU)%j{yP*q=CWA45Z=rFNTYkfO?!$Q_o+&{s0WlT)E;? zRQUhj|NkdWF!J+%fBF<4fS7B68jOwqzkLe|6QI@S&;S4b-#s()-1Y1C!Qjl5tA6F> zpisYc>&x@!00G2Y!@$5~Xb92(47=Z8{{bD%z~Ggi4>bPny?b}>+&OjWQc!g@0~6Et z-Maw-h`Ac5K~JB7o9jOp7XvpB0}lu>-nqlT$mpA&|LpDCZ{NOs`t<42?c44-IbZwx z0Rjj;B7x{N1H(%OhUW|nPgz+XA3Vr_1a9x%4G>@ep<^{rq?UTJ00000NkvXXu0mjf Doa;3l literal 0 HcmV?d00001 diff --git a/static/flags/tv.png b/static/flags/tv.png new file mode 100755 index 0000000000000000000000000000000000000000..28274c5fb40e5d3bacd7c05d9a1b8017eeaffa6c GIT binary patch literal 536 zcmV+z0_XjSP)mzpv3Mmw05Sgm{~xFtLc$sUu>nR##!sI<0R#{WMEdpj-yJ7j ze)|0V&%b{_!~X#7`1>EofS_N0|E)GoUH&SsFy}2m05O4F@}ffYb$qvjbfSUipMQUU zgY^9U_4m&&5D8KZ)HC5u^uad<48Q&W1P~L@hOIAb7eDp_T4W)^*Xg48{r4ZBJ-_}k z{QCPJq~Q-pPnz693xQJ%zkUG(5aZwHtqd&u|9`*u&+TyOvq{_Ghd=&6oB?#w{~Yv(xYPgr|NRH*haKioowt*& z{dC`3v>70P7=Ql!$;`|Q@(GT>fdHT^FqGcDeG3pkjNS|k>E&sEfzAeo{ckY&=g(gd z`CCrwmxA8!XLtTy-uM6CzrVnM%iVPzAb=R%ks=j>et^j`MFs;Wh8c4i)_^1XKP)u> a1Q-A&>r+tW$-Nl>0000<~s!0-E7R}a|Ns2?4|9|}gs%Dgx1=;`*KrBFO{{8#+``2Fv2B6@-@8AFY{`(K80jdYk13&NH4;SYnOGgJvc0I@K9VW@Vk1}Xmk4~YK$|NH0P z-@pI<0D+Rop8&DnA}oIvEc_iD{O9-Y-=|4+U?1uFgf@9*z_zyJRJ z%fS3QR^zuR^Y0tyerNXndi(YlP_?gzto2+5fB<3vIsj-gQ0X6_*?&Q*d^>boB3^zoi8Kq^tbl{qlR!{9jwQ|Nij< z=(=A?F~8j-MSe1{Hl8Yc@zaXo%Ljk}VgUvb(2HJbe?0kqy?_3vsPXrUmq2rWE6M!I zE@4*I;Mw}vw&7&iFGdC>zW)rr{s9CK3xfnhrsi*1wqMhx{@J=6sPgxpU%z6)f4fBr zzxpd#a3tyYE8}0lKnA+|-+zWbe*glA<)R0}-=}{Pnt#7~1q_Mb;=;f3i~oshNgsS> zIr~z~(_bRL|NZ|1LO_>;A_pLVSoBpHQd9nLa7ao@{lMMx#__lBLe9Cjx?EiU z71{s)`Oon8FXP|;z>s7BItd_v7-5mj(Adb}701wVj$!S*>kNN{fN~5FV)t0eYh-DxnQ(+0I@JIfmA>F`X8wD?>`2h#NWRRzyE`zA&Pzh5tt#% z!^rUCA3y+sZ1@LM1hf`pHc0ia|NsB|1uKPX0CRu;1-SztfLMSo`wOxir1}rsY$VlC z667idh7Sw?0mQ-}a!Q0#;n&}vAb0=!_Zy@WNd5!6=O2ju7s{65Vq=gx0uVrqe;+b1 z$mIY3|KLBvF9x7j{{!v#g_UGtQhI;<6hHv607H@yECdWlR7EJN!LomVp$!l~APvkQ z4p0cL2#YobhQA>6hXEjfKpL3-19eKmL_s!=;22W8vpXP)6RGKQPvx1q)UK1Q6rb{|u}Q zRsa7#{m<~1f#L7}|GzNK{&HxZVEKJ4>jAefr9{u_M=MTegAo-i2ynN}MJ5kZm z42KRel$J95{>|{~*Z<$Y8RdVo9Ap3pAeIsa2H!t_KmPs=bot-kKnMR0GBy2s>sC=w zQFmwO;@`jj{`v(%zkl=p`BTQg01!Yd{Xp;j{qx|@pI^U!0X_En_iwRd$6{h)tX8f( zaOhC?&!0e%U%!3phy1#1%V=eK#YHXK~n$!{#(ib5I~Gyfqpu4^P)1J@ZrOUii!$=0Ad7ci1(2A^!3kwFaT->5i7Ttz54h6XL$JkA3s3o z=g)t?e>01U3h&zo5I`(I-#Hr#t~u}$WXZu-Kyv1Rm&rE5wcB1YFI@@=0EYkn8G$4- z^Xb{M0Ro8S57@^*QJ}#<$Im$M^4iKw z00a=@`Sa(sw6y;I{R{T)e~6KA2AmBHF`#D(ii!XNh(#nN}rF)(}plRy9vU;su%e@J`J?dSji002ov JPDHLkV1n4Y8}|SJ literal 0 HcmV?d00001 diff --git a/static/flags/us.png b/static/flags/us.png new file mode 100755 index 0000000000000000000000000000000000000000..10f451fe85c41c6c9a06d543a57114ae2f87ecc1 GIT binary patch literal 609 zcmV-n0-pVeP){qW|y?pud`Sa)3|NY&vWd%S0u>b>P!2!lUe;6EF*#G_c zFVXVt@6Q{uX@40W{p0iY2Aa+A^Cu7i8KT+YH}2j52q4BskM2rJ$^k9;2Xxc_|Np=M z&VaLlA*IO5FlECMfB<5VUNC{tBZO(|zW*;@GJN;|bTJ71`0*d;`d`2P!x=ymOA`2> z+y@9C##^^8%gd{MW@Y91_2d742B2~OQNf=-zkmD?Vqkdk_wPTUNeuu2#KPTG{_;O4 v7C%8E5*DLB7#Kb?Fnj}}-(W6879hX?8lYRg`Y`<~00000NkvXXu0mjfD6Jtx literal 0 HcmV?d00001 diff --git a/static/flags/uy.png b/static/flags/uy.png new file mode 100755 index 0000000000000000000000000000000000000000..31d948a067fe02d067a8c2e69f28cca446bc7c57 GIT binary patch literal 532 zcmV+v0_**WP)_vmzq~N}&z08z z0*LYY{pZr+B0$d}2MCnI@DC;m3N;oM#uMkR0R#{ugY)L9Y<*xj0QCR^`!^)W!R$Za z5CobHbl5+T3;%B|S`QFFjQ1Zt|MTw;G#Vi+hCg5i(ELAtfD|ak8UBG;ObiSF0R{lf Wla#5zB1?M!0000JMe1P}`Y1HZufM;3|NZsr4^XwNEI-g5fB<4iWtjhPj`qjL zFGT_P{{Q>;-(R370Ro7T!5$Ws$Po%5A+Zb!3j_cNFaSC{Z(fWD@s$7o002ovPDHLk FV1jsy^u+)G literal 0 HcmV?d00001 diff --git a/static/flags/va.png b/static/flags/va.png new file mode 100755 index 0000000000000000000000000000000000000000..b31eaf225d6fd770e0557c2baf8747c91ce88983 GIT binary patch literal 553 zcmV+^0@nSBP)|05Jg_ z#sD@3Z1&&(|Ni{{_Zx)%v%Gr!NnLzkb;C z@#QWhJ{xI9$+*)bNX$S?E90e{K^EMkYok78VXhR-hjM0*K`g z$j^Tmm_>oEVgxdn{xJOg$-v0L$jHRN$OsH@P9Y&+^ne@=1^@xXcy~X;zaPM$WdOPj ri2i^{AeYDB@IM9-1r;P))4B5XW#s0WPsWLbObPT z00IbN14#96puqp%TKvBf)PA*{`~CO-uM~~n%6z|m{re4Z55!3T0R+GV5`UO(`=kK4te?c|?1P~}#f$jmC10=!0@{8gBFK@Zu z-~WJALqveC|MTzfA7GIDVE_mqkOrW8BqZ2?K4D^#WMJTBVE7%b47BbKBg1c?EHl#| zW&XdQF#ikE01!Zo3=CVrargu%_x5NZPzVyc@Ms2-@*Gr#1lu5DU{kh6%sopXB}uDxAo`@Bt_a*7F+) z{Q{%kjEu5C8vp``Wse8Lf5q7h438n|z~nEOsZga5l7ZnjPy;{!05Jg0{{a91!FF~d z;^O)I`~dv>{`>s@o}L{E2?GEB|Mm6!N=n`P`~Ld+{`>p?A0G$7!M*~B3FM_eAU;q6 zNCH*w+4I@c^Ny?Q?QPpWZQiU1R1HBuWkA0H1P}`l|NYDG=gP=Ihyj(0CItil0R{kn^jdV2 S*Eqib00003_-&c2+@O*Bba;fM%rBo$$qwJnuekcf#0k*RG7MM`2+5Y7dK4k?R% z*@ue~6f;u_A~T0evP6qS=VxXnGS_mt>CSmS&gmG`kLSL)e_Vf_=c&!fKB7`4C;*C(7s2O*P zOs1$U0urzb3<=a`d9ABG4Q$eK<6~5Cg~V%B8`UqrfRSN8f&?QTVICs^VT=&p*?Eut zt4Ur&-BL_ON(Z|Xfgo93lf|gRkT$Mz-7^OQoD^XMF@}g>R?uoU0094KbXv)l?aF0E zh@GXQVr04m@05R(Rjxq*p|CCIRfv;QJmH1kf!hsqX*sha?_l;f%e5i5I~4YG#H4;6sPG2&U~bv( zNr`eMXGIX9?wP^zPQP(6+&$05Jg0{{;N}{t6CR|M}we`P%>f+X)5&j)Fc04NUj< zI`HZ2Woe@k6UF22`V|Qe2MTi(6bb?WF#yj00*Hv<{QLmnFd+P z9@fS%;@9^E|H1b5`Vk8^2@Yw;#}(}C_yUN9iGkt%y>Cxm>T2lO13mifZBc!n`jhHL z!MK>$6Z_d%|GfHMapIVnqod%T-`{|q1_&S~IR%b4Z+;63vi@iI?>jBz=eJjkjQ{>J z{QUQa@gMhBW_GSe5B=V~`@+h~@c%z3lmG&V@$K8U{QUg?|NjRX|KX9x@@rf{MxIY^ z?fG>3gQ&3ruaE-Yw>fW_PfAH~0~Or8dmA8tSRg?T(ZDLQOiOw%6RWM9%$i>kkAMHu z-oH0qLBYb*loP0ck&zJ?LI42-(g0BnBsn<*tTlsx%zxbLe*S!R<%*E3>|Z7(9Y#iG zpdch>0Ro8e`Sa&!arp;m4%k`<1H=Xjf<=G;Aix0Vb{`Xo7A9K&0000@|4`Xj5kLT%B_22*h{r-RE_y1qN|Ns8=|JN^|IHRmA&<212VgZ}|A4N4# z+WpUe-rxU^{Q|504bi~x`!`SnKmf4-F(Xhl(8fQ1fG+vp^85d{-~aW0|NsB{f9tRR zg1`PJA~XO^2M8drlm7gLxRT-bpa1p0|1bLmQVm3Azy5pw{{IQ;B%q-{(*XjA3FM@| zf53hMJK)W)|CK-uK=ku}!>|93eu7kk5yVLV0R(o^Z;+)RSAk6exg_KF|98LtFaPy_ z#c#OrKtum9FaQJ)NCPuC$bbfbRI>n`@$3IHusZAC|2cmD|MKhqAD{+Mr~sV<5I`Ue zOuzpyNJ@f@0s0=KlTj9AB*>SXe;D}wK*A7+fQkVEi190GMB<5K2mlB$03I1qT8uIj Q5C8xG07*qoM6N<$f}XY6qW}N^ literal 0 HcmV?d00001 diff --git a/static/flags/vu.png b/static/flags/vu.png new file mode 100755 index 0000000000000000000000000000000000000000..b3397bc63d718b344e604266259134e653925c9d GIT binary patch literal 604 zcmV-i0;BzjP)7(YpZ_rO%ce~L0mQ<@*ghnz= zZvXM=_iyVze?clB=ogUu_5ar|Ae&KE_8$WSKmaiTHT?Vg|MaE5OE>+VAUAUr;?j4FCZIvLVX%uQ>mocOU*NTK^}%njy93_oP3+fBpUa=kKpye|`ZO zzyE?r`Mc+5Xcyo_v6>E-#|Nl{r(LkAS94bRQz)6 z1Oq?-fi&zp{`>yDUnV+0)eJF{zWfaN_0t9DjNiZhfxY|}ME?2z=O_CghC>Vh0R+`!~0W%8&aG{{H+4 zRPp!M??1nPG5q=k)Wabw3seITKp+kO{xLwc{r>&$?_UrCGJgGL;^k4Qujka#`tk7L zjnovNAkb9+0R(gvNCCu>f4~1QF);xde}DY=^Xr#I=|`5hhp|NZyp>({@(egUPqbabS$v+tIbNu;L>xVSv%=>ggR z5I`*V_U`A@(fj`3!N1?XfHr^}17rYw{OcFcC69Z0BvMmfELgy8V88%&5l9HrLN(5b9xs8l&q^Gm-@&XkD1Q1BW|346ee?wJ+H2_`p`^l3V z+1Wtu|3AMO{`_T8Q2{Cj2q2bUARGR$NlJo(=nv2bFrDDw2U!bb{QV0-KNuJQ0*G-b s1H(6@xcrC2{sj~H2V-zBFaQJ?0G2^Lae{Q+uK)l507*qoM6N<$f;6K8u>b%7 literal 0 HcmV?d00001 diff --git a/static/flags/ws.png b/static/flags/ws.png new file mode 100755 index 0000000000000000000000000000000000000000..c16950802ea95b40a4e024be6cce870b1991f40e GIT binary patch literal 476 zcmV<20VDp2P)>E69JA<-5ee*C|6>(%ey48MQ<`3*E1sOaY}WDP*a00a=wNxxYB{9yb2 zOU?HFZD2h;3gJl2w`NO~f5I`Ue%-|qnfGfh(_6MlpFT>xzKtBKk z5J&^l?>`KZl3-*0GW-GQWCR<@03m_s?_UT4Dh3E3#;>Rm$$$~H$WlN65MTgr(_Ikn S3@&c~0000=xie?ZoIZW}({TJKY#xC z@#FjV?*|SXNJ&ZAzkmPUy?b}=+__`Nj&0kvZQi_j_wL4%P)h=Z!r1m*T3JtfNUmdS)dI70mLHE z+xy?%p5eHez0mS(A>sL-rPOy{yGk_s3 zz{tq>=+Ps90Al&~?;k`pNCN|I|RMxbJV00L=%3E(v!XamT}{{RArWx|9$7Z{pWi2U{IKN}lRCnF;x&=P&!(V3Rv&T;|GP6K500a;d#1A^U zy8js%fB*jT=jRXRU*A|5K#2L*r(ZvQ{P_O!=da%umKG4l0|XG%NkAKznV4BvSbj4y zawHV~fBoj~uiyXJSQwZYIoR0QIXM3O{tc7`Dgy{0# literal 0 HcmV?d00001 diff --git a/static/flags/za.png b/static/flags/za.png new file mode 100755 index 0000000000000000000000000000000000000000..57c58e2119f402072640ca758657798b621f3fb1 GIT binary patch literal 642 zcmV-|0)737P)Cfuwe;F7c=r;qyPX>nX3=Cfx7(O#Fd}LsF&%p4OfdL?Z7#j~W z{9>KL@b8bfkaUokt?1q(EJu$q{Qdp^&mV?AfBydlG2rBvO`8A$h{fmzgIW0J+B07s zK74uV#pQB`MAdI!SdN|k|KJ`--LK#OfB*Xb>lcvCC@cGqfdL=@05Jg0{{a910Lj6A zAt&mC*9zzO1pWQ@b1`Tn1`iV6=KuBe|Nj2}{{8>`{{Q~|0SOB6tE&PCq@k>=Oh@B| zgDu0v2b@p;u)h2C^Y4EK4rY$O|Ni{`3qc?^$?%A8m^2X}fLMSU{`~p7aqHLD@0rW| zzIWc|c>Ry-$DePXKfn0(_xG>AzksTL{re5n#{Tyw!wUw000L?F`}dEV6O*(3zu6Di z9{gne@#pKG|NpqSh1vf81DXBz&mW+Me}8zmL>PD&00Ic4!QY)xLzl7RCikV!EWdtz zoorLj&BXoYF88-DfB*gk`{Eza7yo#;S!C4G00M|*elvr*8B6X-zBgb0FtGkEHc8mM zoOScs_b*;Q0~!ksq<=swfJjA!^Ww!_00G4E&x@hvA~zQkvxU59n3VsHd7Nj?ec|R~ zkmuqAx#JHo0{#K*`TG}00$uYDAb=PdGJ(Ek5Vx?d6PS=4{E7kSFNS|$^b5xL14ayB ck_{lh0N_F{UmK66LjV8(07*qoM6N<$f>aVd=Kufz literal 0 HcmV?d00001 diff --git a/static/flags/zm.png b/static/flags/zm.png new file mode 100755 index 0000000000000000000000000000000000000000..c25b07beef894408ae11c3be294d6e0eeb28c0bb GIT binary patch literal 500 zcmVLz(k0+Rp#|Nr~{@4x^5fB>iy$Oe)U zA3pkg`SAPSuU~)vaR2(F*|!oPfLI`Azxw(Lr25~#KmY#x{rl(7|GyyW-|wp|{||Bf z=)Cuc_0O*fYWnY`7ytr@1!(pEfB(To0uBE22c#NA{{8#+_rKq)zyAFG`zKdY6euFW z2yzlY0I`6SGJqWbGV%`;{r&ytA5hcp-u`P`AAdOg`t|1D?}h2=^+y>10tjRS&?yMj zfBygt2HEouXg1LCzyJLD1w#LR1MLR}1V8|>0KE@nffPa916Bvu_V4#Epof105yNkw zzknJ50tl=DS->P)FK#X6%e&u3i|I74$@9uP0*YE!se={)r{r~?r68Z&3 zzZn^2KYiK`5I`&p3=IF7JHD>uaSofgtUAf*-w!6nU;qF7`S<(x|35&+uYZ4j|Njjl zS;T)|pU40ZKrEjoRWbQ1@P?oGFzcPCjLiCzcU8ZC{rmejNW<@6e}U*1kPT$~=Kk_~ z83O}A05QHjx|ikdd7h}_|NsB_wl9j+&d<}^`}fbEzkmP!1q4tEL@O#P9zA*#Ab?m{ zv`qe9Isj6Ah@Z*IdsTw}WYHgB8-D!*lmGvK*?)d>i2vThzyJ_HEdLn(@uk-N0|t-& z`$Yv&?#y3UfPVP*`ya#a|BS!>G5-DsFR)1c1&eHCHYDzO7ytqc0P0;>l>h9)WB>pF M07*qoM6N<$g71PE`~Uy| literal 0 HcmV?d00001 diff --git a/static/icons/download.png b/static/icons/download.png new file mode 100755 index 0000000000000000000000000000000000000000..ee2c90f67c6154acb3f0de216c9cf105f5eed3a0 GIT binary patch literal 1166 zcmZ`$T}YEr7=FIb$cwHjf=G#= zx)>3)o4WDB1x*FRAf;WHCN^qW>0%Dk8gBc3)_G5SBDl`S`#tBp=Xsy^=iEBk)$Xu* ztpFV1j!+NBS~82m|2uz|&T>%Bb+(64qAwDEKEyrM{T-(-12z|#golsoxwGm@_(WUP zTyrVrTztw(G?UxCZ#HMKS;74Le0+9xwxk;s?nC~dyLI<* zEUzs>)m5a|zN5L}FkChJu)2{$Boc|6{Rjabd_+-{px^JuRR0ow{#wEG;v{z1>ml>$ zJ8gA%mm0;~kN3FKGY+TI85|rO43dZt&@^qpYPBMrPNT3mkaCb>nQT)Bg<|4!PQrt*yV3Ra(Nm< zp$Sx0R>I+Mz-F@{7Ku9Mn*~IR-`?dSuP>9YgWvKV&~n_ TvB<#9RZ0+U>k7RLp1JWCoR!8e literal 0 HcmV?d00001 diff --git a/static/icons/locked.png b/static/icons/locked.png new file mode 100755 index 0000000000000000000000000000000000000000..af561c1e16fd4c89dc5dbe7416227de592c86bef GIT binary patch literal 881 zcmV-%1CIQOP)ag2M8cWWCNBiU1|W- zyiQ6=N|BF`kAaDai2=xG`0?Wh!|T_t8SVoC(4e5Qva$;>Jpcg&Hvp)a2Pk=7Sy@@- z*RNj;j~_o~`1)zy6m@c{ye31$*dFjG=eQswvW z-wd~I-MaVr^JfJhn+=3P?3*`lJ_8vHbe#&&D>*QI00G1TV*mv$xwyC(?%uu20Mz7@ zlauoh$*T{Wo10x8K74phK|ukm7A64@K*$D&g8U4$4aC0BfCfNfAlHG^09`8z69)(& za2Px~lJx)hU3G?+A34E(_R~JY!2JI=!~eg3823wDIf1k%1H(T?1_l-mkR&jGelz_2^O>Q^^(#>PH(1M^ z7019dKmdUa0NDgm_~*?k1{QV^21Z66ph8v#22KH>@IMBIZyy={e!9)@>-$rNe}BF) za4P07{Qvb6Yydz2K@0#ok>MZ6re6#nuAT+@lbb<6%ZlOgj&7iSF$Ot1SB4Kat^y5s z&%mo72z2mYhX22Rfeio%AgBSq!QS`}bgF>58UquX2m=G-KZd_Q|1w;D!^t4W@QXn} zS&`w#S9YM+fF(8)Og=00bBSacqJz)ZpL`QswZ|oA zOU3F({X1SPKk~x6XuEsv=8XAw)8^f6+4yAPz9+8P8=W)OPu+UIb^XJ*={IAh-K<&l zaL$g04k_y_qL(?PteLvye)pzF(NnI6PrMd7;adK@Tb|h)ymQu1+Hhz2k(WyjJzsq2 zdCS`S(UY$R^H=O_U9Zd{AvPgH+2>Qg{FGCIEF}EPEKfGc2i>$IdJCCsWznp=MJ7c z+N*Qm@ag0F3LOu)IlDW$I=wxbEQ5lAE*Whq`ozW6<)yH1Q`f3lyV{mb+t$~|*Rg)} z^8AF1l$@k2w##{WiJ7Un$=U4&7w#Rrc=F~^QN;((-aUNu@+t50-#>o+WM^SJ`17FR zLLQ#Phk^!mDIq2uU5y`;A3qATojIZ76gz``gmBZ9{g>N-4pc31jVMV;EJ?LWE=mPb z3`Pb<#<~U;x&|g8hNf1==2j-A+6D$z1_nnZrhGurkei>9nO2Eg!xmQ^AD{*exD6$l jxv9k^iMa*ndMvCA%^;R!2Rl6n>S6G7^>bP0l+XkKPgggY literal 0 HcmV?d00001 diff --git a/static/spoiler.png b/static/spoiler.png new file mode 100755 index 0000000000000000000000000000000000000000..013467bbbd44a1d8f4a632b13e8043a0bb1b6bae GIT binary patch literal 2682 zcmcImc{rO{7Y{W>`zf7irk0o*r5m+V`%*$fnUIzgwGJvs)dUesN~>ByhiXwpi`1@F zYsS{r7#d4DL6wk{+CsBfLn6#O^GBcd`=00f=X<{U-20yMocEsJz4x5=ch7qV?qnym zPktW=1d@WCvvC1r@83gWFYv5E))s<5BFVwl)^M1$wNiM*)xhA;01)UzW_+gExi0vj z8dB!Af#N->Lc2gYFftAM$22{}s4? zKcIF<{w#!mOcFb|@6?H6F$L%GNEdY#rs>?&kET_8-L4r!pFEYP~zpsUXhPD{yh~%pq-!(_E)$1^nK>;t)UzU5RrJ=%kD@A#K!eL zMV}9Eesv`MxD_l(f^ZXT8QCIdn=L61O`7M7oQ_;SG;r$L9tcFVB!=w8!$!LaCU#iC zgB)>F$%xFxkzH{hFMItQ>}&uDv@PpaJRl^)&t3Wj1kyPA_YlDnEusLUI0ohj6`z+B z0Uws|Ph-{rCOHfgiLt&K78ZcUfUF||d@%t(D@6xmt|-~T9N}(>2M&Wk63#Fis|(n1 z)`a&tgm6#KGNpt`eGc_a9!M&8zKMUFFPd5Ya-Y2@f%{rvzi8L(+j=rf$6QW6L4S|B zaLCH}g#=ZH@Z7@ZHT>Ip%i+Y+G7pJc$IU3+t1U&shorHLfgaxen{Vqm8Qwhl7TTn& zQ$N6M-9J<+Q?+(wb3mzU-xBW>v;?rI`3l)zxH zdo#M=8Mn5!_HmD4+~)Hr_Jq-F6ch?Yq0u``L2`2PctbD(&NCWAKAF(0Pq1sI)wH#> z1@8_#)%D)(%my3{BH70yS|@Sqi}yc8wN|@UJ#s4Z)W}IC5W03HsAFTyD#6@9{*Zjv zRJd$nZ*MO*HnwaiSS;j4-C2@%pfDpWEUa_=O#Wb;;{`a}hd&_@M36i?v=cK15JWL#`)B=>`r5hUYr50lMyb#ijDq|r&g*hxuA{W!K;@dqCv&_8@W zx&v4|a%Bbvb8&Zn*yi=D2|X!as7dwr^J@s7It!yNERn+- z(Ow`B;KvQj&AkYRHC;VDAB7s^Lk^^{>FrfLcaQ8ggyHd>6KGy3&twD{$QlJ~>+DGr z7>V8Rb#zu}Ja9i!m*oA6RSRXbExe#*XD5L% zPAyuV^@xgUDlRFBZ_dkDt`pso(S0kN-t*^Mido`$Yd=5byE?hYLUWLkl9E8&$rQ>N zVFz$*PYt(T?+M=xN<320%GTCaPfrindvQyPA+fZy7u_tN6S?!VeL4J<**?vl^t80? zSy|xRyn+L|1_nerg@qbbBl1}Sv)GMK*_7K_b}fVP?>h*Q zQ?I{ayt#T$(TF-UqzVI?JOpyV**TL;CMS$iDClvbs8ZAaFGv zkHsPZ97zF5nr1mpqm9t%=1dBYJ*ieTQdwH60=2Q}^{YFfqeJC1m6Vh~g?+~C4JlvO>evO!(BU%rqC^p zW*tC@k&zK%K;MIt#>Vcds;Vdyipruj@A*ww3?(#Rm@W+Y#?n%o_4V}xX&#A0dO>5Q z-p(ESgsCz z?!1+^cab@M2eRVO+BKI{VG(J-InT~9%pc{*wcPTR)yPr%q>-yL3+1OPoXO74E}d+R z4xu%L0XKR_uClybE3*0x27_4uzCnNm ztL+7yxOG%xW8*h^@19tvV751}sj8?f2zVTT?Jgl9RVVRyghrG_)Ti93bzJ(?l&}Al zE4{q~15%r&LN*)i@8hHN*g;>w=cnDewHHxz(3<4U@5%wEtmurvA?*cDWq{ia<7qad zlhJ}=QiQ})mY1nOe)sP$!6GH+nKz9!hu%coOnQUKRcun~+?bxwni~RK^ zk+9aQ409rpIM6F^?8yr;=kcVZs8-eHm@b`MqvC zW^Ex;Gxf|>dMiU0y%{{uaS9{`9 Va!D6I4)_BB!JtkywP$^j{sM_9)SUnT literal 0 HcmV?d00001 diff --git a/static/style.css b/static/style.css new file mode 100755 index 0000000..12c0f87 --- /dev/null +++ b/static/style.css @@ -0,0 +1,442 @@ +body { + min-height: 100vh; + font-family: var(--font); + font-size: 10pt; + background: var(--bg); + color: var(--text); + margin: 0; +} + +a { + color: var(--link-color); +} + +a:hover { + color: var(--link-hover); +} + +details { + display: inline-block; + margin-bottom: 8px; +} + +details:last-child { + margin-bottom: 0; +} + +img, +video { + max-height: 90vh; +} + +hr { + border-top: 1px solid var(--hr-color); + border-left: none; + border-right: none; + border-bottom: none; +} + +summary { + cursor: pointer; +} + +.form-table .label { + font-weight: bold; + background-color: var(--table-head); + border: 1px solid var(--table-border); + padding: 4px; +} + +.form-table td { + padding: 0; +} + +.form-table input[type="text"], +.form-table input[type="password"], +.form-table input[type="number"], +.form-table textarea, +.form-table select, +.input-wrapper { + /* FUCK IE7 */ + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + + display: block; + width: 100%; + color: var(--text); + background-color: var(--input-color); + border-radius: 0; + border: 1px solid var(--input-border); + padding: 4px; +} + +.form-table input[type="checkbox"] { + display: block; + margin: 0 auto; +} + +.form-table textarea { + height: 8rem; + resize: none; +} + +.form-table .submit .button { + display: block; + width: 100%; +} + +.reply-mode { + font-weight: bold; + font-size: 18px; + text-align: center; + background-color: var(--table-head); + border: 1px solid var(--table-border); + padding: 8px; +} + +.container > form > .form-table { + margin: 8px auto; +} + +.table-wrap { + overflow-x: auto; + margin: 8px 0; +} + +.data-table { + width: 100%; + background-color: var(--table-primary); + border-spacing: 0; + border: 1px solid var(--table-border); +} + +.data-table tr:nth-child(2n + 1) { + background-color: var(--table-secondary); +} + +.data-table th { + background-color: var(--table-head); +} + +.data-table td, +.data-table th { + padding: 4px; + text-align: center; +} + +.data-table .banner { + margin-top: 0; + margin-bottom: 0; +} + +.box { + background-color: var(--box-color); + border-right: 1px solid var(--box-border); + border-bottom: 1px solid var(--box-border); + padding: 8px; +} + +.box:target { + background-color: var(--hl-box-color); + border-right: 1px solid var(--hl-box-border); + border-bottom: 1px solid var(--hl-box-border); +} + +.infobox { + margin: 8px 0; + border: 1px solid var(--table-border); +} + +.infobox-head { + background-color: var(--table-head); + font-weight: bold; + padding: 4px; +} + +.infobox-content { + background-color: var(--table-primary); + padding: 4px; +} + +.infobox-content .post-files { + margin: 0; +} + +.button { + cursor: pointer; + border-radius: 0; + color: var(--text); + background-color: var(--input-color); + border: 1px solid var(--input-border); + padding: 8px; +} + +.captcha { + width: 100%; + image-rendering: pixelated; + border: 1px solid var(--input-border); +} + +.main { + margin: 8px; +} + +.container { + margin: 0 auto; + max-width: 720px; +} + +.title { + color: var(--title-color); + font-family: var(--title-font); + text-align: center; + letter-spacing: -2px; + margin: 0; +} + +.description { + font-weight: bold; + margin: 0; +} + +.small { + font-size: 8pt; + font-weight: normal; +} + +.center { + text-align: center; +} + +.inline-block { + display: inline-block; +} + +.banner { + display: block; + max-width: 300px; + margin: 8px auto; + border: 1px solid var(--box-border); +} + +.board-links { + padding: 2px; + border-bottom: 1px solid var(--box-border); +} + +.link-separator::after { + content: " / "; +} + +.link-group::before { + content: " [ "; +} + +.link-group::after { + content: " ] "; +} + +.board-links::after { + content: ""; + display: block; + clear: both; +} + +.post { + margin-bottom: 8px; + padding: 8px; +} + +.post.box { + display: inline-block; + min-width: 400px; +} + +.post:last-of-type { + margin-bottom: 0; +} + +.post::after { + display: block; + content: ""; + clear: both; +} + +.board-links a, +.pagination a, +.post-number { + text-decoration: none; +} + +.post-header input[type="checkbox"] { + margin: 0; +} + +.catalog { + text-align: center; +} + +.catalog-entry { + display: inline-block; + width: 200px; + height: 250px; + overflow: scroll; + margin: 4px; + padding: 8px; +} + +.catalog-entry .thumb { + display: block; + max-width: 100%; + max-height: 50%; + box-shadow: 0 0 3px #000; + margin: 4px auto; + padding: 2px; +} + +.catalog-entry .post-content { + margin: 8px; +} + +.name { + font-weight: bold; + color: var(--name-color); +} + +.tripcode { + color: var(--trip-color); +} + +.capcode { + color: var(--capcode-color); + font-weight: bold; +} + +.user-id { + text-shadow: #000 0 0 1px, #000 0 0 1px, #000 0 0 1px, #000 0 0 1px, + #000 0 0 1px, #000 0 0 1px; + color: #ffffff; + border: 1px solid var(--box-border); + padding: 0 2px; +} + +.post-files { + float: left; + margin: 0 8px 8px 8px; +} + +.multi-files { + float: none; +} + +.post-file { + display: inline-block; + vertical-align: top; + text-align: center; + font-size: 8pt; + padding: 4px; +} + +.thumb { + max-width: 150px; + max-height: 150px; +} + +.post-content { + font-family: inherit; + white-space: pre-wrap; + word-break: break-word; + margin: 1rem 2rem; +} + +.post-content a { + color: var(--post-link-color); +} + +.post-content a:hover { + color: var(--post-link-hover); +} + +.quote { + text-decoration: underline; +} + +.dead-quote { + color: var(--dead-quote-color); + text-decoration: line-through; +} + +.greentext { + color: var(--greentext-color); +} + +.orangetext { + color: var(--orangetext-color); +} + +.redtext { + color: var(--redtext-color); + font-weight: bold; +} + +.bluetext { + color: var(--bluetext-color); + font-weight: bold; +} + +.glowtext { + text-shadow: 0 0 40px #00fe20, 0 0 2px #00fe20; +} + +.uh-oh-text { + color: var(--uh-oh-text); + background-color: var(--uh-oh-color); +} + +.spoiler { + color: var(--text); + background-color: var(--text); +} + +.spoiler:hover { + background-color: transparent; +} + +.icon { + height: 1em; + vertical-align: middle; + image-rendering: pixelated; +} + +.posts-omitted { + margin-top: 0; + margin-bottom: 8px; +} + +.recent-posts { + list-style-type: none; + margin: 0; + padding: 0; +} + +@media only screen and (max-width: 600px) { + .thumb { + max-width: 100px; + max-height: 100px; + } + + .post.box { + display: block; + min-width: unset; + } + + .thread > br { + display: none; + } + + .catalog-entry { + width: 140px; + height: 220px; + } +} diff --git a/static/themes/yotsuba-b.css b/static/themes/yotsuba-b.css new file mode 100644 index 0000000..976f686 --- /dev/null +++ b/static/themes/yotsuba-b.css @@ -0,0 +1,38 @@ +:root { + /* General */ + --bg: linear-gradient(#d6daf0 3rem, #eef2ff 230px); + --text: #000000; + --font: Arial, Helvetica, sans-serif; + /* Text */ + --link-color: #34345c; + --link-hover: #dd0000; + --post-link-color: #34345c; + --post-link-hover: #dd0000; + --title-color: #af0a0f; + --title-font: tahoma; + --hr-color: #d3d3d3; + --name-color: #117743; + --trip-color: #117743; + --capcode-color: #cc1105; + /* Tables */ + --table-head: #9988ee; + --table-border: #000000; + --table-primary: #ffffff; + --table-secondary: #d6daf0; + /* Forms */ + --input-color: #ffffff; + --input-border: #808080; + /* Box™ */ + --box-color: #d6daf0; + --box-border: #b7c5d9; + --hl-box-color: #d6bad0; + --hl-box-border: #ba9dbf; + /* Formatting */ + --dead-quote-color: #2e2e2e; + --greentext-color: #008000; + --orangetext-color: #ff5100; + --redtext-color: #af0a0f; + --bluetext-color: #0000ff; + --uh-oh-color: #ffffff; + --uh-oh-text: #0038b8; +} diff --git a/static/themes/yotsuba.css b/static/themes/yotsuba.css new file mode 100644 index 0000000..b49dfea --- /dev/null +++ b/static/themes/yotsuba.css @@ -0,0 +1,38 @@ +:root { + /* General */ + --bg: linear-gradient(#fed6af90 3rem, #ffe 230px); + --text: #800000; + --font: Arial, Helvetica, sans-serif; + /* Text */ + --link-color: #800000; + --link-hover: #dd0000; + --post-link-color: #000080; + --post-link-hover: #dd0000; + --title-color: #af0a0f; + --title-font: tahoma; + --hr-color: #d9bfb7; + --name-color: #117743; + --trip-color: #117743; + --capcode-color: #cc1105; + /* Tables */ + --table-head: #ffccaa; + --table-border: #800000; + --table-primary: #ffffff; + --table-secondary: #ffffff; + /* Forms */ + --input-color: #ffffff; + --input-border: #808080; + /* Box™ */ + --box-color: #f0e0d6; + --box-border: #d9bfb7; + --hl-box-color: #f0c0b0; + --hl-box-border: #d99f91; + /* Formatting */ + --dead-quote-color: #2e2e2e; + --greentext-color: #008000; + --orangetext-color: #ff5100; + --redtext-color: #af0a0f; + --bluetext-color: #0000ff; + --uh-oh-color: #ffffff; + --uh-oh-text: #0038b8; +} diff --git a/templates/action.html b/templates/action.html new file mode 100644 index 0000000..156fc43 --- /dev/null +++ b/templates/action.html @@ -0,0 +1,18 @@ +{% extends "base.html" %} + +{% block title %}Výsledek{% endblock %} + +{% block content %} +

+
+
Výsledek
+
+ {% if !response.is_empty() %} + {{ response|linebreaksbr|safe }} + {% else %} + Nic se nezměnilo. + {% endif %} +
+
+
+{% endblock %} diff --git a/templates/banned.html b/templates/banned.html new file mode 100644 index 0000000..bc7aa15 --- /dev/null +++ b/templates/banned.html @@ -0,0 +1,64 @@ +{% extends "base.html" %} + +{% block title %}Máš ban!{% endblock %} + +{% block content %} +
+

Jsi trans, btw.

+
+
Máš ban!
+
+ + Byl jsi zabanován + + {% if let Some(board) = ban.board %} + z /{{ board }}/ + {% else %} + ze všech nástěněk + {% endif %} + + z následujícího důvodu: + +
+ {{ ban.reason }} +
+ Udělil {{ ban.issued_by }} +
+
+ + Tvůj ban platí pro IP adresu/rozsah {{ ban.ip_range }} a + {% if let Some(expires) = ban.expires %} + vyprší {{ expires|czech_datetime }} ({{ expires|czech_humantime }}). + {% else %} + je trvalý. + {% endif %} + + {% if ban.appealable %} +
+
+ {% if let Some(appeal) = ban.appeal %} + Tvé odvolání: +
+ {{ appeal }} +
+ {% else %} + Můžeš se pokusit svůj ban odvolat: +
+ + + + + + + + +
Odvolání
+ +
+
+ {% endif %} + {% endif %} +
+
+
+{% endblock %} diff --git a/templates/base.html b/templates/base.html new file mode 100755 index 0000000..ed59932 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,34 @@ + + + + + + {% block title %}{% endblock %} + + + + + + + +
+
{% block content %}{% endblock %}
+ + diff --git a/templates/board.html b/templates/board.html new file mode 100755 index 0000000..f2239dc --- /dev/null +++ b/templates/board.html @@ -0,0 +1,50 @@ +{% import "./macros/pagination.html" as pagination %} +{% import "./macros/post-actions.html" as post_actions %} +{% import "./macros/post-form.html" as post_form %} +{% import "./macros/post.html" as post %} + +{% extends "base.html" %} + +{% block title %}/{{ board.id }}/ - {{ board.name }}{% endblock %} + +{% block content %} +
+
+ {% if let Some(banner) = board.random_banner() %} + + {% endif %} +

/{{ board.id }}/ - {{ board.name }}

+

{{ board.description }}

+ Katalog +
+ {% call post_form::post_form(board, tcx.perms, false, 0) %} +
+
+
+ {% for (thread, replies) in threads %} +
+ {% call post::post(board, thread, false) %} + {% let count = replies.len() %} + {% if count > 5 %} +

+ {% let omitted = count - 5 %} + {{ "Vynechán|Vynechány|Vynecháno"|czech_plural(omitted) }} {{ omitted }} {{ "příspěvek|příspěvky|příspěvků"|czech_plural(omitted) }}. Zobrazit celé vlákno. +

+ {% for reply_post in replies.iter().rev().take(5).rev() %} + {% call post::post(board, reply_post, true) %} +
+ {% endfor %} + {% else %} + {% for reply_post in replies %} + {% call post::post(board, reply_post, true) %} +
+ {% endfor %} + {% endif %} +
+
+ {% endfor %} + {% call pagination::pagination("/boards/{}"|format(board.id), pages, page) %} +
+ {% call post_actions::post_actions(tcx.perms) %} +
+{% endblock %} diff --git a/templates/board_catalog.html b/templates/board_catalog.html new file mode 100755 index 0000000..2e2150b --- /dev/null +++ b/templates/board_catalog.html @@ -0,0 +1,29 @@ +{% import "./macros/catalog-entry.html" as catalog_entry %} +{% import "./macros/post-actions.html" as post_actions %} + +{% extends "base.html" %} + +{% block title %}Katalog (/{{ board.id }}/){% endblock %} + +{% block content %} +
+
+ {% if let Some(banner) = board.random_banner() %} + + {% endif %} +

Katalog (/{{ board.id }}/)

+

{{ board.description }}

+ Index +
+
+
+
+
+ {% for thread in threads %} + {% call catalog_entry::catalog_entry(thread, loop.index, board.config.0.page_size.into()) %} + {% endfor %} +
+
+ {% call post_actions::post_actions(tcx.perms) %} +
+{% endblock %} diff --git a/templates/error.html b/templates/error.html new file mode 100755 index 0000000..0d41e8f --- /dev/null +++ b/templates/error.html @@ -0,0 +1,28 @@ + + + + + + Chyba + + + + +
+
+

Je konec...

+ +
+
+ Chyba {{ error_code }} +
+ {% if !error_message.is_empty() %} +
+ {{ error_message }} +
+ {% endif %} +
+
+
+ + diff --git a/templates/index.html b/templates/index.html new file mode 100755 index 0000000..3d13377 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,47 @@ +{% extends "base.html" %} + +{% block title %}{{ tcx.cfg.site.name }}{% endblock %} + +{% block content %} +
+
+ {% if let Some(banner) = tcx.cfg.site.site_banner %} + + {% endif %} +

{{ tcx.cfg.site.name }}

+

{{ tcx.cfg.site.description }}

+
+ {% if !posts.is_empty() %} +
+
+ Nejnovější příspěvky +
+
+ +
+
+ {% endif %} + {% if !files.is_empty() %} +
+
+ Nejnovější soubory +
+
+
+ {% for post in files %} +
+ + + +
+ {% endfor %} +
+
+
+ {% endif %} +
+{% endblock %} diff --git a/templates/login.html b/templates/login.html new file mode 100755 index 0000000..3735568 --- /dev/null +++ b/templates/login.html @@ -0,0 +1,24 @@ +{% extends "base.html" %} + +{% block title %}Přihlásit se{% endblock %} + +{% block content %} +
+

Přihlásit se

+
+ + + + + + + + + + + + +
Jméno
Heslo
+
+
+{% endblock %} diff --git a/templates/macros/catalog-entry.html b/templates/macros/catalog-entry.html new file mode 100644 index 0000000..42de933 --- /dev/null +++ b/templates/macros/catalog-entry.html @@ -0,0 +1,23 @@ +{% macro catalog_entry(post, index, page_size) %} +
+ + /{{ post.board }}/{{ post.id }} + {% if let Some(file) = post.files.0.get(0) %} + + + + {% else %} +

[Link]

+ {% endif %} + + R: {{ post.replies }} / P: {{ index|get_page(page_size) }} + {% if post.sticky %} + + {% endif %} + {% if post.locked %} + + {% endif %} + +
{{ post.content|add_yous(post.board, tcx.yous)|safe }}
+
+{% endmacro %} diff --git a/templates/macros/pagination.html b/templates/macros/pagination.html new file mode 100644 index 0000000..444b24b --- /dev/null +++ b/templates/macros/pagination.html @@ -0,0 +1,15 @@ +{% macro pagination(base, pages, current) %} + +{% endmacro %} diff --git a/templates/macros/post-actions.html b/templates/macros/post-actions.html new file mode 100644 index 0000000..d21a8d4 --- /dev/null +++ b/templates/macros/post-actions.html @@ -0,0 +1,188 @@ +{% macro post_actions(perms) %} +
+ Uživatelské akce + + + + + + + + + + + + + + + + + + + + + +
Odstranit příspěvky +
+ +
+
Odstranit soubory +
+ +
+
Přidat/odstranit spoiler +
+ +
+
Heslo + +
+ +
+ + + + + + + + +
Důvod hlášení
+ +
+
+
+{% if perms.owner() || perms.manage_posts() || perms.bans() || perms.edit_posts() %} +
+ Uklízečské akce + + {% if perms.owner() || perms.manage_posts() %} + + + + + + + + + + + + + + + + + + + + + {% endif %} + {% if perms.owner() || perms.bans() %} + + + + + + + + + + + + + + + + + + + + + + + + + {% endif %} + + + +
Odstranit příspěvky +
+ +
+
Odstranit soubory +
+ +
+
Přidat/odstranit spoiler +
+ +
+
Připnout/odepnout +
+ +
+
Uzamknout/odemknout +
+ +
+
Zabanovat uživatele +
+ +
+
Globální ban +
+ +
+
Neodvolatelný ban +
+ +
+
Důvod banu
Délka banu (dny)
Rozsah banu + +
+ +
+ {% if perms.owner() || perms.edit_posts() %} + + + + +
+ +
+ {% endif %} +
+{% endif %} +{% endmacro %} diff --git a/templates/macros/post-form.html b/templates/macros/post-form.html new file mode 100644 index 0000000..6afbf02 --- /dev/null +++ b/templates/macros/post-form.html @@ -0,0 +1,87 @@ +{% macro post_form(board, perms, reply, reply_to) %} +
+ + {% if reply %} + + {% endif %} + + {% if reply %} + + + + {% endif %} + + + + + + + + + + + + + + + + + + + + + + + + + {% if !(perms.bypass_captcha() || perms.owner()) %} + {% if reply %} + {% if let Some((id, base64)) = board.reply_captcha() %} + + + + + {% endif %} + {% else %} + {% if let Some((id, base64)) = board.thread_captcha() %} + + + + + {% endif %} + {% endif %} + {% endif %} + + {% if reply %} + + {% else %} + + {% endif %} + +
Režim: Odpověď [Zpět]
Jméno + +
Email + +
Obsah + +
Soubory +
+ 1 %} multiple="multiple"{% endif %}{% if (!reply && board.config.0.require_thread_file) || (reply && board.config.0.require_reply_file) %} required="required"{% endif %}> +
+
Spoiler? +
+ +
+
Heslo (na odstranění) + +
CAPTCHA + + + +
CAPTCHA + + + +
+
+{% endmacro %} diff --git a/templates/macros/post.html b/templates/macros/post.html new file mode 100644 index 0000000..d4720a8 --- /dev/null +++ b/templates/macros/post.html @@ -0,0 +1,59 @@ +{% macro post(board, post, boxed) %} +
+
+ + {% if let Some(email) = post.email %} + {{ post.name }} + {% else %} + {{ post.name }} + {% endif %} + {% if let Some(tripcode) = post.tripcode %} + {{ tripcode }} + {% endif %} + {% if let Some(capcode) = post.capcode %} + ## {{ capcode }} + {% endif %} + {% if tcx.ip == post.ip %} + {# Technically not a tripcode or something but same styling #} + (Ty) + {% endif %} + {% if board.config.0.flags %} + + {% endif %} + {{ post.created|czech_humantime }} + {% if board.config.0.user_ids %} + {{ post.user_id }} + {% endif %} + Č.{{ post.id }} + {% if post.sticky %} + + {% endif %} + {% if post.locked %} + + {% endif %} + + {% if !boxed %} + [Odpovědět] + {% endif %} +
+ {% if !post.files.0.is_empty() %} +
+ {% for file in post.files.0 %} +
+ + {% if file.spoiler %}[Spoiler]{% else %}{{ file.original_name }}{% endif %} + + +
+ ({{ file.size|filesizeformat }}, {{ file.width }}x{{ file.height }}) +
+ + + +
+ {% endfor %} +
+ {% endif %} +
{{ post.content|add_yous(post.board, tcx.yous)|safe }}
+
+{% endmacro %} diff --git a/templates/macros/staff-nav.html b/templates/macros/staff-nav.html new file mode 100644 index 0000000..171dc61 --- /dev/null +++ b/templates/macros/staff-nav.html @@ -0,0 +1,18 @@ +{% macro staff_nav(perms) %} + +{% endmacro %} diff --git a/templates/overboard.html b/templates/overboard.html new file mode 100644 index 0000000..d35520d --- /dev/null +++ b/templates/overboard.html @@ -0,0 +1,49 @@ +{% import "./macros/pagination.html" as pagination %} +{% import "./macros/post-actions.html" as post_actions %} +{% import "./macros/post.html" as post %} + +{% extends "base.html" %} + +{% block title %}Index nadnástěnky{% endblock %} + +{% block content %} +
+
+ {% if let Some(banner) = tcx.cfg.site.site_banner %} + + {% endif %} +

Index nadnástěnky

+

Nově naťuknutá vlákna ze všech nástěnek

+ Katalog +
+
+
+
+ {% for (thread, replies) in threads %} +
+ Vlákno z /{{ thread.board }}/ + {% call post::post(boards[thread.board.as_str()], thread, false) %} + {% let count = replies.len() %} + {% if count > 5 %} +

+ {% let omitted = count - 5 %} + {{ "Vynechán|Vynechány|Vynecháno"|czech_plural(omitted) }} {{ omitted }} {{ "příspěvek|příspěvky|příspěvků"|czech_plural(omitted) }}. Zobrazit celé vlákno. +

+ {% for reply_post in replies.iter().rev().take(5).rev() %} + {% call post::post(boards[reply_post.board.as_str()], reply_post, true) %} +
+ {% endfor %} + {% else %} + {% for reply_post in replies %} + {% call post::post(boards[reply_post.board.as_str()], reply_post, true) %} +
+ {% endfor %} + {% endif %} +
+
+ {% endfor %} + {% call pagination::pagination("/overboard", pages, page) %} +
+ {% call post_actions::post_actions(tcx.perms) %} +
+{% endblock %} diff --git a/templates/overboard_catalog.html b/templates/overboard_catalog.html new file mode 100755 index 0000000..5dd507c --- /dev/null +++ b/templates/overboard_catalog.html @@ -0,0 +1,29 @@ +{% import "./macros/catalog-entry.html" as catalog_entry %} +{% import "./macros/post-actions.html" as post_actions %} + +{% extends "base.html" %} + +{% block title %}Katalog nadnístěnky{% endblock %} + +{% block content %} +
+
+ {% if let Some(banner) = tcx.cfg.site.site_banner %} + + {% endif %} +

Katalog nadnástěnky

+

Nově naťuknutá vlákna ze všech nástěnek

+ Index +
+
+
+
+
+ {% for thread in threads %} + {% call catalog_entry::catalog_entry(thread, loop.index, 15) %} + {% endfor %} +
+
+ {% call post_actions::post_actions(tcx.perms) %} +
+{% endblock %} diff --git a/templates/staff/account.html b/templates/staff/account.html new file mode 100755 index 0000000..a81f9ad --- /dev/null +++ b/templates/staff/account.html @@ -0,0 +1,68 @@ +{% import "../macros/staff-nav.html" as staff_nav %} + +{% extends "base.html" %} + +{% block title %}Účet ({{ account.username }}){% endblock %} + +{% block content %} +

Účet ({{ account.username }})

+{% call staff_nav::staff_nav(tcx.perms) %} +
+

Změnit heslo

+
+ + + + + + + + + + + + +
Staré heslo
Nové heslo
+
+
+{% if tcx.perms.owner() %} +

Předat vlastnictví

+
+ + + + + + + + + + + + +
Účet
Potvrdit +
+ +
+
+
+
+{% endif %} +

Vymazat účet

+
+ + + + + + + + +
Potvrdit +
+ +
+
+
+
+{% endblock %} diff --git a/templates/staff/accounts.html b/templates/staff/accounts.html new file mode 100755 index 0000000..aa178fe --- /dev/null +++ b/templates/staff/accounts.html @@ -0,0 +1,57 @@ +{% import "../macros/staff-nav.html" as staff_nav %} + +{% extends "base.html" %} + +{% block title %}Účty{% endblock %} + +{% block content %} +

Účty

+{% call staff_nav::staff_nav(tcx.perms) %} +
+

Účty

+
+
+ + + + + + + + + {% for account in accounts %} + + + + + + + + {% endfor %} +
JménoVlastníkVytvořenOprávnění
{{ account.username }}{% if account.owner %}Ano{% else %}Ne{% endif %}{{ account.created|czech_datetime }}{{ account.permissions.0 }} [Zobrazit]
+
+ {% if tcx.perms.owner() %} + + {% endif %} +
+
+{% if tcx.perms.owner() %} +

Vytvořit účet

+
+ + + + + + + + + + + + +
Jméno
Heslo
+
+
+{% endif %} +{% endblock %} diff --git a/templates/staff/banners.html b/templates/staff/banners.html new file mode 100755 index 0000000..ce00b12 --- /dev/null +++ b/templates/staff/banners.html @@ -0,0 +1,50 @@ +{% import "../macros/staff-nav.html" as staff_nav %} + +{% extends "base.html" %} + +{% block title %}Bannery (/{{ board.id }}/){% endblock %} + +{% block content %} +

Bannery (/{{ board.id }}/)

+{% call staff_nav::staff_nav(tcx.perms) %} +
+

Bannery

+
+ + +
+ + + + + + {% for banner in board.banners.0 %} + + + + + {% endfor %} +
Banner
+ +
+
+ + +
+
+

Přidat bannery

+
+ + + + + + + + + + +
Bannery
+
+
+{% endblock %} diff --git a/templates/staff/bans.html b/templates/staff/bans.html new file mode 100755 index 0000000..1f45038 --- /dev/null +++ b/templates/staff/bans.html @@ -0,0 +1,47 @@ +{% import "../macros/staff-nav.html" as staff_nav %} + +{% extends "base.html" %} + +{% block title %}Bany{% endblock %} + +{% block content %} +

Bany

+{% call staff_nav::staff_nav(tcx.perms) %} +
+

Bany

+
+
+ + + + + + + + + + + + + {% for ban in bans %} + + + + + + + + + + + + {% endfor %} +
IPNástěnkaDůvodUdělilOdvolatelnýOdvoláníUdělěnVyprší
{{ ban.ip_range.network() }}-{{ ban.ip_range.broadcast() }}{% if let Some(board) = ban.board %}/{{ board }}/{% else %}Všechny{% endif %}
{{ ban.reason }}
{{ ban.issued_by }}{% if ban.appealable %}Ano{% else %}Ne{% endif %}{% if let Some(appeal) = ban.appeal %}
{{ appeal }}
{% else %}-{% endif %}
{{ ban.created|czech_datetime }}{% if let Some(expires) = ban.expires %}{{ expires|czech_humantime }}{% else %}Nikdy{% endif %}
+
+ + {% if tcx.perms.owner() || tcx.perms.bans() %} + + {% endif %} +
+
+{% endblock %} diff --git a/templates/staff/board-config.html b/templates/staff/board-config.html new file mode 100755 index 0000000..39c42e4 --- /dev/null +++ b/templates/staff/board-config.html @@ -0,0 +1,154 @@ +{% import "../macros/staff-nav.html" as staff_nav %} + +{% extends "base.html" %} + +{% block title %}Nastavení (/{{ board.id }}/){% endblock %} + +{% block content %} +

Nastavení (/{{ board.id }}/)

+{% call staff_nav::staff_nav(tcx.perms) %} +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Uzamknout nástěnku +
+ +
+
Výchozí jméno
Velikost stránky
Počet stránek
Limit souborů
Limit naťuknutí
Limit odpovědí
Identifikátory (anti-samefag) +
+ +
+
Vlajky +
+ +
+
CAPTCHA (vlákno) + +
CAPTCHA (odpověď) + +
Vyžadovat obsah ve vlákně +
+ +
+
Vyžadovat soubor ve vlákně +
+ +
+
Vyžadovat obsah v odpovědi +
+ +
+
Vyžadovat soubor v odpovědi +
+ +
+
+
+
+{% endblock %} diff --git a/templates/staff/boards.html b/templates/staff/boards.html new file mode 100755 index 0000000..26e9b48 --- /dev/null +++ b/templates/staff/boards.html @@ -0,0 +1,82 @@ +{% import "../macros/staff-nav.html" as staff_nav %} + +{% extends "base.html" %} + +{% block title %}Nástěnky{% endblock %} + +{% block content %} +

Nástěnky

+{% call staff_nav::staff_nav(tcx.perms) %} +
+

Nástěnky

+
+
+ + + + + + + + + + + {% for board in boards %} + + + + + + + + + + {% endfor %} +
IDJménoPopisVytvořenaBanneryNastavení
/{{ board.id }}/{{ board.name }}{{ board.description }}{{ board.created|czech_datetime }}{% if tcx.perms.owner() || tcx.perms.board_banners() %}[Zobrazit]{% else %}-{% endif %}{% if tcx.perms.owner() || tcx.perms.board_config() %}[Zobrazit]{% else %}-{% endif %}
+
+ + {% if tcx.perms.owner() %} + + {% endif %} + +
+ + {% if tcx.perms.owner() || tcx.perms.board_config() %} + + + + + + + + + + + + +
Jméno
Popis
+ {% endif %} +
+
+

Vytvořit nástěnku

+
+ + + + + + + + + + + + + + + + +
ID
Jméno
Popis
+
+
+{% endblock %} diff --git a/templates/staff/logs.html b/templates/staff/logs.html new file mode 100755 index 0000000..986a422 --- /dev/null +++ b/templates/staff/logs.html @@ -0,0 +1,30 @@ +{% import "../macros/pagination.html" as pagination %} +{% import "../macros/staff-nav.html" as staff_nav %} + +{% extends "base.html" %} + +{% block title %}Záznamy{% endblock %} + +{% block content %} +

Záznamy

+{% call staff_nav::staff_nav(tcx.perms) %} +
+

Záznamy

+
+ + + + + + {% for record in records %} + + + + + {% endfor %} +
ZprávaDatum
{{ record.message }}{{ record.created|czech_datetime }}
+
+
+{% call pagination::pagination("/staff/logs", pages, page) %} +
+{% endblock %} diff --git a/templates/staff/permissions.html b/templates/staff/permissions.html new file mode 100755 index 0000000..4cfce88 --- /dev/null +++ b/templates/staff/permissions.html @@ -0,0 +1,135 @@ +{% import "../macros/staff-nav.html" as staff_nav %} + +{% extends "base.html" %} + +{% block title %}Oprávnění ({{ account.username }}){% endblock %} + +{% block content %} +

Oprávnění ({{ account.username }})

+{% call staff_nav::staff_nav(tcx.perms) %} +
+{% if account.perms().owner() %} +

Tento uživatel je vlastník, změny nebudou mít žádný vliv.

+
+{% endif %} +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {% if tcx.perms.owner() %} + + + + {% endif %} +
Upravit příspěvky +
+ +
+
Spravovat příspěvky +
+ +
+
Používat capcode +
+ +
+
Záznamy +
+ +
+
Hlášení +
+ +
+
Bany +
+ +
+
Bannery nástěnek +
+ +
+
Nastavení nástěnek +
+ +
+
Obejít ban +
+ +
+
Obejít uzamčení nástěnky +
+ +
+
Obejít uzamčení vlákna +
+ +
+
Obejít CAPTCHA +
+ +
+
+
+
+{% endblock %} diff --git a/templates/staff/reports.html b/templates/staff/reports.html new file mode 100755 index 0000000..37c63e6 --- /dev/null +++ b/templates/staff/reports.html @@ -0,0 +1,14 @@ +{% import "../macros/pagination.html" as pagination %} +{% import "../macros/staff-nav.html" as staff_nav %} + +{% extends "base.html" %} + +{% block title %}Hlášení{% endblock %} + +{% block content %} +

Hlášení

+{% call staff_nav::staff_nav(tcx.perms) %} +
+

Dočasně nedostupné

+
+{% endblock %} diff --git a/templates/thread.html b/templates/thread.html new file mode 100644 index 0000000..a40a1f6 --- /dev/null +++ b/templates/thread.html @@ -0,0 +1,33 @@ +{% import "./macros/post-actions.html" as post_actions %} +{% import "./macros/post-form.html" as post_form %} +{% import "./macros/post.html" as post %} + +{% extends "base.html" %} + +{% block title %}/{{ board.id }}/ - {{ thread.content_nomarkup|inline_post }}{% endblock %} + +{% block content %} +
+
+ {% if let Some(banner) = board.random_banner() %} + + {% endif %} +

/{{ board.id }}/ - {{ board.name }}

+

{{ board.description }}

+ Katalog +
+ {% call post_form::post_form(board, tcx.perms, true, thread.id) %} +
+
+
+
+ {% call post::post(board, thread, false) %} + {% for reply_post in replies %} + {% call post::post(board, reply_post, true) %} +
+ {% endfor %} +
+
+ {% call post_actions::post_actions(tcx.perms) %} +
+{% endblock %}