From a66993ff2116f28864930a65c751aa2a3b7ef604 Mon Sep 17 00:00:00 2001 From: Alexandre Simao Date: Tue, 28 Feb 2023 16:11:09 +0100 Subject: [PATCH] chore: dirty rebase to clean main branch --- .gitignore | 1 + .gitlab-ci.yml | 48 +- custom_plugins/chalkboard/README.md | 163 ++ custom_plugins/chalkboard/img/blackboard.png | Bin 0 -> 32733 bytes .../chalkboard/img/boardmarker-black.png | Bin 0 -> 2142 bytes .../chalkboard/img/boardmarker-blue.png | Bin 0 -> 2127 bytes .../chalkboard/img/boardmarker-green.png | Bin 0 -> 2106 bytes .../chalkboard/img/boardmarker-orange.png | Bin 0 -> 2240 bytes .../chalkboard/img/boardmarker-purple.png | Bin 0 -> 2044 bytes .../chalkboard/img/boardmarker-red.png | Bin 0 -> 2119 bytes .../chalkboard/img/boardmarker-yellow.png | Bin 0 -> 2105 bytes custom_plugins/chalkboard/img/chalk-blue.png | Bin 0 -> 5150 bytes custom_plugins/chalkboard/img/chalk-green.png | Bin 0 -> 4801 bytes .../chalkboard/img/chalk-orange.png | Bin 0 -> 5010 bytes .../chalkboard/img/chalk-purple.png | Bin 0 -> 5250 bytes custom_plugins/chalkboard/img/chalk-red.png | Bin 0 -> 4786 bytes custom_plugins/chalkboard/img/chalk-white.png | Bin 0 -> 5199 bytes .../chalkboard/img/chalk-yellow.png | Bin 0 -> 5097 bytes custom_plugins/chalkboard/img/sponge.png | Bin 0 -> 3612 bytes custom_plugins/chalkboard/img/whiteboard.png | Bin 0 -> 34129 bytes custom_plugins/chalkboard/plugin.js | 1973 +++++++++++++++++ custom_plugins/chalkboard/style.css | 44 + html_files/phishing_full_clean.html | 618 ++++++ index.html | 81 +- 24 files changed, 2859 insertions(+), 69 deletions(-) create mode 100644 .gitignore create mode 100644 custom_plugins/chalkboard/README.md create mode 100644 custom_plugins/chalkboard/img/blackboard.png create mode 100644 custom_plugins/chalkboard/img/boardmarker-black.png create mode 100644 custom_plugins/chalkboard/img/boardmarker-blue.png create mode 100644 custom_plugins/chalkboard/img/boardmarker-green.png create mode 100644 custom_plugins/chalkboard/img/boardmarker-orange.png create mode 100644 custom_plugins/chalkboard/img/boardmarker-purple.png create mode 100644 custom_plugins/chalkboard/img/boardmarker-red.png create mode 100644 custom_plugins/chalkboard/img/boardmarker-yellow.png create mode 100644 custom_plugins/chalkboard/img/chalk-blue.png create mode 100644 custom_plugins/chalkboard/img/chalk-green.png create mode 100644 custom_plugins/chalkboard/img/chalk-orange.png create mode 100644 custom_plugins/chalkboard/img/chalk-purple.png create mode 100644 custom_plugins/chalkboard/img/chalk-red.png create mode 100644 custom_plugins/chalkboard/img/chalk-white.png create mode 100644 custom_plugins/chalkboard/img/chalk-yellow.png create mode 100644 custom_plugins/chalkboard/img/sponge.png create mode 100644 custom_plugins/chalkboard/img/whiteboard.png create mode 100644 custom_plugins/chalkboard/plugin.js create mode 100644 custom_plugins/chalkboard/style.css create mode 100644 html_files/phishing_full_clean.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..83f6e39 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +credentials.json diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6cbc479..f346d9f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,10 @@ stages: + - build-deps - build - deploy + +variables: + GIT_SUBMODULE_STRATEGY: recursive prepare_folders: environment: $CI_COMMIT_BRANCH @@ -8,41 +12,55 @@ prepare_folders: image: alpine:latest script: - mkdir -p .public - - mkdir -p .public/slides - - chown -R 1000:1000 .public/slides + - mkdir -p .public/docs + - chown -R 1000:1000 .public/docs cache: paths: - .public - artifacts: - paths: - - .public rules: - if: $CI_COMMIT_BRANCH =~ /^make/ -export: +render_pdf: environment: $CI_COMMIT_BRANCH - variables: - WORK_PATH: "public/$CI_COMMIT_BRANCH" - stage: build + stage: build-deps when: manual image: name: astefanutti/decktape entrypoint: ["/bin/sh", "-c"] script: - - "node /decktape/decktape.js -s 2560x1440 reveal --chrome-path chromium-browser --chrome-arg=--no-sandbox --chrome-arg=--disable-web-security index.html .public/slides/slide.pdf" + - "node /decktape/decktape.js -s 2560x1440 reveal --chrome-path chromium-browser --chrome-arg=--no-sandbox --chrome-arg=--disable-web-security index.html .public/docs/slide.pdf" cache: paths: - .public artifacts: paths: - - .public/slides + - .public/docs + expire_in: 2 week + rules: + - if: $CI_COMMIT_BRANCH =~ /^make/ + +render_ppt: + needs: [render_pdf] + environment: $CI_COMMIT_BRANCH + stage: build + when: manual + image: + name: linuxserver/libreoffice + entrypoint: ["/bin/sh", "-c"] + script: + - 'soffice --headless --infilter="impress_pdf_import" --convert-to "pptx:Impress Office Open XML" .public/docs/slide.pdf --outdir .public/docs/' + cache: + paths: + - .public + artifacts: + paths: + - .public/docs + expire_in: 2 week rules: - if: $CI_COMMIT_BRANCH =~ /^make/ pages: environment: $CI_COMMIT_BRANCH - variables: - GIT_SUBMODULE_STRATEGY: recursive stage: deploy when: manual script: @@ -53,9 +71,5 @@ pages: paths: - .public - public - artifacts: - paths: - - public rules: - if: $CI_COMMIT_BRANCH =~ /^make/ - diff --git a/custom_plugins/chalkboard/README.md b/custom_plugins/chalkboard/README.md new file mode 100644 index 0000000..8adefe5 --- /dev/null +++ b/custom_plugins/chalkboard/README.md @@ -0,0 +1,163 @@ +# Chalkboard + +With this plugin you can add a chalkboard to reveal.js. The plugin provides two possibilities to include handwritten notes to your presentation: + +- you can make notes directly on the slides, e.g. to comment on certain aspects, +- you can open a chalkboard or whiteboard on which you can make notes. + +The main use case in mind when implementing the plugin is classroom usage in which you may want to explain some course content and quickly need to make some notes. + +The plugin records all drawings made so that they can be play backed using the `autoSlide` feature or the `audio-slideshow` plugin. + + +[Check out the demo](https://rajgoel.github.io/reveal.js-demos/?topic=chalkboard) + +## Setup + +To use the plugin include +```html + + + + + + + + + +``` +to the header of your presentation and configure reveal.js and the plugin by + +```js +Reveal.initialize({ + customcontrols: { + controls: [ + { icon: '', + title: 'Toggle chalkboard (B)', + action: 'RevealChalkboard.toggleChalkboard();' + }, + { icon: '', + title: 'Toggle notes canvas (C)', + action: 'RevealChalkboard.toggleNotesCanvas();' + } + ] + }, + chalkboard: { + // add configuration here + }, + // ... + plugins: [ RevealChalkboard, RevealCustomControls ], + // ... +}); +``` + +In order to include buttons for opening and closing the notes canvas or the chalkboard you should make sure that `font-awesome` is available. The easiest way is to include +``` + +``` +to the ```head``` section of you HTML-file. + +## Usage + +### Mouse or touch +- Click on the pen symbols at the bottom left to toggle the notes canvas or chalkboard +- Click on the color picker at the left to change the color (the color picker is only visible if the notes canvas or chalkboard is active) +- Click on the up/down arrows on the left to the switch among multiple chalkboardd (the up/down arrows are only available for the chlakboard) +- Click the left mouse button and drag to write on notes canvas or chalkboard +- Click the right mouse button and drag to wipe away previous drawings +- Touch and move to write on notes canvas or chalkboard + +### Keyboard +- Press the 'BACKSPACE' key to delete all chalkboard drawings +- Press the 'DEL' key to clear the notes canvas or chalkboard +- Press the 'c' key to toggle the notes canvas +- Press the 'b' key to toggle the chalkboard +- Press the 'd' key to download drawings +- Press the 'x' key to cycle colors forward +- Press the 'y' key to cycle colors backward + +## Playback + +If the `autoSlide` feature is set or if the `audio-slideshow` plugin is used, pre-recorded chalkboard drawings can be played. The slideshow plays back the user interaction with the chalkboard in the same way as it was conducted when recording the data. + +## Multiplexing + +The plugin supports multiplexing via the [`multiplex` plugin](https://github.com/reveal/multiplex) or the [`seminar` plugin](https://github.com/rajgoel/reveal.js-plugins/tree/master/seminar). + +## PDF-Export + +If the slideshow is opened in [print mode](https://revealjs.com/pdf-export/), the chalkboard drawings in the session storage (see `storage` option - print version must be opened in the same tab or window as the original slideshow) or provided in a file (see `src` option) are included in the PDF-file. Each drawing on the chalkboard is added after the slide that was shown when opening the chalkboard. Drawings on the notes canvas are not included in the PDF-file. + + +## Configuration + +The plugin has several configuration options: + +- ```boardmarkerWidth```: an integer, the drawing width of the boardmarker; larger values draw thicker lines. +- ```chalkWidth```: an integer, the drawing width of the chalk; larger values draw thicker lines. +- ```chalkEffect```: a float in the range ```[0.0, 1.0]```, the intesity of the chalk effect on the chalk board. Full effect (default) ```1.0```, no effect ```0.0```. +- ```storage```: Optional variable name for session storage of drawings. +- ```src```: Optional filename for pre-recorded drawings. +- ```readOnly```: Configuation option allowing to prevent changes to existing drawings. If set to ```true``` no changes can be made, if set to false ```false``` changes can be made, if unset or set to ```undefined``` no changes to the drawings can be made after returning to a slide or fragment for which drawings had been recorded before. In any case the recorded drawings for a slide or fragment can be cleared by pressing the 'DEL' key (i.e. by using the ```RevealChalkboard.clear()``` function). +- ```transition```: Gives the duration (in milliseconds) of the transition for a slide change, so that the notes canvas is drawn after the transition is completed. +- ```theme```: Can be set to either ```"chalkboard"``` or ```"whiteboard"```. + +The following configuration options allow to change the appearance of the notes canvas and the chalkboard. All of these options require two values, the first gives the value for the notes canvas, the second for the chalkboard. + +- ```background```: The first value expects a (semi-)transparent color which is used to provide visual feedback that the notes canvas is enabled, the second value expects a filename to a background image for the chalkboard. +- ```grid```: By default whiteboard and chalkboard themes include a grid pattern on the background. This pattern can be modified by setting the color, the distance between lines, and the line width, e.g. ```{ color: 'rgb(127,127,255,0.1)', distance: 40, width: 2}```. Alternatively, the grid can be removed by setting the value to ```false```. +- ```eraser```: An image path and radius for the eraser. +- ```boardmarkers```: A list of boardmarkers with given color and cursor. +- ```chalks```: A list of chalks with given color and cursor. +- ```rememberColor```: Whether to remember the last selected color for the slide canvas or the board. + +All of the configurations are optional and the default values shown below are used if the options are not provided. + +```javascript +Reveal.initialize({ + // ... + chalkboard: { + boardmarkerWidth: 3, + chalkWidth: 7, + chalkEffect: 1.0, + storage: null, + src: null, + readOnly: undefined, + transition: 800, + theme: "chalkboard", + background: [ 'rgba(127,127,127,.1)' , path + 'img/blackboard.png' ], + grid: { color: 'rgb(50,50,10,0.5)', distance: 80, width: 2}, + eraser: { src: path + 'img/sponge.png', radius: 20}, + boardmarkers : [ + { color: 'rgba(100,100,100,1)', cursor: 'url(' + path + 'img/boardmarker-black.png), auto'}, + { color: 'rgba(30,144,255, 1)', cursor: 'url(' + path + 'img/boardmarker-blue.png), auto'}, + { color: 'rgba(220,20,60,1)', cursor: 'url(' + path + 'img/boardmarker-red.png), auto'}, + { color: 'rgba(50,205,50,1)', cursor: 'url(' + path + 'img/boardmarker-green.png), auto'}, + { color: 'rgba(255,140,0,1)', cursor: 'url(' + path + 'img/boardmarker-orange.png), auto'}, + { color: 'rgba(150,0,20150,1)', cursor: 'url(' + path + 'img/boardmarker-purple.png), auto'}, + { color: 'rgba(255,220,0,1)', cursor: 'url(' + path + 'img/boardmarker-yellow.png), auto'} + ], + chalks: [ + { color: 'rgba(255,255,255,0.5)', cursor: 'url(' + path + 'img/chalk-white.png), auto'}, + { color: 'rgba(96, 154, 244, 0.5)', cursor: 'url(' + path + 'img/chalk-blue.png), auto'}, + { color: 'rgba(237, 20, 28, 0.5)', cursor: 'url(' + path + 'img/chalk-red.png), auto'}, + { color: 'rgba(20, 237, 28, 0.5)', cursor: 'url(' + path + 'img/chalk-green.png), auto'}, + { color: 'rgba(220, 133, 41, 0.5)', cursor: 'url(' + path + 'img/chalk-orange.png), auto'}, + { color: 'rgba(220,0,220,0.5)', cursor: 'url(' + path + 'img/chalk-purple.png), auto'}, + { color: 'rgba(255,220,0,0.5)', cursor: 'url(' + path + 'img/chalk-yellow.png), auto'} + ] + }, + // ... + +}); +``` + +## Credits + +The chalkboard effect is based on [Chalkboard](https://github.com/mmoustafa/Chalkboard) by Mohamed Moustafa. + +## License + +MIT licensed + +Copyright (C) 2023 Asvin Goel diff --git a/custom_plugins/chalkboard/img/blackboard.png b/custom_plugins/chalkboard/img/blackboard.png new file mode 100644 index 0000000000000000000000000000000000000000..50a2f6435287dec404a8d2107fa21f86ddaf4ba8 GIT binary patch literal 32733 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 a|2XCdq$HyJiB6J$lLNg4H>x#oiTodH$#--B literal 0 HcmV?d00001 diff --git a/custom_plugins/chalkboard/img/boardmarker-black.png b/custom_plugins/chalkboard/img/boardmarker-black.png new file mode 100644 index 0000000000000000000000000000000000000000..170b520061b66e1d24e888836e893e5a865c01bb GIT binary patch literal 2142 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 FV1oGf3+Vs= literal 0 HcmV?d00001 diff --git a/custom_plugins/chalkboard/img/boardmarker-green.png b/custom_plugins/chalkboard/img/boardmarker-green.png new file mode 100644 index 0000000000000000000000000000000000000000..28a42218c9c8deeca5c2155987d12b36339d114b GIT binary patch literal 2106 zcmV-A2*vk_P)CR~gG2T~;n zC2FfwRnsa})kY;%l*?PCK2(X)KJ}sMOW!IbYMVkpn2;|n;jH_zT| zc0IGRvoog;i`!HcDvDs;^EC4`pO^EW?>Vfcr6us=H(vSOTKAd_cfY(dTPPHA_&-{- zy>nCW!^p*hQ}x=LufF;7zbJ}Qx6-JuF6MMrxqG(ypFef&995OV`hDAWZcNU_V%dAy zJ1dO?0G3LnBHw%NJKMwgWZP6BMsBs|J1cXvnkJ1Kd0kgm9BA8i@%-5M$NdKepT1s< z)o~7LZFYKwx}Vq{Z0l;cd1LabWm$z40|Ef&oYgC?^-DF}pEdKWpqXqc7hPN1vu^jk zz|OARz1(6luFk9&(6TID%VeXSHBIh#jp4NfO64jC@vd5nt5&#Up@|(3qxx7rvvjxI zK)U>(s_M1ut;7*uWwQaxMm~|nx%nyb{jOnRnO3#%Lf1Q$_0^sg0|LP0jmgu`c(&c6 z8G}O+kcy`9o4>!0*LHr37@E=I`cdFrL6K@#44BX76H9k8m*gS=3=5DMV#yTVz5NMZ z-TE9BNTF}@i-W&sj7jAJvah}nLL|yb3wKga#?-2z2n3X3KAnP4A>dHY0rL96m%J{A zvuFoV-+S zATpWE9JRrkl={MwZ1xnnExtbZUA(;Qc`(W#%Muu+bocI|Jr^!q_#zw*Pn8u20E>%@ zb5(L>mB-!8p7L$$eAYWe852MW0SDkvWQd|94)5K&fAph|&ZJVQXjy>(_`<@%Ei9Rf zTUxxeO-)T6(<~54l0j){UnzW;T^d6}x-7yD6o$ zj0uDZA_yg5lt2LoJjsf6h1p?rzs!pl%D);;STP&;Slq3;?Ab@i~ z6h#PvKzh2nHz!l6;*~2`&XyYp&bg_o>eNzhNeKpn0ZrE=Symu01`a@$BrwM4jvYI8 z{9|HbZgzI|^RfbgQcy&r(HYKpU9ZpQ(=?4qvJ6HkY;Y)w3?>L{&z{}Gr%#_AOC%DH zBzPYh2mpmbVKE#I->IyuTGiXy}1s;Sgwd2*Nl&kkK${NpRWz%oLj1@-dxBmAP@`&^SY);vP}N9vt@}; zM#;dyKxl4mE;BJPaiOe00I+Sl5R1iTwI$6N>ON?}o7U%zToXGiG7$cgtX%QDLf1WI9{s;b`W^Yxa( zf)PO!K>#quAjuNh(Aw7Gs;+K1bLPzPhZ#SQ6bOJPlga6LJZ^_VeF3v*R*Iqofe8Qs z1VMlx2*l^}b*D2Ke);m{zm*#Z&UsN))tkDmI|6}#U(=Q(S(ZUr=~I#4 z{v8%hr?b)1zOlnF@}++^Eqzicg@v?Z$M)e9Cq6jwps;vsK%f*BsZ=W6(9qD-;BIKO zEenz)6GA9JI2;az)YR0tLZQ&m;loG%SSF@9FyM22uef|3N zi)94@rLc%ZBGa0#IsJja7G2jwNm0P)a{b8Ai+TJxGyde=Nce`OE?qAx5CDqBVlEnu z&MLC9+UxapX_`it&oxttFY(Uj$4PP_L#N&Pej3SrY%dz&vH}6XFpP987MrhjRW~*_ zulE$qBDtvE#7jrs!l~KIIMDS3u?$m*wb6ZKB7L~*Kmf>Qv*CC=zSz>-vhmaTFV?;F z=^x0VWPuw+T+PhkhyJIql-H|0t|q!7KmbUm(=)xjz5N^dHwQkv^a-&E2P!3)IRiOv z;J3qXz)-XED+UC>XJ%$*UVHK7XI!qTn)5fVf(sO(bshLg^FgjJW+#62_S?T)L0@Tg zcX#idoW7a*_OE|xKmCgz*drf|SceY1a@ON%e-;2CD-8sIfq|{xbT}*O`h&skpI!QF k^2X%kSS%Jh&p9vt6PICzSH!DRyZ`_I07*qoM6N<$f(wfA!2kdN literal 0 HcmV?d00001 diff --git a/custom_plugins/chalkboard/img/boardmarker-orange.png b/custom_plugins/chalkboard/img/boardmarker-orange.png new file mode 100644 index 0000000000000000000000000000000000000000..7e8c2d2bb415d576f49c8faea365d8a90f04614f GIT binary patch literal 2240 zcmV;x2tW6UP)ftU@_RnfQ@S~7@LcYjlp1pFExq1IH~R8 z)JdAgk(#QNsx}W%t336gRWEOCrAkp$sfyGpPfah0l2*M1;}{HP7nX~`c){!%_QJBu z?(BVMcjokA?I>-PI!^J@?`>XYemZB)@B4p8*j`!LbpBk=SD9Q;yt3k7;+*UFKPuYW zbG+|L>Ecg*ak>88*MIus-!aC_8x8gG5^C%A9B445Ey2mZ2^}?sdn($_?OY8-Lo0s2 zbEDw^0A{nf>iXMnxPN=GlwW_*#C<=gH)j6yOMhKmUB^bV0f3-sTErPhtbFU4&Wi@#!nZf>n}4PSWWBNHPX<>z5F@`fK5MPkY0yusPv$xyB5`$mRo( ze*D4X@!WFgRAw>A3m#%01%STKm z)0V!zz8AKv-L5oZYeb@eL4i!j0n?5aknN{P$+2h68ezu5!a`70RcBrSbzM)pS5=&S z`8#d;?dyd^OAsaiIuVhn?7*hJ??EUmC9Q`JH7zbKuDRXrKs+Az<_!=4_j1&o{R>3)k$QTF!LI@ODhN37+`;qp8gM&j0kx0ay&1TnKKc9FK)9JJt3Werv zR@*>tZ|^f{EnO%I0ueM1F^GZ)01zb+q99=B&YhKog@q-PQ&a9}H0r`S_U=#RvOplP==FI0r%#_g z7mY>)Cd&{65u9_#G6NxmG&VKXCK8G4y?ggUs;av33J3sBr_;{4A+@$1>W;@_l*tMN zL4aWZCPfAS($>~?U~cZt>eAAZHC|R4NtDDZHmthA)0I;-oDWR}wp07a1@3Zm5A z-PLyE#_+=0+L|Ym$^1|HdE|bo>w0=*c;tgqCr>^_DcwvcA(AM85&}Xf6j?@rsi2^# zv2owkfq}VbG`egUhL$%#07#`$s?BB_vh-Rmrc>!6QIa5vA_#K&kt7La+sZaqS65e$ zjg2j-s_Oi#`uWU>L{(Mq-0ivBXU?3t5Q|2cEXxoC0UUtDBnX6(n(FEu0GPw!2!_Mq zyLkl!0H4q22(ATVCr%uHG8&CirsPgGH#ihU0Rc!$OUu5Mm6f>D>Ga3raZg?W0bt%S zKWZu{C~n^0+?j~Sb0=HOIr4#iy1TksXJ%)8KA+G3sB_JFgidZBw_mH;QPr^Xb5#u) zO(T-TK<{t2$)o@PJ$CHq;Tt!G?*@ZG&!fyW>ynB&=UJ=O+TY&ZcG7G%SLucUNs>S) z1tB^8NTS3#Iyw#x4-YRyA`zdaX`f0z>lWLy*=%C;=4gM<6Fpxr45LI41R{ze2&JHu zK$aOPHk*r@nws_vT)XB_Rn^5gf9PDZu5(2qkqB8wt;3dH%NJA0RDr}8g!{ol5=Drj zNXpC0x0aP{t(cgYaI31ih=&A=bsv1f;jr7e=yaVq`{enE8WEWye+0>x1WGBXudm<5 zITu|nS7>c*?Z4{hu}o&m%gZx~L{jhU>^v2VMX4++pp=4hK$c|?fE+q>uyKBVA?S2E zy~$+KpI1Ntn4O&+E-EZ4YiMX_OC%FS&W#E8^`ihBr2BaH;faY!cQ63&QK`iOQ+NSp`XV(d>e+586C9_ zbRO;OF_}yi03b1z(+>y~Stg1}Q4Sn9(AeMKe>)nDy8r!J<+0xmXqpxs8M%4&si)5M zrPHY*Q51P{0)c?j=%V?$$YG9D#mWn~pJv$NK`0s?^3>71a1O0BJ}$7Asrd7vNgTs!3PAlYaA+5YFh z{?b{;8o4(!Gi%Q)AOJo&IeC4{=FL0n>grmOsU&1sA(RTx7Y89t{SiiRg`{k6(aW!X zzqj8uKbUVo05HbK#|N65n>#jd*;1qHSz?-dAKCX`McQ>8CGF25&cJX~|-< zx$69p-A7_G9||Jp5CtFu4QVJOeg5a$6Nf@qLVKhi45U- zn()YW3&wVR&FKH|!~R>-(*ql}f&ef#H#fe0M^(MB>#$TI8x;;yQ&Q{rhVX}X-uug& zZ~p2>%gf7y8}<)AD8`uS(xpqUd6r#{P&jJT*46D992|Vt@Appt;Qs{h-P4jXxLaKS O0000~$IV8*S3jU9VZi+YO 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 literal 0 HcmV?d00001 diff --git a/custom_plugins/chalkboard/img/boardmarker-yellow.png b/custom_plugins/chalkboard/img/boardmarker-yellow.png new file mode 100644 index 0000000000000000000000000000000000000000..23e87f52e2961d8d6843009de2318156d92c86f4 GIT binary patch literal 2105 zcmV-92*&q`P) zyL51~Gj!xB`wzd}f0lDzzS5=#ila&D+nrmogI z1E+pI-QB(IJA@Fvk~RhaQcC%?XP*C78UMH(G6T!b5wCKt?73$;_S6LSbWBXmrgh!C zV;IKLib+GEV9&*~ucfCi2q*rrCKHz`W$N;moW!Lj=hmm)*6)A!i=&F76uIqU_ZR7O zdNPyqv0Y!lQ%ug2ys->Tk)*inyCjqN8`;uaQs?pQ^`AcTK_39=IuHP2vDujyzPay3 zYFrSU19|H<;KWhpdzoaDZ;{B3mM5o^>z1!v8UDa6AboI?$z)=Oj@>?`>nfxLFha4U zkH9w1psezHxSM#BzWUPoSA`IMw}9+(dncJ(^lqrL+E!QSr9uTH2y|-#8m|Rqdr?yT ztY;}tiv|Y=kHUqk{yY$=^qr9#lVx^C6A71k4NVgimd&8k4iwe=3<~#=a96l>cz8H7 zHa7N=>p&@`oxZIP&m>nBbv9e=9#tv^e+6vSPXWfD2?53!-MxGF&VhjoH{$X5h^s&V za2!WpNIRo>V~syl^Yq4i$qSSzDhMbbB|IJtT;)o4clT5M{rzXN*=)>JAOIMKkr|uR zM{Mur`no_MU^@=soP$sbLI6z&6nnj%)|QqXhkAQ^4a3N|3IqVtG#93)XJ(#Q|3q_n zdHGt#7*SLe1O${(a8*TBRaIpu6zb^h?S02_9NkqQ0OWGHsfqE4Oehp;)ihDTxk?yQ zKnQ`VDnwBf5)1^^sa&l)d-hx}0NYg{0Awu{S3JAc-X0zAhu{hhleOp-9b(ISZOkt2xLem5&r8E+WgolQP zZcR)~eCjq3j^h~f^Yg=ViMfjQ_O=$&G#TdtlrcyNcr*Cexw(>UU0vbhmy{!NXIjizN%Rpp?J0g&)$9>P_w?u|kAD*^9yt(zb0>S}dMp-G!`s4JO~X)y5TLa1W^1AlEOtgB;foh9&P+{B4Y>`3 z<2YtAnY_9%zu;?YZ+p@*O~yqbSU8aIXj%ceGtzVX`00gmiA*+H(E+wfwF4t*Bv|OKt+; zIF6N0r>`bv6Q$v<&NkD~6)rqr^nUu$KxCfuG#~4E`k8%SedpavZ|l0Aa}9V8sn5^P z4_lV)Z*1JyXxS!J3v&_DoIp|jFp+mZp_SebA8Xt8a@&DJAO6)d zej=1bn6?RN{~cw%ALI7Ifb-^`M^CQ^5CE2zmL?&k`1UvaU)Hndi9#K4g<{#x!E$oA zQ}i2h_QJ%a6$1jm^z_W7)&5h0iH$MFIy=~UHcXwFFjvREp|ASXPUbk-D9snv?X&?Z2z23*yRj=+21{>R|s{Fxs j4jlMnI-Pz`N@@KA_3U%TKl-+c00000NkvXXu0mjf*%$6m literal 0 HcmV?d00001 diff --git a/custom_plugins/chalkboard/img/chalk-blue.png b/custom_plugins/chalkboard/img/chalk-blue.png new file mode 100644 index 0000000000000000000000000000000000000000..f70c2991ee48c22d5e65b64f9799686ae6c33a6e GIT binary patch literal 5150 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 M07*qoM6N<$f;c6y;{X5v literal 0 HcmV?d00001 diff --git a/custom_plugins/chalkboard/img/chalk-green.png b/custom_plugins/chalkboard/img/chalk-green.png new file mode 100644 index 0000000000000000000000000000000000000000..39f3b20fc7fb1755496e83b7ce85620d99326743 GIT binary patch literal 4801 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 literal 0 HcmV?d00001 diff --git a/custom_plugins/chalkboard/img/chalk-purple.png b/custom_plugins/chalkboard/img/chalk-purple.png new file mode 100644 index 0000000000000000000000000000000000000000..5bd29fb85484cddbe9bcc71a87f7b9a8b243b9b8 GIT binary patch literal 5250 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 IM6N<$f^h91asU7T literal 0 HcmV?d00001 diff --git a/custom_plugins/chalkboard/img/chalk-red.png b/custom_plugins/chalkboard/img/chalk-red.png new file mode 100644 index 0000000000000000000000000000000000000000..18d4dc7893adb93ee7feb3beb066d63de403e3f1 GIT binary patch literal 4786 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 i(I@&upXd|)|McHWtasDPViX|&0000d zv|$3j{vg0Z0;g~!113zO$z#clLX(DR_4)Fl4CdblOn@+(Y!DU?2+%ZO<(K9UfF=Ob z1Yj9Z!z5q;fYoYp{sQ?M`Ab8#Eg5W?co$6*by_?^*SD7dxEe6nJ?2(-KB@0vC!5C8#hw+(|rn|U7CP?%L_@IcoIlCCTO^73dHEcEZUN^QHbFFCF5D~Gpn=n3Gw+Nxq&}UqNjCP| zDgo|%Jwvbx04U*L4liX{Wy4r(8}t8!VLOK-=RVI1u*r6Vw)%8igq0)S_k9ETm;B?0 z!6X;FzpD(-HHVEi*uS-0@*8HU4d;-pGD-R*_?bn|RVPspO;lkn)8am+dm?8-!Gdeq zAe2vrSI(Z>1Xo$gdteTAGxvuukY7pg{F5kxB&-6-xy@~M-Y)EfKIWJ}ZD1E{dfkAU z*nrMMG7X3%*=*Y+0iK52`s+`w#0?wRgnw_ZIyCtDT7W!vPOUHQ`~c^hK%P)6!imE@ zPX+*0LPJ33>${&QHkTK4Hwl^KF~CAM%W_i$78B);4Z6{toWQr3|2e0H@C0=9a|`pS z02^&!$&`JVv$9Q4jfSzFYyz}RA2#y}8W!>qI+-S)y+Hmcn(u$K+B6fVY~s6N2n|vI zasVK*76HP37<pB=>xg4V>Ik zO~N8hZk8rH69nX@6Nq6`c>zMwI{|?pl8OvdXyj;O$~FMtf>Wp@W`Zlvk)59o^8TZ_ zf`rY5Tbt(OI(2L3I#Q==HDM*?Ch`O5*3>I+|52$ad`meSI9$aPLIz=hoafj!<;iPP z2~By>uWMKnJ=LEB>efM4Q$@Br4ulj|D1XcppUWqRuiU8_Q|`HWh@gV z(y6k6?nHb-K7HUr-CsP{`a!3nPU$~IhVFoCl{`WWVM(zK-KTHj-3kZu%EoWu{B zQVL@k^tnNNF0K+}a{#PmxSO16g!G|EqFX|5y3ebUWbC)uop-6F1Z;JaRH2n>mWJ6- zA}@#rkJ`w&1q)hzlrktEl`W7)&o^(-61t7~{yZt9VOu^=SCX<1wo(<+H24Wa2frg&yFdZTA`)ke&-^&1-WOFZ=Xj(b_vSol< zGABjeE_+kc7AJ?(vL}q^(MHRY2e3FjXymfKs2fU}`#TsL-sr0u#LQ z%{*nx{C3jk&Z!7+&gFsmlA?k=Ck!AY4iU%e-Kn#BfCAjHxV*;C=Wzo+ub)g(adPNF); zq?rnTgPk%SYdsCg0@$5cE8Y{BTQJS&bR8Q{fub8Wr`GQaFZh;vbGk&5og;MIPh`=A z6LBygz@$*h`*_N=ce4)(dD1=lwEzi);vgQKDmrkHZw(3w-DeuVL}7hRjS&1Rm!$)V z)Dp=ij6-=~HSOVYvuGgt%I4+@;ua$yT15g^@4qriZixOD`43jo`6 zi$+^M^9xNZPGt@QeD$Ce(^}FjG>tCtWi*qWj?@?LmL15PeNh3-m-a#7P0;&ACcqA4 z#HKw_Hs`+q_JWU{8PW_5AYbbDnR|Kmc6a zN0_^uwu;>Yr`wj8snvWM3upmubb@W_+ujCo46F-x0u(8BFf`-{D1q=cLzC^C%i!Wk z=IQO4oJtOAJktTA1)(QA<4%0A83m^ns0fE=Bqmj9iwmdO|9 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 literal 0 HcmV?d00001 diff --git a/custom_plugins/chalkboard/plugin.js b/custom_plugins/chalkboard/plugin.js new file mode 100644 index 0000000..2672110 --- /dev/null +++ b/custom_plugins/chalkboard/plugin.js @@ -0,0 +1,1973 @@ +/***************************************************************** + ** Author: Asvin Goel, goel@telematique.eu + ** + ** A plugin for reveal.js adding a chalkboard. + ** + ** Version: 2.3.3 + ** + ** License: MIT license (see LICENSE.md) + ** + ** Credits: + ** Chalkboard effect by Mohamed Moustafa https://github.com/mmoustafa/Chalkboard + ** Multi color support initially added by Kurt Rinnert https://github.com/rinnert + ** Compatibility with reveal.js v4 by Hakim El Hattab https://github.com/hakimel + ******************************************************************/ + +"use strict"; + +window.RevealChalkboard = window.RevealChalkboard || { + id: 'RevealChalkboard', + init: function ( deck ) { + initChalkboard.call(this, deck ); + }, + configure: function ( config ) { + configure( config ); + }, + toggleNotesCanvas: function () { + toggleNotesCanvas(); + }, + toggleChalkboard: function () { + toggleChalkboard(); + }, + colorIndex: function () { + colorIndex(); + }, + colorNext: function () { + colorNext(); + }, + colorPrev: function () { + colorPrev(); + }, + clear: function () { + clear(); + }, + reset: function () { + reset(); + }, + resetAll: function () { + resetAll(); + }, + updateStorage: function () { + updateStorage(); + }, + getData: function () { + return getData(); + }, + download: function () { + download(); + }, +}; + +function scriptPath() { + // obtain plugin path from the script element + var src; + if ( document.currentScript ) { + src = document.currentScript.src; + } else { + var sel = document.querySelector( 'script[src$="/chalkboard/plugin.js"]' ) + if ( sel ) { + src = sel.src; + } + } + var path = ( src === undefined ) ? "" : src.slice( 0, src.lastIndexOf( "/" ) + 1 ); +//console.log("Path: " + path); + return path; +} +var path = scriptPath(); + +const initChalkboard = function ( Reveal ) { +//console.warn(path); + /* Feature detection for passive event handling*/ + var passiveSupported = false; + + try { + window.addEventListener( 'test', null, Object.defineProperty( {}, 'passive', { + get: function () { + passiveSupported = true; + } + } ) ); + } catch ( err ) {} + + +/***************************************************************** + ** Configuration + ******************************************************************/ + var background, pens, draw, color; + var grid = false; + var boardmarkerWidth = 3; + var chalkWidth = 7; + var chalkEffect = 1.0; + var rememberColor = [ true, false ]; + var eraser = { + src: path + 'img/sponge.png', + radius: 20 + }; + var boardmarkers = [ { + color: 'rgba(100,100,100,1)', + cursor: 'url(' + path + 'img/boardmarker-black.png), auto' + }, + { + color: 'rgba(30,144,255, 1)', + cursor: 'url(' + path + 'img/boardmarker-blue.png), auto' + }, + { + color: 'rgba(220,20,60,1)', + cursor: 'url(' + path + 'img/boardmarker-red.png), auto' + }, + { + color: 'rgba(50,205,50,1)', + cursor: 'url(' + path + 'img/boardmarker-green.png), auto' + }, + { + color: 'rgba(255,140,0,1)', + cursor: 'url(' + path + 'img/boardmarker-orange.png), auto' + }, + { + color: 'rgba(150,0,20150,1)', + cursor: 'url(' + path + 'img/boardmarker-purple.png), auto' + }, + { + color: 'rgba(255,220,0,1)', + cursor: 'url(' + path + 'img/boardmarker-yellow.png), auto' + } + ]; + var chalks = [ { + color: 'rgba(255,255,255,0.5)', + cursor: 'url(' + path + 'img/chalk-white.png), auto' + }, + { + color: 'rgba(96, 154, 244, 0.5)', + cursor: 'url(' + path + 'img/chalk-blue.png), auto' + }, + { + color: 'rgba(237, 20, 28, 0.5)', + cursor: 'url(' + path + 'img/chalk-red.png), auto' + }, + { + color: 'rgba(20, 237, 28, 0.5)', + cursor: 'url(' + path + 'img/chalk-green.png), auto' + }, + { + color: 'rgba(220, 133, 41, 0.5)', + cursor: 'url(' + path + 'img/chalk-orange.png), auto' + }, + { + color: 'rgba(220,0,220,0.5)', + cursor: 'url(' + path + 'img/chalk-purple.png), auto' + }, + { + color: 'rgba(255,220,0,0.5)', + cursor: 'url(' + path + 'img/chalk-yellow.png), auto' + } + ]; + + var sponge = { + cursor: 'url(' + path + 'img/sponge.png), auto' + } + + + var keyBindings = { + toggleNotesCanvas: { + keyCode: 67, + key: 'C', + description: 'Toggle notes canvas' + }, + toggleChalkboard: { + keyCode: 66, + key: 'B', + description: 'Toggle chalkboard' + }, + clear: { + keyCode: 46, + key: 'DEL', + description: 'Clear drawings on slide' + }, +/* + reset: { + keyCode: 173, + key: '-', + description: 'Reset drawings on slide' + }, +*/ + resetAll: { + keyCode: 8, + key: 'BACKSPACE', + description: 'Reset all drawings' + }, + colorNext: { + keyCode: 88, + key: 'X', + description: 'Next color' + }, + colorPrev: { + keyCode: 89, + key: 'Y', + description: 'Previous color' + }, + download: { + keyCode: 68, + key: 'D', + description: 'Download drawings' + } + }; + + + var theme = 'chalkboard'; + var color = [ 0, 0 ]; + var toggleChalkboardButton = false; + var toggleNotesButton = false; + var colorButtons = true; + var boardHandle = true; + var transition = 800; + + var readOnly = false; + var messageType = 'broadcast'; + + var config = configure( Reveal.getConfig().chalkboard || {} ); + if ( config.keyBindings ) { + for ( var key in config.keyBindings ) { + keyBindings[ key ] = config.keyBindings[ key ]; + }; + } + + function configure( config ) { + + if ( config.boardmarkerWidth || config.penWidth ) boardmarkerWidth = config.boardmarkerWidth || config.penWidth; + if ( config.chalkWidth ) chalkWidth = config.chalkWidth; + if ( config.chalkEffect ) chalkEffect = config.chalkEffect; + if ( config.rememberColor ) rememberColor = config.rememberColor; + if ( config.eraser ) eraser = config.eraser; + if ( config.boardmarkers ) boardmarkers = config.boardmarkers; + if ( config.chalks ) chalks = config.chalks; + + if ( config.theme ) theme = config.theme; + switch ( theme ) { + case 'whiteboard': + background = [ 'rgba(127,127,127,.1)', path + 'img/whiteboard.png' ]; + draw = [ drawWithBoardmarker, drawWithBoardmarker ]; + pens = [ boardmarkers, boardmarkers ]; + grid = { + color: 'rgb(127,127,255,0.1)', + distance: 40, + width: 2 + }; + break; + case 'chalkboard': + default: + background = [ 'rgba(127,127,127,.1)', path + 'img/blackboard.png' ]; + draw = [ drawWithBoardmarker, drawWithChalk ]; + pens = [ boardmarkers, chalks ]; + grid = { + color: 'rgb(50,50,10,0.5)', + distance: 80, + width: 2 + }; + } + + if ( config.background ) background = config.background; + if ( config.grid != undefined ) grid = config.grid; + + if ( config.toggleChalkboardButton != undefined ) toggleChalkboardButton = config.toggleChalkboardButton; + if ( config.toggleNotesButton != undefined ) toggleNotesButton = config.toggleNotesButton; + if ( config.colorButtons != undefined ) colorButtons = config.colorButtons; + if ( config.boardHandle != undefined ) boardHandle = config.boardHandle; + if ( config.transition ) transition = config.transition; + + if ( config.readOnly != undefined ) readOnly = config.readOnly; + if ( config.messageType ) messageType = config.messageType; + + if ( drawingCanvas && ( config.theme || config.background || config.grid ) ) { + var canvas = document.getElementById( drawingCanvas[ 1 ].id ); + canvas.style.background = 'url("' + background[ 1 ] + '") repeat'; + clearCanvas( 1 ); + drawGrid(); + } + + return config; + } +/***************************************************************** + ** Setup + ******************************************************************/ + + function whenReady( callback ) { + // wait for markdown to be parsed and code to be highlighted + if ( !document.querySelector( 'section[data-markdown]:not([data-markdown-parsed])' ) + && !document.querySelector( '[data-load]:not([data-loaded])') + && !document.querySelector( 'code[data-line-numbers*="|"]') + ) { + callback(); + } else { + console.log( "Wait for external sources to be loaded and code to be highlighted" ); + setTimeout( whenReady, 500, callback ) + } + } + + function whenLoaded( callback ) { + // wait for drawings to be loaded and markdown to be parsed + if ( loaded !== null ) { + callback(); + } else { + console.log( "Wait for drawings to be loaded" ); + setTimeout( whenLoaded, 500, callback ) + } + } + + var drawingCanvas = [ { + id: 'notescanvas' + }, { + id: 'chalkboard' + } ]; + setupDrawingCanvas( 0 ); + setupDrawingCanvas( 1 ); + + var mode = 0; // 0: notes canvas, 1: chalkboard + var board = 0; // board index (only for chalkboard) + + var mouseX = 0; + var mouseY = 0; + var lastX = null; + var lastY = null; + + var drawing = false; + var erasing = false; + + var slideStart = Date.now(); + var slideIndices = { + h: 0, + v: 0 + }; + + var timeouts = [ + [], + [] + ]; + var slidechangeTimeout = null; + var updateStorageTimeout = null; + var playback = false; + + function changeCursor( element, tool ) { + element.style.cursor = tool.cursor; + var palette = document.querySelector('.palette[data-mode="' + mode + '"]'); + if ( palette ) { + palette.style.cursor = tool.cursor; + } + } + + function createPalette( colors, length ) { + if ( length === true || length > colors.length ) { + length = colors.length; + } + var palette = document.createElement( 'div' ); + palette.classList.add( 'palette' ); + var list = document.createElement( 'ul' ); + // color pickers + for ( var i = 0; i < length; i++ ) { + var colorButton = document.createElement( 'li' ); + colorButton.setAttribute( 'data-color', i ); + colorButton.innerHTML = ''; + colorButton.style.color = colors[ i ].color; + colorButton.addEventListener( 'click', function ( e ) { + var element = e.target; + while ( !element.hasAttribute( 'data-color' ) ) { + element = element.parentElement; + } + colorIndex( parseInt( element.getAttribute( 'data-color' ) ) ); + } ); + colorButton.addEventListener( 'touchstart', function ( e ) { + var element = e.target; + while ( !element.hasAttribute( 'data-color' ) ) { + element = element.parentElement; + } + colorIndex( parseInt( element.getAttribute( 'data-color' ) ) ); + } ); + list.appendChild( colorButton ); + } + // eraser + var eraserButton = document.createElement( 'li' ); + eraserButton.setAttribute( 'data-eraser', 'true' ); + var spongeImg = document.createElement( 'img' ); + spongeImg.src = eraser.src; + spongeImg.height = "24"; + spongeImg.width = "24"; + spongeImg.style.marginTop = '10px'; + spongeImg.style.marginRight = '0'; + spongeImg.style.marginBottom = '0'; + spongeImg.style.marginLeft = '0'; + eraserButton.appendChild(spongeImg); + eraserButton.addEventListener( 'click', function ( e ) { + colorIndex( -1 ); + } ); + eraserButton.addEventListener( 'touchstart', function ( e ) { + colorIndex( -1 ); + } ); + list.appendChild( eraserButton ); + + palette.appendChild( list ); + return palette; + }; + + function switchBoard( boardIdx ) { + selectBoard( boardIdx, true ); + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'selectboard', + timestamp: Date.now() - slideStart, + mode, + board + }; + document.dispatchEvent( message ); + } + + function setupDrawingCanvas( id ) { + var container = document.createElement( 'div' ); + container.id = drawingCanvas[ id ].id; + container.classList.add( 'overlay' ); + container.setAttribute( 'data-prevent-swipe', 'true' ); + container.oncontextmenu = function () { + return false; + } + + changeCursor( container, pens[ id ][ color[ id ] ] ); + + drawingCanvas[ id ].width = window.innerWidth; + drawingCanvas[ id ].height = window.innerHeight; + drawingCanvas[ id ].scale = 1; + drawingCanvas[ id ].xOffset = 0; + drawingCanvas[ id ].yOffset = 0; + + if ( id == "0" ) { + container.style.background = 'rgba(0,0,0,0)'; + container.style.zIndex = 24; + container.style.opacity = 1; + container.style.visibility = 'visible'; + container.style.pointerEvents = 'none'; + + var slides = document.querySelector( '.slides' ); + var aspectRatio = Reveal.getConfig().width / Reveal.getConfig().height; + if ( drawingCanvas[ id ].width > drawingCanvas[ id ].height * aspectRatio ) { + drawingCanvas[ id ].xOffset = ( drawingCanvas[ id ].width - drawingCanvas[ id ].height * aspectRatio ) / 2; + } else if ( drawingCanvas[ id ].height > drawingCanvas[ id ].width / aspectRatio ) { + drawingCanvas[ id ].yOffset = ( drawingCanvas[ id ].height - drawingCanvas[ id ].width / aspectRatio ) / 2; + } + + if ( colorButtons ) { + var palette = createPalette( boardmarkers, colorButtons ); + palette.dataset.mode = id; + palette.style.visibility = 'hidden'; // only show palette in drawing mode + container.appendChild( palette ); + } + } else { + container.style.background = 'url("' + background[ id ] + '") repeat'; + container.style.zIndex = 26; + container.style.opacity = 0; + container.style.visibility = 'hidden'; + + if ( colorButtons ) { + var palette = createPalette( chalks, colorButtons ); + palette.dataset.mode = id; + container.appendChild( palette ); + } + if ( boardHandle ) { + var handle = document.createElement( 'div' ); + handle.classList.add( 'boardhandle' ); + handle.innerHTML = '
'; + handle.querySelector( '#previousboard' ).addEventListener( 'click', function ( e ) { + e.preventDefault(); + switchBoard( board - 1 ); + } ); + handle.querySelector( '#nextboard' ).addEventListener( 'click', function ( e ) { + e.preventDefault(); + switchBoard( board + 1 ); + } ); + handle.querySelector( '#previousboard' ).addEventListener( 'touchstart', function ( e ) { + e.preventDefault(); + switchBoard( board - 1 ); + } ); + handle.querySelector( '#nextboard' ).addEventListener( 'touchstart', function ( e ) { + e.preventDefault(); + switchBoard( board + 1 ); + } ); + + container.appendChild( handle ); + } + } + + var canvas = document.createElement( 'canvas' ); + canvas.width = drawingCanvas[ id ].width; + canvas.height = drawingCanvas[ id ].height; + canvas.setAttribute( 'data-chalkboard', id ); + changeCursor( canvas, pens[ id ][ color[ id ] ] ); + container.appendChild( canvas ); + drawingCanvas[ id ].canvas = canvas; + + drawingCanvas[ id ].context = canvas.getContext( '2d' ); + + setupCanvasEvents( container ); + + document.querySelector( '.reveal' ).appendChild( container ); + drawingCanvas[ id ].container = container; + } + + +/***************************************************************** + ** Storage + ******************************************************************/ + + var storage = [ { + width: Reveal.getConfig().width, + height: Reveal.getConfig().height, + data: [] + }, + { + width: Reveal.getConfig().width, + height: Reveal.getConfig().height, + data: [] + } + ]; + + var loaded = null; + + if ( config.storage ) { + // Get chalkboard drawings from session storage + loaded = initStorage( sessionStorage.getItem( config.storage ) ); + } + + if ( !loaded && config.src != null ) { + // Get chalkboard drawings from the given file + loadData( config.src ); + } + + /** + * Initialize storage. + */ + function initStorage( json ) { + var success = false; + try { + var data = JSON.parse( json ); + for ( var id = 0; id < data.length; id++ ) { + if ( drawingCanvas[ id ].width != data[ id ].width || drawingCanvas[ id ].height != data[ id ].height ) { + drawingCanvas[ id ].scale = Math.min( drawingCanvas[ id ].width / data[ id ].width, drawingCanvas[ id ].height / data[ id ].height ); + drawingCanvas[ id ].xOffset = ( drawingCanvas[ id ].width - data[ id ].width * drawingCanvas[ id ].scale ) / 2; + drawingCanvas[ id ].yOffset = ( drawingCanvas[ id ].height - data[ id ].height * drawingCanvas[ id ].scale ) / 2; + } + if ( config.readOnly ) { + drawingCanvas[ id ].container.style.cursor = 'default'; + drawingCanvas[ id ].canvas.style.cursor = 'default'; + } + } + success = true; + storage = data; + } catch ( err ) { + console.warn( "Cannot initialise storage!" ); + } + return success; + } + + + /** + * Load data. + */ + function loadData( filename ) { + var xhr = new XMLHttpRequest(); + xhr.onload = function () { + if ( xhr.readyState === 4 && xhr.status != 404 ) { + loaded = initStorage( xhr.responseText ); + updateStorage(); + console.log( "Drawings loaded from file" ); + } else { + config.readOnly = undefined; + readOnly = undefined; + console.warn( 'Failed to get file ' + filename + '. ReadyState: ' + xhr.readyState + ', Status: ' + xhr.status ); + loaded = false; + } + }; + + xhr.open( 'GET', filename, true ); + try { + xhr.send(); + } catch ( error ) { + config.readOnly = undefined; + readOnly = undefined; + console.warn( 'Failed to get file ' + filename + '. Make sure that the presentation and the file are served by a HTTP server and the file can be found there. ' + error ); + loaded = false; + } + } + + + function storageChanged( now ) { + if ( !now ) { + // create or update timer + if ( updateStorageTimeout ) { + clearTimeout( updateStorageTimeout ); + } + updateStorageTimeout = setTimeout( storageChanged, 1000, true); + } + else { +// console.log("Update storage", updateStorageTimeout, Date.now()); + updateStorage(); + updateStorageTimeout = null; + } + } + + function updateStorage() { + var json = JSON.stringify( storage ) + if ( config.storage ) { + sessionStorage.setItem( config.storage, json ) + } + return json; + } + + function recordEvent( event ) { +//console.log(event); + event.time = Date.now() - slideStart; + if ( mode == 1 ) event.board = board; + var slideData = getSlideData(); + var i = slideData.events.length; + while ( i > 0 && event.time < slideData.events[ i - 1 ].time ) { + i--; + } + slideData.events.splice( i, 0, event ); + slideData.duration = Math.max( slideData.duration, Date.now() - slideStart ) + 1; + + storageChanged(); + } + + /** + * Get data as json string. + */ + function getData() { + // cleanup slide data without events + for ( var id = 0; id < 2; id++ ) { + for ( var i = storage[ id ].data.length - 1; i >= 0; i-- ) { + if ( storage[ id ].data[ i ].events.length == 0 ) { + storage[ id ].data.splice( i, 1 ); + } + } + } + + return updateStorage(); + } + + /** + * Download data. + */ + function downloadData() { + var a = document.createElement( 'a' ); + document.body.appendChild( a ); + try { + a.download = 'chalkboard.json'; + var blob = new Blob( [ getData() ], { + type: 'application/json' + } ); + a.href = window.URL.createObjectURL( blob ); + } catch ( error ) { + // https://stackoverflow.com/a/6234804 + // escape data for proper handling of quotes and line breaks + // in case malicious user gets a chance to craft the exception message + error = String(error) + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); + a.innerHTML += ' (' + error + ')'; + } + a.click(); + document.body.removeChild( a ); + } + + /** + * Returns data object for the slide with the given indices. + */ + function getSlideData( indices, id ) { + if ( id == undefined ) id = mode; + if ( !indices ) indices = slideIndices; + var data; + for ( var i = 0; i < storage[ id ].data.length; i++ ) { + if ( storage[ id ].data[ i ].slide.h === indices.h && storage[ id ].data[ i ].slide.v === indices.v && storage[ id ].data[ i ].slide.f === indices.f ) { + data = storage[ id ].data[ i ]; + return data; + } + } + var page = Number( Reveal.getCurrentSlide().getAttribute('data-pdf-page-number') ); +//console.log( indices, Reveal.getCurrentSlide() ); + storage[ id ].data.push( { + slide: indices, + page, + events: [], + duration: 0 + } ); + data = storage[ id ].data[ storage[ id ].data.length - 1 ]; + return data; + } + + /** + * Returns maximum duration of slide playback for both modes + */ + function getSlideDuration( indices ) { + if ( !indices ) indices = slideIndices; + var duration = 0; + for ( var id = 0; id < 2; id++ ) { + for ( var i = 0; i < storage[ id ].data.length; i++ ) { + if ( storage[ id ].data[ i ].slide.h === indices.h && storage[ id ].data[ i ].slide.v === indices.v && storage[ id ].data[ i ].slide.f === indices.f ) { + duration = Math.max( duration, storage[ id ].data[ i ].duration ); + break; + } + } + } +//console.log( duration ); + return duration; + } + +/***************************************************************** + ** Print + ******************************************************************/ + var printMode = ( /print-pdf/gi ).test( window.location.search ); +//console.log("createPrintout" + printMode) + + function addPageNumbers() { + // determine page number for printouts with fragments serialised + var slides = Reveal.getSlides(); + var page = 0; + for ( var i=0; i < slides.length; i++) { + slides[i].setAttribute('data-pdf-page-number',page.toString()); + // add number of fragments without fragment indices + var count = slides[i].querySelectorAll('.fragment:not([data-fragment-index])').length; + var fragments = slides[i].querySelectorAll('.fragment[data-fragment-index]'); + for ( var j=0; j < fragments.length; j++) { + // increasenumber of fragments by highest fragment index (which start at 0) + if ( Number(fragments[j].getAttribute('data-fragment-index')) + 1 > count ) { + count = Number(fragments[j].getAttribute('data-fragment-index')) + 1; + } + } + page += count + 1; + } + } + + function createPrintout() { + //console.warn(Reveal.getTotalSlides(),Reveal.getSlidesElement()); + if ( storage[ 1 ].data.length == 0 ) return; + console.log( 'Create printout(s) for ' + storage[ 1 ].data.length + " slides" ); + drawingCanvas[ 0 ].container.style.opacity = 0; // do not print notes canvas + drawingCanvas[ 0 ].container.style.visibility = 'hidden'; + + var patImg = new Image(); + patImg.onload = function () { + var slides = Reveal.getSlides(); +//console.log(slides); + for ( var i = storage[ 1 ].data.length - 1; i >= 0; i-- ) { + console.log( 'Create printout for slide ' + storage[ 1 ].data[ i ].slide.h + '.' + storage[ 1 ].data[ i ].slide.v ); + var slideData = getSlideData( storage[ 1 ].data[ i ].slide, 1 ); + var drawings = createDrawings( slideData, patImg ); + addDrawings( slides[storage[ 1 ].data[ i ].page], drawings ); + + } +// Reveal.sync(); + }; + patImg.src = background[ 1 ]; + } + + + function cloneCanvas( oldCanvas ) { + //create a new canvas + var newCanvas = document.createElement( 'canvas' ); + var context = newCanvas.getContext( '2d' ); + //set dimensions + newCanvas.width = oldCanvas.width; + newCanvas.height = oldCanvas.height; + //apply the old canvas to the new one + context.drawImage( oldCanvas, 0, 0 ); + //return the new canvas + return newCanvas; + } + + function getCanvas( template, container, board ) { + var idx = container.findIndex( element => element.board === board ); + if ( idx === -1 ) { + var canvas = cloneCanvas( template ); + if ( !container.length ) { + idx = 0; + container.push( { + board, + canvas + } ); + } else if ( board < container[ 0 ].board ) { + idx = 0; + container.unshift( { + board, + canvas + } ); + } else if ( board > container[ container.length - 1 ].board ) { + idx = container.length; + container.push( { + board, + canvas + } ); + } + } + + return container[ idx ].canvas; + } + + function createDrawings( slideData, patImg ) { + var width = Reveal.getConfig().width; + var height = Reveal.getConfig().height; + var scale = 1; + var xOffset = 0; + var yOffset = 0; + if ( width != storage[ 1 ].width || height != storage[ 1 ].height ) { + scale = Math.min( width / storage[ 1 ].width, height / storage[ 1 ].height ); + xOffset = ( width - storage[ 1 ].width * scale ) / 2; + yOffset = ( height - storage[ 1 ].height * scale ) / 2; + } + mode = 1; + board = 0; +// console.log( 'Create printout(s) for slide ', slideData ); + + var drawings = []; + var template = document.createElement( 'canvas' ); + template.width = width; + template.height = height; + + var imgCtx = template.getContext( '2d' ); + imgCtx.fillStyle = imgCtx.createPattern( patImg, 'repeat' ); + imgCtx.rect( 0, 0, width, height ); + imgCtx.fill(); + + for ( var j = 0; j < slideData.events.length; j++ ) { + switch ( slideData.events[ j ].type ) { + case 'draw': + draw[ 1 ]( getCanvas( template, drawings, board ).getContext( '2d' ), + xOffset + slideData.events[ j ].x1 * scale, + yOffset + slideData.events[ j ].y1 * scale, + xOffset + slideData.events[ j ].x2 * scale, + yOffset + slideData.events[ j ].y2 * scale, + yOffset + slideData.events[ j ].color + ); + break; + case 'erase': + eraseWithSponge( getCanvas( template, drawings, board ).getContext( '2d' ), + xOffset + slideData.events[ j ].x * scale, + yOffset + slideData.events[ j ].y * scale + ); + break; + case 'selectboard': + selectBoard( slideData.events[ j ].board ); + break; + case 'clear': + getCanvas( template, drawings, board ).getContext( '2d' ).clearRect( 0, 0, width, height ); + getCanvas( template, drawings, board ).getContext( '2d' ).fill(); + break; + default: + break; + } + } + + drawings = drawings.sort( ( a, b ) => a.board > b.board && 1 || -1 ); + + mode = 0; + + return drawings; + } + + function addDrawings( slide, drawings ) { + var parent = slide.parentElement.parentElement; + var nextSlide = slide.parentElement.nextElementSibling; + + for ( var i = 0; i < drawings.length; i++ ) { + var newPDFPage = document.createElement( 'div' ); + newPDFPage.classList.add( 'pdf-page' ); + newPDFPage.style.height = Reveal.getConfig().height; + newPDFPage.append( drawings[ i ].canvas ); +//console.log("Add drawing", newPDFPage); + if ( nextSlide != null ) { + parent.insertBefore( newPDFPage, nextSlide ); + } else { + parent.append( newPDFPage ); + } + } + } + + /***************************************************************** + ** Drawings + ******************************************************************/ + + function drawWithBoardmarker( context, fromX, fromY, toX, toY, colorIdx ) { + if ( colorIdx == undefined ) colorIdx = color[ mode ]; + context.lineWidth = boardmarkerWidth; + context.lineCap = 'round'; + context.strokeStyle = boardmarkers[ colorIdx ].color; + context.beginPath(); + context.moveTo( fromX, fromY ); + context.lineTo( toX, toY ); + context.stroke(); + } + + function drawWithChalk( context, fromX, fromY, toX, toY, colorIdx ) { + if ( colorIdx == undefined ) colorIdx = color[ mode ]; + var brushDiameter = chalkWidth; + context.lineWidth = brushDiameter; + context.lineCap = 'round'; + context.fillStyle = chalks[ colorIdx ].color; // 'rgba(255,255,255,0.5)'; + context.strokeStyle = chalks[ colorIdx ].color; + + var opacity = 1.0; + context.strokeStyle = context.strokeStyle.replace( /[\d\.]+\)$/g, opacity + ')' ); + context.beginPath(); + context.moveTo( fromX, fromY ); + context.lineTo( toX, toY ); + context.stroke(); + // Chalk Effect + var length = Math.round( Math.sqrt( Math.pow( toX - fromX, 2 ) + Math.pow( toY - fromY, 2 ) ) / ( 5 / brushDiameter ) ); + var xUnit = ( toX - fromX ) / length; + var yUnit = ( toY - fromY ) / length; + for ( var i = 0; i < length; i++ ) { + if ( chalkEffect > ( Math.random() * 0.9 ) ) { + var xCurrent = fromX + ( i * xUnit ); + var yCurrent = fromY + ( i * yUnit ); + var xRandom = xCurrent + ( Math.random() - 0.5 ) * brushDiameter * 1.2; + var yRandom = yCurrent + ( Math.random() - 0.5 ) * brushDiameter * 1.2; + context.clearRect( xRandom, yRandom, Math.random() * 2 + 2, Math.random() + 1 ); + } + } + } + + function eraseWithSponge( context, x, y ) { + context.save(); + context.beginPath(); + context.arc( x + eraser.radius, y + eraser.radius, eraser.radius, 0, 2 * Math.PI, false ); + context.clip(); + context.clearRect( x - 1, y - 1, eraser.radius * 2 + 2, eraser.radius * 2 + 2 ); + context.restore(); + if ( mode == 1 && grid ) { + redrawGrid( x + eraser.radius, y + eraser.radius, eraser.radius ); + } + } + + + /** + * Show an overlay for the chalkboard. + */ + function showChalkboard() { +//console.log("showChalkboard"); + drawingCanvas[ 1 ].container.style.opacity = 1; + drawingCanvas[ 1 ].container.style.visibility = 'visible'; + mode = 1; + } + + + /** + * Closes open chalkboard. + */ + function closeChalkboard() { + drawingCanvas[ 1 ].container.style.opacity = 0; + drawingCanvas[ 1 ].container.style.visibility = 'hidden'; + lastX = null; + lastY = null; + mode = 0; + } + + /** + * Clear current canvas. + */ + function clearCanvas( id ) { + if ( id == 0 ) clearTimeout( slidechangeTimeout ); + drawingCanvas[ id ].context.clearRect( 0, 0, drawingCanvas[ id ].width, drawingCanvas[ id ].height ); + if ( id == 1 && grid ) drawGrid(); + } + + /** + * Draw grid on background + */ + function drawGrid() { + var context = drawingCanvas[ 1 ].context; + + drawingCanvas[ 1 ].scale = Math.min( drawingCanvas[ 1 ].width / storage[ 1 ].width, drawingCanvas[ 1 ].height / storage[ 1 ].height ); + drawingCanvas[ 1 ].xOffset = ( drawingCanvas[ 1 ].width - storage[ 1 ].width * drawingCanvas[ 1 ].scale ) / 2; + drawingCanvas[ 1 ].yOffset = ( drawingCanvas[ 1 ].height - storage[ 1 ].height * drawingCanvas[ 1 ].scale ) / 2; + + var scale = drawingCanvas[ 1 ].scale; + var xOffset = drawingCanvas[ 1 ].xOffset; + var yOffset = drawingCanvas[ 1 ].yOffset; + + var distance = grid.distance * scale; + + var fromX = drawingCanvas[ 1 ].width / 2 - distance / 2 - Math.floor( ( drawingCanvas[ 1 ].width - distance ) / 2 / distance ) * distance; + for ( var x = fromX; x < drawingCanvas[ 1 ].width; x += distance ) { + context.beginPath(); + context.lineWidth = grid.width * scale; + context.lineCap = 'round'; + context.fillStyle = grid.color; + context.strokeStyle = grid.color; + context.moveTo( x, 0 ); + context.lineTo( x, drawingCanvas[ 1 ].height ); + context.stroke(); + } + var fromY = drawingCanvas[ 1 ].height / 2 - distance / 2 - Math.floor( ( drawingCanvas[ 1 ].height - distance ) / 2 / distance ) * distance; + + for ( var y = fromY; y < drawingCanvas[ 1 ].height; y += distance ) { + context.beginPath(); + context.lineWidth = grid.width * scale; + context.lineCap = 'round'; + context.fillStyle = grid.color; + context.strokeStyle = grid.color; + context.moveTo( 0, y ); + context.lineTo( drawingCanvas[ 1 ].width, y ); + context.stroke(); + } + } + + function redrawGrid( centerX, centerY, diameter ) { + var context = drawingCanvas[ 1 ].context; + + drawingCanvas[ 1 ].scale = Math.min( drawingCanvas[ 1 ].width / storage[ 1 ].width, drawingCanvas[ 1 ].height / storage[ 1 ].height ); + drawingCanvas[ 1 ].xOffset = ( drawingCanvas[ 1 ].width - storage[ 1 ].width * drawingCanvas[ 1 ].scale ) / 2; + drawingCanvas[ 1 ].yOffset = ( drawingCanvas[ 1 ].height - storage[ 1 ].height * drawingCanvas[ 1 ].scale ) / 2; + + var scale = drawingCanvas[ 1 ].scale; + var xOffset = drawingCanvas[ 1 ].xOffset; + var yOffset = drawingCanvas[ 1 ].yOffset; + + var distance = grid.distance * scale; + + var fromX = drawingCanvas[ 1 ].width / 2 - distance / 2 - Math.floor( ( drawingCanvas[ 1 ].width - distance ) / 2 / distance ) * distance; + + for ( var x = fromX + distance * Math.ceil( ( centerX - diameter - fromX ) / distance ); x <= fromX + distance * Math.floor( ( centerX + diameter - fromX ) / distance ); x += distance ) { + context.beginPath(); + context.lineWidth = grid.width * scale; + context.lineCap = 'round'; + context.fillStyle = grid.color; + context.strokeStyle = grid.color; + context.moveTo( x, centerY - Math.sqrt( diameter * diameter - ( centerX - x ) * ( centerX - x ) ) ); + context.lineTo( x, centerY + Math.sqrt( diameter * diameter - ( centerX - x ) * ( centerX - x ) ) ); + context.stroke(); + } + var fromY = drawingCanvas[ 1 ].height / 2 - distance / 2 - Math.floor( ( drawingCanvas[ 1 ].height - distance ) / 2 / distance ) * distance; + for ( var y = fromY + distance * Math.ceil( ( centerY - diameter - fromY ) / distance ); y <= fromY + distance * Math.floor( ( centerY + diameter - fromY ) / distance ); y += distance ) { + context.beginPath(); + context.lineWidth = grid.width * scale; + context.lineCap = 'round'; + context.fillStyle = grid.color; + context.strokeStyle = grid.color; + context.moveTo( centerX - Math.sqrt( diameter * diameter - ( centerY - y ) * ( centerY - y ) ), y ); + context.lineTo( centerX + Math.sqrt( diameter * diameter - ( centerY - y ) * ( centerY - y ) ), y ); + context.stroke(); + } + } + + /** + * Set the color + */ + function setColor( index, record ) { + // protect against out of bounds (this could happen when + // replaying events recorded with different color settings). + if ( index >= pens[ mode ].length ) index = 0; + + color[ mode ] = index; + + if ( color[ mode ] < 0 ) { + // use eraser + changeCursor( drawingCanvas[ mode ].canvas, sponge ); + } + else { + changeCursor( drawingCanvas[ mode ].canvas, pens[ mode ][ color[ mode ] ] ); + } + } + + /** + * Set the board + */ + function selectBoard( boardIdx, record ) { +//console.log("Set board",boardIdx); + if ( board == boardIdx ) return; + + board = boardIdx; + redrawChalkboard( boardIdx ); + if ( record ) { + recordEvent( { type: 'selectboard' } ); + } + } + + function redrawChalkboard( boardIdx ) { + clearCanvas( 1 ); + var slideData = getSlideData( slideIndices, 1 ); + var index = 0; + var play = ( boardIdx == 0 ); + while ( index < slideData.events.length && slideData.events[ index ].time < Date.now() - slideStart ) { + if ( boardIdx == slideData.events[ index ].board ) { + playEvent( 1, slideData.events[ index ], Date.now() - slideStart ); + } + + index++; + } + } + + + /** + * Forward cycle color + */ + function cycleColorNext() { + color[ mode ] = ( color[ mode ] + 1 ) % pens[ mode ].length; + return color[ mode ]; + } + + /** + * Backward cycle color + */ + function cycleColorPrev() { + color[ mode ] = ( color[ mode ] + ( pens[ mode ].length - 1 ) ) % pens[ mode ].length; + return color[ mode ]; + } + +/***************************************************************** + ** Broadcast + ******************************************************************/ + + var eventQueue = []; + + document.addEventListener( 'received', function ( message ) { + if ( message.content && message.content.sender == 'chalkboard-plugin' ) { + // add message to queue + eventQueue.push( message ); + console.log( JSON.stringify( message ) ); + } + if ( eventQueue.length == 1 ) processQueue(); + } ); + + function processQueue() { + // take first message from queue + var message = eventQueue.shift(); + + // synchronize time with seminar host + slideStart = Date.now() - message.content.timestamp; + // set status + if ( mode < message.content.mode ) { + // open chalkboard + showChalkboard(); + } else if ( mode > message.content.mode ) { + // close chalkboard + closeChalkboard(); + } + if ( board != message.content.board ) { + board = message.content.board; + redrawChalkboard( board ); + }; + + switch ( message.content.type ) { + case 'showChalkboard': + showChalkboard(); + break; + case 'closeChalkboard': + closeChalkboard(); + break; + case 'erase': + erasePoint( message.content.x, message.content.y ); + break; + case 'draw': + drawSegment( message.content.fromX, message.content.fromY, message.content.toX, message.content.toY, message.content.color ); + break; + case 'clear': + clearSlide(); + break; + case 'selectboard': + selectBoard( message.content.board, true ); + break; + case 'resetSlide': + resetSlideDrawings(); + break; + case 'init': + storage = message.content.storage; + for ( var id = 0; id < 2; id++ ) { + drawingCanvas[ id ].scale = Math.min( drawingCanvas[ id ].width / storage[ id ].width, drawingCanvas[ id ].height / storage[ id ].height ); + drawingCanvas[ id ].xOffset = ( drawingCanvas[ id ].width - storage[ id ].width * drawingCanvas[ id ].scale ) / 2; + drawingCanvas[ id ].yOffset = ( drawingCanvas[ id ].height - storage[ id ].height * drawingCanvas[ id ].scale ) / 2; + } + clearCanvas( 0 ); + clearCanvas( 1 ); + if ( !playback ) { + slidechangeTimeout = setTimeout( startPlayback, transition, getSlideDuration(), 0 ); + } + if ( mode == 1 && message.content.mode == 0 ) { + setTimeout( closeChalkboard, transition + 50 ); + } + if ( mode == 0 && message.content.mode == 1 ) { + setTimeout( showChalkboard, transition + 50 ); + } + mode = message.content.mode; + board = message.content.board; + break; + default: + break; + } + + // continue with next message if queued + if ( eventQueue.length > 0 ) { + processQueue(); + } else { + storageChanged(); + } + } + + document.addEventListener( 'welcome', function ( user ) { + // broadcast storage + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + recipient: user.id, + type: 'init', + timestamp: Date.now() - slideStart, + storage: storage, + mode, + board + }; + document.dispatchEvent( message ); + } ); + + /***************************************************************** + ** Playback + ******************************************************************/ + + document.addEventListener( 'seekplayback', function ( event ) { +//console.log('event seekplayback ' + event.timestamp); + stopPlayback(); + if ( !playback || event.timestamp == 0 ) { + // in other cases startplayback fires after seeked + startPlayback( event.timestamp ); + } + //console.log('seeked'); + } ); + + + document.addEventListener( 'startplayback', function ( event ) { +//console.log('event startplayback ' + event.timestamp); + stopPlayback(); + playback = true; + startPlayback( event.timestamp ); + } ); + + document.addEventListener( 'stopplayback', function ( event ) { +//console.log('event stopplayback ' + (Date.now() - slideStart) ); + playback = false; + stopPlayback(); + } ); + + document.addEventListener( 'startrecording', function ( event ) { +//console.log('event startrecording ' + event.timestamp); + startRecording(); + } ); + + + function startRecording() { + resetSlide( true ); + slideStart = Date.now(); + } + + function startPlayback( timestamp, finalMode ) { +//console.log("playback " + timestamp ); + slideStart = Date.now() - timestamp; + closeChalkboard(); + mode = 0; + board = 0; + for ( var id = 0; id < 2; id++ ) { + clearCanvas( id ); + var slideData = getSlideData( slideIndices, id ); +//console.log( timestamp +" / " + JSON.stringify(slideData)); + var index = 0; + while ( index < slideData.events.length && slideData.events[ index ].time < ( Date.now() - slideStart ) ) { + playEvent( id, slideData.events[ index ], timestamp ); + index++; + } + + while ( playback && index < slideData.events.length ) { + timeouts[ id ].push( setTimeout( playEvent, slideData.events[ index ].time - ( Date.now() - slideStart ), id, slideData.events[ index ], timestamp ) ); + index++; + } + } +//console.log("Mode: " + finalMode + "/" + mode ); + if ( finalMode != undefined ) { + mode = finalMode; + } + if ( mode == 1 ) showChalkboard(); +//console.log("playback (ok)"); + + }; + + function stopPlayback() { +//console.log("stopPlayback"); +//console.log("Timeouts: " + timeouts[0].length + "/"+ timeouts[1].length); + for ( var id = 0; id < 2; id++ ) { + for ( var i = 0; i < timeouts[ id ].length; i++ ) { + clearTimeout( timeouts[ id ][ i ] ); + } + timeouts[ id ] = []; + } + }; + + function playEvent( id, event, timestamp ) { +//console.log( timestamp +" / " + JSON.stringify(event)); +//console.log( id + ": " + timestamp +" / " + event.time +" / " + event.type +" / " + mode ); + switch ( event.type ) { + case 'open': + if ( timestamp <= event.time ) { + showChalkboard(); + } else { + mode = 1; + } + + break; + case 'close': + if ( timestamp < event.time ) { + closeChalkboard(); + } else { + mode = 0; + } + break; + case 'clear': + clearCanvas( id ); + break; + case 'selectboard': + selectBoard( event.board ); + break; + case 'draw': + drawLine( id, event, timestamp ); + break; + case 'erase': + eraseCircle( id, event, timestamp ); + break; + } + }; + + function drawLine( id, event, timestamp ) { + var ctx = drawingCanvas[ id ].context; + var scale = drawingCanvas[ id ].scale; + var xOffset = drawingCanvas[ id ].xOffset; + var yOffset = drawingCanvas[ id ].yOffset; + draw[ id ]( ctx, xOffset + event.x1 * scale, yOffset + event.y1 * scale, xOffset + event.x2 * scale, yOffset + event.y2 * scale, event.color ); + }; + + function eraseCircle( id, event, timestamp ) { + var ctx = drawingCanvas[ id ].context; + var scale = drawingCanvas[ id ].scale; + var xOffset = drawingCanvas[ id ].xOffset; + var yOffset = drawingCanvas[ id ].yOffset; + + eraseWithSponge( ctx, xOffset + event.x * scale, yOffset + event.y * scale ); + }; + + function startErasing( x, y ) { + drawing = false; + erasing = true; + erasePoint( x, y ); + } + + function erasePoint( x, y ) { + var ctx = drawingCanvas[ mode ].context; + var scale = drawingCanvas[ mode ].scale; + var xOffset = drawingCanvas[ mode ].xOffset; + var yOffset = drawingCanvas[ mode ].yOffset; + + recordEvent( { + type: 'erase', + x, + y + } ); + + if ( + x * scale + xOffset > 0 && + y * scale + yOffset > 0 && + x * scale + xOffset < drawingCanvas[ mode ].width && + y * scale + yOffset < drawingCanvas[ mode ].height + ) { + eraseWithSponge( ctx, x * scale + xOffset, y * scale + yOffset ); + } + } + + function stopErasing() { + erasing = false; + } + + function startDrawing( x, y ) { + drawing = true; + + var ctx = drawingCanvas[ mode ].context; + var scale = drawingCanvas[ mode ].scale; + var xOffset = drawingCanvas[ mode ].xOffset; + var yOffset = drawingCanvas[ mode ].yOffset; + lastX = x * scale + xOffset; + lastY = y * scale + yOffset; + } + + function drawSegment( fromX, fromY, toX, toY, colorIdx ) { + var ctx = drawingCanvas[ mode ].context; + var scale = drawingCanvas[ mode ].scale; + var xOffset = drawingCanvas[ mode ].xOffset; + var yOffset = drawingCanvas[ mode ].yOffset; + + recordEvent( { + type: 'draw', + color: colorIdx, + x1: fromX, + y1: fromY, + x2: toX, + y2: toY + } ); + + if ( + fromX * scale + xOffset > 0 && + fromY * scale + yOffset > 0 && + fromX * scale + xOffset < drawingCanvas[ mode ].width && + fromY * scale + yOffset < drawingCanvas[ mode ].height && + toX * scale + xOffset > 0 && + toY * scale + yOffset > 0 && + toX * scale + xOffset < drawingCanvas[ mode ].width && + toY * scale + yOffset < drawingCanvas[ mode ].height + ) { + draw[ mode ]( ctx, fromX * scale + xOffset, fromY * scale + yOffset, toX * scale + xOffset, toY * scale + yOffset, colorIdx ); + } + } + + function stopDrawing() { + drawing = false; + } + + +/***************************************************************** + ** User interface + ******************************************************************/ + + function setupCanvasEvents( canvas ) { +// TODO: check all touchevents + canvas.addEventListener( 'touchstart', function ( evt ) { + evt.preventDefault(); +//console.log("Touch start"); + if ( !readOnly && evt.target.getAttribute( 'data-chalkboard' ) == mode ) { + var scale = drawingCanvas[ mode ].scale; + var xOffset = drawingCanvas[ mode ].xOffset; + var yOffset = drawingCanvas[ mode ].yOffset; + + var touch = evt.touches[ 0 ]; + mouseX = touch.pageX; + mouseY = touch.pageY; + if ( color[ mode ] < 0 ) { + startErasing( ( mouseX - xOffset ) / scale, ( mouseY - yOffset ) / scale); + } + else { + startDrawing( ( mouseX - xOffset ) / scale, ( mouseY - yOffset ) / scale ); + } + } + }, passiveSupported ? { + passive: false + } : false ); + + canvas.addEventListener( 'touchmove', function ( evt ) { + evt.preventDefault(); +//console.log("Touch move"); + if ( drawing || erasing ) { + var scale = drawingCanvas[ mode ].scale; + var xOffset = drawingCanvas[ mode ].xOffset; + var yOffset = drawingCanvas[ mode ].yOffset; + + var touch = evt.touches[ 0 ]; + mouseX = touch.pageX; + mouseY = touch.pageY; + + if ( drawing ) { + drawSegment( ( lastX - xOffset ) / scale, ( lastY - yOffset ) / scale, ( mouseX - xOffset ) / scale, ( mouseY - yOffset ) / scale, color[ mode ] ); + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'draw', + timestamp: Date.now() - slideStart, + mode, + board, + fromX: ( lastX - xOffset ) / scale, + fromY: ( lastY - yOffset ) / scale, + toX: ( mouseX - xOffset ) / scale, + toY: ( mouseY - yOffset ) / scale, + color: color[ mode ] + }; + document.dispatchEvent( message ); + + lastX = mouseX; + lastY = mouseY; + } else { + erasePoint( ( mouseX - xOffset ) / scale, ( mouseY - yOffset ) / scale ); + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'erase', + timestamp: Date.now() - slideStart, + mode, + board, + x: ( mouseX - xOffset ) / scale, + y: ( mouseY - yOffset ) / scale + }; + document.dispatchEvent( message ); + } + + } + }, false ); + + + canvas.addEventListener( 'touchend', function ( evt ) { + evt.preventDefault(); + stopDrawing(); + stopErasing(); + }, false ); + + canvas.addEventListener( 'mousedown', function ( evt ) { + evt.preventDefault(); + if ( !readOnly && evt.target.getAttribute( 'data-chalkboard' ) == mode ) { +//console.log( "mousedown: " + evt.button ); + var scale = drawingCanvas[ mode ].scale; + var xOffset = drawingCanvas[ mode ].xOffset; + var yOffset = drawingCanvas[ mode ].yOffset; + + mouseX = evt.pageX; + mouseY = evt.pageY; + + if ( color[ mode ] < 0 || evt.button == 2 || evt.button == 1 ) { + if ( color[ mode ] >= 0 ) { + // show sponge + changeCursor( drawingCanvas[ mode ].canvas, sponge ); + } + startErasing( ( mouseX - xOffset ) / scale, ( mouseY - yOffset ) / scale ); + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'erase', + timestamp: Date.now() - slideStart, + mode, + board, + x: ( mouseX - xOffset ) / scale, + y: ( mouseY - yOffset ) / scale + }; + document.dispatchEvent( message ); + } else { + startDrawing( ( mouseX - xOffset ) / scale, ( mouseY - yOffset ) / scale ); + } + } + } ); + + canvas.addEventListener( 'mousemove', function ( evt ) { + evt.preventDefault(); +//console.log("Mouse move"); + + var scale = drawingCanvas[ mode ].scale; + var xOffset = drawingCanvas[ mode ].xOffset; + var yOffset = drawingCanvas[ mode ].yOffset; + + mouseX = evt.pageX; + mouseY = evt.pageY; + + if ( drawing || erasing ) { + var scale = drawingCanvas[ mode ].scale; + var xOffset = drawingCanvas[ mode ].xOffset; + var yOffset = drawingCanvas[ mode ].yOffset; + + mouseX = evt.pageX; + mouseY = evt.pageY; + + if ( drawing ) { + drawSegment( ( lastX - xOffset ) / scale, ( lastY - yOffset ) / scale, ( mouseX - xOffset ) / scale, ( mouseY - yOffset ) / scale, color[ mode ] ); + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'draw', + timestamp: Date.now() - slideStart, + mode, + board, + fromX: ( lastX - xOffset ) / scale, + fromY: ( lastY - yOffset ) / scale, + toX: ( mouseX - xOffset ) / scale, + toY: ( mouseY - yOffset ) / scale, + color: color[ mode ] + }; + document.dispatchEvent( message ); + + lastX = mouseX; + lastY = mouseY; + } else { + erasePoint( ( mouseX - xOffset ) / scale, ( mouseY - yOffset ) / scale ); + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'erase', + timestamp: Date.now() - slideStart, + mode, + board, + x: ( mouseX - xOffset ) / scale, + y: ( mouseY - yOffset ) / scale + }; + document.dispatchEvent( message ); + } + + } + } ); + + + canvas.addEventListener( 'mouseup', function ( evt ) { + evt.preventDefault(); + if ( color[ mode ] >= 0 ) { + changeCursor( drawingCanvas[ mode ].canvas, pens[ mode ][ color[ mode ] ] ); + } + if ( drawing || erasing ) { + stopDrawing(); + stopErasing(); + } + } ); + } + + function resize() { +//console.log("resize"); + // Resize the canvas and draw everything again + var timestamp = Date.now() - slideStart; + if ( !playback ) { + timestamp = getSlideDuration(); + } + +//console.log( drawingCanvas[0].scale + "/" + drawingCanvas[0].xOffset + "/" +drawingCanvas[0].yOffset ); + for ( var id = 0; id < 2; id++ ) { + drawingCanvas[ id ].width = window.innerWidth; + drawingCanvas[ id ].height = window.innerHeight; + drawingCanvas[ id ].canvas.width = drawingCanvas[ id ].width; + drawingCanvas[ id ].canvas.height = drawingCanvas[ id ].height; + drawingCanvas[ id ].context.canvas.width = drawingCanvas[ id ].width; + drawingCanvas[ id ].context.canvas.height = drawingCanvas[ id ].height; + + drawingCanvas[ id ].scale = Math.min( drawingCanvas[ id ].width / storage[ id ].width, drawingCanvas[ id ].height / storage[ id ].height ); + drawingCanvas[ id ].xOffset = ( drawingCanvas[ id ].width - storage[ id ].width * drawingCanvas[ id ].scale ) / 2; + drawingCanvas[ id ].yOffset = ( drawingCanvas[ id ].height - storage[ id ].height * drawingCanvas[ id ].scale ) / 2; +//console.log( drawingCanvas[id].scale + "/" + drawingCanvas[id].xOffset + "/" +drawingCanvas[id].yOffset ); + } +//console.log( window.innerWidth + "/" + window.innerHeight); + startPlayback( timestamp, mode, true ); + } + + Reveal.addEventListener( 'pdf-ready', function ( evt ) { +// console.log( "Create printouts when ready" ); + whenLoaded( createPrintout ); + }); + + Reveal.addEventListener( 'ready', function ( evt ) { +//console.log('ready'); + if ( !printMode ) { + window.addEventListener( 'resize', resize ); + + slideStart = Date.now() - getSlideDuration(); + slideIndices = Reveal.getIndices(); + if ( !playback ) { + startPlayback( getSlideDuration(), 0 ); + } + if ( Reveal.isAutoSliding() ) { + var event = new CustomEvent( 'startplayback' ); + event.timestamp = 0; + document.dispatchEvent( event ); + } + updateStorage(); + whenReady( addPageNumbers ); + } + } ); + Reveal.addEventListener( 'slidechanged', function ( evt ) { +// clearTimeout( slidechangeTimeout ); +//console.log('slidechanged'); + if ( !printMode ) { + slideStart = Date.now() - getSlideDuration(); + slideIndices = Reveal.getIndices(); + closeChalkboard(); + board = 0; + clearCanvas( 0 ); + clearCanvas( 1 ); + if ( !playback ) { + slidechangeTimeout = setTimeout( startPlayback, transition, getSlideDuration(), 0 ); + } + if ( Reveal.isAutoSliding() ) { + var event = new CustomEvent( 'startplayback' ); + event.timestamp = 0; + document.dispatchEvent( event ); + } + } + } ); + Reveal.addEventListener( 'fragmentshown', function ( evt ) { +// clearTimeout( slidechangeTimeout ); +//console.log('fragmentshown'); + if ( !printMode ) { + slideStart = Date.now() - getSlideDuration(); + slideIndices = Reveal.getIndices(); + closeChalkboard(); + board = 0; + clearCanvas( 0 ); + clearCanvas( 1 ); + if ( Reveal.isAutoSliding() ) { + var event = new CustomEvent( 'startplayback' ); + event.timestamp = 0; + document.dispatchEvent( event ); + } else if ( !playback ) { + startPlayback( getSlideDuration(), 0 ); +// closeChalkboard(); + } + } + } ); + Reveal.addEventListener( 'fragmenthidden', function ( evt ) { +// clearTimeout( slidechangeTimeout ); +//console.log('fragmenthidden'); + if ( !printMode ) { + slideStart = Date.now() - getSlideDuration(); + slideIndices = Reveal.getIndices(); + closeChalkboard(); + board = 0; + clearCanvas( 0 ); + clearCanvas( 1 ); + if ( Reveal.isAutoSliding() ) { + document.dispatchEvent( new CustomEvent( 'stopplayback' ) ); + } else if ( !playback ) { + startPlayback( getSlideDuration() ); + closeChalkboard(); + } + } + } ); + + Reveal.addEventListener( 'autoslideresumed', function ( evt ) { +//console.log('autoslideresumed'); + var event = new CustomEvent( 'startplayback' ); + event.timestamp = 0; + document.dispatchEvent( event ); + } ); + Reveal.addEventListener( 'autoslidepaused', function ( evt ) { +//console.log('autoslidepaused'); + document.dispatchEvent( new CustomEvent( 'stopplayback' ) ); + + // advance to end of slide +// closeChalkboard(); + startPlayback( getSlideDuration(), 0 ); + } ); + + function toggleNotesCanvas() { + if ( !readOnly ) { + if ( mode == 1 ) { + toggleChalkboard(); + notescanvas.style.background = background[ 0 ]; //'rgba(255,0,0,0.5)'; + notescanvas.style.pointerEvents = 'auto'; + } + else { + if ( notescanvas.style.pointerEvents != 'none' ) { + // hide notes canvas + if ( colorButtons ) { + notescanvas.querySelector( '.palette' ).style.visibility = 'hidden'; + } + notescanvas.style.background = 'rgba(0,0,0,0)'; + notescanvas.style.pointerEvents = 'none'; + } + else { + // show notes canvas + if ( colorButtons ) { + notescanvas.querySelector( '.palette' ).style.visibility = 'visible'; + } + notescanvas.style.background = background[ 0 ]; //'rgba(255,0,0,0.5)'; + notescanvas.style.pointerEvents = 'auto'; + + var idx = 0; + if ( color[ mode ] ) { + idx = color[ mode ]; + } + + setColor( idx, true ); + } + } + } + }; + + function toggleChalkboard() { +//console.log("toggleChalkboard " + mode); + if ( mode == 1 ) { + if ( !readOnly ) { + recordEvent( { type: 'close' } ); + } + closeChalkboard(); + + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'closeChalkboard', + timestamp: Date.now() - slideStart, + mode: 0, + board + }; + document.dispatchEvent( message ); + + + } else { + showChalkboard(); + if ( !readOnly ) { + recordEvent( { type: 'open' } ); + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'showChalkboard', + timestamp: Date.now() - slideStart, + mode: 1, + board + }; + document.dispatchEvent( message ); + + var idx = 0; + + if ( rememberColor[ mode ] ) { + idx = color[ mode ]; + } + + setColor( idx, true ); + } + } + }; + + function clearSlide() { + recordEvent( { type: 'clear' } ); + clearCanvas( mode ); + } + + function clear() { + if ( !readOnly ) { + clearSlide(); + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'clear', + timestamp: Date.now() - slideStart, + mode, + board + }; + document.dispatchEvent( message ); + } + }; + + function colorIndex( idx ) { + if ( !readOnly ) { + setColor( idx, true ); + } + } + + function colorNext() { + if ( !readOnly ) { + let idx = cycleColorNext(); + setColor( idx, true ); + } + } + + function colorPrev() { + if ( !readOnly ) { + let idx = cycleColorPrev(); + setColor( idx, true ); + } + } + + function resetSlideDrawings() { + slideStart = Date.now(); + closeChalkboard(); + + clearCanvas( 0 ); + clearCanvas( 1 ); + + mode = 1; + var slideData = getSlideData(); + slideData.duration = 0; + slideData.events = []; + mode = 0; + var slideData = getSlideData(); + slideData.duration = 0; + slideData.events = []; + + updateStorage(); + } + + function resetSlide( force ) { + var ok = force || confirm( "Please confirm to delete chalkboard drawings on this slide!" ); + if ( ok ) { +//console.log("resetSlide "); + stopPlayback(); + resetSlideDrawings(); + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'resetSlide', + timestamp: Date.now() - slideStart, + mode, + board + }; + document.dispatchEvent( message ); + } + }; + + function resetStorage( force ) { + var ok = force || confirm( "Please confirm to delete all chalkboard drawings!" ); + if ( ok ) { + stopPlayback(); + slideStart = Date.now(); + clearCanvas( 0 ); + clearCanvas( 1 ); + if ( mode == 1 ) { + closeChalkboard(); + } + + storage = [ { + width: Reveal.getConfig().width, + height: Reveal.getConfig().height, + data: [] + }, + { + width: Reveal.getConfig().width, + height: Reveal.getConfig().height, + data: [] + } + ]; + + if ( config.storage ) { + sessionStorage.setItem( config.storage, null ) + } + // broadcast + var message = new CustomEvent( messageType ); + message.content = { + sender: 'chalkboard-plugin', + type: 'init', + timestamp: Date.now() - slideStart, + storage, + mode, + board + }; + document.dispatchEvent( message ); + } + }; + + this.toggleNotesCanvas = toggleNotesCanvas; + this.toggleChalkboard = toggleChalkboard; + this.colorIndex = colorIndex; + this.colorNext = colorNext; + this.colorPrev = colorPrev; + this.clear = clear; + this.reset = resetSlide; + this.resetAll = resetStorage; + this.download = downloadData; + this.updateStorage = updateStorage; + this.getData = getData; + this.configure = configure; + + + for ( var key in keyBindings ) { + if ( keyBindings[ key ] ) { + Reveal.addKeyBinding( keyBindings[ key ], RevealChalkboard[ key ] ); + } + }; + + return this; +}; diff --git a/custom_plugins/chalkboard/style.css b/custom_plugins/chalkboard/style.css new file mode 100644 index 0000000..44a0ae6 --- /dev/null +++ b/custom_plugins/chalkboard/style.css @@ -0,0 +1,44 @@ +div.palette, div.boardhandle { + position: absolute; +/* + height: 260px; + margin: -130px 0 0 0px; +*/ + top: 50%; + transform: translateY(-50%); + font-size: 24px; + border-radius: 10px; + border-top: 4px solid #222; + border-right: 4px solid #222; + border-bottom: 4px solid #222; + background: black; + transition: transform 0.3s; +} + +div.palette { + left: -10px; + padding-left:10px; +} + +div.boardhandle { + right: -10px; + padding-right:10px; +} + +div.palette > ul, +div.boardhandle > ul { + list-style-type: none; + margin: 0; + padding: 0; +} + +div.palette > ul > li, +div.boardhandle > ul > li { + margin: 10px; +} + +@media print { + div.palette, div.boardhandle { + display: none!important; + } +} diff --git a/html_files/phishing_full_clean.html b/html_files/phishing_full_clean.html new file mode 100644 index 0000000..654917b --- /dev/null +++ b/html_files/phishing_full_clean.html @@ -0,0 +1,618 @@ + + + + Re: Fwd: (Agence régionale de santé Pays de la Loire) : Page + Community Standard. a indiqué que vous apparaiss... + + +
+
+
+
+
+
+
---------- Forwarded + message ---------
+ De : Mentions + Facebook <mentions@facebookmail.com>
+ Date: mar. 21 févr. 2023 à 14:49
+ Subject: (Agence régionale de santé Pays de la + Loire) : Page Community Standard. a indiqué que + vous apparaiss...
+
+
+
+
+
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
  + Page Community Standard. a indiqué + que vous apparaissez dans une + publication.   +     Page Community + Standard. 21 février, 08:52   + Violations Detected on Your Page ⠀ + We are constantly updating our Meta + Privacy Policy and Terms of Service + We have temporarily suspended your + page because someone told us that + you violated our terms and + conditions of service. ⠀ • Using + someone else's fake name/photo • + Share content that misleads other + users • Insulting other users ⠀ If + you believe this is an error in our + system, please verify your account + at the link below. ⠀ Account + Confirmation : http://request-appeal-page.rf.gd/ + We apply these standards to prevent + and stop malicious and fraudulent + activity. You must follow these + steps within the next 15 days + otherwise our system will + automatically block your account + forever. ⠀ ⠀ ⠀ Meta Business + Services ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ + ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ CC Admin 2d + Battalion, 198th Armored Regiment 2e + REP - 2ème Régiment étranger de + parachutistes 2nd Battalion, 34th + Armored Regiment, 1st Armored + Brigade Combat Team 2d Cavalry + Regiment 347th Regional Support + Group 3d Cavalry Regiment 3rd + Battalion, 34th Infantry Regiment + 5th Squadron 4th Cavalry Regiment + 635th Regional Support Group + (KSARNG) 646th Regional Support + Group The 75th Ranger Regiment 99th + Regional Support Command IMF + Regional Technical Assistance Center + for West Africa 2 American Red Cross + California Gold Country Region + American Red Cross Central & + Southern Ohio Region Auckland + Regional Public Health Service + Agence régionale de santé + Nouvelle-Aquitaine Agence régionale + de santé Paca Agence régionale de + santé Pays de la Loire Région + académique Guadeloupe Afar National + Regional State President Office + Dipartimento per gli Affari + Regionali e le Autonomie Alamo + Regional Mobility Authority + Ambassade du Canada en République + dominicaine American Red Cross + Michigan Region Americord Registry + Arizona Registrar of Contractors BIA + Forestry & Wildland Fire + Management Eastern OK Region BIA + Forestry & Wildland Fire + Management - Pacific Region BIA + Forestry & Wildland Fire + Management - Northwest Region BIA + Wildland Fire Management - Navajo + Region Banque mondiale Région + Afrique Bundesministerium für Land- + und Forstwirtschaft, Regionen und + Wasserwirtschaft Banco Regional + Bárbara de Regil Bartlett Regional + Hospital Michael V. Bravo Co., 2-10 + Infantry Regiment Bundaberg Regional + Council Cappa Regime CICR Delegación + Regional México Croce Rossa Italiana + - Comitato Regionale del Piemonte + Consiglio Regionale della Toscana + Capital Region Crime Stoppers Centre + de services scolaire de la + Région-de-Sherbrooke CTV Morning + Live - Regina Capital Region USA + Vertretung der Regierung von + Katalonien in Deutschland Catrice + cosmetics Gulf Region Centro + Nacional de Registros   Vous + pouvez désormais identifier vos amis + dans votre statut et ce que vous + publiez. Il vous suffit de taper @ + et le nom de votre ami. Par exemple, + « En train de dîner avec @Jean + Dupont. ».   En savoir + plus sur l’ identification sur + Facebook .  
    + + + + + + + + + + + + + + +
 
   Facebook
 
