├── .gitignore
├── README.md
├── components
├── ending.js
├── filmGrain.js
├── hackPack.js
├── intro.js
├── meta.js
├── progressButton.js
├── selectable.js
├── sketchEmbed.js
├── slack.js
├── split.js
└── step.js
├── docs
└── runbook.md
├── draw-dino-auth
├── .gitignore
├── Dockerfile
├── metrics.js
├── package.json
├── server.js
└── yarn.lock
├── metrics.js
├── package.json
├── pages
├── api
│ └── metric.js
├── index.js
└── slackAuthSuccess.js
├── public
├── FileSaver.js
├── back-black.png
├── back-white.png
├── canvas-toBlob.js
├── decorative-bottom.png
├── decorative-corner.png
├── decorative-corner.svg
├── dinoisseur.png
├── down-black.png
├── down-white.png
├── erase-button.gif
├── excanvas.js
├── favicon.ico
├── fonts
│ ├── PhantomSans0.6-Bold.ttf
│ ├── PhantomSans0.6-Bold.woff
│ ├── PhantomSans0.6-Bold.woff2
│ ├── PhantomSans0.6-Book.ttf
│ ├── PhantomSans0.6-Book.woff
│ ├── PhantomSans0.6-Book.woff2
│ ├── PhantomSans0.6-Italic.ttf
│ ├── PhantomSans0.6-Italic.woff
│ ├── PhantomSans0.6-Italic.woff2
│ ├── PhantomSans0.6-Medium.ttf
│ ├── PhantomSans0.6-Medium.woff
│ ├── PhantomSans0.6-Medium.woff2
│ ├── PhantomSans0.6-Regular.ttf
│ ├── PhantomSans0.6-Regular.woff
│ ├── PhantomSans0.6-Regular.woff2
│ ├── PhantomSans0.6-Semibold.ttf
│ ├── PhantomSans0.6-Semibold.woff
│ └── PhantomSans0.6-Semibold.woff2
├── github-edit.svg
├── github.svg
├── grain.jpg
├── next-black.png
├── next-white.png
├── portrait-decoration.svg
├── save-button.gif
├── sketch.html
├── sketch.js
├── slack.svg
├── steps
│ ├── create-pr.gif
│ ├── create-pr.mp4
│ ├── dino-wallpaper.jpg
│ ├── drawing-dino.gif
│ ├── drawing-dino.png
│ ├── edit-readme.gif
│ ├── edit-readme.mp4
│ ├── motivational-dino.png
│ ├── new-branch.gif
│ ├── new-branch.mp4
│ ├── star.gif
│ ├── star.mp4
│ ├── start-editing-readme.gif
│ ├── start-editing-readme.mp4
│ ├── upload.gif
│ └── upload.mp4
├── template-button.gif
├── template.jpg
├── thick-button.gif
└── thin-button.gif
├── screenshot.png
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules/
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | .env*
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Make a Dino
4 |
5 | Hack Club's workshop on submitting PRs on GitHub
6 |
7 | ```sh
8 | # install
9 | $ git clone https://github.com/hackclub/draw-dino
10 | $ cd draw-dino
11 | $ yarn install
12 |
13 | # run a live-reloading server in development
14 | $ yarn dev
15 | ```
16 |
17 | Before committing, make sure to run the built-in formatter:
18 |
19 | ```sh
20 | $ yarn fmt
21 | ```
22 |
--------------------------------------------------------------------------------
/components/ending.js:
--------------------------------------------------------------------------------
1 | import FilmGrain from './filmGrain'
2 | import packageJson from '../package.json'
3 |
4 | const containerStyle = {
5 | width: '100%',
6 | height: '100vh',
7 | minHeight: '30em',
8 | overflow: 'hidden',
9 | margin: 0,
10 | background: 'black',
11 | fontFamily: "'Bellefair', serif",
12 | display: 'flex',
13 | position: 'relative',
14 | alignItems: 'center',
15 | justifyContent: 'center',
16 | }
17 |
18 | const bannerStyle = {
19 | background: '#222',
20 | boxShadow: '0 0 15vh 15vh #222',
21 | textAlign: 'center',
22 | color: 'white',
23 | margin: '0 auto',
24 | display: 'flex',
25 | flexDirection: 'column',
26 | position: 'absolute',
27 | padding: '1em',
28 | }
29 |
30 | const titleStyle = {
31 | fontFamily: "'Yesteryear', cursive",
32 | fontSize: '8em',
33 | padding: '1em',
34 | paddingBottom: 0,
35 | fontStyle: 'italic',
36 | marginTop: 0,
37 | marginBottom: 0,
38 | textShadow: `
39 | 1px 1px 3px #ddd,
40 | 2px 2px 9px #555,
41 | 3px 3px 2px #999,
42 | 4px 4px 4px #999,
43 | 6px 6px 6px #999,
44 | 6px 6px 6px #999,
45 | 0.2em 0.2em 0.25em black`,
46 | }
47 |
48 | const footerStyle = {
49 | fontSize: '0.5em',
50 | textShadow: `
51 | 0px 0px 2px #ddd,
52 | 1px 1px 2px #ccc,
53 | 0 0 1em black`,
54 | }
55 |
56 | export default () => (
57 | <>
58 |
85 |
86 |
87 |
91 |
100 |
109 |
118 |
The End
119 |
120 | Orpheus says:
121 | “That's all for now folks!”
122 |
123 |
127 |
136 |
137 |
138 |
139 | >
140 | )
141 |
--------------------------------------------------------------------------------
/components/filmGrain.js:
--------------------------------------------------------------------------------
1 | // from this tutorial: https://redstapler.co/css-film-grain-effect/
2 |
3 | const maskStyle = {
4 | position: 'absolute',
5 | top: '-20%',
6 | bottom: '-20%',
7 | right: '-20%',
8 | left: '-20%',
9 | pointerEvents: 'none',
10 | zIndex: '999',
11 | backgroundImage:
12 | 'url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAOh0lEQVR4nO1dbVczNw69JCEvBJInEEIgEIb//6/6fbu73e77tt0P1o2vZQ3QPgRCmHsOJ8mMx5ZlWZJljQEynlBia58ncq3nykzs8wzApVy/ATAAMANwJdevACxdnbCyp/bHNhqpn/DP3aMdS/ucAri17xurQ/s6AnBhfbiQZzZSbgvgzuiE1Te0MgDwIO2RdsUaJR/0OvtwzYuPdsPjSgjcyOfICBjZNWXSBuXALIJ6WfejPctONkE5DkgPiWEed0YLvxNDa2OM1NELxBja81P7fenun9vnSK7N5ftUngXSAPo6psg84qDMXRkveNggd6yxB+5cmbl1wGOENCPY4K0RtXXlKQl9+xzb5zVEOgw9o8d3DqiFRwXi2ujnLCMDhsidvkItKMoQlfq+K0fhmSHNiBt3PxIaIA+ob3fsC0ZYSAXs2D1K5pKwaIBWSExaIxG9QGICpWIZPAMkBpAxQ6snkuyVfXJgrqy8DtTG2ovUhEo71fIKtfq7RBKuKcoB2yLPijPUwnRjbbPMDIlf/E3ePSDPwL6VC/FoD9+5xuGIbuS7lgGSLfDg4M5Rqyf/G9b+Vcs9IEsXO3KGPNgDV/bO2h9aOaWPA0k7wxnnbeoCZT/HyIyeSnmdJQ+oQYGiMFQDQcltXOOXyJLBxm6s8SFKVeF14AMSE0aI4dUhkKSlQckIDuI31AzigPSRmPrcDFQ6orYVT1LXwmhoXJlv7vfAlaFArJD6tZV7aj/OkQekB9MIE/tT9UNvR3XkUhoaW2XKJA7QBKnTvKfMaJBm2SVidQK752fYOerBpbTOrS2VtBVKpg2NdtIY2SbarElwf+3KeW8P9lyb2hkh95d2hHWQ74UH23OfS+SpBaQBoLGLDNc98pQHsrSsUXoZC6tHO7hGNp5nqD0QoB68to73hE5fhgIS2b1DUtNFZZwVHFE1WNqRKbLK2CCrmwnylD9FGqRuBia8dgaGeETq0NoaO0di/AWyZ6ANRd7Q1OpRREzyM2JrBHvDzLZ8nQTdbV8XdfgSaQZurc0TpIF5QCks6opeIktyNHMVHNA5kiZYol6zRJgajbt2STQlgJ7DAFnfTZAk+hzZgDdSXsHrlJZzpI6rsZ0jM4+E3iLNmGhwGySB0MGgmpsgCQ7VDjFs+a44sXojFeg9JGqLjbXD/tyiXvkDdT+qxR+yKpugNPw7xpNJG7k3kt+8T9UUgeuQtntkmhqxi5b6blAO5I3R2ragOrV6dOCeiwQAecaz/ceAFg7oFcp1ySlqY+3tMdE2QFR9u34+WKWcBRO5zk5EBmuIeBo27vfIffJZxSXSoLOdOdpVEzFA6erSqWiQ+kOmqvRPkIRli3jVPEEO6XhsUTs0V8gaZYV2N19xgWTnIjuGPtIIjQH8COBXAP+zzvwA4L/296s8uEZi4C9GzBDAv+X+qdTzaN//hcSAfxjx1/bMCDkI+U8j9me79pN18gyJQf+xjvxkdfxiz8Dq/dm+/8Wuz6x/Y7kHo+dXAH+1+v9u1/tW54/2e2Y0sszfjAYgCe5v1s6NPXMqdS2Mr1O5Rlzb839GEp7fkAb2TyygKoF6rO9+k0B6RXyGQTxfVw9Zymh7+qiDbA3ygPj2IrB9hmN8edXTY5R2gG00KD0kfUbpUxea6CNWfTTMsGeoATgLB0hC3Ecd/3oRh2joxshqKVqJqzdD71CxRvbxvbfU2Oc3o/MWNd41vhcZUxZ8ycXVihgQhBCvnWuT/pHdU2lUg3iP53XzBVJnv6EeCJ0JM6OHwkaBU1s4D+icIPWL6zNYPeQRI790fnywUfF7lhM79JGYwAXRLbIB1cGgJMxQGsgV0vRk8A3IqoBSskDSuZ7RrJPttO2neOjCTQc2WiEz7qVrFhWmJ6H7GnmAFmj3HlmeTGWb90h94SC17YNUa5xHZK/mEvW0O0XqaIMaAyTGjqQBejIeOk3ZlnYAyPsoayQmsR52Vj27jbXZRzL+qmZpBxkGipjpbQRD50BiIuvzM49qZ2P0qaCukWa4Z7LydIS81tvAeW8RoQOUU+gaZbhEQ8hUS7QvfuqpC8r21OXTWaA2ZYjSaRij3GcgNOw+Q9mfl5wEIAlDE7TfQ21HKQBLpD40SMxl/y6Q+MD+qWZQurikeJLrT3C8O4ZF1RTlYA+l/BZlVIFtMFJBUFqXqEM96tQsrGwj96iuF8gz5Ll9f1gbbGcX0G0LJysir4uzQxMJgNhAqcpbW/n7lrZJ4IO1u21pP9oAasMS9cDeIhtWMq5BXugByTtboYx+c32j9D5nYyKoSqPg7GzqH5pSUhYoDTi9GSCpuwFiT0I7xaAfwRCJN/ysX58dIrusZ0jSz4gvmTtDGQbi8xoU9Fih3mjzq3XvTPA+B5/C9Yhsd85Q268q8LrPUad6mFiZyEGg+vELJ6oghvm958UsGIXfauXzpHGGWi2yHBkarUdW7ne0LADqBfXC/eZ97evO6B9CLpKqI89wZfZJcB/IEqw2Qr0aXbACmbEbuU7m+oG6RC2UjbQ1QTx4OjM8dCC4Z1RAiRhIZQw6MiuCDzdITFCDrfDGPSK4DSSOzIoWhZwBDeqp7xlAhnH29lBK8Eu06X59z+jh4HmnxLdL0L2PbB7p3w163xqiyog2jLRRHz0ldIXqjacPd3DRScZ6pirOkCVaJWvqaL1DYi4H5NyeJY0DpD56lajrDt31W7gyXNDOUQ+izjQg86htU4p94SxrS+QD0O2PAx+cxtSg2ws/pGyUF9G2M9i2a+cZ1LjfHGh+955Klyf2TGGGmLfIiyONeXmP5Mme2SV9Cei1KbPaGMR41pe0b5fIy34FPQJuuDB2ox04Qew5cBreIas85skqesjq7hT1xs5K7rH8sacpdfErHEj8yoPeEZOS+cBaCO6yU/YviMVU3Rhht6gThL2h1FWvVqqSR9dY77W9Q3GKchB6yNIT2QDS1zg6FTrg3Ia9QJ3EF4XpeT8yuuyvDgj549coDRJPVWDUftA7C/fadVOeFesU9luyXYJdje/NO9jhqBIFBJ/uRaCj7hz295bTDWLXmsJIzUCw77oQ1ecKjbHXytFtgP3eDbAuGmufr4rGovaMhkaDus+vgXfXd7bsBHHc/gSpU55QGsYFEkN0N9GnCymYegpXpxK2RburDJS7mL7uY0jMwAjliI6lYnoCDbqkbGLvSdkD5OAbjGA/JSOdPQzKedwib2YRczwf5TxFzhM7QR1h1QzCa+SMRXUYFtbuOTLTvLA08l2lXMNIqm5PUeYe6Hv7HCS/2OQCEXi94HfrCIePzl/eodPvCR+deLcDkxaiRtUL8qCq21qFqsY4QJENWSOn/iwCYq+RB4wpNEAZVOSZKwxF8KyVtZThQpXvjAPZBaVGeA5851FVot96VZd1hFJAZq6M8ke/77zJr75Dxzqi98VVU0zd9UhANVq8ROo77VAUTIwSSgDkaUbp4+cjyhmj6oHSxvQgRffe+3fs63evPcd0erzZa8/Iwqk8aGAzpAvoJRxKzKvQ8Vw4+dh8FL6INndm8p3eEJ/V9w+BbOwb++0F4kGIf3DXgcR0VadcizyiVJXEZ3l/coeDeC0Y5ZtXERop2zbzgHKWXBptfpGoMbcGh2NDAXQR34OK+HahkfcLjbwYE/SLsgESU7xkTKTxaFuX72aQmAfk6a770uqX08PTVCGCNPUdLVGe1DG9qFpgry8zWn3eXXxEzp3yYOc2KDtKZi3db481ktTNUB5qyfb5+oU/3o+g4PkMGAqTzggyNzqsQPHSVkf44N4WPYbuTMaE0D59ST0d9AU4jL2bSn+x8QXKVNAoCNjZm4Q3tTeqN48pa/xJ6vqI00UjdfTaRPYCnSv78SoSQHf4/sG88PqZU/ePcc9mJ01KFNN7ogTg7uD+jH0c3P9dJw6o16C6GshSrxLcSB1r1IE6IAuIl/Jr1AxtSwQnEyPD7yVWkwyAfKqQvp6hr0d4+DWNd1oo6FvUKlmT+gDjdRM0cqyLrhcPwheQJs487gkRPtOFkQxtR6E7mUAaiB6C/9/yGVNljvqov3fbmjR4JvmNmwekzt6jTBiI8CD3t2i3eY2VpXD05ZM2rI8sKDcoPbVof8bP4rfyUnfgJk5bw7oj1kMaEO603SDPJk+oBxslszXYNkGp0r7kbibf8eYmzTdk3eYfUAxRbrgQXioa5BkXLd7YCf/cQmjQPe0T5HcNN+7+udHkVSB/05tr23TSvF/Cb4wRumE3QG0Px8jODssQKmjkTZGE2IU7vj/c8Wbv7XfHLCXs45ila2Rvqgme9/nSEyAxlY1x2vnVq6ZBMicWyAPgZ0hkizwzoiM0gHxi9Z279lq02bBPcxTIUWb/GT7jRlgXJpFrB/H/Dd/KOxigVBfKINbFtE4eVAl5hgdV3qI8jpvQl+91hjAACXdPB0RTfnx2OpAPzdSzV7Yo7RDTpCigdKPVaXgL9d9FcQUHkXk/lwcogWOUg9MduZGx7yM3ureX8A7HhktZ4Pkzjju31/329HzECXgAPnF0NMCnfx2izUApukTojL2f/a4GlqHg7t31jPfMatnh4BPIAqirexT/WYf4KidGk46+1bmwvydkZrKftFdPyHs/QH7T1m8pQJ5jW3/kELgQh3wm4bEfjrnzKr7k/3vC4b0iUeHDsi0MV8hM38gn/08I7Y92mCc4EG026ArZMXhuxnPW9RBHEO6QZ4iul7j4HSMJWdv7j9y1JC8LJ0Ull0xqgntKfJcZn+t+a8cGQBc2aXAYYZPCqDPpjHhC7e/rsRZkcJtL54npDrapER1sAwjBrz2xpssDTtjHBlcF75o1QeWKaM+jy/H6jhwvVRfdv0I9ANe4W4W/3yr8NUcoFujWIB+8BgHaPYHW/+9tlSmjdYZQujilaRA5AN62qMt9KgTyiFamrJKZK5TRYjJHhSU63pX4NDaywfGfsvMZTqrrjnLFYb2f0h3x10Knx7u8R/N/zoJhKaqY2qsAAAAASUVORK5CYII=)',
13 | }
14 | const containerStyle = {
15 | position: 'absolute',
16 | overflow: 'hidden',
17 | top: 0,
18 | right: 0,
19 | left: 0,
20 | bottom: 0,
21 | pointerEvents: 'none',
22 | }
23 | export default () => (
24 | <>
25 |
66 |
69 | >
70 | )
71 |
--------------------------------------------------------------------------------
/components/hackPack.js:
--------------------------------------------------------------------------------
1 | import ProgressButton from "./progressButton";
2 | import FilmGrain from "./filmGrain";
3 |
4 | const containerStyle = {
5 | width: "100%",
6 | height: "100vh",
7 | minHeight: "30em",
8 | overflow: "hidden",
9 | margin: 0,
10 | background: "black",
11 | fontFamily: "'Bellefair', serif",
12 | display: "flex",
13 | position: "relative",
14 | alignItems: "center",
15 | justifyContent: "center",
16 | };
17 |
18 | const bannerStyle = {
19 | background: "#222",
20 | boxShadow: "0 0 15vh 15vh #222",
21 | textAlign: "center",
22 | color: "white",
23 | margin: "0 auto",
24 | display: "flex",
25 | flexDirection: "column",
26 | position: "absolute",
27 | padding: "1em",
28 | };
29 |
30 | const footerStyle = {
31 | fontSize: "0.5em",
32 | textShadow: `
33 | 1px 1px 1px #ddd,
34 | 2px 2px 1px #ccc,
35 | 0 0 1em black`,
36 | };
37 |
38 | export default ({ index, progress, setProgress }) => (
39 | <>
40 |
112 |
191 | >
192 | );
193 |
--------------------------------------------------------------------------------
/components/intro.js:
--------------------------------------------------------------------------------
1 | import ProgressButton from './progressButton'
2 | import packageJson from '../package.json'
3 | import FilmGrain from './filmGrain'
4 |
5 | const containerStyle = {
6 | width: '100%',
7 | height: '100vh',
8 | minHeight: '30em',
9 | overflow: 'auto',
10 | margin: 0,
11 | background: 'black',
12 | fontFamily: "'Bellefair', serif",
13 | display: 'flex',
14 | position: 'relative',
15 | alignItems: 'center',
16 | justifyContent: 'center',
17 | }
18 |
19 | const supertitleStyle = {
20 | fontFamily: "'Bellefair', serif",
21 | }
22 |
23 | const subtitleStyle = {
24 | fontSize: '2em',
25 | }
26 |
27 | const footerStyle = {
28 | fontSize: '0.5em',
29 | textShadow: `
30 | 1px 1px 1px #ddd,
31 | 2px 2px 1px #ccc,
32 | 0 0 1em black`,
33 | }
34 |
35 | export default ({ index, progress, setProgress, github }) => (
36 | <>
37 |
132 |
133 |
134 |
138 |
147 |
156 |
165 |
“HACK CLUB PRESENTS”
166 |
Orpheus the Dinosaur and {github} co-star in...
167 |
168 | “Draw a
169 | Dino”
170 |
171 |
172 | Or, An “Inter-Active” Primer to Submit Pull Requests
173 |
174 |
179 |
180 |
Click to Continue
181 |
185 |
186 |
187 |
196 |
197 |
198 |
199 | >
200 | )
201 |
--------------------------------------------------------------------------------
/components/meta.js:
--------------------------------------------------------------------------------
1 | import Head from 'next/head'
2 |
3 | const fontImport = (family, weight, file) => `
4 | @font-face {
5 | font-family: '${family}';
6 | ${
7 | weight &&
8 | `
9 | font-weight: ${weight};
10 | `
11 | }
12 | src: url('fonts/${file}.woff2') format('woff2'),
13 | url('fonts/${file}.woff') format('woff'),
14 | url('fonts/${file}.ttf') format('truetype');
15 | }
16 | `
17 |
18 | export default () => (
19 | <>
20 |
21 |
22 |
23 |
33 |
34 | Draw Dino
35 |
36 |
91 | >
92 | )
93 |
--------------------------------------------------------------------------------
/components/progressButton.js:
--------------------------------------------------------------------------------
1 | import Scroll from 'react-scroll'
2 |
3 | export default ({ children, setProgress, index, progress, ...props }) => {
4 | const active = index == progress
5 |
6 | const onClick = () => {
7 | if (progress < index + 1) {
8 | setProgress(index + 1)
9 | }
10 | Scroll.animateScroll.scrollToBottom()
11 | }
12 |
13 | return (
14 | <>
15 |
28 |
29 | {children}
30 |
31 | >
32 | )
33 | }
34 |
--------------------------------------------------------------------------------
/components/selectable.js:
--------------------------------------------------------------------------------
1 | export default ({ children }) => {
2 | const select = (e) => {
3 | e.preventDefault()
4 | const range = document.createRange()
5 | const sel = window.getSelection()
6 | range.selectNodeContents(e.target)
7 | sel.removeAllRanges()
8 | sel.addRange(range)
9 | document.createRange()
10 | }
11 |
12 | return (
13 | <>
14 |
26 | {children}
27 | >
28 | )
29 | }
30 |
--------------------------------------------------------------------------------
/components/sketchEmbed.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react'
2 | import Scroll from 'react-scroll'
3 |
4 | const containerStyle = {
5 | height: '100vh',
6 | position: 'relative',
7 | }
8 |
9 | const iframeStyle = {
10 | width: '100%',
11 | height: '100%',
12 | margin: 0,
13 | border: 'none',
14 | }
15 |
16 | const continueMessage = {
17 | color: 'white',
18 | textAlign: 'center',
19 | textShadow: '0px 0px 8px black',
20 | position: 'absolute',
21 | marginBottom: '10%',
22 | marginRight: '10%',
23 | bottom: 0,
24 | right: 0,
25 | }
26 |
27 | export default ({ setDinoName, progress, index, setProgress, filePrefix }) => {
28 | useEffect(() => {
29 | window.addEventListener(
30 | 'message',
31 | (e) => {
32 | if (e.data.filename && e.data.blob) {
33 | const dinoName = e.data.filename.replace('.png', '')
34 | setDinoName(dinoName)
35 |
36 | if (progress < index + 1) {
37 | setProgress(index + 1)
38 | }
39 | Scroll.animateScroll.scrollToBottom()
40 | }
41 | },
42 | false
43 | )
44 | })
45 |
46 | return (
47 |
48 |
49 | Finish and save your dino drawing to continue
50 |
51 |
55 |
56 | )
57 | }
58 |
--------------------------------------------------------------------------------
/components/slack.js:
--------------------------------------------------------------------------------
1 | import FilmGrain from "./filmGrain";
2 | import ProgressButton from "./progressButton";
3 |
4 | const containerStyle = {
5 | width: "100%",
6 | height: "100vh",
7 | minHeight: "30em",
8 | overflow: "hidden",
9 | margin: 0,
10 | background: "black",
11 | fontFamily: "'Bellefair', serif",
12 | display: "flex",
13 | position: "relative",
14 | alignItems: "center",
15 | justifyContent: "center",
16 | };
17 |
18 | const bannerStyle = {
19 | background: "#222",
20 | boxShadow: "0 0 15vh 15vh #222",
21 | textAlign: "center",
22 | color: "white",
23 | margin: "0 auto",
24 | display: "flex",
25 | flexDirection: "column",
26 | position: "absolute",
27 | padding: "1em",
28 | };
29 |
30 | const footerStyle = {
31 | fontSize: "0.5em",
32 | textShadow: `
33 | 1px 1px 1px #ddd,
34 | 2px 2px 1px #ccc,
35 | 0 0 1em black`,
36 | };
37 |
38 | export default ({ index, progress, setProgress, github }) => (
39 | <>
40 |
112 |
222 | >
223 | );
224 |
--------------------------------------------------------------------------------
/components/split.js:
--------------------------------------------------------------------------------
1 | import ProgressButton from './progressButton'
2 |
3 | const subStyle = {
4 | fontStyle: 'italic',
5 | opacity: 0.7,
6 | }
7 |
8 | const imageStyle = {
9 | maxWidth: '90%',
10 | maxHeight: '90%',
11 | borderRadius: '0.5em',
12 | boxShadow: 'rgba(0, 0, 0, 1) 0 0 1em, rgba(255, 255, 255, 0.1) 0 0 5em',
13 | }
14 |
15 | const progressStyle = {
16 | position: 'absolute',
17 | marginBottom: '10%',
18 | marginRight: '10%',
19 | bottom: 0,
20 | right: 0,
21 | width: '10em',
22 | }
23 |
24 | export default ({
25 | subtitle,
26 | image,
27 | imageLink,
28 | setProgress,
29 | progress,
30 | index,
31 | children,
32 | }) => (
33 | <>
34 |
94 |
95 |
96 | {image && (
97 | <>
98 |
99 |
100 |
101 |
{subtitle || image}
102 | >
103 | )}
104 |
105 |
106 | {children}
107 |
113 |
117 |
118 |
119 |
120 | >
121 | )
122 |
--------------------------------------------------------------------------------
/components/step.js:
--------------------------------------------------------------------------------
1 | const containerStyle = {
2 | width: '100%',
3 | overflow: 'scrollY',
4 | }
5 |
6 | const hiddenStyle = {
7 | display: 'none',
8 | }
9 |
10 | export default ({ revealed, children }) => (
11 | {children}
12 | )
13 |
--------------------------------------------------------------------------------
/docs/runbook.md:
--------------------------------------------------------------------------------
1 | # draw-dino runbook
2 |
3 | ## References
4 | - Grafana Dashboard at [telemetry.hackclub.com](https://telemetry.hackclub.com/d/dfd172a5-ba5e-43c0-b9c5-3dd46197bc39/draw-dino?orgId=1)
5 | - Draw Dino Slack Authentication service app at [draw-dino-slack-auth](https://railway.app/project/83c44d6e-0f65-4b4a-aa19-bef5909c047a)
6 |
7 | ## draw-dino fails to authenticate with slack
8 |
9 | - Open the app dashboard on railway.app at [draw-dino-slack-oauth](https://railway.app/project/83c44d6e-0f65-4b4a-aa19-bef5909c047a/service/9687e7fd-6efd-424b-9817-f59d9792ad39)
10 | - Checkout the logs by clicking on the "View Logs" button under the Deployments tab of the *draw-dino* app to identify what's wrong with the app
11 |
12 | ## Making sure the application works
13 |
14 | - Open [draw-dino.hackclub.com](https://draw-dino.hackclub.com/).
15 | - After a few seconds, the application should reload. Make sure there's a text saying `Orpheus the Dinosaur and co-star in...`
16 | - Click the "Click to Continue" button which should take you to the next page
17 | - Click on the text saying "Click here to sign into Slack" and sign into your Slack account.
18 | - If the sign in is successful, you should be redirected back to the draw-dino application within a few seconds.
19 | - Otherwise, go back and check why Slack authentication fails
20 |
--------------------------------------------------------------------------------
/draw-dino-auth/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/draw-dino-auth/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:23-alpine3.20
2 |
3 | WORKDIR /app
4 |
5 | COPY package.json .
6 | COPY yarn.lock .
7 |
8 | RUN yarn install
9 |
10 | COPY . .
11 |
12 | EXPOSE 3000
13 | CMD ["yarn", "start"]
14 |
--------------------------------------------------------------------------------
/draw-dino-auth/metrics.js:
--------------------------------------------------------------------------------
1 | const { StatsD } = require("node-statsd");
2 | const { config } = require("dotenv");
3 |
4 | config();
5 |
6 | const environment = process.env.NODE_ENV;
7 | const graphite = process.env.GRAPHITE_HOST;
8 |
9 | if (graphite == null) throw new Error("Graphite host is not configured");
10 |
11 | const options = {
12 | host: graphite,
13 | port: 8125,
14 | prefix: `${environment}.dino.`,
15 | };
16 |
17 | const metrics = new StatsD(options);
18 |
19 | module.exports = metrics;
20 |
--------------------------------------------------------------------------------
/draw-dino-auth/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "slack-oauth",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "node server.js"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "body-parser": "^1.19.0",
14 | "dotenv": "^16.4.5",
15 | "express": "^4.19.2",
16 | "express-session": "^1.18.0",
17 | "node-fetch": "^2.6.0",
18 | "node-statsd": "^0.1.1",
19 | "passport": "^0.7.0",
20 | "passport-slack": "0.0.7"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/draw-dino-auth/server.js:
--------------------------------------------------------------------------------
1 | const {
2 | CLIENT_ID, CLIENT_SECRET
3 | } = process.env
4 | const SlackStrategy = require('passport-slack').Strategy
5 | const passport = require('passport')
6 | const express = require('express')
7 | const session = require("express-session")
8 | const fetch = require('node-fetch')
9 | const app = express()
10 | const metrics = require("./metrics.js");
11 | const { config } = require("dotenv");
12 |
13 | // load environment variables
14 | config();
15 |
16 | passport.use(new SlackStrategy({
17 | clientID: CLIENT_ID,
18 | clientSecret: CLIENT_SECRET,
19 | state: true
20 | }, (accessToken, refreshToken, profile, done) => {
21 | done(null, profile)
22 | }))
23 |
24 | app.use(session({
25 | secret: process.env.PASSPORT_SESSION_SECRET,
26 | resave: true,
27 | saveUninitialized: true
28 | }))
29 | app.use(passport.initialize())
30 | app.use(passport.session())
31 | app.use(require('body-parser').urlencoded({ extended: true }))
32 |
33 | app.get("/failed-slack-auth", (req, res) => {
34 | metrics.increment("errors.slack_auth", 1);
35 | })
36 |
37 | app.get(
38 | '/update-github-url',
39 | passport.authorize('slack', { failureRedirect: "/failed-slack-auth" }),
40 | (req, res) => {
41 | const data = {
42 | slack: req.account.user.id,
43 | github: req.query.state
44 | }
45 |
46 | metrics.increment("success.slack_auth", 1);
47 | const webhook = 'https://hooks.zapier.com/hooks/catch/507705/odyc4wo/'
48 | fetch(webhook, {
49 | method: 'POST',
50 | body: JSON.stringify(data)
51 | })
52 | return res.redirect(302, "https://draw-dino.hackclub.com/slackAuthSuccess")
53 | }
54 | )
55 |
56 | const port = process.env.PORT || 3000
57 | app.listen(port, server => console.log('server is running on port', port))
58 |
--------------------------------------------------------------------------------
/draw-dino-auth/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | accepts@~1.3.8:
6 | version "1.3.8"
7 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
8 | integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
9 | dependencies:
10 | mime-types "~2.1.34"
11 | negotiator "0.6.3"
12 |
13 | array-flatten@1.1.1:
14 | version "1.1.1"
15 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
16 | integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==
17 |
18 | body-parser@1.20.2, body-parser@^1.19.0:
19 | version "1.20.2"
20 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd"
21 | integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==
22 | dependencies:
23 | bytes "3.1.2"
24 | content-type "~1.0.5"
25 | debug "2.6.9"
26 | depd "2.0.0"
27 | destroy "1.2.0"
28 | http-errors "2.0.0"
29 | iconv-lite "0.4.24"
30 | on-finished "2.4.1"
31 | qs "6.11.0"
32 | raw-body "2.5.2"
33 | type-is "~1.6.18"
34 | unpipe "1.0.0"
35 |
36 | bytes@3.1.2:
37 | version "3.1.2"
38 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
39 | integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
40 |
41 | call-bind@^1.0.7:
42 | version "1.0.7"
43 | resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
44 | integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
45 | dependencies:
46 | es-define-property "^1.0.0"
47 | es-errors "^1.3.0"
48 | function-bind "^1.1.2"
49 | get-intrinsic "^1.2.4"
50 | set-function-length "^1.2.1"
51 |
52 | content-disposition@0.5.4:
53 | version "0.5.4"
54 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
55 | integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
56 | dependencies:
57 | safe-buffer "5.2.1"
58 |
59 | content-type@~1.0.4, content-type@~1.0.5:
60 | version "1.0.5"
61 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
62 | integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
63 |
64 | cookie-signature@1.0.6:
65 | version "1.0.6"
66 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
67 | integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
68 |
69 | cookie-signature@1.0.7:
70 | version "1.0.7"
71 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.7.tgz#ab5dd7ab757c54e60f37ef6550f481c426d10454"
72 | integrity sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==
73 |
74 | cookie@0.6.0:
75 | version "0.6.0"
76 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
77 | integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==
78 |
79 | debug@2.6.9:
80 | version "2.6.9"
81 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
82 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
83 | dependencies:
84 | ms "2.0.0"
85 |
86 | define-data-property@^1.1.4:
87 | version "1.1.4"
88 | resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
89 | integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
90 | dependencies:
91 | es-define-property "^1.0.0"
92 | es-errors "^1.3.0"
93 | gopd "^1.0.1"
94 |
95 | depd@2.0.0, depd@~2.0.0:
96 | version "2.0.0"
97 | resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
98 | integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
99 |
100 | destroy@1.2.0:
101 | version "1.2.0"
102 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
103 | integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
104 |
105 | dotenv@^16.4.5:
106 | version "16.4.5"
107 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
108 | integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==
109 |
110 | ee-first@1.1.1:
111 | version "1.1.1"
112 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
113 | integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
114 |
115 | encodeurl@~1.0.2:
116 | version "1.0.2"
117 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
118 | integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
119 |
120 | es-define-property@^1.0.0:
121 | version "1.0.0"
122 | resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845"
123 | integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
124 | dependencies:
125 | get-intrinsic "^1.2.4"
126 |
127 | es-errors@^1.3.0:
128 | version "1.3.0"
129 | resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
130 | integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
131 |
132 | escape-html@~1.0.3:
133 | version "1.0.3"
134 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
135 | integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
136 |
137 | etag@~1.8.1:
138 | version "1.8.1"
139 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
140 | integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
141 |
142 | express-session@^1.18.0:
143 | version "1.18.0"
144 | resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.18.0.tgz#a6ae39d9091f2efba5f20fc5c65a3ce7c9ce16a3"
145 | integrity sha512-m93QLWr0ju+rOwApSsyso838LQwgfs44QtOP/WBiwtAgPIo/SAh1a5c6nn2BR6mFNZehTpqKDESzP+fRHVbxwQ==
146 | dependencies:
147 | cookie "0.6.0"
148 | cookie-signature "1.0.7"
149 | debug "2.6.9"
150 | depd "~2.0.0"
151 | on-headers "~1.0.2"
152 | parseurl "~1.3.3"
153 | safe-buffer "5.2.1"
154 | uid-safe "~2.1.5"
155 |
156 | express@^4.19.2:
157 | version "4.19.2"
158 | resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465"
159 | integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==
160 | dependencies:
161 | accepts "~1.3.8"
162 | array-flatten "1.1.1"
163 | body-parser "1.20.2"
164 | content-disposition "0.5.4"
165 | content-type "~1.0.4"
166 | cookie "0.6.0"
167 | cookie-signature "1.0.6"
168 | debug "2.6.9"
169 | depd "2.0.0"
170 | encodeurl "~1.0.2"
171 | escape-html "~1.0.3"
172 | etag "~1.8.1"
173 | finalhandler "1.2.0"
174 | fresh "0.5.2"
175 | http-errors "2.0.0"
176 | merge-descriptors "1.0.1"
177 | methods "~1.1.2"
178 | on-finished "2.4.1"
179 | parseurl "~1.3.3"
180 | path-to-regexp "0.1.7"
181 | proxy-addr "~2.0.7"
182 | qs "6.11.0"
183 | range-parser "~1.2.1"
184 | safe-buffer "5.2.1"
185 | send "0.18.0"
186 | serve-static "1.15.0"
187 | setprototypeof "1.2.0"
188 | statuses "2.0.1"
189 | type-is "~1.6.18"
190 | utils-merge "1.0.1"
191 | vary "~1.1.2"
192 |
193 | finalhandler@1.2.0:
194 | version "1.2.0"
195 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32"
196 | integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==
197 | dependencies:
198 | debug "2.6.9"
199 | encodeurl "~1.0.2"
200 | escape-html "~1.0.3"
201 | on-finished "2.4.1"
202 | parseurl "~1.3.3"
203 | statuses "2.0.1"
204 | unpipe "~1.0.0"
205 |
206 | forwarded@0.2.0:
207 | version "0.2.0"
208 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
209 | integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
210 |
211 | fresh@0.5.2:
212 | version "0.5.2"
213 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
214 | integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==
215 |
216 | function-bind@^1.1.2:
217 | version "1.1.2"
218 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
219 | integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
220 |
221 | get-intrinsic@^1.1.3, get-intrinsic@^1.2.4:
222 | version "1.2.4"
223 | resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
224 | integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
225 | dependencies:
226 | es-errors "^1.3.0"
227 | function-bind "^1.1.2"
228 | has-proto "^1.0.1"
229 | has-symbols "^1.0.3"
230 | hasown "^2.0.0"
231 |
232 | gopd@^1.0.1:
233 | version "1.0.1"
234 | resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
235 | integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
236 | dependencies:
237 | get-intrinsic "^1.1.3"
238 |
239 | has-property-descriptors@^1.0.2:
240 | version "1.0.2"
241 | resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
242 | integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
243 | dependencies:
244 | es-define-property "^1.0.0"
245 |
246 | has-proto@^1.0.1:
247 | version "1.0.3"
248 | resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd"
249 | integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==
250 |
251 | has-symbols@^1.0.3:
252 | version "1.0.3"
253 | resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
254 | integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
255 |
256 | hasown@^2.0.0:
257 | version "2.0.2"
258 | resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
259 | integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
260 | dependencies:
261 | function-bind "^1.1.2"
262 |
263 | http-errors@2.0.0:
264 | version "2.0.0"
265 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
266 | integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
267 | dependencies:
268 | depd "2.0.0"
269 | inherits "2.0.4"
270 | setprototypeof "1.2.0"
271 | statuses "2.0.1"
272 | toidentifier "1.0.1"
273 |
274 | iconv-lite@0.4.24:
275 | version "0.4.24"
276 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
277 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
278 | dependencies:
279 | safer-buffer ">= 2.1.2 < 3"
280 |
281 | inherits@2.0.4:
282 | version "2.0.4"
283 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
284 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
285 |
286 | ipaddr.js@1.9.1:
287 | version "1.9.1"
288 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
289 | integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
290 |
291 | media-typer@0.3.0:
292 | version "0.3.0"
293 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
294 | integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
295 |
296 | merge-descriptors@1.0.1:
297 | version "1.0.1"
298 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
299 | integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==
300 |
301 | methods@~1.1.2:
302 | version "1.1.2"
303 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
304 | integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
305 |
306 | mime-db@1.52.0:
307 | version "1.52.0"
308 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
309 | integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
310 |
311 | mime-types@~2.1.24, mime-types@~2.1.34:
312 | version "2.1.35"
313 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
314 | integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
315 | dependencies:
316 | mime-db "1.52.0"
317 |
318 | mime@1.6.0:
319 | version "1.6.0"
320 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
321 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
322 |
323 | ms@2.0.0:
324 | version "2.0.0"
325 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
326 | integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
327 |
328 | ms@2.1.3:
329 | version "2.1.3"
330 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
331 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
332 |
333 | negotiator@0.6.3:
334 | version "0.6.3"
335 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
336 | integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
337 |
338 | node-fetch@^2.6.0:
339 | version "2.7.0"
340 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
341 | integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
342 | dependencies:
343 | whatwg-url "^5.0.0"
344 |
345 | node-statsd@^0.1.1:
346 | version "0.1.1"
347 | resolved "https://registry.yarnpkg.com/node-statsd/-/node-statsd-0.1.1.tgz#27a59348763d0af7a037ac2a031fef3f051013d3"
348 | integrity sha512-QDf6R8VXF56QVe1boek8an/Rb3rSNaxoFWb7Elpsv2m1+Noua1yy0F1FpKpK5VluF8oymWM4w764A4KsYL4pDg==
349 |
350 | oauth@0.9.x:
351 | version "0.9.15"
352 | resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1"
353 | integrity sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==
354 |
355 | object-inspect@^1.13.1:
356 | version "1.13.1"
357 | resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2"
358 | integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==
359 |
360 | on-finished@2.4.1:
361 | version "2.4.1"
362 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
363 | integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
364 | dependencies:
365 | ee-first "1.1.1"
366 |
367 | on-headers@~1.0.2:
368 | version "1.0.2"
369 | resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
370 | integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
371 |
372 | parseurl@~1.3.3:
373 | version "1.3.3"
374 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
375 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
376 |
377 | passport-oauth@~0.1.1:
378 | version "0.1.15"
379 | resolved "https://registry.yarnpkg.com/passport-oauth/-/passport-oauth-0.1.15.tgz#fb74e0afe84614bfa256c5fc716cc56bbfc8cec0"
380 | integrity sha512-ma4W++dGNS/WKxkInG03VDqCRPD/9K/eSaqhvMLBFhpLOfycBus8+FnhcoSR6ug+NzXLjYtjGxMPBE/Gt8KqqA==
381 | dependencies:
382 | oauth "0.9.x"
383 | passport "~0.1.1"
384 | pkginfo "0.2.x"
385 |
386 | passport-slack@0.0.7:
387 | version "0.0.7"
388 | resolved "https://registry.yarnpkg.com/passport-slack/-/passport-slack-0.0.7.tgz#167eb80f0ab622d2156e7cae7055e16d0b1890d0"
389 | integrity sha512-E9WDCfd1GO/2zYCz3L1MZcB0eYHTHB6yBi9lRkK+LFBl1p6wcV7pGF6+Vb+XLVq1G6+TLSJCTAxcW5O0rvE4/A==
390 | dependencies:
391 | passport-oauth "~0.1.1"
392 | pkginfo "0.2.x"
393 |
394 | passport-strategy@1.x.x:
395 | version "1.0.0"
396 | resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4"
397 | integrity sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==
398 |
399 | passport@^0.7.0:
400 | version "0.7.0"
401 | resolved "https://registry.yarnpkg.com/passport/-/passport-0.7.0.tgz#3688415a59a48cf8068417a8a8092d4492ca3a05"
402 | integrity sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==
403 | dependencies:
404 | passport-strategy "1.x.x"
405 | pause "0.0.1"
406 | utils-merge "^1.0.1"
407 |
408 | passport@~0.1.1:
409 | version "0.1.18"
410 | resolved "https://registry.yarnpkg.com/passport/-/passport-0.1.18.tgz#c8264479dcb6414cadbb66752d12b37e0b6525a1"
411 | integrity sha512-qteYojKG/qth7UBbbGU7aqhe5ndJs6YaUkH2B6+7FWQ0OeyYmWknzOATpMhdoSTDcLLliq9n4Fcy1mGs80iUMw==
412 | dependencies:
413 | pause "0.0.1"
414 | pkginfo "0.2.x"
415 |
416 | path-to-regexp@0.1.7:
417 | version "0.1.7"
418 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
419 | integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==
420 |
421 | pause@0.0.1:
422 | version "0.0.1"
423 | resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d"
424 | integrity sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==
425 |
426 | pkginfo@0.2.x:
427 | version "0.2.3"
428 | resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.2.3.tgz#7239c42a5ef6c30b8f328439d9b9ff71042490f8"
429 | integrity sha512-7W7wTrE/NsY8xv/DTGjwNIyNah81EQH0MWcTzrHL6pOpMocOGZc0Mbdz9aXxSrp+U0mSmkU8jrNCDCfUs3sOBg==
430 |
431 | proxy-addr@~2.0.7:
432 | version "2.0.7"
433 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
434 | integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
435 | dependencies:
436 | forwarded "0.2.0"
437 | ipaddr.js "1.9.1"
438 |
439 | qs@6.11.0:
440 | version "6.11.0"
441 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
442 | integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
443 | dependencies:
444 | side-channel "^1.0.4"
445 |
446 | random-bytes@~1.0.0:
447 | version "1.0.0"
448 | resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b"
449 | integrity sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==
450 |
451 | range-parser@~1.2.1:
452 | version "1.2.1"
453 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
454 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
455 |
456 | raw-body@2.5.2:
457 | version "2.5.2"
458 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
459 | integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
460 | dependencies:
461 | bytes "3.1.2"
462 | http-errors "2.0.0"
463 | iconv-lite "0.4.24"
464 | unpipe "1.0.0"
465 |
466 | safe-buffer@5.2.1:
467 | version "5.2.1"
468 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
469 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
470 |
471 | "safer-buffer@>= 2.1.2 < 3":
472 | version "2.1.2"
473 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
474 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
475 |
476 | send@0.18.0:
477 | version "0.18.0"
478 | resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be"
479 | integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==
480 | dependencies:
481 | debug "2.6.9"
482 | depd "2.0.0"
483 | destroy "1.2.0"
484 | encodeurl "~1.0.2"
485 | escape-html "~1.0.3"
486 | etag "~1.8.1"
487 | fresh "0.5.2"
488 | http-errors "2.0.0"
489 | mime "1.6.0"
490 | ms "2.1.3"
491 | on-finished "2.4.1"
492 | range-parser "~1.2.1"
493 | statuses "2.0.1"
494 |
495 | serve-static@1.15.0:
496 | version "1.15.0"
497 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540"
498 | integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==
499 | dependencies:
500 | encodeurl "~1.0.2"
501 | escape-html "~1.0.3"
502 | parseurl "~1.3.3"
503 | send "0.18.0"
504 |
505 | set-function-length@^1.2.1:
506 | version "1.2.2"
507 | resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
508 | integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
509 | dependencies:
510 | define-data-property "^1.1.4"
511 | es-errors "^1.3.0"
512 | function-bind "^1.1.2"
513 | get-intrinsic "^1.2.4"
514 | gopd "^1.0.1"
515 | has-property-descriptors "^1.0.2"
516 |
517 | setprototypeof@1.2.0:
518 | version "1.2.0"
519 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
520 | integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
521 |
522 | side-channel@^1.0.4:
523 | version "1.0.6"
524 | resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
525 | integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==
526 | dependencies:
527 | call-bind "^1.0.7"
528 | es-errors "^1.3.0"
529 | get-intrinsic "^1.2.4"
530 | object-inspect "^1.13.1"
531 |
532 | statuses@2.0.1:
533 | version "2.0.1"
534 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
535 | integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
536 |
537 | toidentifier@1.0.1:
538 | version "1.0.1"
539 | resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
540 | integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
541 |
542 | tr46@~0.0.3:
543 | version "0.0.3"
544 | resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
545 | integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
546 |
547 | type-is@~1.6.18:
548 | version "1.6.18"
549 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
550 | integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
551 | dependencies:
552 | media-typer "0.3.0"
553 | mime-types "~2.1.24"
554 |
555 | uid-safe@~2.1.5:
556 | version "2.1.5"
557 | resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.1.5.tgz#2b3d5c7240e8fc2e58f8aa269e5ee49c0857bd3a"
558 | integrity sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==
559 | dependencies:
560 | random-bytes "~1.0.0"
561 |
562 | unpipe@1.0.0, unpipe@~1.0.0:
563 | version "1.0.0"
564 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
565 | integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
566 |
567 | utils-merge@1.0.1, utils-merge@^1.0.1:
568 | version "1.0.1"
569 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
570 | integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
571 |
572 | vary@~1.1.2:
573 | version "1.1.2"
574 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
575 | integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
576 |
577 | webidl-conversions@^3.0.0:
578 | version "3.0.1"
579 | resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
580 | integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
581 |
582 | whatwg-url@^5.0.0:
583 | version "5.0.0"
584 | resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
585 | integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
586 | dependencies:
587 | tr46 "~0.0.3"
588 | webidl-conversions "^3.0.0"
589 |
--------------------------------------------------------------------------------
/metrics.js:
--------------------------------------------------------------------------------
1 | import { StatsD } from "node-statsd";
2 | import { config } from "dotenv";
3 |
4 | config();
5 |
6 | const environment = process.env.NODE_ENV;
7 | const graphite = process.env.GRAPHITE_HOST;
8 |
9 | if (graphite == null) throw new Error("Graphite host is not configured");
10 |
11 | const options = {
12 | host: graphite,
13 | port: 8125,
14 | prefix: `${environment}.dino.`,
15 | };
16 |
17 | const metrics = new StatsD(options);
18 |
19 | export default metrics;
20 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "draw-dino",
3 | "version": "0.1.0",
4 | "private": true,
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/hackclub/draw-dino"
8 | },
9 | "scripts": {
10 | "dev": "next dev",
11 | "build": "next build",
12 | "start": "next start",
13 | "fmt": "npx prettier \"{components,pages}/*.js\" --single-quote --no-semi --trailing-comma es5 --write"
14 | },
15 | "dependencies": {
16 | "dotenv": "^16.4.5",
17 | "next": "^14.1.1",
18 | "node-statsd": "^0.1.1",
19 | "react": "^18.2.0",
20 | "react-dom": "^18.2.0",
21 | "react-input-autosize": "^2.2.2",
22 | "react-scroll": "^1.8.1"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/pages/api/metric.js:
--------------------------------------------------------------------------------
1 | import metrics from "../../metrics";
2 |
3 | export default async function sendMetric(req, res) {
4 | const metric = req.body;
5 |
6 | if (req.method !== "POST") return res.send("Method not supported");
7 |
8 | if (metric.type === "increment") {
9 | metrics.increment(metric.key, metric.value);
10 | } else if (metrics.type === "timing") {
11 | metrics.timing(metrics.key, metrics.value);
12 | }
13 |
14 | res.send("Sent");
15 | }
16 |
--------------------------------------------------------------------------------
/pages/index.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react'
2 |
3 | import Step from '../components/step'
4 | import Meta from '../components/meta'
5 | import Intro from '../components/intro'
6 | import HackPack from '../components/hackPack'
7 | import Slack from '../components/slack'
8 | import Ending from '../components/ending'
9 | import SketchEmbed from '../components/sketchEmbed'
10 | import Split from '../components/split'
11 | import Selectable from '../components/selectable'
12 |
13 | const styleInput = {
14 | borderRadius: '10px',
15 | fontSize: '1.5rem',
16 | }
17 |
18 | const quoteStyle = {
19 | color: '#333',
20 | }
21 |
22 | const subtitleStyle = {
23 | fontStyle: 'italic',
24 | opacity: 0.6,
25 | }
26 |
27 | const GITHUB_OAUTH_URL = process.env.NEXT_PUBLIC_GITHUB_OAUTH_URL;
28 |
29 | export default () => {
30 | const [dinoName, setDinoName] = useState('')
31 | const [progress, setProgress] = useState(0)
32 | const [github, setGithub] = useState(Date.now().toString(36)) // we're putting some random value here in case we can't later figure out what the user's github username is
33 | const [inviteStatus, setInviteStatus] = useState('')
34 |
35 | const slack = true;
36 |
37 | useEffect(() => {
38 | const result = {}
39 | window.location.search
40 | .replace('?', '')
41 | .split('&')
42 | .forEach((kvString) => {
43 | const [key, value] = kvString.split('=')
44 | result[key] = value
45 | })
46 |
47 | const { username, inviteStatus } = result
48 | if (username) {
49 | setGithub(username)
50 | } else {
51 | window.location.replace(`${GITHUB_OAUTH_URL}?destination=${location.origin}`)
52 | }
53 | if (inviteStatus) {
54 | setInviteStatus(inviteStatus)
55 | }
56 | })
57 |
58 | const getName = () => dinoName.replace(/[^\w+]/g, '_') || 'YOUR-DINO-NAME'
59 | const getFilename = () => getName() + '.png'
60 |
61 | const easterEggs = [
62 | 'https://youtu.be/kRpODt0rflA',
63 | 'https://youtu.be/Cw_f4OgW0vQ',
64 | 'https://youtu.be/SXDcpkbkItw',
65 | 'https://youtu.be/51reoULiSjI',
66 | 'https://youtu.be/Z9AJlTnNf_0',
67 | ]
68 | const eggLink = easterEggs[Math.floor(easterEggs.length * Math.random())]
69 |
70 | let index = 0
71 | return (
72 | <>
73 |
74 |
75 |
81 |
82 | {console.log(index++)}
83 |
84 | {slack && (
85 | <>
86 |
87 |
93 |
94 | {console.log(index++)}
95 | >
96 | )}
97 |
98 |
99 |
107 | We take pride in our poorly-drawn dinos™
108 |
109 | And we've got the best collection anywhere in the universe™. Anyone
110 | who sends us a dino drawing will earn the dinoisseur badge, as well
111 | as get an exclusive emoji on Slack.
112 |
113 |
117 |
118 | Hack Club stores all its code on GitHub, including{' '}
119 |
123 | this website
124 |
125 | , {/* AHAHAHAHAH, no one shall ever find this message!!! */}
126 | and the best way to make changes (such as adding a dinosaur) is by
127 | submitting a pull request on GitHub.
128 |
129 |
130 | The first step is to make our dino. Don't worry about setup—we've
131 | included a full dino-drawing-a-tron below for you to use. Just click
132 | "next" and make that dino! You're also free to use a photo.
133 |
134 |
135 | If you already know how to submit PRs to the dino repo, go ahead and{' '}
136 |
140 | read this
141 |
142 | .
143 |
144 |
145 |
146 | {console.log(index++)}
147 |
148 |
149 |
156 |
157 | {console.log(index++)}
158 |
159 | {inviteStatus !== 'active' && (
160 | <>
161 |
162 |
163 |
164 | Now you'll need permission to edit the dinos repo. We've just
165 | sent you an invite, and depending on your settings, it will be
166 | auto-accepted or you'll need to{' '}
167 |
171 | accept it here
172 |
173 | . If it doesn't show up there, check your email.
174 |
175 | Go to the next step once you've accepted your invite.
176 |
177 |
178 | {console.log(index++)}
179 | >
180 | )}
181 |
182 |
183 |
191 |
192 | Now go to{' '}
193 |
194 | https://github.com/hackclub/dinosaurs
195 | {' '}
196 | and click “star”. This bookmarks the repository in GitHub.
197 |
198 | Afterwards, tab back to this page to continue.
199 |
200 |
201 | {console.log(index++)}
202 |
203 |
204 |
212 | Find and click the dropdown “Branch: main ▼”.
213 |
214 | Type in {getName()}
215 |
216 | Click “Create branch: {getName()}”
217 |
218 |
219 | {console.log(index++)}
220 |
221 |
222 |
230 | Click “Add file” and add your dino image
231 |
232 | Below “Commit changes”, type this into the first text box:
233 | Add {getFilename()}
234 |
235 |
236 | Then click{' '}
237 | COMMIT CHANGES
238 |
239 |
240 | Warning:{' '}
241 | Do not {' '}
242 | click the green button that says "Create pull request" just yet–
243 | we'll get there in a couple more steps.
244 |
245 |
246 |
247 | {console.log(index++)}
248 |
249 |
250 |
258 | Scroll through the list of files & find “README.md”.
259 |
260 | To edit the file, click it & click the {' '}
261 | icon.
262 |
263 |
264 |
265 | {console.log(index++)}
266 |
267 |
268 |
276 | Add the following lines to the bottom of the file:
277 |
278 | "{getName()}"
279 |
280 |
281 | })
282 |
283 |
284 | Below “Commit changes”, type{' '}
285 | Add {getName()} to README in the first text
286 | box
287 |
288 |
289 | Then click{' '}
290 | COMMIT CHANGES
291 |
292 |
293 |
294 | {console.log(index++)}
295 |
296 |
297 |
305 |
306 | Go back to{' '}
307 |
308 | https://github.com/hackclub/dinosaurs
309 | {' '}
310 | and click{' '}
311 |
312 | Compare & pull request
313 |
314 | .
315 |
316 |
317 | {' '}
318 | Then click{' '}
319 |
320 | Create pull request
321 |
322 |
323 |
324 |
325 | {console.log(index++)}
326 |
327 | {/*
328 |
329 |
334 |
335 | */}
336 | {/* console.log(index++) */}
337 |
338 |
339 |
340 |
341 | >
342 | )
343 | }
344 |
--------------------------------------------------------------------------------
/pages/slackAuthSuccess.js:
--------------------------------------------------------------------------------
1 | import Meta from '../components/meta'
2 |
3 | export default () => {
4 | if (process.browser) {
5 | window.close()
6 | }
7 | return (
8 | <>
9 |
10 |
11 | Success! Once you submit your pull request you'll automatically have
12 | access to the badge on Slack.
13 |
14 |
15 | Now close this window and return to the workshop...
16 |
17 | >
18 | )
19 | }
20 |
--------------------------------------------------------------------------------
/public/FileSaver.js:
--------------------------------------------------------------------------------
1 | (function (global, factory) {
2 | if (typeof define === "function" && define.amd) {
3 | define([], factory);
4 | } else if (typeof exports !== "undefined") {
5 | factory();
6 | } else {
7 | var mod = {
8 | exports: {}
9 | };
10 | factory();
11 | global.FileSaver = mod.exports;
12 | }
13 | })(this, function () {
14 | "use strict";
15 |
16 | /*
17 | * FileSaver.js
18 | * A saveAs() FileSaver implementation.
19 | *
20 | * By Eli Grey, http://eligrey.com
21 | *
22 | * License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT)
23 | * source : http://purl.eligrey.com/github/FileSaver.js
24 | */
25 | // The one and only way of getting global scope in all environments
26 | // https://stackoverflow.com/q/3277182/1008999
27 | var _global = typeof window === 'object' && window.window === window ? window : typeof self === 'object' && self.self === self ? self : typeof global === 'object' && global.global === global ? global : void 0;
28 |
29 | function bom(blob, opts) {
30 | if (typeof opts === 'undefined') opts = {
31 | autoBom: false
32 | };else if (typeof opts !== 'object') {
33 | console.warn('Deprecated: Expected third argument to be a object');
34 | opts = {
35 | autoBom: !opts
36 | };
37 | } // prepend BOM for UTF-8 XML and text/* types (including HTML)
38 | // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
39 |
40 | if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
41 | return new Blob([String.fromCharCode(0xFEFF), blob], {
42 | type: blob.type
43 | });
44 | }
45 |
46 | return blob;
47 | }
48 |
49 | function download(url, name, opts) {
50 | var xhr = new XMLHttpRequest();
51 | xhr.open('GET', url);
52 | xhr.responseType = 'blob';
53 |
54 | xhr.onload = function () {
55 | saveAs(xhr.response, name, opts);
56 | };
57 | xhr.onerror = function() {
58 | throw Error("could not download file");
59 | }
60 | xhr.send();
61 | }
62 |
63 | function corsEnabled(url) {
64 | var xhr = new XMLHttpRequest(); // use sync to avoid popup blocker
65 |
66 | xhr.open('HEAD', url, false);
67 |
68 | try {
69 | xhr.send();
70 | } catch (e) {}
71 |
72 | return xhr.status >= 200 && xhr.status <= 299;
73 | } // `a.click()` doesn't work for all browsers (#465)
74 |
75 |
76 | function click(node) {
77 | try {
78 | node.dispatchEvent(new MouseEvent('click'));
79 | } catch (e) {
80 | var evt = document.createEvent('MouseEvents');
81 | evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null);
82 | node.dispatchEvent(evt);
83 | }
84 | }
85 |
86 | var saveAs = _global.saveAs || ( // probably in some web worker
87 | typeof window !== 'object' || window !== _global ? function saveAs() {}
88 | /* noop */
89 | // Use download attribute first if possible (#193 Lumia mobile)
90 | : 'download' in HTMLAnchorElement.prototype ? function saveAs(blob, name, opts) {
91 | var URL = _global.URL || _global.webkitURL;
92 | var a = document.createElement('a');
93 | name = name || blob.name || 'download';
94 | a.download = name;
95 | a.rel = 'noopener'; // tabnabbing
96 | // TODO: detect chrome extensions & packaged apps
97 | // a.target = '_blank'
98 |
99 | if (typeof blob === 'string') {
100 | // Support regular links
101 | a.href = blob;
102 |
103 | if (a.origin !== location.origin) {
104 | corsEnabled(a.href) ? download(blob, name, opts) : click(a, a.target = '_blank');
105 | } else {
106 | click(a);
107 | }
108 | } else {
109 | // Support blobs
110 | a.href = URL.createObjectURL(blob);
111 | setTimeout(function () {
112 | URL.revokeObjectURL(a.href);
113 | }, 4E4); // 40s
114 |
115 | setTimeout(function () {
116 | click(a);
117 | }, 0);
118 | }
119 | } // Use msSaveOrOpenBlob as a second approach
120 | : 'msSaveOrOpenBlob' in navigator ? function saveAs(blob, name, opts) {
121 | name = name || blob.name || 'download';
122 |
123 | if (typeof blob === 'string') {
124 | if (corsEnabled(blob)) {
125 | download(blob, name, opts);
126 | } else {
127 | var a = document.createElement('a');
128 | a.href = blob;
129 | a.target = '_blank';
130 | setTimeout(function () {
131 | click(a);
132 | });
133 | }
134 | } else {
135 | navigator.msSaveOrOpenBlob(bom(blob, opts), name);
136 | }
137 | } // Fallback to using FileReader and a popup
138 | : function saveAs(blob, name, opts, popup) {
139 | // Open a popup immediately do go around popup blocker
140 | // Mostly only available on user interaction and the fileReader is async so...
141 | popup = popup || open('', '_blank');
142 |
143 | if (popup) {
144 | popup.document.title = popup.document.body.innerText = 'downloading...';
145 | }
146 |
147 | if (typeof blob === 'string') return download(blob, name, opts);
148 | var force = blob.type === 'application/octet-stream';
149 |
150 | var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari;
151 |
152 | var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent);
153 |
154 | if ((isChromeIOS || force && isSafari) && typeof FileReader !== 'undefined') {
155 | // Safari doesn't allow downloading of blob URLs
156 | var reader = new FileReader();
157 |
158 | reader.onloadend = function () {
159 | var url = reader.result;
160 | url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;');
161 | if (popup) popup.location.href = url;else location = url;
162 | popup = null; // reverse-tabnabbing #460
163 | };
164 |
165 | reader.readAsDataURL(blob);
166 | } else {
167 | var URL = _global.URL || _global.webkitURL;
168 | var url = URL.createObjectURL(blob);
169 | if (popup) popup.location = url;else location.href = url;
170 | popup = null; // reverse-tabnabbing #460
171 |
172 | setTimeout(function () {
173 | URL.revokeObjectURL(url);
174 | }, 4E4); // 40s
175 | }
176 | });
177 | _global.saveAs = saveAs.saveAs = saveAs;
178 |
179 | if (typeof module !== 'undefined') {
180 | module.exports = saveAs;
181 | }
182 | });
183 |
--------------------------------------------------------------------------------
/public/back-black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/back-black.png
--------------------------------------------------------------------------------
/public/back-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/back-white.png
--------------------------------------------------------------------------------
/public/canvas-toBlob.js:
--------------------------------------------------------------------------------
1 | /* canvas-toBlob.js
2 | * A canvas.toBlob() implementation.
3 | * 2016-05-26
4 | *
5 | * By Eli Grey, http://eligrey.com and Devin Samarin, https://github.com/eboyjr
6 | * License: MIT
7 | * See https://github.com/eligrey/canvas-toBlob.js/blob/master/LICENSE.md
8 | */
9 |
10 | /*global self */
11 | /*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
12 | plusplus: true */
13 |
14 | /*! @source http://purl.eligrey.com/github/canvas-toBlob.js/blob/master/canvas-toBlob.js */
15 |
16 | (function(view) {
17 | "use strict";
18 | var
19 | Uint8Array = view.Uint8Array
20 | , HTMLCanvasElement = view.HTMLCanvasElement
21 | , canvas_proto = HTMLCanvasElement && HTMLCanvasElement.prototype
22 | , is_base64_regex = /\s*;\s*base64\s*(?:;|$)/i
23 | , to_data_url = "toDataURL"
24 | , base64_ranks
25 | , decode_base64 = function(base64) {
26 | var
27 | len = base64.length
28 | , buffer = new Uint8Array(len / 4 * 3 | 0)
29 | , i = 0
30 | , outptr = 0
31 | , last = [0, 0]
32 | , state = 0
33 | , save = 0
34 | , rank
35 | , code
36 | , undef
37 | ;
38 | while (len--) {
39 | code = base64.charCodeAt(i++);
40 | rank = base64_ranks[code-43];
41 | if (rank !== 255 && rank !== undef) {
42 | last[1] = last[0];
43 | last[0] = code;
44 | save = (save << 6) | rank;
45 | state++;
46 | if (state === 4) {
47 | buffer[outptr++] = save >>> 16;
48 | if (last[1] !== 61 /* padding character */) {
49 | buffer[outptr++] = save >>> 8;
50 | }
51 | if (last[0] !== 61 /* padding character */) {
52 | buffer[outptr++] = save;
53 | }
54 | state = 0;
55 | }
56 | }
57 | }
58 | // 2/3 chance there's going to be some null bytes at the end, but that
59 | // doesn't really matter with most image formats.
60 | // If it somehow matters for you, truncate the buffer up outptr.
61 | return buffer;
62 | }
63 | ;
64 | if (Uint8Array) {
65 | base64_ranks = new Uint8Array([
66 | 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1
67 | , -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
68 | , 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
69 | , -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35
70 | , 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
71 | ]);
72 | }
73 | if (HTMLCanvasElement && (!canvas_proto.toBlob || !canvas_proto.toBlobHD)) {
74 | if (!canvas_proto.toBlob)
75 | canvas_proto.toBlob = function(callback, type /*, ...args*/) {
76 | if (!type) {
77 | type = "image/png";
78 | } if (this.mozGetAsFile) {
79 | callback(this.mozGetAsFile("canvas", type));
80 | return;
81 | } if (this.msToBlob && /^\s*image\/png\s*(?:$|;)/i.test(type)) {
82 | callback(this.msToBlob());
83 | return;
84 | }
85 |
86 | var
87 | args = Array.prototype.slice.call(arguments, 1)
88 | , dataURI = this[to_data_url].apply(this, args)
89 | , header_end = dataURI.indexOf(",")
90 | , data = dataURI.substring(header_end + 1)
91 | , is_base64 = is_base64_regex.test(dataURI.substring(0, header_end))
92 | , blob
93 | ;
94 | if (Blob.fake) {
95 | // no reason to decode a data: URI that's just going to become a data URI again
96 | blob = new Blob
97 | if (is_base64) {
98 | blob.encoding = "base64";
99 | } else {
100 | blob.encoding = "URI";
101 | }
102 | blob.data = data;
103 | blob.size = data.length;
104 | } else if (Uint8Array) {
105 | if (is_base64) {
106 | blob = new Blob([decode_base64(data)], {type: type});
107 | } else {
108 | blob = new Blob([decodeURIComponent(data)], {type: type});
109 | }
110 | }
111 | callback(blob);
112 | };
113 |
114 | if (!canvas_proto.toBlobHD && canvas_proto.toDataURLHD) {
115 | canvas_proto.toBlobHD = function() {
116 | to_data_url = "toDataURLHD";
117 | var blob = this.toBlob();
118 | to_data_url = "toDataURL";
119 | return blob;
120 | }
121 | } else {
122 | canvas_proto.toBlobHD = canvas_proto.toBlob;
123 | }
124 | }
125 | }(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this));
126 |
--------------------------------------------------------------------------------
/public/decorative-bottom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/decorative-bottom.png
--------------------------------------------------------------------------------
/public/decorative-corner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/decorative-corner.png
--------------------------------------------------------------------------------
/public/decorative-corner.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/dinoisseur.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/dinoisseur.png
--------------------------------------------------------------------------------
/public/down-black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/down-black.png
--------------------------------------------------------------------------------
/public/down-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/down-white.png
--------------------------------------------------------------------------------
/public/erase-button.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/erase-button.gif
--------------------------------------------------------------------------------
/public/excanvas.js:
--------------------------------------------------------------------------------
1 | // Copyright 2006 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 |
16 | // Known Issues:
17 | //
18 | // * Patterns only support repeat.
19 | // * Radial gradient are not implemented. The VML version of these look very
20 | // different from the canvas one.
21 | // * Clipping paths are not implemented.
22 | // * Coordsize. The width and height attribute have higher priority than the
23 | // width and height style values which isn't correct.
24 | // * Painting mode isn't implemented.
25 | // * Canvas width/height should is using content-box by default. IE in
26 | // Quirks mode will draw the canvas using border-box. Either change your
27 | // doctype to HTML5
28 | // (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
29 | // or use Box Sizing Behavior from WebFX
30 | // (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
31 | // * Non uniform scaling does not correctly scale strokes.
32 | // * Optimize. There is always room for speed improvements.
33 |
34 | // Only add this code if we do not already have a canvas implementation
35 | if (!document.createElement('canvas').getContext) {
36 |
37 | (function() {
38 |
39 | // alias some functions to make (compiled) code shorter
40 | var m = Math;
41 | var mr = m.round;
42 | var ms = m.sin;
43 | var mc = m.cos;
44 | var abs = m.abs;
45 | var sqrt = m.sqrt;
46 |
47 | // this is used for sub pixel precision
48 | var Z = 10;
49 | var Z2 = Z / 2;
50 |
51 | /**
52 | * This funtion is assigned to the elements as element.getContext().
53 | * @this {HTMLElement}
54 | * @return {CanvasRenderingContext2D_}
55 | */
56 | function getContext() {
57 | return this.context_ ||
58 | (this.context_ = new CanvasRenderingContext2D_(this));
59 | }
60 |
61 | var slice = Array.prototype.slice;
62 |
63 | /**
64 | * Binds a function to an object. The returned function will always use the
65 | * passed in {@code obj} as {@code this}.
66 | *
67 | * Example:
68 | *
69 | * g = bind(f, obj, a, b)
70 | * g(c, d) // will do f.call(obj, a, b, c, d)
71 | *
72 | * @param {Function} f The function to bind the object to
73 | * @param {Object} obj The object that should act as this when the function
74 | * is called
75 | * @param {*} var_args Rest arguments that will be used as the initial
76 | * arguments when the function is called
77 | * @return {Function} A new function that has bound this
78 | */
79 | function bind(f, obj, var_args) {
80 | var a = slice.call(arguments, 2);
81 | return function() {
82 | return f.apply(obj, a.concat(slice.call(arguments)));
83 | };
84 | }
85 |
86 | function encodeHtmlAttribute(s) {
87 | return String(s).replace(/&/g, '&').replace(/"/g, '"');
88 | }
89 |
90 | function addNamespace(doc, prefix, urn) {
91 | if (!doc.namespaces[prefix]) {
92 | doc.namespaces.add(prefix, urn, '#default#VML');
93 | }
94 | }
95 |
96 | function addNamespacesAndStylesheet(doc) {
97 | addNamespace(doc, 'g_vml_', 'urn:schemas-microsoft-com:vml');
98 | addNamespace(doc, 'g_o_', 'urn:schemas-microsoft-com:office:office');
99 |
100 | // Setup default CSS. Only add one style sheet per document
101 | if (!doc.styleSheets['ex_canvas_']) {
102 | var ss = doc.createStyleSheet();
103 | ss.owningElement.id = 'ex_canvas_';
104 | ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
105 | // default size is 300x150 in Gecko and Opera
106 | 'text-align:left;width:300px;height:150px}';
107 | }
108 | }
109 |
110 | // Add namespaces and stylesheet at startup.
111 | addNamespacesAndStylesheet(document);
112 |
113 | var G_vmlCanvasManager_ = {
114 | init: function(opt_doc) {
115 | var doc = opt_doc || document;
116 | // Create a dummy element so that IE will allow canvas elements to be
117 | // recognized.
118 | doc.createElement('canvas');
119 | doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
120 | },
121 |
122 | init_: function(doc) {
123 | // find all canvas elements
124 | var els = doc.getElementsByTagName('canvas');
125 | for (var i = 0; i < els.length; i++) {
126 | this.initElement(els[i]);
127 | }
128 | },
129 |
130 | /**
131 | * Public initializes a canvas element so that it can be used as canvas
132 | * element from now on. This is called automatically before the page is
133 | * loaded but if you are creating elements using createElement you need to
134 | * make sure this is called on the element.
135 | * @param {HTMLElement} el The canvas element to initialize.
136 | * @return {HTMLElement} the element that was created.
137 | */
138 | initElement: function(el) {
139 | if (!el.getContext) {
140 | el.getContext = getContext;
141 |
142 | // Add namespaces and stylesheet to document of the element.
143 | addNamespacesAndStylesheet(el.ownerDocument);
144 |
145 | // Remove fallback content. There is no way to hide text nodes so we
146 | // just remove all childNodes. We could hide all elements and remove
147 | // text nodes but who really cares about the fallback content.
148 | el.innerHTML = '';
149 |
150 | // do not use inline function because that will leak memory
151 | el.attachEvent('onpropertychange', onPropertyChange);
152 | el.attachEvent('onresize', onResize);
153 |
154 | var attrs = el.attributes;
155 | if (attrs.width && attrs.width.specified) {
156 | // TODO: use runtimeStyle and coordsize
157 | // el.getContext().setWidth_(attrs.width.nodeValue);
158 | el.style.width = attrs.width.nodeValue + 'px';
159 | } else {
160 | el.width = el.clientWidth;
161 | }
162 | if (attrs.height && attrs.height.specified) {
163 | // TODO: use runtimeStyle and coordsize
164 | // el.getContext().setHeight_(attrs.height.nodeValue);
165 | el.style.height = attrs.height.nodeValue + 'px';
166 | } else {
167 | el.height = el.clientHeight;
168 | }
169 | //el.getContext().setCoordsize_()
170 | }
171 | return el;
172 | }
173 | };
174 |
175 | function onPropertyChange(e) {
176 | var el = e.srcElement;
177 |
178 | switch (e.propertyName) {
179 | case 'width':
180 | el.getContext().clearRect();
181 | el.style.width = el.attributes.width.nodeValue + 'px';
182 | // In IE8 this does not trigger onresize.
183 | el.firstChild.style.width = el.clientWidth + 'px';
184 | break;
185 | case 'height':
186 | el.getContext().clearRect();
187 | el.style.height = el.attributes.height.nodeValue + 'px';
188 | el.firstChild.style.height = el.clientHeight + 'px';
189 | break;
190 | }
191 | }
192 |
193 | function onResize(e) {
194 | var el = e.srcElement;
195 | if (el.firstChild) {
196 | el.firstChild.style.width = el.clientWidth + 'px';
197 | el.firstChild.style.height = el.clientHeight + 'px';
198 | }
199 | }
200 |
201 | G_vmlCanvasManager_.init();
202 |
203 | // precompute "00" to "FF"
204 | var decToHex = [];
205 | for (var i = 0; i < 16; i++) {
206 | for (var j = 0; j < 16; j++) {
207 | decToHex[i * 16 + j] = i.toString(16) + j.toString(16);
208 | }
209 | }
210 |
211 | function createMatrixIdentity() {
212 | return [
213 | [1, 0, 0],
214 | [0, 1, 0],
215 | [0, 0, 1]
216 | ];
217 | }
218 |
219 | function matrixMultiply(m1, m2) {
220 | var result = createMatrixIdentity();
221 |
222 | for (var x = 0; x < 3; x++) {
223 | for (var y = 0; y < 3; y++) {
224 | var sum = 0;
225 |
226 | for (var z = 0; z < 3; z++) {
227 | sum += m1[x][z] * m2[z][y];
228 | }
229 |
230 | result[x][y] = sum;
231 | }
232 | }
233 | return result;
234 | }
235 |
236 | function copyState(o1, o2) {
237 | o2.fillStyle = o1.fillStyle;
238 | o2.lineCap = o1.lineCap;
239 | o2.lineJoin = o1.lineJoin;
240 | o2.lineWidth = o1.lineWidth;
241 | o2.miterLimit = o1.miterLimit;
242 | o2.shadowBlur = o1.shadowBlur;
243 | o2.shadowColor = o1.shadowColor;
244 | o2.shadowOffsetX = o1.shadowOffsetX;
245 | o2.shadowOffsetY = o1.shadowOffsetY;
246 | o2.strokeStyle = o1.strokeStyle;
247 | o2.globalAlpha = o1.globalAlpha;
248 | o2.font = o1.font;
249 | o2.textAlign = o1.textAlign;
250 | o2.textBaseline = o1.textBaseline;
251 | o2.arcScaleX_ = o1.arcScaleX_;
252 | o2.arcScaleY_ = o1.arcScaleY_;
253 | o2.lineScale_ = o1.lineScale_;
254 | }
255 |
256 | var colorData = {
257 | aliceblue: '#F0F8FF',
258 | antiquewhite: '#FAEBD7',
259 | aquamarine: '#7FFFD4',
260 | azure: '#F0FFFF',
261 | beige: '#F5F5DC',
262 | bisque: '#FFE4C4',
263 | black: '#000000',
264 | blanchedalmond: '#FFEBCD',
265 | blueviolet: '#8A2BE2',
266 | brown: '#A52A2A',
267 | burlywood: '#DEB887',
268 | cadetblue: '#5F9EA0',
269 | chartreuse: '#7FFF00',
270 | chocolate: '#D2691E',
271 | coral: '#FF7F50',
272 | cornflowerblue: '#6495ED',
273 | cornsilk: '#FFF8DC',
274 | crimson: '#DC143C',
275 | cyan: '#00FFFF',
276 | darkblue: '#00008B',
277 | darkcyan: '#008B8B',
278 | darkgoldenrod: '#B8860B',
279 | darkgray: '#A9A9A9',
280 | darkgreen: '#006400',
281 | darkgrey: '#A9A9A9',
282 | darkkhaki: '#BDB76B',
283 | darkmagenta: '#8B008B',
284 | darkolivegreen: '#556B2F',
285 | darkorange: '#FF8C00',
286 | darkorchid: '#9932CC',
287 | darkred: '#8B0000',
288 | darksalmon: '#E9967A',
289 | darkseagreen: '#8FBC8F',
290 | darkslateblue: '#483D8B',
291 | darkslategray: '#2F4F4F',
292 | darkslategrey: '#2F4F4F',
293 | darkturquoise: '#00CED1',
294 | darkviolet: '#9400D3',
295 | deeppink: '#FF1493',
296 | deepskyblue: '#00BFFF',
297 | dimgray: '#696969',
298 | dimgrey: '#696969',
299 | dodgerblue: '#1E90FF',
300 | firebrick: '#B22222',
301 | floralwhite: '#FFFAF0',
302 | forestgreen: '#228B22',
303 | gainsboro: '#DCDCDC',
304 | ghostwhite: '#F8F8FF',
305 | gold: '#FFD700',
306 | goldenrod: '#DAA520',
307 | grey: '#808080',
308 | greenyellow: '#ADFF2F',
309 | honeydew: '#F0FFF0',
310 | hotpink: '#FF69B4',
311 | indianred: '#CD5C5C',
312 | indigo: '#4B0082',
313 | ivory: '#FFFFF0',
314 | khaki: '#F0E68C',
315 | lavender: '#E6E6FA',
316 | lavenderblush: '#FFF0F5',
317 | lawngreen: '#7CFC00',
318 | lemonchiffon: '#FFFACD',
319 | lightblue: '#ADD8E6',
320 | lightcoral: '#F08080',
321 | lightcyan: '#E0FFFF',
322 | lightgoldenrodyellow: '#FAFAD2',
323 | lightgreen: '#90EE90',
324 | lightgrey: '#D3D3D3',
325 | lightpink: '#FFB6C1',
326 | lightsalmon: '#FFA07A',
327 | lightseagreen: '#20B2AA',
328 | lightskyblue: '#87CEFA',
329 | lightslategray: '#778899',
330 | lightslategrey: '#778899',
331 | lightsteelblue: '#B0C4DE',
332 | lightyellow: '#FFFFE0',
333 | limegreen: '#32CD32',
334 | linen: '#FAF0E6',
335 | magenta: '#FF00FF',
336 | mediumaquamarine: '#66CDAA',
337 | mediumblue: '#0000CD',
338 | mediumorchid: '#BA55D3',
339 | mediumpurple: '#9370DB',
340 | mediumseagreen: '#3CB371',
341 | mediumslateblue: '#7B68EE',
342 | mediumspringgreen: '#00FA9A',
343 | mediumturquoise: '#48D1CC',
344 | mediumvioletred: '#C71585',
345 | midnightblue: '#191970',
346 | mintcream: '#F5FFFA',
347 | mistyrose: '#FFE4E1',
348 | moccasin: '#FFE4B5',
349 | navajowhite: '#FFDEAD',
350 | oldlace: '#FDF5E6',
351 | olivedrab: '#6B8E23',
352 | orange: '#FFA500',
353 | orangered: '#FF4500',
354 | orchid: '#DA70D6',
355 | palegoldenrod: '#EEE8AA',
356 | palegreen: '#98FB98',
357 | paleturquoise: '#AFEEEE',
358 | palevioletred: '#DB7093',
359 | papayawhip: '#FFEFD5',
360 | peachpuff: '#FFDAB9',
361 | peru: '#CD853F',
362 | pink: '#FFC0CB',
363 | plum: '#DDA0DD',
364 | powderblue: '#B0E0E6',
365 | rosybrown: '#BC8F8F',
366 | royalblue: '#4169E1',
367 | saddlebrown: '#8B4513',
368 | salmon: '#FA8072',
369 | sandybrown: '#F4A460',
370 | seagreen: '#2E8B57',
371 | seashell: '#FFF5EE',
372 | sienna: '#A0522D',
373 | skyblue: '#87CEEB',
374 | slateblue: '#6A5ACD',
375 | slategray: '#708090',
376 | slategrey: '#708090',
377 | snow: '#FFFAFA',
378 | springgreen: '#00FF7F',
379 | steelblue: '#4682B4',
380 | tan: '#D2B48C',
381 | thistle: '#D8BFD8',
382 | tomato: '#FF6347',
383 | turquoise: '#40E0D0',
384 | violet: '#EE82EE',
385 | wheat: '#F5DEB3',
386 | whitesmoke: '#F5F5F5',
387 | yellowgreen: '#9ACD32'
388 | };
389 |
390 |
391 | function getRgbHslContent(styleString) {
392 | var start = styleString.indexOf('(', 3);
393 | var end = styleString.indexOf(')', start + 1);
394 | var parts = styleString.substring(start + 1, end).split(',');
395 | // add alpha if needed
396 | if (parts.length != 4 || styleString.charAt(3) != 'a') {
397 | parts[3] = 1;
398 | }
399 | return parts;
400 | }
401 |
402 | function percent(s) {
403 | return parseFloat(s) / 100;
404 | }
405 |
406 | function clamp(v, min, max) {
407 | return Math.min(max, Math.max(min, v));
408 | }
409 |
410 | function hslToRgb(parts){
411 | var r, g, b, h, s, l;
412 | h = parseFloat(parts[0]) / 360 % 360;
413 | if (h < 0)
414 | h++;
415 | s = clamp(percent(parts[1]), 0, 1);
416 | l = clamp(percent(parts[2]), 0, 1);
417 | if (s == 0) {
418 | r = g = b = l; // achromatic
419 | } else {
420 | var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
421 | var p = 2 * l - q;
422 | r = hueToRgb(p, q, h + 1 / 3);
423 | g = hueToRgb(p, q, h);
424 | b = hueToRgb(p, q, h - 1 / 3);
425 | }
426 |
427 | return '#' + decToHex[Math.floor(r * 255)] +
428 | decToHex[Math.floor(g * 255)] +
429 | decToHex[Math.floor(b * 255)];
430 | }
431 |
432 | function hueToRgb(m1, m2, h) {
433 | if (h < 0)
434 | h++;
435 | if (h > 1)
436 | h--;
437 |
438 | if (6 * h < 1)
439 | return m1 + (m2 - m1) * 6 * h;
440 | else if (2 * h < 1)
441 | return m2;
442 | else if (3 * h < 2)
443 | return m1 + (m2 - m1) * (2 / 3 - h) * 6;
444 | else
445 | return m1;
446 | }
447 |
448 | var processStyleCache = {};
449 |
450 | function processStyle(styleString) {
451 | if (styleString in processStyleCache) {
452 | return processStyleCache[styleString];
453 | }
454 |
455 | var str, alpha = 1;
456 |
457 | styleString = String(styleString);
458 | if (styleString.charAt(0) == '#') {
459 | str = styleString;
460 | } else if (/^rgb/.test(styleString)) {
461 | var parts = getRgbHslContent(styleString);
462 | var str = '#', n;
463 | for (var i = 0; i < 3; i++) {
464 | if (parts[i].indexOf('%') != -1) {
465 | n = Math.floor(percent(parts[i]) * 255);
466 | } else {
467 | n = +parts[i];
468 | }
469 | str += decToHex[clamp(n, 0, 255)];
470 | }
471 | alpha = +parts[3];
472 | } else if (/^hsl/.test(styleString)) {
473 | var parts = getRgbHslContent(styleString);
474 | str = hslToRgb(parts);
475 | alpha = parts[3];
476 | } else {
477 | str = colorData[styleString] || styleString;
478 | }
479 | return processStyleCache[styleString] = {color: str, alpha: alpha};
480 | }
481 |
482 | var DEFAULT_STYLE = {
483 | style: 'normal',
484 | variant: 'normal',
485 | weight: 'normal',
486 | size: 10,
487 | family: 'sans-serif'
488 | };
489 |
490 | // Internal text style cache
491 | var fontStyleCache = {};
492 |
493 | function processFontStyle(styleString) {
494 | if (fontStyleCache[styleString]) {
495 | return fontStyleCache[styleString];
496 | }
497 |
498 | var el = document.createElement('div');
499 | var style = el.style;
500 | try {
501 | style.font = styleString;
502 | } catch (ex) {
503 | // Ignore failures to set to invalid font.
504 | }
505 |
506 | return fontStyleCache[styleString] = {
507 | style: style.fontStyle || DEFAULT_STYLE.style,
508 | variant: style.fontVariant || DEFAULT_STYLE.variant,
509 | weight: style.fontWeight || DEFAULT_STYLE.weight,
510 | size: style.fontSize || DEFAULT_STYLE.size,
511 | family: style.fontFamily || DEFAULT_STYLE.family
512 | };
513 | }
514 |
515 | function getComputedStyle(style, element) {
516 | var computedStyle = {};
517 |
518 | for (var p in style) {
519 | computedStyle[p] = style[p];
520 | }
521 |
522 | // Compute the size
523 | var canvasFontSize = parseFloat(element.currentStyle.fontSize),
524 | fontSize = parseFloat(style.size);
525 |
526 | if (typeof style.size == 'number') {
527 | computedStyle.size = style.size;
528 | } else if (style.size.indexOf('px') != -1) {
529 | computedStyle.size = fontSize;
530 | } else if (style.size.indexOf('em') != -1) {
531 | computedStyle.size = canvasFontSize * fontSize;
532 | } else if(style.size.indexOf('%') != -1) {
533 | computedStyle.size = (canvasFontSize / 100) * fontSize;
534 | } else if (style.size.indexOf('pt') != -1) {
535 | computedStyle.size = fontSize / .75;
536 | } else {
537 | computedStyle.size = canvasFontSize;
538 | }
539 |
540 | // Different scaling between normal text and VML text. This was found using
541 | // trial and error to get the same size as non VML text.
542 | computedStyle.size *= 0.981;
543 |
544 | return computedStyle;
545 | }
546 |
547 | function buildStyle(style) {
548 | return style.style + ' ' + style.variant + ' ' + style.weight + ' ' +
549 | style.size + 'px ' + style.family;
550 | }
551 |
552 | var lineCapMap = {
553 | 'butt': 'flat',
554 | 'round': 'round'
555 | };
556 |
557 | function processLineCap(lineCap) {
558 | return lineCapMap[lineCap] || 'square';
559 | }
560 |
561 | /**
562 | * This class implements CanvasRenderingContext2D interface as described by
563 | * the WHATWG.
564 | * @param {HTMLElement} canvasElement The element that the 2D context should
565 | * be associated with
566 | */
567 | function CanvasRenderingContext2D_(canvasElement) {
568 | this.m_ = createMatrixIdentity();
569 |
570 | this.mStack_ = [];
571 | this.aStack_ = [];
572 | this.currentPath_ = [];
573 |
574 | // Canvas context properties
575 | this.strokeStyle = '#000';
576 | this.fillStyle = '#000';
577 |
578 | this.lineWidth = 1;
579 | this.lineJoin = 'miter';
580 | this.lineCap = 'butt';
581 | this.miterLimit = Z * 1;
582 | this.globalAlpha = 1;
583 | this.font = '10px sans-serif';
584 | this.textAlign = 'left';
585 | this.textBaseline = 'alphabetic';
586 | this.canvas = canvasElement;
587 |
588 | var cssText = 'width:' + canvasElement.clientWidth + 'px;height:' +
589 | canvasElement.clientHeight + 'px;overflow:hidden;position:absolute';
590 | var el = canvasElement.ownerDocument.createElement('div');
591 | el.style.cssText = cssText;
592 | canvasElement.appendChild(el);
593 |
594 | var overlayEl = el.cloneNode(false);
595 | // Use a non transparent background.
596 | overlayEl.style.backgroundColor = 'red';
597 | overlayEl.style.filter = 'alpha(opacity=0)';
598 | canvasElement.appendChild(overlayEl);
599 |
600 | this.element_ = el;
601 | this.arcScaleX_ = 1;
602 | this.arcScaleY_ = 1;
603 | this.lineScale_ = 1;
604 | }
605 |
606 | var contextPrototype = CanvasRenderingContext2D_.prototype;
607 | contextPrototype.clearRect = function() {
608 | if (this.textMeasureEl_) {
609 | this.textMeasureEl_.removeNode(true);
610 | this.textMeasureEl_ = null;
611 | }
612 | this.element_.innerHTML = '';
613 | };
614 |
615 | contextPrototype.beginPath = function() {
616 | // TODO: Branch current matrix so that save/restore has no effect
617 | // as per safari docs.
618 | this.currentPath_ = [];
619 | };
620 |
621 | contextPrototype.moveTo = function(aX, aY) {
622 | var p = getCoords(this, aX, aY);
623 | this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
624 | this.currentX_ = p.x;
625 | this.currentY_ = p.y;
626 | };
627 |
628 | contextPrototype.lineTo = function(aX, aY) {
629 | var p = getCoords(this, aX, aY);
630 | this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
631 |
632 | this.currentX_ = p.x;
633 | this.currentY_ = p.y;
634 | };
635 |
636 | contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
637 | aCP2x, aCP2y,
638 | aX, aY) {
639 | var p = getCoords(this, aX, aY);
640 | var cp1 = getCoords(this, aCP1x, aCP1y);
641 | var cp2 = getCoords(this, aCP2x, aCP2y);
642 | bezierCurveTo(this, cp1, cp2, p);
643 | };
644 |
645 | // Helper function that takes the already fixed cordinates.
646 | function bezierCurveTo(self, cp1, cp2, p) {
647 | self.currentPath_.push({
648 | type: 'bezierCurveTo',
649 | cp1x: cp1.x,
650 | cp1y: cp1.y,
651 | cp2x: cp2.x,
652 | cp2y: cp2.y,
653 | x: p.x,
654 | y: p.y
655 | });
656 | self.currentX_ = p.x;
657 | self.currentY_ = p.y;
658 | }
659 |
660 | contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
661 | // the following is lifted almost directly from
662 | // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
663 |
664 | var cp = getCoords(this, aCPx, aCPy);
665 | var p = getCoords(this, aX, aY);
666 |
667 | var cp1 = {
668 | x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
669 | y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
670 | };
671 | var cp2 = {
672 | x: cp1.x + (p.x - this.currentX_) / 3.0,
673 | y: cp1.y + (p.y - this.currentY_) / 3.0
674 | };
675 |
676 | bezierCurveTo(this, cp1, cp2, p);
677 | };
678 |
679 | contextPrototype.arc = function(aX, aY, aRadius,
680 | aStartAngle, aEndAngle, aClockwise) {
681 | aRadius *= Z;
682 | var arcType = aClockwise ? 'at' : 'wa';
683 |
684 | var xStart = aX + mc(aStartAngle) * aRadius - Z2;
685 | var yStart = aY + ms(aStartAngle) * aRadius - Z2;
686 |
687 | var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
688 | var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
689 |
690 | // IE won't render arches drawn counter clockwise if xStart == xEnd.
691 | if (xStart == xEnd && !aClockwise) {
692 | xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
693 | // that can be represented in binary
694 | }
695 |
696 | var p = getCoords(this, aX, aY);
697 | var pStart = getCoords(this, xStart, yStart);
698 | var pEnd = getCoords(this, xEnd, yEnd);
699 |
700 | this.currentPath_.push({type: arcType,
701 | x: p.x,
702 | y: p.y,
703 | radius: aRadius,
704 | xStart: pStart.x,
705 | yStart: pStart.y,
706 | xEnd: pEnd.x,
707 | yEnd: pEnd.y});
708 |
709 | };
710 |
711 | contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
712 | this.moveTo(aX, aY);
713 | this.lineTo(aX + aWidth, aY);
714 | this.lineTo(aX + aWidth, aY + aHeight);
715 | this.lineTo(aX, aY + aHeight);
716 | this.closePath();
717 | };
718 |
719 | contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
720 | var oldPath = this.currentPath_;
721 | this.beginPath();
722 |
723 | this.moveTo(aX, aY);
724 | this.lineTo(aX + aWidth, aY);
725 | this.lineTo(aX + aWidth, aY + aHeight);
726 | this.lineTo(aX, aY + aHeight);
727 | this.closePath();
728 | this.stroke();
729 |
730 | this.currentPath_ = oldPath;
731 | };
732 |
733 | contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
734 | var oldPath = this.currentPath_;
735 | this.beginPath();
736 |
737 | this.moveTo(aX, aY);
738 | this.lineTo(aX + aWidth, aY);
739 | this.lineTo(aX + aWidth, aY + aHeight);
740 | this.lineTo(aX, aY + aHeight);
741 | this.closePath();
742 | this.fill();
743 |
744 | this.currentPath_ = oldPath;
745 | };
746 |
747 | contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
748 | var gradient = new CanvasGradient_('gradient');
749 | gradient.x0_ = aX0;
750 | gradient.y0_ = aY0;
751 | gradient.x1_ = aX1;
752 | gradient.y1_ = aY1;
753 | return gradient;
754 | };
755 |
756 | contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
757 | aX1, aY1, aR1) {
758 | var gradient = new CanvasGradient_('gradientradial');
759 | gradient.x0_ = aX0;
760 | gradient.y0_ = aY0;
761 | gradient.r0_ = aR0;
762 | gradient.x1_ = aX1;
763 | gradient.y1_ = aY1;
764 | gradient.r1_ = aR1;
765 | return gradient;
766 | };
767 |
768 | contextPrototype.drawImage = function(image, var_args) {
769 | var dx, dy, dw, dh, sx, sy, sw, sh;
770 |
771 | // to find the original width we overide the width and height
772 | var oldRuntimeWidth = image.runtimeStyle.width;
773 | var oldRuntimeHeight = image.runtimeStyle.height;
774 | image.runtimeStyle.width = 'auto';
775 | image.runtimeStyle.height = 'auto';
776 |
777 | // get the original size
778 | var w = image.width;
779 | var h = image.height;
780 |
781 | // and remove overides
782 | image.runtimeStyle.width = oldRuntimeWidth;
783 | image.runtimeStyle.height = oldRuntimeHeight;
784 |
785 | if (arguments.length == 3) {
786 | dx = arguments[1];
787 | dy = arguments[2];
788 | sx = sy = 0;
789 | sw = dw = w;
790 | sh = dh = h;
791 | } else if (arguments.length == 5) {
792 | dx = arguments[1];
793 | dy = arguments[2];
794 | dw = arguments[3];
795 | dh = arguments[4];
796 | sx = sy = 0;
797 | sw = w;
798 | sh = h;
799 | } else if (arguments.length == 9) {
800 | sx = arguments[1];
801 | sy = arguments[2];
802 | sw = arguments[3];
803 | sh = arguments[4];
804 | dx = arguments[5];
805 | dy = arguments[6];
806 | dw = arguments[7];
807 | dh = arguments[8];
808 | } else {
809 | throw Error('Invalid number of arguments');
810 | }
811 |
812 | var d = getCoords(this, dx, dy);
813 |
814 | var w2 = sw / 2;
815 | var h2 = sh / 2;
816 |
817 | var vmlStr = [];
818 |
819 | var W = 10;
820 | var H = 10;
821 |
822 | // For some reason that I've now forgotten, using divs didn't work
823 | vmlStr.push(' ' ,
864 | ' ',
872 | ' ');
873 |
874 | this.element_.insertAdjacentHTML('BeforeEnd', vmlStr.join(''));
875 | };
876 |
877 | contextPrototype.stroke = function(aFill) {
878 | var lineStr = [];
879 | var lineOpen = false;
880 |
881 | var W = 10;
882 | var H = 10;
883 |
884 | lineStr.push('');
952 |
953 | if (!aFill) {
954 | appendStroke(this, lineStr);
955 | } else {
956 | appendFill(this, lineStr, min, max);
957 | }
958 |
959 | lineStr.push(' ');
960 |
961 | this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
962 | };
963 |
964 | function appendStroke(ctx, lineStr) {
965 | var a = processStyle(ctx.strokeStyle);
966 | var color = a.color;
967 | var opacity = a.alpha * ctx.globalAlpha;
968 | var lineWidth = ctx.lineScale_ * ctx.lineWidth;
969 |
970 | // VML cannot correctly render a line if the width is less than 1px.
971 | // In that case, we dilute the color to make the line look thinner.
972 | if (lineWidth < 1) {
973 | opacity *= lineWidth;
974 | }
975 |
976 | lineStr.push(
977 | ' '
984 | );
985 | }
986 |
987 | function appendFill(ctx, lineStr, min, max) {
988 | var fillStyle = ctx.fillStyle;
989 | var arcScaleX = ctx.arcScaleX_;
990 | var arcScaleY = ctx.arcScaleY_;
991 | var width = max.x - min.x;
992 | var height = max.y - min.y;
993 | if (fillStyle instanceof CanvasGradient_) {
994 | // TODO: Gradients transformed with the transformation matrix.
995 | var angle = 0;
996 | var focus = {x: 0, y: 0};
997 |
998 | // additional offset
999 | var shift = 0;
1000 | // scale factor for offset
1001 | var expansion = 1;
1002 |
1003 | if (fillStyle.type_ == 'gradient') {
1004 | var x0 = fillStyle.x0_ / arcScaleX;
1005 | var y0 = fillStyle.y0_ / arcScaleY;
1006 | var x1 = fillStyle.x1_ / arcScaleX;
1007 | var y1 = fillStyle.y1_ / arcScaleY;
1008 | var p0 = getCoords(ctx, x0, y0);
1009 | var p1 = getCoords(ctx, x1, y1);
1010 | var dx = p1.x - p0.x;
1011 | var dy = p1.y - p0.y;
1012 | angle = Math.atan2(dx, dy) * 180 / Math.PI;
1013 |
1014 | // The angle should be a non-negative number.
1015 | if (angle < 0) {
1016 | angle += 360;
1017 | }
1018 |
1019 | // Very small angles produce an unexpected result because they are
1020 | // converted to a scientific notation string.
1021 | if (angle < 1e-6) {
1022 | angle = 0;
1023 | }
1024 | } else {
1025 | var p0 = getCoords(ctx, fillStyle.x0_, fillStyle.y0_);
1026 | focus = {
1027 | x: (p0.x - min.x) / width,
1028 | y: (p0.y - min.y) / height
1029 | };
1030 |
1031 | width /= arcScaleX * Z;
1032 | height /= arcScaleY * Z;
1033 | var dimension = m.max(width, height);
1034 | shift = 2 * fillStyle.r0_ / dimension;
1035 | expansion = 2 * fillStyle.r1_ / dimension - shift;
1036 | }
1037 |
1038 | // We need to sort the color stops in ascending order by offset,
1039 | // otherwise IE won't interpret it correctly.
1040 | var stops = fillStyle.colors_;
1041 | stops.sort(function(cs1, cs2) {
1042 | return cs1.offset - cs2.offset;
1043 | });
1044 |
1045 | var length = stops.length;
1046 | var color1 = stops[0].color;
1047 | var color2 = stops[length - 1].color;
1048 | var opacity1 = stops[0].alpha * ctx.globalAlpha;
1049 | var opacity2 = stops[length - 1].alpha * ctx.globalAlpha;
1050 |
1051 | var colors = [];
1052 | for (var i = 0; i < length; i++) {
1053 | var stop = stops[i];
1054 | colors.push(stop.offset * expansion + shift + ' ' + stop.color);
1055 | }
1056 |
1057 | // When colors attribute is used, the meanings of opacity and o:opacity2
1058 | // are reversed.
1059 | lineStr.push(' ');
1068 | } else if (fillStyle instanceof CanvasPattern_) {
1069 | if (width && height) {
1070 | var deltaLeft = -min.x;
1071 | var deltaTop = -min.y;
1072 | lineStr.push(' ');
1080 | }
1081 | } else {
1082 | var a = processStyle(ctx.fillStyle);
1083 | var color = a.color;
1084 | var opacity = a.alpha * ctx.globalAlpha;
1085 | lineStr.push(' ');
1087 | }
1088 | }
1089 |
1090 | contextPrototype.fill = function() {
1091 | this.stroke(true);
1092 | };
1093 |
1094 | contextPrototype.closePath = function() {
1095 | this.currentPath_.push({type: 'close'});
1096 | };
1097 |
1098 | function getCoords(ctx, aX, aY) {
1099 | var m = ctx.m_;
1100 | return {
1101 | x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
1102 | y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
1103 | };
1104 | };
1105 |
1106 | contextPrototype.save = function() {
1107 | var o = {};
1108 | copyState(this, o);
1109 | this.aStack_.push(o);
1110 | this.mStack_.push(this.m_);
1111 | this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
1112 | };
1113 |
1114 | contextPrototype.restore = function() {
1115 | if (this.aStack_.length) {
1116 | copyState(this.aStack_.pop(), this);
1117 | this.m_ = this.mStack_.pop();
1118 | }
1119 | };
1120 |
1121 | function matrixIsFinite(m) {
1122 | return isFinite(m[0][0]) && isFinite(m[0][1]) &&
1123 | isFinite(m[1][0]) && isFinite(m[1][1]) &&
1124 | isFinite(m[2][0]) && isFinite(m[2][1]);
1125 | }
1126 |
1127 | function setM(ctx, m, updateLineScale) {
1128 | if (!matrixIsFinite(m)) {
1129 | return;
1130 | }
1131 | ctx.m_ = m;
1132 |
1133 | if (updateLineScale) {
1134 | // Get the line scale.
1135 | // Determinant of this.m_ means how much the area is enlarged by the
1136 | // transformation. So its square root can be used as a scale factor
1137 | // for width.
1138 | var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
1139 | ctx.lineScale_ = sqrt(abs(det));
1140 | }
1141 | }
1142 |
1143 | contextPrototype.translate = function(aX, aY) {
1144 | var m1 = [
1145 | [1, 0, 0],
1146 | [0, 1, 0],
1147 | [aX, aY, 1]
1148 | ];
1149 |
1150 | setM(this, matrixMultiply(m1, this.m_), false);
1151 | };
1152 |
1153 | contextPrototype.rotate = function(aRot) {
1154 | var c = mc(aRot);
1155 | var s = ms(aRot);
1156 |
1157 | var m1 = [
1158 | [c, s, 0],
1159 | [-s, c, 0],
1160 | [0, 0, 1]
1161 | ];
1162 |
1163 | setM(this, matrixMultiply(m1, this.m_), false);
1164 | };
1165 |
1166 | contextPrototype.scale = function(aX, aY) {
1167 | this.arcScaleX_ *= aX;
1168 | this.arcScaleY_ *= aY;
1169 | var m1 = [
1170 | [aX, 0, 0],
1171 | [0, aY, 0],
1172 | [0, 0, 1]
1173 | ];
1174 |
1175 | setM(this, matrixMultiply(m1, this.m_), true);
1176 | };
1177 |
1178 | contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
1179 | var m1 = [
1180 | [m11, m12, 0],
1181 | [m21, m22, 0],
1182 | [dx, dy, 1]
1183 | ];
1184 |
1185 | setM(this, matrixMultiply(m1, this.m_), true);
1186 | };
1187 |
1188 | contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
1189 | var m = [
1190 | [m11, m12, 0],
1191 | [m21, m22, 0],
1192 | [dx, dy, 1]
1193 | ];
1194 |
1195 | setM(this, m, true);
1196 | };
1197 |
1198 | /**
1199 | * The text drawing function.
1200 | * The maxWidth argument isn't taken in account, since no browser supports
1201 | * it yet.
1202 | */
1203 | contextPrototype.drawText_ = function(text, x, y, maxWidth, stroke) {
1204 | var m = this.m_,
1205 | delta = 1000,
1206 | left = 0,
1207 | right = delta,
1208 | offset = {x: 0, y: 0},
1209 | lineStr = [];
1210 |
1211 | var fontStyle = getComputedStyle(processFontStyle(this.font),
1212 | this.element_);
1213 |
1214 | var fontStyleString = buildStyle(fontStyle);
1215 |
1216 | var elementStyle = this.element_.currentStyle;
1217 | var textAlign = this.textAlign.toLowerCase();
1218 | switch (textAlign) {
1219 | case 'left':
1220 | case 'center':
1221 | case 'right':
1222 | break;
1223 | case 'end':
1224 | textAlign = elementStyle.direction == 'ltr' ? 'right' : 'left';
1225 | break;
1226 | case 'start':
1227 | textAlign = elementStyle.direction == 'rtl' ? 'right' : 'left';
1228 | break;
1229 | default:
1230 | textAlign = 'left';
1231 | }
1232 |
1233 | // 1.75 is an arbitrary number, as there is no info about the text baseline
1234 | switch (this.textBaseline) {
1235 | case 'hanging':
1236 | case 'top':
1237 | offset.y = fontStyle.size / 1.75;
1238 | break;
1239 | case 'middle':
1240 | break;
1241 | default:
1242 | case null:
1243 | case 'alphabetic':
1244 | case 'ideographic':
1245 | case 'bottom':
1246 | offset.y = -fontStyle.size / 2.25;
1247 | break;
1248 | }
1249 |
1250 | switch(textAlign) {
1251 | case 'right':
1252 | left = delta;
1253 | right = 0.05;
1254 | break;
1255 | case 'center':
1256 | left = right = delta / 2;
1257 | break;
1258 | }
1259 |
1260 | var d = getCoords(this, x + offset.x, y + offset.y);
1261 |
1262 | lineStr.push('');
1266 |
1267 | if (stroke) {
1268 | appendStroke(this, lineStr);
1269 | } else {
1270 | // TODO: Fix the min and max params.
1271 | appendFill(this, lineStr, {x: -left, y: 0},
1272 | {x: right, y: fontStyle.size});
1273 | }
1274 |
1275 | var skewM = m[0][0].toFixed(3) + ',' + m[1][0].toFixed(3) + ',' +
1276 | m[0][1].toFixed(3) + ',' + m[1][1].toFixed(3) + ',0,0';
1277 |
1278 | var skewOffset = mr(d.x / Z) + ',' + mr(d.y / Z);
1279 |
1280 | lineStr.push(' ',
1282 | ' ',
1283 | ' ');
1288 |
1289 | this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
1290 | };
1291 |
1292 | contextPrototype.fillText = function(text, x, y, maxWidth) {
1293 | this.drawText_(text, x, y, maxWidth, false);
1294 | };
1295 |
1296 | contextPrototype.strokeText = function(text, x, y, maxWidth) {
1297 | this.drawText_(text, x, y, maxWidth, true);
1298 | };
1299 |
1300 | contextPrototype.measureText = function(text) {
1301 | if (!this.textMeasureEl_) {
1302 | var s = ' ';
1305 | this.element_.insertAdjacentHTML('beforeEnd', s);
1306 | this.textMeasureEl_ = this.element_.lastChild;
1307 | }
1308 | var doc = this.element_.ownerDocument;
1309 | this.textMeasureEl_.innerHTML = '';
1310 | this.textMeasureEl_.style.font = this.font;
1311 | // Don't use innerHTML or innerText because they allow markup/whitespace.
1312 | this.textMeasureEl_.appendChild(doc.createTextNode(text));
1313 | return {width: this.textMeasureEl_.offsetWidth};
1314 | };
1315 |
1316 | /******** STUBS ********/
1317 | contextPrototype.clip = function() {
1318 | // TODO: Implement
1319 | };
1320 |
1321 | contextPrototype.arcTo = function() {
1322 | // TODO: Implement
1323 | };
1324 |
1325 | contextPrototype.createPattern = function(image, repetition) {
1326 | return new CanvasPattern_(image, repetition);
1327 | };
1328 |
1329 | // Gradient / Pattern Stubs
1330 | function CanvasGradient_(aType) {
1331 | this.type_ = aType;
1332 | this.x0_ = 0;
1333 | this.y0_ = 0;
1334 | this.r0_ = 0;
1335 | this.x1_ = 0;
1336 | this.y1_ = 0;
1337 | this.r1_ = 0;
1338 | this.colors_ = [];
1339 | }
1340 |
1341 | CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
1342 | aColor = processStyle(aColor);
1343 | this.colors_.push({offset: aOffset,
1344 | color: aColor.color,
1345 | alpha: aColor.alpha});
1346 | };
1347 |
1348 | function CanvasPattern_(image, repetition) {
1349 | assertImageIsValid(image);
1350 | switch (repetition) {
1351 | case 'repeat':
1352 | case null:
1353 | case '':
1354 | this.repetition_ = 'repeat';
1355 | break
1356 | case 'repeat-x':
1357 | case 'repeat-y':
1358 | case 'no-repeat':
1359 | this.repetition_ = repetition;
1360 | break;
1361 | default:
1362 | throwException('SYNTAX_ERR');
1363 | }
1364 |
1365 | this.src_ = image.src;
1366 | this.width_ = image.width;
1367 | this.height_ = image.height;
1368 | }
1369 |
1370 | function throwException(s) {
1371 | throw new DOMException_(s);
1372 | }
1373 |
1374 | function assertImageIsValid(img) {
1375 | if (!img || img.nodeType != 1 || img.tagName != 'IMG') {
1376 | throwException('TYPE_MISMATCH_ERR');
1377 | }
1378 | if (img.readyState != 'complete') {
1379 | throwException('INVALID_STATE_ERR');
1380 | }
1381 | }
1382 |
1383 | function DOMException_(s) {
1384 | this.code = this[s];
1385 | this.message = s +': DOM Exception ' + this.code;
1386 | }
1387 | var p = DOMException_.prototype = new Error;
1388 | p.INDEX_SIZE_ERR = 1;
1389 | p.DOMSTRING_SIZE_ERR = 2;
1390 | p.HIERARCHY_REQUEST_ERR = 3;
1391 | p.WRONG_DOCUMENT_ERR = 4;
1392 | p.INVALID_CHARACTER_ERR = 5;
1393 | p.NO_DATA_ALLOWED_ERR = 6;
1394 | p.NO_MODIFICATION_ALLOWED_ERR = 7;
1395 | p.NOT_FOUND_ERR = 8;
1396 | p.NOT_SUPPORTED_ERR = 9;
1397 | p.INUSE_ATTRIBUTE_ERR = 10;
1398 | p.INVALID_STATE_ERR = 11;
1399 | p.SYNTAX_ERR = 12;
1400 | p.INVALID_MODIFICATION_ERR = 13;
1401 | p.NAMESPACE_ERR = 14;
1402 | p.INVALID_ACCESS_ERR = 15;
1403 | p.VALIDATION_ERR = 16;
1404 | p.TYPE_MISMATCH_ERR = 17;
1405 |
1406 | // set up externs
1407 | G_vmlCanvasManager = G_vmlCanvasManager_;
1408 | CanvasRenderingContext2D = CanvasRenderingContext2D_;
1409 | CanvasGradient = CanvasGradient_;
1410 | CanvasPattern = CanvasPattern_;
1411 | DOMException = DOMException_;
1412 | })();
1413 |
1414 | } // if
1415 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/favicon.ico
--------------------------------------------------------------------------------
/public/fonts/PhantomSans0.6-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/fonts/PhantomSans0.6-Bold.ttf
--------------------------------------------------------------------------------
/public/fonts/PhantomSans0.6-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/fonts/PhantomSans0.6-Bold.woff
--------------------------------------------------------------------------------
/public/fonts/PhantomSans0.6-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/fonts/PhantomSans0.6-Bold.woff2
--------------------------------------------------------------------------------
/public/fonts/PhantomSans0.6-Book.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/fonts/PhantomSans0.6-Book.ttf
--------------------------------------------------------------------------------
/public/fonts/PhantomSans0.6-Book.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/fonts/PhantomSans0.6-Book.woff
--------------------------------------------------------------------------------
/public/fonts/PhantomSans0.6-Book.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/fonts/PhantomSans0.6-Book.woff2
--------------------------------------------------------------------------------
/public/fonts/PhantomSans0.6-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/fonts/PhantomSans0.6-Italic.ttf
--------------------------------------------------------------------------------
/public/fonts/PhantomSans0.6-Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/fonts/PhantomSans0.6-Italic.woff
--------------------------------------------------------------------------------
/public/fonts/PhantomSans0.6-Italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/fonts/PhantomSans0.6-Italic.woff2
--------------------------------------------------------------------------------
/public/fonts/PhantomSans0.6-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/fonts/PhantomSans0.6-Medium.ttf
--------------------------------------------------------------------------------
/public/fonts/PhantomSans0.6-Medium.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/fonts/PhantomSans0.6-Medium.woff
--------------------------------------------------------------------------------
/public/fonts/PhantomSans0.6-Medium.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/fonts/PhantomSans0.6-Medium.woff2
--------------------------------------------------------------------------------
/public/fonts/PhantomSans0.6-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/fonts/PhantomSans0.6-Regular.ttf
--------------------------------------------------------------------------------
/public/fonts/PhantomSans0.6-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/fonts/PhantomSans0.6-Regular.woff
--------------------------------------------------------------------------------
/public/fonts/PhantomSans0.6-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/fonts/PhantomSans0.6-Regular.woff2
--------------------------------------------------------------------------------
/public/fonts/PhantomSans0.6-Semibold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/fonts/PhantomSans0.6-Semibold.ttf
--------------------------------------------------------------------------------
/public/fonts/PhantomSans0.6-Semibold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/fonts/PhantomSans0.6-Semibold.woff
--------------------------------------------------------------------------------
/public/fonts/PhantomSans0.6-Semibold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/fonts/PhantomSans0.6-Semibold.woff2
--------------------------------------------------------------------------------
/public/github-edit.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/public/github.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/public/grain.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/grain.jpg
--------------------------------------------------------------------------------
/public/next-black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/next-black.png
--------------------------------------------------------------------------------
/public/next-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/next-white.png
--------------------------------------------------------------------------------
/public/portrait-decoration.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/public/save-button.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/save-button.gif
--------------------------------------------------------------------------------
/public/sketch.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Draw your dino. Hover over any tool for more info and example usage.
13 |
14 | ✏️ Draw thin
15 | 🖌 Draw thick
16 | 🦕 Hide / Show template
17 | ⏪Undo
18 | ⏩Redo
19 | 💄 Eraser tool
20 | 💾 Save masterpiece
21 |
22 |
23 |
24 |
25 |
31 |
32 |
--------------------------------------------------------------------------------
/public/sketch.js:
--------------------------------------------------------------------------------
1 | async function sendMetric(type, key, value) {
2 | const response = await fetch("/api/metric", {
3 | method: "POST",
4 | headers: {
5 | "Content-Type": "application/json",
6 | },
7 | body: JSON.stringify({ type, key, value })
8 | });
9 | if (!response.ok) {
10 | throw Error("Failed to send metric");
11 | }
12 | }
13 |
14 | // Customization
15 | const scaling = 3
16 | const canvasWidth = 256
17 | const canvasHeight = 256
18 | const drawColor = 'black'
19 | const backgroundColor = 'white'
20 | const thinSize = 2
21 | const thickSize = 4
22 |
23 | var clicks = []
24 | var templateVisibility = true
25 | var size = thinSize
26 | var color = drawColor
27 | var unsavedChanges = false
28 | var paint
29 |
30 | // Initialization
31 | const canvasDiv = document.querySelector('#canvasDiv')
32 | canvas = document.createElement('canvas')
33 | canvas.setAttribute('width', canvasWidth)
34 | canvas.setAttribute('height', canvasHeight)
35 | canvas.setAttribute('id', 'canvas')
36 | const pixelation = 'image-rendering: crisp-edges; image-rendering: pixelated;'
37 | const borders = 'border: 1px solid black;'
38 | canvas.setAttribute('style', `${pixelation} ${borders} width: ${canvasWidth * scaling}px; height: ${canvasHeight * scaling}px;`)
39 | canvasDiv.appendChild(canvas)
40 | if (typeof G_vmlCanvasManager != 'undefined') {
41 | canvas = G_vmlCanvasManager.initElement(canvas)
42 | }
43 | context = canvas.getContext('2d')
44 | const templateImage = new Image()
45 | templateImage.src = 'template.jpg'
46 | templateImage.addEventListener('load', e => {
47 | redraw()
48 | })
49 |
50 | // Buttons & tools
51 | document.querySelector('#thickButton').addEventListener('click', e => {
52 | size = thickSize
53 | color = drawColor
54 | })
55 | document.querySelector('#thinButton').addEventListener('click', e => {
56 | size = thinSize
57 | color = drawColor
58 | })
59 | document.querySelector('#eraseButton').addEventListener('click', e => {
60 | color = backgroundColor
61 | })
62 | document.querySelector('#templateButton').addEventListener('click', e => {
63 | templateVisibility = !templateVisibility
64 | redraw()
65 | })
66 | function undo() {
67 | const doneClicks = clicks.filter(click => !click.undone)
68 | if (doneClicks.length > 0) {
69 | doneClicks[doneClicks.length - 1].undone = true
70 | redraw()
71 | }
72 | }
73 | document.querySelector('#undoButton').addEventListener('click', e => {
74 | undo()
75 | })
76 | function redo() {
77 | const recentUndoneClick = clicks.find(click => click.undone)
78 | if (recentUndoneClick) {
79 | recentUndoneClick.undone = false
80 | redraw()
81 | }
82 | }
83 | document.querySelector('#redoButton').addEventListener('click', e => {
84 | redo()
85 | })
86 | document.querySelector('#saveButton').addEventListener('click', e => {
87 | const filename = prompt("Name your dino drawing", "dino")
88 |
89 | const urlParams = {}
90 | window.location.search.replace('?', '').split('&').forEach(kvString => {
91 | const [key, value] = kvString.split('=')
92 | urlParams[key] = value
93 | })
94 | const filePrefix = urlParams['filePrefix']
95 |
96 | if (filename) {
97 | canvas.toBlob(blob => {
98 | let safeFileName = `${filePrefix}-${filename}`.replace(/[^\w+]/g, '_')
99 |
100 | try{
101 | saveAs(blob, safeFileName + '.png')
102 | sendMetric("increment", "success.save_drawing", 1);
103 | unsavedChanges = false
104 | } catch (e) {
105 | console.log(e.message);
106 | sendMetric("increment", "errors.save_drawing", 1);
107 | }
108 |
109 | // If this is running as an embed, send the file off to the parent window
110 | if (window.parent) {
111 | window.parent.postMessage({filename: safeFileName + '.png', blob}, "*")
112 | }
113 | })
114 | }
115 | })
116 |
117 | document.addEventListener('keypress', e => {
118 | if ((e.ctrlKey || e.metaKey) && e.key === 'z') {
119 | e.preventDefault()
120 |
121 | undo()
122 | }
123 | if ((e.ctrlKey || e.metaKey) && e.key === 'y') {
124 | e.preventDefault()
125 |
126 | redo()
127 | }
128 | })
129 |
130 | // double check with user before closing the page
131 | window.addEventListener('beforeunload', e => {
132 | if (unsavedChanges) {
133 | e.returnValue = 'You have unsaved changes that will be lost.';
134 | }
135 | });
136 |
137 | // sketching
138 | function addClick(x, y, dragging) {
139 | if (dragging) {
140 | // get the last click and add the coordinate
141 | const lastClick = clicks[clicks.length - 1]
142 | lastClick.points.push({x, y})
143 | } else {
144 | // when we start clicking, we'll delete the "undone" history for good
145 | clicks = clicks.filter(click => !click.undone)
146 | // create a new click
147 | clicks.push({size, color, points: [ {x, y} ]})
148 | }
149 | }
150 |
151 | function redraw() {
152 | context.fillStyle = backgroundColor
153 | context.fillRect(0, 0, context.canvas.width, context.canvas.height)
154 |
155 | if (templateVisibility) {
156 | context.drawImage(templateImage, context.canvas.width / 5, context.canvas.height / 5, context.canvas.width * 3 / 5, context.canvas.height * 3 / 5)
157 | }
158 |
159 | context.strokeStyle = drawColor
160 |
161 | clicks.filter(clicks => !clicks.undone).forEach(click => {
162 | context.beginPath()
163 | for (let i = 0; i < click.points.length; i++) {
164 | context.beginPath()
165 | let point = click.points[i]
166 | let prevPoint = click.points[i - 1]
167 | if (prevPoint) {
168 | context.moveTo(prevPoint.x, prevPoint.y)
169 | } else {
170 | context.moveTo(point.x - 1, point.y)
171 | }
172 | context.lineTo(point.x, point.y)
173 | context.closePath()
174 | context.strokeStyle = click.color
175 | context.lineWidth = click.size
176 | context.stroke()
177 | }
178 | })
179 | }
180 |
181 | function clickStart(event) {
182 | event.preventDefault()
183 | unsavedChanges = true
184 | mouseX = (event.pageX - canvas.offsetLeft) / scaling
185 | mouseY = (event.pageY - canvas.offsetTop) / scaling
186 | addClick(mouseX, mouseY, false)
187 | paint = true
188 | redraw()
189 | }
190 |
191 | canvas.addEventListener('mousedown', e => {
192 | clickStart(e)
193 | })
194 | canvas.addEventListener('touchstart', e => {
195 | clickStart(e)
196 | })
197 |
198 | function clickDrag(event) {
199 | event.preventDefault()
200 | if (paint) {
201 | mouseX = (event.pageX - canvas.offsetLeft) / scaling
202 | mouseY = (event.pageY - canvas.offsetTop) / scaling
203 | addClick(mouseX, mouseY, true)
204 | redraw()
205 | }
206 | }
207 | canvas.addEventListener('mousemove', e => {
208 | clickDrag(e)
209 | })
210 | canvas.addEventListener('touchmove', e => {
211 | clickDrag(e)
212 | })
213 |
214 | function clickStop() {
215 | paint = false
216 | }
217 | canvas.addEventListener('mouseup', e => {
218 | clickStop()
219 | })
220 | canvas.addEventListener('mouseleave', e => {
221 | clickStop()
222 | })
223 | canvas.addEventListener('touchstop', e => {
224 | clickStop()
225 | })
226 | canvas.addEventListener('touchcancel', e => {
227 | clickStop()
228 | })
229 |
230 | // tooltips
231 | function genTooltip(id, image, description='') {
232 | tippy(`#${id}`, {
233 | content: `${description}
`,
234 | delay: [500, 0],
235 | followCursor: 'horizontal',
236 | placement: 'bottom'
237 | })
238 | }
239 | genTooltip('thinButton', 'thin-button.gif', 'Draw a thin black line')
240 | genTooltip('thickButton', 'thick-button.gif', 'Draw a thick black line')
241 | genTooltip('templateButton', 'template-button.gif', 'Show a dino outline you can use as a starting point. You can toggle it on and off anytime.')
242 | genTooltip('eraseButton', 'erase-button.gif', 'Draw with a white marker to erase mistakes or cut out black parts of an image. Also covers the dino template.')
243 | genTooltip('saveButton', 'save-button.gif', 'Saves the drawing to your computer. Automatically adds a file extension. This will not save your dino on this website.')
244 |
--------------------------------------------------------------------------------
/public/slack.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/steps/create-pr.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/steps/create-pr.gif
--------------------------------------------------------------------------------
/public/steps/create-pr.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/steps/create-pr.mp4
--------------------------------------------------------------------------------
/public/steps/dino-wallpaper.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/steps/dino-wallpaper.jpg
--------------------------------------------------------------------------------
/public/steps/drawing-dino.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/steps/drawing-dino.gif
--------------------------------------------------------------------------------
/public/steps/drawing-dino.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/steps/drawing-dino.png
--------------------------------------------------------------------------------
/public/steps/edit-readme.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/steps/edit-readme.gif
--------------------------------------------------------------------------------
/public/steps/edit-readme.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/steps/edit-readme.mp4
--------------------------------------------------------------------------------
/public/steps/motivational-dino.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/steps/motivational-dino.png
--------------------------------------------------------------------------------
/public/steps/new-branch.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/steps/new-branch.gif
--------------------------------------------------------------------------------
/public/steps/new-branch.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/steps/new-branch.mp4
--------------------------------------------------------------------------------
/public/steps/star.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/steps/star.gif
--------------------------------------------------------------------------------
/public/steps/star.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/steps/star.mp4
--------------------------------------------------------------------------------
/public/steps/start-editing-readme.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/steps/start-editing-readme.gif
--------------------------------------------------------------------------------
/public/steps/start-editing-readme.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/steps/start-editing-readme.mp4
--------------------------------------------------------------------------------
/public/steps/upload.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/steps/upload.gif
--------------------------------------------------------------------------------
/public/steps/upload.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/steps/upload.mp4
--------------------------------------------------------------------------------
/public/template-button.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/template-button.gif
--------------------------------------------------------------------------------
/public/template.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/template.jpg
--------------------------------------------------------------------------------
/public/thick-button.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/thick-button.gif
--------------------------------------------------------------------------------
/public/thin-button.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/public/thin-button.gif
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackclub/draw-dino/bf6878eb9e2dce56410a3af6a3d6bd128a1eacd6/screenshot.png
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@next/env@14.1.1":
6 | version "14.1.1"
7 | resolved "https://registry.yarnpkg.com/@next/env/-/env-14.1.1.tgz#80150a8440eb0022a73ba353c6088d419b908bac"
8 | integrity sha512-7CnQyD5G8shHxQIIg3c7/pSeYFeMhsNbpU/bmvH7ZnDql7mNRgg8O2JZrhrc/soFnfBnKP4/xXNiiSIPn2w8gA==
9 |
10 | "@next/swc-darwin-arm64@14.1.1":
11 | version "14.1.1"
12 | resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.1.1.tgz#b74ba7c14af7d05fa2848bdeb8ee87716c939b64"
13 | integrity sha512-yDjSFKQKTIjyT7cFv+DqQfW5jsD+tVxXTckSe1KIouKk75t1qZmj/mV3wzdmFb0XHVGtyRjDMulfVG8uCKemOQ==
14 |
15 | "@next/swc-darwin-x64@14.1.1":
16 | version "14.1.1"
17 | resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.1.tgz#82c3e67775e40094c66e76845d1a36cc29c9e78b"
18 | integrity sha512-KCQmBL0CmFmN8D64FHIZVD9I4ugQsDBBEJKiblXGgwn7wBCSe8N4Dx47sdzl4JAg39IkSN5NNrr8AniXLMb3aw==
19 |
20 | "@next/swc-linux-arm64-gnu@14.1.1":
21 | version "14.1.1"
22 | resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.1.tgz#4f4134457b90adc5c3d167d07dfb713c632c0caa"
23 | integrity sha512-YDQfbWyW0JMKhJf/T4eyFr4b3tceTorQ5w2n7I0mNVTFOvu6CGEzfwT3RSAQGTi/FFMTFcuspPec/7dFHuP7Eg==
24 |
25 | "@next/swc-linux-arm64-musl@14.1.1":
26 | version "14.1.1"
27 | resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.1.tgz#594bedafaeba4a56db23a48ffed2cef7cd09c31a"
28 | integrity sha512-fiuN/OG6sNGRN/bRFxRvV5LyzLB8gaL8cbDH5o3mEiVwfcMzyE5T//ilMmaTrnA8HLMS6hoz4cHOu6Qcp9vxgQ==
29 |
30 | "@next/swc-linux-x64-gnu@14.1.1":
31 | version "14.1.1"
32 | resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.1.tgz#cb4e75f1ff2b9bcadf2a50684605928ddfc58528"
33 | integrity sha512-rv6AAdEXoezjbdfp3ouMuVqeLjE1Bin0AuE6qxE6V9g3Giz5/R3xpocHoAi7CufRR+lnkuUjRBn05SYJ83oKNQ==
34 |
35 | "@next/swc-linux-x64-musl@14.1.1":
36 | version "14.1.1"
37 | resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.1.tgz#15f26800df941b94d06327f674819ab64b272e25"
38 | integrity sha512-YAZLGsaNeChSrpz/G7MxO3TIBLaMN8QWMr3X8bt6rCvKovwU7GqQlDu99WdvF33kI8ZahvcdbFsy4jAFzFX7og==
39 |
40 | "@next/swc-win32-arm64-msvc@14.1.1":
41 | version "14.1.1"
42 | resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.1.tgz#060c134fa7fa843666e3e8574972b2b723773dd9"
43 | integrity sha512-1L4mUYPBMvVDMZg1inUYyPvFSduot0g73hgfD9CODgbr4xiTYe0VOMTZzaRqYJYBA9mana0x4eaAaypmWo1r5A==
44 |
45 | "@next/swc-win32-ia32-msvc@14.1.1":
46 | version "14.1.1"
47 | resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.1.tgz#5c06889352b1f77e3807834a0d0afd7e2d2d1da2"
48 | integrity sha512-jvIE9tsuj9vpbbXlR5YxrghRfMuG0Qm/nZ/1KDHc+y6FpnZ/apsgh+G6t15vefU0zp3WSpTMIdXRUsNl/7RSuw==
49 |
50 | "@next/swc-win32-x64-msvc@14.1.1":
51 | version "14.1.1"
52 | resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.1.tgz#d38c63a8f9b7f36c1470872797d3735b4a9c5c52"
53 | integrity sha512-S6K6EHDU5+1KrBDLko7/c1MNy/Ya73pIAmvKeFwsF4RmBFJSO7/7YeD4FnZ4iBdzE69PpQ4sOMU9ORKeNuxe8A==
54 |
55 | "@swc/helpers@0.5.2":
56 | version "0.5.2"
57 | resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.2.tgz#85ea0c76450b61ad7d10a37050289eded783c27d"
58 | integrity sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==
59 | dependencies:
60 | tslib "^2.4.0"
61 |
62 | busboy@1.6.0:
63 | version "1.6.0"
64 | resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
65 | integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==
66 | dependencies:
67 | streamsearch "^1.1.0"
68 |
69 | caniuse-lite@^1.0.30001579:
70 | version "1.0.30001589"
71 | resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001589.tgz#7ad6dba4c9bf6561aec8291976402339dc157dfb"
72 | integrity sha512-vNQWS6kI+q6sBlHbh71IIeC+sRwK2N3EDySc/updIGhIee2x5z00J4c1242/5/d6EpEMdOnk/m+6tuk4/tcsqg==
73 |
74 | client-only@0.0.1:
75 | version "0.0.1"
76 | resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1"
77 | integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==
78 |
79 | dotenv@^16.4.5:
80 | version "16.4.5"
81 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
82 | integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==
83 |
84 | graceful-fs@^4.2.11:
85 | version "4.2.11"
86 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
87 | integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
88 |
89 | "js-tokens@^3.0.0 || ^4.0.0":
90 | version "4.0.0"
91 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
92 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
93 |
94 | lodash.throttle@^4.1.1:
95 | version "4.1.1"
96 | resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
97 | integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=
98 |
99 | loose-envify@^1.1.0, loose-envify@^1.4.0:
100 | version "1.4.0"
101 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
102 | integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
103 | dependencies:
104 | js-tokens "^3.0.0 || ^4.0.0"
105 |
106 | nanoid@^3.3.6:
107 | version "3.3.7"
108 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
109 | integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
110 |
111 | next@^14.1.1:
112 | version "14.1.1"
113 | resolved "https://registry.yarnpkg.com/next/-/next-14.1.1.tgz#92bd603996c050422a738e90362dff758459a171"
114 | integrity sha512-McrGJqlGSHeaz2yTRPkEucxQKe5Zq7uPwyeHNmJaZNY4wx9E9QdxmTp310agFRoMuIYgQrCrT3petg13fSVOww==
115 | dependencies:
116 | "@next/env" "14.1.1"
117 | "@swc/helpers" "0.5.2"
118 | busboy "1.6.0"
119 | caniuse-lite "^1.0.30001579"
120 | graceful-fs "^4.2.11"
121 | postcss "8.4.31"
122 | styled-jsx "5.1.1"
123 | optionalDependencies:
124 | "@next/swc-darwin-arm64" "14.1.1"
125 | "@next/swc-darwin-x64" "14.1.1"
126 | "@next/swc-linux-arm64-gnu" "14.1.1"
127 | "@next/swc-linux-arm64-musl" "14.1.1"
128 | "@next/swc-linux-x64-gnu" "14.1.1"
129 | "@next/swc-linux-x64-musl" "14.1.1"
130 | "@next/swc-win32-arm64-msvc" "14.1.1"
131 | "@next/swc-win32-ia32-msvc" "14.1.1"
132 | "@next/swc-win32-x64-msvc" "14.1.1"
133 |
134 | node-statsd@^0.1.1:
135 | version "0.1.1"
136 | resolved "https://registry.yarnpkg.com/node-statsd/-/node-statsd-0.1.1.tgz#27a59348763d0af7a037ac2a031fef3f051013d3"
137 | integrity sha512-QDf6R8VXF56QVe1boek8an/Rb3rSNaxoFWb7Elpsv2m1+Noua1yy0F1FpKpK5VluF8oymWM4w764A4KsYL4pDg==
138 |
139 | object-assign@^4.1.1:
140 | version "4.1.1"
141 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
142 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
143 |
144 | picocolors@^1.0.0:
145 | version "1.0.0"
146 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
147 | integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
148 |
149 | postcss@8.4.31:
150 | version "8.4.31"
151 | resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d"
152 | integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==
153 | dependencies:
154 | nanoid "^3.3.6"
155 | picocolors "^1.0.0"
156 | source-map-js "^1.0.2"
157 |
158 | prop-types@^15.5.8, prop-types@^15.7.2:
159 | version "15.7.2"
160 | resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
161 | integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
162 | dependencies:
163 | loose-envify "^1.4.0"
164 | object-assign "^4.1.1"
165 | react-is "^16.8.1"
166 |
167 | react-dom@^18.2.0:
168 | version "18.2.0"
169 | resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
170 | integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
171 | dependencies:
172 | loose-envify "^1.1.0"
173 | scheduler "^0.23.0"
174 |
175 | react-input-autosize@^2.2.2:
176 | version "2.2.2"
177 | resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-2.2.2.tgz#fcaa7020568ec206bc04be36f4eb68e647c4d8c2"
178 | integrity sha512-jQJgYCA3S0j+cuOwzuCd1OjmBmnZLdqQdiLKRYrsMMzbjUrVDS5RvJUDwJqA7sKuksDuzFtm6hZGKFu7Mjk5aw==
179 | dependencies:
180 | prop-types "^15.5.8"
181 |
182 | react-is@^16.8.1:
183 | version "16.13.1"
184 | resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
185 | integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
186 |
187 | react-scroll@^1.8.1:
188 | version "1.8.1"
189 | resolved "https://registry.yarnpkg.com/react-scroll/-/react-scroll-1.8.1.tgz#eb4052265f1606cf60855c981ebcfed1bc3beff3"
190 | integrity sha512-UAKmawFHn+c7x/DoXuHqOsQ5xwNk2Dxv7vP8Ft41K2hglPWkshcSos0tMTr8704UkFqImoUGzMTdN4vuZXoqbw==
191 | dependencies:
192 | lodash.throttle "^4.1.1"
193 | prop-types "^15.7.2"
194 |
195 | react@^18.2.0:
196 | version "18.2.0"
197 | resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
198 | integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
199 | dependencies:
200 | loose-envify "^1.1.0"
201 |
202 | scheduler@^0.23.0:
203 | version "0.23.0"
204 | resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
205 | integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
206 | dependencies:
207 | loose-envify "^1.1.0"
208 |
209 | source-map-js@^1.0.2:
210 | version "1.0.2"
211 | resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
212 | integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
213 |
214 | streamsearch@^1.1.0:
215 | version "1.1.0"
216 | resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
217 | integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
218 |
219 | styled-jsx@5.1.1:
220 | version "5.1.1"
221 | resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.1.tgz#839a1c3aaacc4e735fed0781b8619ea5d0009d1f"
222 | integrity sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==
223 | dependencies:
224 | client-only "0.0.1"
225 |
226 | tslib@^2.4.0:
227 | version "2.6.2"
228 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
229 | integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
230 |
--------------------------------------------------------------------------------