├── .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}) => (
8 | {children} 9 |
10 | @agarcia_me 11 |
) 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 |
9 | 10 | https://iamprettydamn.cool/racist-code 11 | 12 |
) 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 | 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 | --------------------------------------------------------------------------------