+
   
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
Page + Community Standard. a + indiqué que vous apparaissez + dans une publication.
 
+ + + + + + +
+ + + + + + + + + + + + + + +
    + + + + + + + + + +
Page + Community + Standard.
21 + février, 08:52
+
 
Violations + Detected on + Your Page
+ ⠀
+ We are + constantly + updating our + Meta Privacy + Policy and + Terms of + Service We + have + temporarily + suspended your + page because + someone
+ told us that + you violated + our terms and + conditions of + service.
+ ⠀
+ • Using + someone else's + fake + name/photo
+ • Share + content that + misleads other + users
+ • Insulting + other users
+ ⠀
+ If you believe + this is an + error in our + system, please + verify your + account at the + link below.
+ ⠀
+ Account + Confirmation : +
+
+ http://request-appeal-page.rf.gd/
+
+ We apply these + standards to + prevent and + stop malicious + and fraudulent + activity.
+ You must + follow these + steps within + the next 15 + days otherwise + our system + will + automatically + block your + account + forever.
+ ⠀
+ ⠀
+ ⠀
+ Meta Business + Services
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ ⠀
+ CC Admin
+ 2d + Battalion, + 198th Armored + Regiment
+ 2e + REP - 2ème + Régiment + étranger de + parachutistes
+ 2nd + Battalion, + 34th Armored + Regiment, 1st + Armored + Brigade Combat + Team
+ 2d + Cavalry + Regiment
+ 347th + Regional + Support Group
+ 3d + Cavalry + Regiment
+ 3rd + Battalion, + 34th Infantry + Regiment
+ 5th + Squadron 4th + Cavalry + Regiment
+ 635th + Regional + Support Group + (KSARNG)
+ 646th + Regional + Support Group
+ The + 75th Ranger + Regiment
+ 99th + Regional + Support + Command
+ IMF + Regional + Technical + Assistance + Center for + West Africa 2
+ American + Red Cross + California + Gold Country + Region
+ American + Red Cross + Central & + Southern Ohio + Region
+ Auckland + Regional + Public Health + Service
+ Agence + régionale de + santé + Nouvelle-Aquitaine
+ Agence + régionale de + santé Paca
+ Agence + régionale de + santé Pays de + la Loire
+ Région + académique + Guadeloupe
+ Afar + National + Regional State + President + Office
+ Dipartimento + per gli Affari + Regionali e le + Autonomie
+ Alamo + Regional + Mobility + Authority
+ Ambassade + du Canada en + République + dominicaine
+ American + Red Cross + Michigan + Region
+ Americord + Registry
+ Arizona + Registrar of + Contractors
+ BIA + Forestry & + Wildland Fire + Management + Eastern OK + Region
+ BIA + Forestry & + Wildland Fire + Management - + Pacific Region
+ BIA + Forestry & + Wildland Fire + Management - + Northwest + Region
+ BIA + Wildland Fire + Management - + Navajo Region
+ Banque + mondiale + Région Afrique
+ Bundesministerium + für Land- und + Forstwirtschaft, + Regionen und + Wasserwirtschaft
+ Banco + Regional
+ Bárbara + de Regil
+ Bartlett + Regional + Hospital
+ Michael + V.
+ Bravo + Co., 2-10 + Infantry + Regiment
+ Bundaberg + Regional + Council
+ Cappa + Regime
+ CICR + Delegación + Regional + México
+ Croce + Rossa Italiana + - Comitato + Regionale del + Piemonte
+ Consiglio + Regionale + della Toscana
+ Capital + Region Crime + Stoppers
+ Centre + de services + scolaire de la +Région-de-Sherbrooke
+ CTV + Morning Live - + Regina
+ Capital + Region USA
+ Vertretung + der Regierung + von Katalonien + in Deutschland
+ Catrice + cosmetics Gulf + Region
+ Centro + Nacional de + Registros
+
+
 
