├── .eslintignore
├── presentation
├── components
│ ├── SentimentPlot.jsx
│ ├── Number.css
│ ├── Name.css
│ ├── Site.css
│ ├── AmazonFace.css
│ ├── Number.jsx
│ ├── Title.css
│ ├── Title.jsx
│ ├── Name.jsx
│ ├── RacistDataExplain.jsx
│ ├── Site.jsx
│ ├── SentimentFood.jsx
│ ├── QuotePic.css
│ ├── AmazonFace.jsx
│ ├── SentimentNames.jsx
│ └── QuotePic.jsx
├── index.css
├── regular-component.js
├── assets.js
├── theme
│ └── index.js
├── slides.js
├── components.js
└── index.mdx
├── .gitignore
├── assets
├── aoc.jpg
├── food.gif
├── gerry.jpg
├── amazon1.png
├── amazon2.png
├── amazon3.png
├── amazon4.png
├── favicon.ico
├── saavedra.jpg
├── sent-food-1.png
├── sent-food-2.png
├── sent-food-3.png
├── sent-name-1.png
├── sent-name-2.png
├── sent-name-3.png
├── sent-name-4.png
├── indp-headline.png
└── names-boxplot.png
├── createTheme.js
├── .eslintrc
├── .babelrc
├── index.html
├── README.md
├── server.js
├── LICENSE
├── webpack.config.production.js
├── webpack.config.js
├── index.js
├── loader.js
└── package.json
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist/
2 |
--------------------------------------------------------------------------------
/presentation/components/SentimentPlot.jsx:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | npm-debug.log
4 | dist
5 |
--------------------------------------------------------------------------------
/presentation/components/Number.css:
--------------------------------------------------------------------------------
1 | .Number {
2 | border-radius: 50%;
3 | }
4 |
--------------------------------------------------------------------------------
/assets/aoc.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/racist-code-slides/master/assets/aoc.jpg
--------------------------------------------------------------------------------
/assets/food.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/racist-code-slides/master/assets/food.gif
--------------------------------------------------------------------------------
/assets/gerry.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/racist-code-slides/master/assets/gerry.jpg
--------------------------------------------------------------------------------
/assets/amazon1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/racist-code-slides/master/assets/amazon1.png
--------------------------------------------------------------------------------
/assets/amazon2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/racist-code-slides/master/assets/amazon2.png
--------------------------------------------------------------------------------
/assets/amazon3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/racist-code-slides/master/assets/amazon3.png
--------------------------------------------------------------------------------
/assets/amazon4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/racist-code-slides/master/assets/amazon4.png
--------------------------------------------------------------------------------
/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/racist-code-slides/master/assets/favicon.ico
--------------------------------------------------------------------------------
/assets/saavedra.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/racist-code-slides/master/assets/saavedra.jpg
--------------------------------------------------------------------------------
/assets/sent-food-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/racist-code-slides/master/assets/sent-food-1.png
--------------------------------------------------------------------------------
/assets/sent-food-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/racist-code-slides/master/assets/sent-food-2.png
--------------------------------------------------------------------------------
/assets/sent-food-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/racist-code-slides/master/assets/sent-food-3.png
--------------------------------------------------------------------------------
/assets/sent-name-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/racist-code-slides/master/assets/sent-name-1.png
--------------------------------------------------------------------------------
/assets/sent-name-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/racist-code-slides/master/assets/sent-name-2.png
--------------------------------------------------------------------------------
/assets/sent-name-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/racist-code-slides/master/assets/sent-name-3.png
--------------------------------------------------------------------------------
/assets/sent-name-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/racist-code-slides/master/assets/sent-name-4.png
--------------------------------------------------------------------------------
/assets/indp-headline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/racist-code-slides/master/assets/indp-headline.png
--------------------------------------------------------------------------------
/assets/names-boxplot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/racist-code-slides/master/assets/names-boxplot.png
--------------------------------------------------------------------------------
/presentation/components/Name.css:
--------------------------------------------------------------------------------
1 | .Name {
2 | margin-top: 2.5rem;
3 | text-align: right;
4 | font-size: 2.5rem;
5 | }
6 |
--------------------------------------------------------------------------------
/presentation/components/Site.css:
--------------------------------------------------------------------------------
1 | .Site {
2 | position: absolute;
3 | left: 1rem;
4 | bottom: 1rem;
5 | text-decoration: underline;
6 | }
7 |
--------------------------------------------------------------------------------
/presentation/components/AmazonFace.css:
--------------------------------------------------------------------------------
1 | .AmazonFace-imgcont{
2 | position:absolute;
3 | top:4rem;
4 | left:20%;
5 | margin:0 auto;
6 | }
7 |
--------------------------------------------------------------------------------
/presentation/index.css:
--------------------------------------------------------------------------------
1 | .react-live-dark pre.prism-code {
2 | background: black !important;
3 | }
4 |
5 | h1 {
6 | text-align: right;
7 | }
8 |
9 | .special {
10 | color: #f5ab35;
11 | }
12 |
--------------------------------------------------------------------------------
/presentation/components/Number.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import './Number.css'
3 |
4 | export default class Number extends React.Component {
5 | render() {
6 | const {number } = this.props;
7 | return (#{number} )
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/presentation/components/Title.css:
--------------------------------------------------------------------------------
1 | .Title {
2 | color: orange;
3 | position: absolute;
4 | left: 0;
5 | top: 0;
6 | margin-left: 1.5rem;
7 | margin-top: 1.5rem;
8 | font-size: 3rem;
9 | }
10 |
11 | .Title-text {
12 | color: white;
13 | margin-left: 2rem;
14 | }
15 |
--------------------------------------------------------------------------------
/presentation/components/Title.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Number from './Number.jsx'
3 | import './Title.css'
4 |
5 | const Title = ({number, children}) => (
6 |
7 | {children}
8 |
)
9 | export default Title
10 |
--------------------------------------------------------------------------------
/createTheme.js:
--------------------------------------------------------------------------------
1 | import createSpectacleTheme from "spectacle/lib/themes/default";
2 | import merge from 'deepmerge';
3 |
4 | const createTheme = (colors, fonts, overrides = {}) => {
5 | let t = createSpectacleTheme(colors, fonts);
6 | t.screen = merge(t.screen, overrides);
7 | return t;
8 | };
9 |
10 | export default createTheme;
--------------------------------------------------------------------------------
/presentation/components/Name.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import './Name.css'
3 | import {darkComponents} from '../slides.js'
4 |
5 | const A = darkComponents.a;
6 |
7 | export default ({children}) => ()
12 |
--------------------------------------------------------------------------------
/presentation/components/RacistDataExplain.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Appear} from 'spectacle'
3 | import theme from '../theme'
4 |
5 | export default ()=>(
6 |
7 |
8 |
9 |
10 | racist data
11 | in data-driven decisions → racist decisions
12 |
13 |
14 |
15 |
16 |
)
17 |
--------------------------------------------------------------------------------
/presentation/components/Site.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import './Site.css'
3 | import {darkComponents} from '../slides.js';
4 |
5 | const A = darkComponents.a;
6 |
7 | const Site = () => (
8 | )
13 | export default Site;
14 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | ---
2 | "extends":
3 | - "formidable/configurations/es6-react"
4 |
5 | "rules":
6 | "indent": [2, 2, {"SwitchCase": 1}]
7 | "max-len": 0
8 | "no-magic-numbers": 0
9 | "react/prefer-es6-class": 0
10 | "react/no-multi-comp": 0
11 |
12 | "env":
13 | "browser": true,
14 | "node": true
15 | "globals":
16 | "afterEach": true,
17 | "describe": true,
18 | "expect": true,
19 | "it": true,
20 | "jest": true,
21 | "test": true
22 |
--------------------------------------------------------------------------------
/presentation/components/SentimentFood.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Image, Appear} from 'spectacle';
3 | //import {darkComponents} from '../slides.js'
4 | import {sf1,sf2,sf3} from '../assets.js'
5 |
6 | const foods = [sf1,sf2,sf3]
7 | export default () => (
8 |
9 | {foods.map((f,i)=>(
10 |
11 |
12 |
13 |
14 |
15 |
16 |
))}
17 |
)
18 |
--------------------------------------------------------------------------------
/presentation/components/QuotePic.css:
--------------------------------------------------------------------------------
1 | .QuotePic {
2 | display: grid;
3 | grid-template-columns: 300px auto;
4 | min-height: 200px;
5 | font-size: 1rem;
6 | }
7 |
8 | .QuotePic.right {
9 | grid-template-columns: auto 300px;
10 | grid-auto-flow: dense;
11 | }
12 |
13 | .QuotePic-pic {
14 | grid-column: 1;
15 | margin: 0 auto;
16 | }
17 | .QuotePic-quote {
18 | grid-column: 2;
19 | }
20 |
21 | .QuotePic.right> .QuotePic-pic {
22 | grid-column: 2;
23 | }
24 | .QuotePic.right> .QuotePic-quote {
25 | grid-column: 1;
26 | }
27 |
28 | .QuotePic-source {
29 | font-size: .8rem;
30 | }
31 |
32 | .QuotePic-sauce {
33 | text-align: right;
34 | }
35 |
--------------------------------------------------------------------------------
/presentation/components/AmazonFace.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {az1, az2, az3, az4} from '../assets.js'
3 | import {Appear, Image} from 'spectacle'
4 | import './AmazonFace.css'
5 |
6 | export default class AmazonFace extends React.Component{
7 | render() {
8 | const azs = [az1,az2,az3,az4]
9 | return (
10 |
11 |
12 | {azs.map((az,i)=>(
13 |
14 |
15 |
16 |
17 |
18 |
19 |
))}
20 |
21 |
22 |
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [ "es2015", { "loose": true, "modules" : false } ],
4 | "stage-0",
5 | "react"
6 | ],
7 | "plugins": [
8 | "react-hot-loader/babel",
9 | "transform-decorators-legacy"
10 | ],
11 | "env": {
12 | "production": {
13 | "plugins": [
14 | "transform-es2015-modules-commonjs",
15 | "transform-react-remove-prop-types",
16 | "transform-react-constant-elements",
17 | "transform-react-inline-elements",
18 | "transform-runtime",
19 | "transform-decorators-legacy"
20 | ]
21 | },
22 | "test": {
23 | "plugins": [
24 | "transform-es2015-modules-commonjs"
25 | ]
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 5 ways to write racist code | Alex Garcia
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 5 ways to write racist code - Slides
2 |
3 | This repository contains a [spectacle presentation](https://github.com/FormidableLabs/spectacle)
4 | that is the slide tech for the "5 ways to write racist code" talk that I'm going
5 | to give at [#NICAR19](https://www.ire.org/conferences/nicar-2019/).
6 |
7 | I choose spectacle over google slides because I wanted to do special javascript stuff
8 | that didn't make sense in google slides, and I choose the MDX boilerplate because
9 | I thought it would be cool. On further reflection, literally everything I did here
10 | was so very extra and unnecessary but ¯\_(ツ)_/¯
11 |
12 | If you want to run this presentation for some reason (god help you):
13 |
14 | ```bash
15 | yarn
16 | yarn start
17 | ```
18 |
19 | Then http://localhost:3000
20 |
--------------------------------------------------------------------------------
/presentation/components/SentimentNames.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Image, Appear} from 'spectacle';
3 | //import {darkComponents} from '../slides.js'
4 | import {sn1,sn2,sn3,sn4} from '../assets.js'
5 |
6 | const names = [sn1,sn2,sn3,sn4]
7 | export default () => (
8 |
9 | {names.map((n,i)=>(
10 |
11 |
12 |
13 |
14 |
15 |
16 |
))}
17 |
)
18 |
19 |
20 | /*```python
21 | text_to_sentiment("Let's go get Italian food")
22 | 2.0429166109408983
23 | text_to_sentiment("Let's go get Chinese food")
24 | 1.4094033658140972
25 | text_to_sentiment("Let's go get Mexican food")
26 | 0.38801985560121732
27 | ```
28 | */
29 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | var path = require("path");
4 | var express = require("express");
5 | var webpack = require("webpack");
6 | var config = require("./webpack.config");
7 |
8 | var app = express();
9 | var compiler = webpack(config);
10 |
11 | var serverPort = process.env.PORT || 3000;
12 |
13 | app.use(require("webpack-dev-middleware")(compiler, {
14 | publicPath: config.output.publicPath
15 | }));
16 |
17 | app.use(require("webpack-hot-middleware")(compiler));
18 |
19 | app.use(express.static('assets'))
20 |
21 | app.get("*", function (req, res) {
22 | res.sendFile(path.join(__dirname, "index.html"));
23 | });
24 |
25 | app.listen(serverPort, "localhost", function (err) {
26 | if (err) {
27 | console.log(err);
28 | return;
29 | }
30 |
31 | console.log("Listening at http://localhost:" + serverPort);
32 | });
33 |
--------------------------------------------------------------------------------
/presentation/regular-component.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Heading, Text } from 'spectacle';
3 |
4 | export default class RegularComponent extends React.Component {
5 | state = {
6 | count: 0
7 | };
8 |
9 | incrementCount = () => {
10 | this.setState(state => ({
11 | count: state.count + 1
12 | }))
13 | }
14 |
15 | render() {
16 | return (
17 |
18 | This is a normal react component
19 |
20 | but you're adding it to your presentation in MDX
21 |
22 | {this.state.count}
23 |
24 | Click the button to rate how cool that is from 1-10
25 |
26 | Rate It
27 |
28 | )
29 | }
30 | }
--------------------------------------------------------------------------------
/presentation/assets.js:
--------------------------------------------------------------------------------
1 | export const aoc = require('../assets/aoc.jpg')
2 | export const saavedra = require('../assets/saavedra.jpg')
3 | export const food = require('../assets/food.gif')
4 | export const gerry = require('../assets/gerry.jpg')
5 | export const az1 = require('../assets/amazon1.png')
6 | export const az2 = require('../assets/amazon2.png')
7 | export const az3 = require('../assets/amazon3.png')
8 | export const az4 = require('../assets/amazon4.png')
9 | export const names = require('../assets/names-boxplot.png')
10 |
11 | export const sn1 = require('../assets/sent-name-1.png')
12 | export const sn2 = require('../assets/sent-name-2.png')
13 | export const sn3 = require('../assets/sent-name-3.png')
14 | export const sn4 = require('../assets/sent-name-4.png')
15 |
16 | export const sf1 = require('../assets/sent-food-1.png')
17 | export const sf2 = require('../assets/sent-food-2.png')
18 | export const sf3 = require('../assets/sent-food-3.png')
19 |
20 | export const ind = require('../assets/indp-headline.png')
21 |
--------------------------------------------------------------------------------
/presentation/theme/index.js:
--------------------------------------------------------------------------------
1 | import createTheme from "../../createTheme";
2 |
3 | const colors = {
4 | white: '#fff',
5 | orange: "#f5ab35",
6 | blue: "#00e0e0",
7 | darkBlue: "#007acc",
8 | }
9 | colors['primary'] = colors.orange
10 | colors['secondary'] = colors.white
11 | colors['tertiary'] = colors.darkBlue
12 | colors['quaternary'] = colors.orange // for progress
13 |
14 | const theme = createTheme(colors, {
15 | primary: "Montserrat",
16 | secondary: "Helvetica"
17 | }, {
18 | components: {
19 | heading: {
20 | h1: {
21 | fontSize: '3.5rem',
22 | textAlign:'left'
23 | },
24 | h2: {
25 | fontSize: '3.25rem',
26 | },
27 | h3: {
28 | fontSize: '3rem',
29 | },
30 | h4: {
31 | fontSize: '2rem',
32 | },
33 | h5: {
34 | fontSize: '1.5rem',
35 | },
36 | h6: {
37 | fontSize: '1.25rem',
38 | }
39 | },
40 | codePane: {
41 | fontSize: '2rem'
42 | }
43 | }
44 | });
45 |
46 | export default theme;
47 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/presentation/components/QuotePic.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Appear, Text, Image} from 'spectacle'
3 | import components from '../components.js'
4 | import {darkComponents} from '../slides.js'
5 | import './QuotePic.css'
6 |
7 | const BlockQuoteX = darkComponents.blockquote;
8 | const TextX = darkComponents.p;
9 | const LinkX = darkComponents.a;
10 |
11 | export default class QuotePic extends React.Component {
12 | render() {
13 | const {pic, quote, align,appear, quoter, source, ...rest} = this.props
14 | const qp = (
15 |
16 |
17 |
18 |
19 |
20 |
21 | {quote}
22 |
23 |
24 |
25 |
26 | {quoter}
27 |
28 |
29 | source: {source.text}
30 |
31 |
32 |
33 |
)
34 | if(appear)
35 | return (
36 |
37 | {qp}
38 | )
39 | return qp
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/presentation/slides.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Slide, Text, Heading,Link } from 'spectacle';
3 | import { MDXProvider } from '@mdx-js/tag'
4 | import components from './components';
5 | import theme from './theme';
6 |
7 | export const darkComponents = {
8 | ...components,
9 | h1: ({ children }) => {children} ,
10 | h2: ({ children }) => {children} ,
11 | h3: ({ children }) => {children} ,
12 | h4: ({ children }) => {children} ,
13 | h5: ({ children }) => {children} ,
14 | h6: ({ children }) => {children} ,
15 | p: ({ children, ...rest}) => {
16 | return {children}
17 | },
18 | a: ({children, ...rest}) => {children},
19 | }
20 |
21 |
22 | export const DefaultSlide = ({ children, ...rest }) => (
23 |
24 | {children}
25 |
26 | );
27 |
28 | // CODE LAYOUT
29 |
30 | export const CodeSlide = ({ children, ...rest }) => (
31 |
32 | {children}
33 |
34 | );
35 |
--------------------------------------------------------------------------------
/webpack.config.production.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | var path = require("path");
4 | var webpack = require("webpack");
5 | var HtmlWebpackPlugin = require('html-webpack-plugin')
6 | const CopyPlugin = require('copy-webpack-plugin');
7 |
8 | module.exports = {
9 | mode: "production",
10 | entry: ["babel-polyfill", "./index"],
11 | output: {
12 | path: path.join(__dirname, "dist"),
13 | filename: "bundle.[contenthash].js",
14 | //publicPath: "/dist/"
15 | },
16 | plugins: [
17 | new webpack.DefinePlugin({
18 | "process.env": {
19 | NODE_ENV: JSON.stringify("production")
20 | }
21 | }),
22 | new HtmlWebpackPlugin({
23 | template: 'index.html',
24 | //filename: '../index.html'
25 | hash: true,
26 | }),
27 | new CopyPlugin([
28 | {from : 'assets/favicon.ico'}
29 | ])
30 | ],
31 | optimization: {
32 | minimize: true
33 | },
34 | module: {
35 | rules: [
36 | {
37 | test: /\.md$/,
38 | loader: "html-loader!markdown-loader?gfm=false"
39 | },
40 | {
41 | test: /\.mdx$/,
42 | exclude: /node_modules/,
43 | use: [
44 | { loader: "babel-loader" },
45 | { loader: require.resolve("./loader.js") }
46 | ]
47 | },
48 | {
49 | test: /\.(js|jsx)$/,
50 | exclude: /node_modules/,
51 | loader: "babel-loader"
52 | },
53 | {
54 | test: /\.css$/,
55 | loader: "style-loader!css-loader"
56 | },
57 | {
58 | test: /\.(png|jpg|gif|ico)$/,
59 | loader: "url-loader?limit=8192"
60 | },
61 | {
62 | test: /\.svg$/,
63 | loader: "url-loader?limit=10000&mimetype=image/svg+xml"
64 | }
65 | ]
66 | }
67 | };
68 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | var path = require("path");
4 | var webpack = require("webpack");
5 |
6 | module.exports = {
7 | mode: "development",
8 | devtool: "cheap-module-source-map",
9 | entry: [
10 | "babel-polyfill",
11 | 'webpack-hot-middleware/client',
12 | "react-hot-loader/patch",
13 | "./index"
14 | ],
15 | output: {
16 | path: path.join(__dirname, "dist"),
17 | filename: "bundle.js",
18 | publicPath: "/dist",
19 | },
20 | plugins: [
21 | new webpack.NamedModulesPlugin(),
22 | new webpack.HotModuleReplacementPlugin()
23 | ],
24 | module: {
25 | rules: [{
26 | test: /\.md$/,
27 | loader: "html-loader!markdown-loader?gfm=false"
28 | },
29 | {
30 | test: /\.mdx$/,
31 | exclude: /node_modules/,
32 | use: [
33 | { loader: "babel-loader" },
34 | { loader: require.resolve('./loader.js') }]
35 | },
36 | {
37 | test: /\.(js|jsx)$/,
38 | exclude: /node_modules/,
39 | loader: "babel-loader",
40 | include: __dirname
41 | }, {
42 | test: /\.css$/,
43 | loaders: ["style-loader", "raw-loader"],
44 | include: __dirname
45 | }, {
46 | test: /\.svg$/,
47 | loader: "url-loader?limit=10000&mimetype=image/svg+xml",
48 | include: path.join(__dirname, "assets")
49 | }, {
50 | test: /\.png$/,
51 | loader: "url-loader?mimetype=image/png",
52 | include: path.join(__dirname, "assets")
53 | }, {
54 | test: /\.gif$/,
55 | loader: "url-loader?mimetype=image/gif",
56 | include: path.join(__dirname, "assets")
57 | }, {
58 | test: /\.jpg$/,
59 | loader: "url-loader?mimetype=image/jpg",
60 | include: path.join(__dirname, "assets")
61 | }]
62 | }
63 | };
64 |
--------------------------------------------------------------------------------
/presentation/components.js:
--------------------------------------------------------------------------------
1 | import React, { createElement, Component } from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import {
5 | Heading,
6 | Image,
7 | Code,
8 | CodePane,
9 | BlockQuote,
10 | Link,
11 | List,
12 | ListItem,
13 | Quote,
14 | S,
15 | Text,
16 | Table,
17 | TableHeader,
18 | TableRow,
19 | TableHeaderItem,
20 | TableBody,
21 | TableItem
22 | } from 'spectacle';
23 |
24 |
25 | const _Heading = size => {
26 | const component = ({ children }) => {children} ;
27 | component.propTypes = { children: PropTypes.node };
28 | return component;
29 | };
30 |
31 | const _S = type => {
32 | const component = ({ children }) => {children} ;
33 | component.propTypes = { children: PropTypes.node };
34 | return component;
35 | };
36 |
37 | const _CombineBlockQuote = ({ children, ...rest }) => (
38 |
39 | {children}
40 |
41 | );
42 |
43 | _CombineBlockQuote.propTypes = { children: PropTypes.node };
44 |
45 |
46 | const Strong = ({children}) => (
47 | {children}
48 | )
49 |
50 |
51 | const _CodePane = ({ children, language }) => (
52 |
53 | );
54 |
55 | _CodePane.propTypes = { code: PropTypes.string, language: PropTypes.string };
56 |
57 | export default {
58 | a: Link,
59 | blockquote: _CombineBlockQuote,
60 | code: _CodePane,
61 | del: _S('strikethrough'),
62 | em: _S('italic'),
63 | h1: _Heading(1),
64 | h2: _Heading(2),
65 | h3: _Heading(3),
66 | h4: _Heading(4),
67 | h5: _Heading(5),
68 | h6: _Heading(6),
69 | img: Image,
70 | codespan: Code,
71 | li: ListItem,
72 | p: Text,
73 | strong: Strong,
74 | ul: List,
75 | table: Table,
76 | thead: TableHeader,
77 | th: TableHeaderItem,
78 | tbody: TableBody,
79 | tr: TableRow,
80 | td: TableItem
81 | };
82 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import ReactDOM from "react-dom";
4 | import { AppContainer } from "react-hot-loader";
5 | import Redbox from "redbox-react";
6 | import { Deck, Slide } from 'spectacle';
7 | import components from './presentation/components';
8 | import slides, { transitions } from "./presentation/index.mdx";
9 | import theme from './presentation/theme';
10 |
11 | require("normalize.css");
12 |
13 | const CustomErrorReporter = ({ error }) => ;
14 |
15 | CustomErrorReporter.propTypes = {
16 | error: PropTypes.instanceOf(Error).isRequired
17 | };
18 |
19 | const creeperTransition = (transitioning, forward) => {
20 | const offset = forward ? 100 : -100;
21 | return {
22 | transform: `
23 | translate3d(${transitioning ? offset : 0}%, 0, 0)
24 | `,
25 | };
26 | };
27 |
28 | ReactDOM.render(
29 |
30 |
31 | {slides.map((S, i) => {
32 | let transition = transitions[i] || null;
33 | return ;
34 | })}
35 |
36 | ,
37 | document.getElementById("root"),
38 | );
39 |
40 | if (module.hot) {
41 | module.hot.accept(() => {
42 | const newTheme = require("./presentation/theme").default;
43 | const newSlides = require("./presentation/index.mdx").default;
44 | ReactDOM.render(
45 |
46 |
47 | {newSlides.map((S, i) => {
48 | let transition = transitions[i] || null;
49 | return ;
50 | })}
51 |
52 | ,
53 | document.getElementById("root"),
54 | );
55 | });
56 | }
57 |
--------------------------------------------------------------------------------
/loader.js:
--------------------------------------------------------------------------------
1 | const { getOptions } = require('loader-utils')
2 | const mdx = require('@mdx-js/mdx')
3 | const matter = require('gray-matter')
4 | const stringifyObject = require('stringify-object')
5 | const normalizeNewline = require('normalize-newline')
6 |
7 | const EXREG = /export\sdefault\s\(/g
8 | const MODREG = /^(import|export)\s/
9 | const SLIDEREG = /\n---\n/
10 | const TRANSREG = /^export const transition.*\s(.*)/
11 | const hasDefaultExport = str => /export default/.test(str);
12 |
13 | const defaultLayout = (str) => {
14 | if (!hasDefaultExport(str)) {
15 | str = `import {DefaultSlide} from './slides'
16 |
17 | export default DefaultSlide
18 |
19 | ${str}`;
20 | }
21 | return str;
22 | }
23 |
24 | module.exports = async function (src) {
25 | const callback = this.async()
26 | const options = getOptions(this) || {}
27 |
28 | const { data, content } = matter(src)
29 |
30 | const transitions = [];
31 |
32 | const inlineModules = []
33 | const slides = normalizeNewline(content)
34 | .split(SLIDEREG)
35 | .map(str => defaultLayout(str))
36 | .map(str => mdx.sync(str, options))
37 | .map(str => str.trim())
38 | .map(str => str.replace(EXREG, '('))
39 | .map(str => {
40 | const lines = str.split('\n')
41 | let transition = null;
42 | lines.forEach(line => {
43 | let match = line.match(TRANSREG);
44 | if (match && match[1]) {
45 | transition = match[1];
46 | }
47 | })
48 |
49 | transitions.push(transition);
50 |
51 | return lines.filter(str => !TRANSREG.test(str))
52 | .filter(Boolean)
53 | .join('\n')
54 | })
55 | .map(str => {
56 | const lines = str.split('\n')
57 | inlineModules.push(
58 | ...lines.filter(str => MODREG.test(str))
59 | );
60 | return lines.filter(str => !MODREG.test(str))
61 | .filter(Boolean)
62 | .join('\n')
63 | })
64 |
65 | const {
66 | modules = []
67 | } = data
68 |
69 | const code = `import React from 'react'
70 | import { MDXTag } from '@mdx-js/tag'
71 | ${modules.join('\n')}
72 | ${inlineModules.filter(function (el, i, arr) {
73 | return arr.indexOf(el) === i;
74 | }).join('\n')}
75 |
76 | export const transitions = [
77 | ${transitions.join(',')}
78 | ]
79 |
80 | export default [
81 | ${slides.join(',\n\n')}
82 | ]`
83 |
84 | return callback(null, code)
85 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "spectacle-boilerplate",
3 | "version": "1.0.1",
4 | "description": "ReactJS Powered Presentation Framework",
5 | "main": "lib/index.js",
6 | "scripts": {
7 | "clean": "rimraf dist",
8 | "build": "cross-env NODE_ENV=production webpack --config webpack.config.production.js",
9 | "lint": "eslint --ext .js,.jsx .",
10 | "deploy": "npm run clean & npm run build & gh-pages -d dist -b gh-pages",
11 | "gh": "gh-pages -d dist -b gh-pages",
12 | "export": "spectacle-renderer --delay 3000",
13 | "start": "cross-env NODE_ENV=development node server.js",
14 | "pages": "gh-pages -d dist -b gh-pages"
15 | },
16 | "author": "",
17 | "license": "MIT",
18 | "dependencies": {
19 | "deepmerge": "^2.1.1",
20 | "gh-pages": "^2.0.1",
21 | "normalize.css": "8.0.0",
22 | "react": "^16.4.2",
23 | "react-dom": "^16.4.2",
24 | "react-transition-group": "2",
25 | "spectacle": "5.4.0",
26 | "spectacle-renderer": "^0.0.3"
27 | },
28 | "devDependencies": {
29 | "@mdx-js/loader": "^0.15.0-2",
30 | "@mdx-js/mdx": "^0.15.0-2",
31 | "babel-cli": "^6.26.0",
32 | "babel-core": "^6.26.3",
33 | "babel-eslint": "^8.2.6",
34 | "babel-loader": "^7.1.5",
35 | "babel-plugin-react-transform": "^3.0.0",
36 | "babel-plugin-transform-decorators-legacy": "^1.3.5",
37 | "babel-plugin-transform-react-constant-elements": "^6.23.0",
38 | "babel-plugin-transform-react-inline-elements": "^6.22.0",
39 | "babel-plugin-transform-react-remove-prop-types": "^0.4.14",
40 | "babel-plugin-transform-runtime": "^6.23.0",
41 | "babel-polyfill": "^6.26.0",
42 | "babel-preset-es2015": "^6.24.1",
43 | "babel-preset-react": "^6.24.1",
44 | "babel-preset-stage-0": "^6.24.1",
45 | "babel-runtime": "^6.26.0",
46 | "copy-webpack-plugin": "^5.0.0",
47 | "cross-env": "^5.2.0",
48 | "css-loader": "^1.0.0",
49 | "eslint": "^5.3.0",
50 | "eslint-config-formidable": "^4.0.0",
51 | "eslint-plugin-filenames": "^1.3.2",
52 | "eslint-plugin-import": "^2.13.0",
53 | "eslint-plugin-react": "^7.10.0",
54 | "express": "^4.16.3",
55 | "file-loader": "^1.1.11",
56 | "gray-matter": "^4.0.1",
57 | "html-loader": "^0.5.5",
58 | "html-webpack-plugin": "^3.2.0",
59 | "is-buffer": "^2.0.3",
60 | "loader-utils": "^1.1.0",
61 | "markdown-loader": "^3.0.0",
62 | "node-libs-browser": "^2.1.0",
63 | "normalize-newline": "^3.0.0",
64 | "prop-types": "^15.6.2",
65 | "raw-loader": "^0.5.1",
66 | "react-hot-loader": "^4.3.4",
67 | "react-transform-catch-errors": "^1.0.2",
68 | "redbox-react": "^1.6.0",
69 | "rimraf": "^2.6.2",
70 | "stringify-object": "^3.2.2",
71 | "style-loader": "^0.22.0",
72 | "url-loader": "^1.0.1",
73 | "webpack": "4.16.5",
74 | "webpack-cli": "^3.1.0",
75 | "webpack-dev-middleware": "^3.1.3",
76 | "webpack-dev-server": "^3.1.5",
77 | "webpack-hot-middleware": "^2.22.3"
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/presentation/index.mdx:
--------------------------------------------------------------------------------
1 | import {Cite, Appear, Image} from 'spectacle';
2 | import Number from './components/Number.jsx';
3 | import Title from './components/Title.jsx';
4 | import Name from './components/Name.jsx';
5 | import AmazonFace from './components/AmazonFace.jsx';
6 | import RacistDataExplain from './components/RacistDataExplain.jsx';
7 | import {aoc, saavedra, food, gerry, ind} from './assets.js'
8 | import QuotePic from './components/QuotePic.jsx';
9 | import Site from './components/Site.jsx'
10 | import {darkComponents, CodeSlide} from './slides.js';
11 |
12 | import SentimentFood from './components/SentimentFood.jsx'
13 | import SentimentName from './components/SentimentNames.jsx'
14 |
15 |
16 | # **5** ways to write **racist code**
17 | Alex Garcia
18 |
19 |
20 |
21 | ---
22 | Use racist data
23 |
24 |
25 |
26 |
27 |
28 | ---
29 |
30 | ## Predictive Policing
31 |
32 | - predict when/where crime will happen, who will commit it
33 | - allocate officers in "high-risk" areas
34 |
35 |
36 |
37 |
38 |
39 | ---
40 |
41 | Don't use diverse data
42 |
43 |
44 |
45 |
46 |
47 | ---
48 |
49 | Accidentally
50 |
51 | Race is *deeply* embedded into many aspects of our life
52 |
53 | - ZIP Codes
54 | - Family wealth
55 | - Incarceration rates
56 |
57 | ---
58 |
59 |
60 |
61 |
62 | > "Fraud and similarity detection software, as well as input from universities,
63 | are used when deciding whether an application needs investigating.""
64 |
65 |
66 |
67 |
68 | ---
69 |
70 | Use magic black boxes 🧙🏼♂️
71 |
72 | - Package creators may not have considered racial bias
73 |
74 |
75 |
76 | ---
77 |
78 |
79 |
80 |
81 |
82 | ---
83 |
84 | Think code has no bias
85 |
86 |
88 | “Algorithms are still made by human beings, and those algorithms are still pegged to basic human assumptions.
89 | {' '}They’re just automated assumptions .”
90 | }
91 | pic={aoc}
92 | align="left"
93 | source={{link:"https://slate.com/news-and-politics/2019/02/aoc-algorithms-racist-bias.html", text:'Slate'}}
94 | quoter="Alexandria Ocasio-Cortez"/>
95 |
96 |
97 | “Socialist Rep. Alexandria Ocasio-Cortez (D-NY) claims that algorithms,
98 | {' '}which are driven by math, {' '}
99 | are racist“}
100 | pic={saavedra}
101 | align="right"
102 | source={{link:"https://twitter.com/RealSaavedra/status/1087627739861897216", text:'Twitter @RealSaavedra'}}
103 | quoter="Ryan Saavedra of Daily Wire"
104 | appear={1}/>
105 |
106 |
107 |
108 | ---
109 |
110 | # Final thoughts
111 | - Never assume your data is free of bias
112 | - Audit your 3rd party packages or models
113 | - Remember biased algorithms *are* possible
114 |
115 | HMU if you like this kind of stuff! [@alexgarcia_me](https://twitter.com/alexgarcia_me)
116 |
117 | 👋🏼
118 |
119 |
120 |
--------------------------------------------------------------------------------