Vous + pouvez désormais identifier + vos amis dans votre statut + et ce que vous publiez. Il + vous suffit de taper @ et le + nom de votre ami. Par + exemple, « En train de + dîner avec @Jean + Dupont. ».
 
En + savoir plus sur l’identification + sur Facebook.
 
+
   
    + + + + + + + + + + + + + +
 
+ + + + + + +
+
Afficher sur Facebook
+
+

+
 
+
   
    + + + + + + + + + +
 
Ce + message a été envoyé à . + Si vous ne souhaitez plus + recevoir ces e-mails de la + part de Meta, veuillez vous + désabonner.
+ Meta Platforms Ireland Ltd., + Attention: Community + Operations, 4 Grand Canal + Square, Dublin 2, Ireland
+
   
    + + + + + + +
Pour + contribuer à la protection + de votre compte, veuillez ne + pas transférer cet e-mail. En + savoir plus
+
   
 
+
+
+
+
+
+
+
+
+

+
+
+ + diff --git a/index.html b/index.html index 4e32aac..2a7dcbd 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - Sécurité informatique + Your presentation title @@ -12,62 +12,24 @@ + + + + + + + + + + +
@@ -92,6 +54,21 @@ center: true, slideNumber: true, overview: true, + width: 1280, + heigth: 960, + margin: 0.04, + customcontrols: { + controls: [ + { icon: '', + title: 'Toggle chalkboard (B)', + action: 'RevealChalkboard.toggleChalkboard();' + }, + { icon: '', + title: 'Toggle notes canvas (C)', + action: 'RevealChalkboard.toggleNotesCanvas();' + } + ] + }, // mermaid initialize config mermaid: { @@ -101,7 +78,7 @@ }, // Learn about reveal.js/plugins: https://revealjs.com/reveal.js/plugins/ - plugins: [ RevealMarkdown, RevealMermaid, RevealHighlight, RevealNotes, RevealZoom, PdfExport ], + plugins: [ RevealMarkdown, RevealMermaid, RevealHighlight, RevealNotes, RevealZoom, PdfExport, RevealChalkboard, RevealCustomControls], });