├── static
├── robots.txt
└── favicon.ico
├── gatsby-browser.js
├── content
├── assets
│ ├── icon.png
│ └── profile-pic.jpg
└── blog
│ └── 2019
│ ├── sup
│ ├── subpage.mdx
│ ├── components
│ │ ├── Glitter.js
│ │ └── Glitter.css
│ └── index.mdx
│ ├── la-earthquake-app
│ ├── index.mdx
│ └── components
│ │ └── Notebook.js
│ ├── racist-code
│ └── index.mdx
│ └── ucsd-fall-career-fair-ice
│ └── index.mdx
├── src
├── pages
│ ├── BlogIndex.module.css
│ ├── 404.js
│ └── index.js
├── components
│ ├── Footer.js
│ ├── Bio.js
│ ├── Layout.js
│ ├── Seo.js
│ ├── Toggle.css
│ └── Toggle.js
├── utils
│ └── typography.js
├── styles
│ └── global.css
├── html.js
└── templates
│ └── blog-post.js
├── .prettierrc
├── README.md
├── LICENSE
├── .gitignore
├── gatsby-node.js
├── package.json
└── gatsby-config.js
/static/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
3 |
--------------------------------------------------------------------------------
/gatsby-browser.js:
--------------------------------------------------------------------------------
1 | // custom typefaces
2 | import "./src/styles/global.css"
3 |
--------------------------------------------------------------------------------
/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/blogX/master/static/favicon.ico
--------------------------------------------------------------------------------
/content/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/blogX/master/content/assets/icon.png
--------------------------------------------------------------------------------
/content/assets/profile-pic.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asg017/blogX/master/content/assets/profile-pic.jpg
--------------------------------------------------------------------------------
/src/pages/BlogIndex.module.css:
--------------------------------------------------------------------------------
1 | .postList {
2 | display: grid;
3 | grid-template-columns: 1fr 100px;
4 | grid-column-gap: 5px;
5 | }
6 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "endOfLine": "lf",
3 | "semi": false,
4 | "singleQuote": false,
5 | "tabWidth": 2,
6 | "trailingComma": "es5"
7 | }
8 |
--------------------------------------------------------------------------------
/content/blog/2019/sup/subpage.mdx:
--------------------------------------------------------------------------------
1 | Importing other markdown files are easy too - this paragraph is another markdown file, imported with:
2 |
3 | ```
4 | import SubPage from "./subpage.mdx"
5 |
6 | ```
7 |
--------------------------------------------------------------------------------
/content/blog/2019/sup/components/Glitter.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import "./Glitter.css"
3 |
4 | export class Glitter extends React.Component {
5 | render() {
6 | return {this.props.children}
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/content/blog/2019/la-earthquake-app/index.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: LA Earthquake Alert App
3 | date: "2019-01-11T12:00:00.000Z"
4 | ---
5 |
6 | import Notebook from "./components/Notebook.js"
7 |
8 | Note: This post originally appeared on my [old site](https://iamprettydamn.cool/2019/la-earthquake-app/?notrack=1),
9 | so this is just porting that old post here in it's originality.
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/components/Footer.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { rhythm } from "../utils/typography"
3 |
4 | const Footer = () => (
5 |
6 | © {new Date().getFullYear()}, Built with
7 | {` `}
8 |
Gatsby , Hosted on{" "}
9 |
GitHub
10 |
11 | )
12 |
13 | export default Footer
14 |
--------------------------------------------------------------------------------
/content/blog/2019/sup/components/Glitter.css:
--------------------------------------------------------------------------------
1 | .Glitter {
2 | color: white;
3 | background: -webkit-linear-gradient(transparent, transparent),
4 | url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/191814/blue_glitter.gif)
5 | repeat 100px 20px;
6 | letter-spacing: 1px;
7 | text-decoration: none;
8 | filter: hue-rotate(50deg);
9 | text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000,
10 | 1px 1px 0 #000;
11 | padding: 0.2rem;
12 | }
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Blog
2 |
3 | My blog, created with [gatsby-starter-blog](https://github.com/gatsbyjs/gatsby-starter-blog), with [gatsby-mdx](https://github.com/ChristopherBiscardi/gatsby-mdx) for cooler looking posts.
4 |
5 | All posts are found inside `content/blog//`.
6 |
7 | To play with, do:
8 |
9 | ```shell
10 | git clone https://github.com/asg017/blogX.git
11 | cd blogX/
12 | yarn
13 | yarn dev
14 | ```
15 |
16 | Then http://localhost:8000 to see the posts, http://localhost:8000___graphql to play with the data.
17 |
--------------------------------------------------------------------------------
/content/blog/2019/la-earthquake-app/components/Notebook.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { Runtime, Inspector } from "@observablehq/notebook-runtime"
3 | import notebook from "la-earthquake-app"
4 |
5 | class Notebook extends React.Component {
6 | rootRef = React.createRef()
7 |
8 | componentDidMount() {
9 | Runtime.load(notebook, Inspector.into(this.rootRef.current))
10 | }
11 |
12 | render() {
13 | return (
14 |
17 | )
18 | }
19 | }
20 |
21 | export default Notebook
22 |
--------------------------------------------------------------------------------
/src/utils/typography.js:
--------------------------------------------------------------------------------
1 | import Typography from "typography"
2 | import Wordpress2016 from "typography-theme-wordpress-2016"
3 |
4 | Wordpress2016.overrideThemeStyles = () => {
5 | return {
6 | "a.gatsby-resp-image-link": {
7 | boxShadow: `none`,
8 | },
9 | body: {
10 | color: "var(--textNormal)",
11 | },
12 | }
13 | }
14 |
15 | delete Wordpress2016.googleFonts
16 |
17 | const typography = new Typography(Wordpress2016)
18 |
19 | // Hot reload typography in development.
20 | if (process.env.NODE_ENV !== `production`) {
21 | typography.injectStyles()
22 | }
23 |
24 | export default typography
25 | export const rhythm = typography.rhythm
26 | export const scale = typography.scale
27 |
--------------------------------------------------------------------------------
/src/pages/404.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { graphql } from "gatsby"
3 |
4 | import Layout from "../components/Layout"
5 | import SEO from "../components/Seo"
6 |
7 | class NotFoundPage extends React.Component {
8 | render() {
9 | const { data } = this.props
10 | const siteTitle = data.site.siteMetadata.title
11 |
12 | return (
13 |
14 |
15 | Not Found
16 | You just hit a route that doesn't exist... the sadness.
17 |
18 | )
19 | }
20 | }
21 |
22 | export default NotFoundPage
23 |
24 | export const pageQuery = graphql`
25 | query {
26 | site {
27 | siteMetadata {
28 | title
29 | }
30 | }
31 | }
32 | `
33 |
--------------------------------------------------------------------------------
/src/styles/global.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: var(--bg);
3 | color: var(--textNormal);
4 | transition: color 0.2s ease-out, background 0.2s ease-out;
5 | --blue: #00e0e0;
6 | --orange: #f5ab35;
7 | --darkBlue: #007acc;
8 | min-width: 477px;
9 | }
10 |
11 | body.dark {
12 | --bg: #2b2b2b;
13 | --textNormal: rgba(255, 255, 255, 0.9);
14 | }
15 |
16 | body.light {
17 | --bg: #fff;
18 | --textNormal: #222;
19 | }
20 |
21 | .dark a {
22 | color: var(--blue);
23 | }
24 | .dark a.special {
25 | color: var(--orange);
26 | }
27 | .light a {
28 | color: var(--darkBlue);
29 | }
30 |
31 | .dark hr {
32 | background-color: rgba(255, 255, 255, 0.7);
33 | }
34 |
35 | code {
36 | background-color: #f7f7f9;
37 | color: #222;
38 | padding: 2px 5px;
39 | border-radius: 2px;
40 | }
41 |
42 | pre {
43 | background-color: #f7f7f9;
44 | padding: 12px;
45 | color: #222;
46 | }
47 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Gatsbyjs
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, 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,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # dotenv environment variables file
55 | .env
56 |
57 | # gatsby files
58 | .cache/
59 | public
60 |
61 | # Mac files
62 | .DS_Store
63 |
64 | # Yarn
65 | yarn-error.log
66 | .pnp/
67 | .pnp.js
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
--------------------------------------------------------------------------------
/content/blog/2019/sup/index.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Sup
3 | date: "2019-03-01T08:27:58.908Z"
4 | ---
5 |
6 | import SubPage from "./subpage.mdx"
7 | import { Glitter } from "./components/Glitter.js"
8 |
9 | Hello! This is the (first?) post for my new blog. Like everything I do, I spent
10 | waaaay to much time setting this site up for little added benefit, so the least
11 | I can do is have my first post talk about the technical pieces behind this blog.
12 |
13 | This is a Gatsby site, generated with the [gatsby-starter-blog](https://github.com/gatsbyjs/gatsby-starter-blog)
14 | recipe. Which is cool, I could just write a simple markdown file and be good to go!
15 |
16 | But, markdown files by themselves are boring. The [internet isn't fun and weird
17 | anymore](https://jarredsumner.com/codeblog/), so I added the [gatsby-mdx](https://github.com/ChristopherBiscardi/gatsby-mdx)
18 | plugin to allow for inline use of whatever React components
19 | that I want. File structure for each post is pretty simple, too - here's the
20 | folder for this post:
21 |
22 | ```
23 | content/blog/2019/sup/
24 | ├── components
25 | │ ├── Glitter.js
26 | │ └── Glitter.css
27 | ├── index.mdx
28 | └── test_a.mdx
29 | ```
30 |
31 |
32 |
33 | 🤠 pretty cool yo
34 |
35 | A lot of the design choices/code comes from Dan Abramov's [overreacted.io blog](https://github.com/gaearon/overreacted.io).
36 |
37 | Basically, this should blog should be easier and more fun than making a blog
38 | post with [Observable notebooks](https://observablehq.com/), but not as cool as
39 | [codeblog.com](http://codeblog.com/) (whenever that is released).
40 |
--------------------------------------------------------------------------------
/src/components/Bio.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { StaticQuery, graphql } from "gatsby"
3 | import Image from "gatsby-image"
4 |
5 | import { rhythm } from "../utils/typography"
6 |
7 | function Bio() {
8 | return (
9 | {
12 | const { author, social } = data.site.siteMetadata
13 | return (
14 |
44 | )
45 | }}
46 | />
47 | )
48 | }
49 |
50 | const bioQuery = graphql`
51 | query BioQuery {
52 | avatar: file(absolutePath: { regex: "/profile-pic.jpg/" }) {
53 | childImageSharp {
54 | fixed(width: 50, height: 50) {
55 | ...GatsbyImageSharpFixed
56 | }
57 | }
58 | }
59 | site {
60 | siteMetadata {
61 | author
62 | social {
63 | twitter
64 | }
65 | }
66 | }
67 | }
68 | `
69 |
70 | export default Bio
71 |
--------------------------------------------------------------------------------
/gatsby-node.js:
--------------------------------------------------------------------------------
1 | const path = require(`path`)
2 | const { createFilePath } = require(`gatsby-source-filesystem`)
3 |
4 | exports.createPages = ({ graphql, actions }) => {
5 | const { createPage } = actions
6 |
7 | const blogPost = path.resolve(`./src/templates/blog-post.js`)
8 | return graphql(
9 | `
10 | {
11 | allMdx(
12 | sort: { fields: [frontmatter___date], order: DESC }
13 | limit: 1000
14 | ) {
15 | edges {
16 | node {
17 | id
18 | tableOfContents
19 | parent {
20 | ... on File {
21 | absolutePath
22 | name
23 | sourceInstanceName
24 | }
25 | }
26 | fields {
27 | slug
28 | }
29 | frontmatter {
30 | title
31 | date
32 | }
33 | fileAbsolutePath
34 | }
35 | }
36 | }
37 | }
38 | `
39 | ).then(result => {
40 | if (result.errors) {
41 | throw result.errors
42 | }
43 |
44 | // Create blog posts pages.
45 | const posts = result.data.allMdx.edges
46 |
47 | posts.forEach((post, index) => {
48 | const previous = index === posts.length - 1 ? null : posts[index + 1].node
49 | const next = index === 0 ? null : posts[index - 1].node
50 | createPage({
51 | path: `${post.node.fields.slug}`,
52 | component: blogPost,
53 | context: {
54 | slug: post.node.fields.slug,
55 | previous,
56 | next,
57 | absPath: post.node.parent.absolutePath,
58 | tableOfContents: post.node.tableOfContents,
59 | id: post.node.id,
60 | },
61 | })
62 | })
63 | })
64 | }
65 |
66 | exports.onCreateNode = ({ node, actions, getNode }) => {
67 | const { createNodeField } = actions
68 |
69 | if (node.internal.type === `Mdx`) {
70 | const value = createFilePath({ node, getNode })
71 | createNodeField({
72 | name: `slug`,
73 | node,
74 | value,
75 | })
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/components/Layout.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { Link } from "gatsby"
3 | import Toggle from "./Toggle"
4 | import Footer from "./Footer"
5 | import { rhythm } from "../utils/typography"
6 |
7 | class Layout extends React.Component {
8 | state = {
9 | theme: null,
10 | }
11 | componentDidMount() {
12 | this.setState({ theme: window.__theme })
13 | window.__onThemeChange = () => {
14 | this.setState({ theme: window.__theme })
15 | }
16 | }
17 | renderTopMenu() {
18 | return (
19 |
20 |
21 |
22 | iamprettydamn.cool blog
23 |
24 |
25 |
26 |
36 | ),
37 | unchecked: (
38 |
45 | ),
46 | }}
47 | checked={this.state.theme === "dark"}
48 | onChange={e => {
49 | window.__setPreferredTheme(e.target.checked ? "dark" : "light")
50 | }}
51 | />
52 |
53 |
54 | )
55 | }
56 | render() {
57 | const { children } = this.props
58 | return (
59 |
68 | {this.renderTopMenu()}
69 | {children}
70 |
73 |
74 | )
75 | }
76 | }
77 |
78 | export default Layout
79 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "alex-garcia-blog",
3 | "private": true,
4 | "description": "A blog to talk about stuff",
5 | "version": "0.1.0",
6 | "author": "Alex Garcia ",
7 | "bugs": {
8 | "url": "https://github.com/asg017/blogX/issues"
9 | },
10 | "dependencies": {
11 | "@mdx-js/mdx": "^0.17.5",
12 | "@mdx-js/tag": "^0.17.5",
13 | "@observablehq/notebook-runtime": "^2.0.0",
14 | "d3-time-format": "^2.1.3",
15 | "gatsby": "^2.1.17",
16 | "gatsby-image": "^2.0.29",
17 | "gatsby-mdx": "^0.4.0",
18 | "gatsby-plugin-feed": "^2.0.13",
19 | "gatsby-plugin-google-analytics": "^2.0.14",
20 | "gatsby-plugin-manifest": "^2.0.19",
21 | "gatsby-plugin-offline": "^2.0.24",
22 | "gatsby-plugin-react-helmet": "^3.0.6",
23 | "gatsby-plugin-sharp": "^2.0.22",
24 | "gatsby-plugin-typography": "^2.2.7",
25 | "gatsby-remark-copy-linked-files": "^2.0.9",
26 | "gatsby-remark-images": "^2.0.6",
27 | "gatsby-remark-prismjs": "^3.2.4",
28 | "gatsby-remark-responsive-iframe": "^2.0.9",
29 | "gatsby-remark-smartypants": "^2.0.8",
30 | "gatsby-source-filesystem": "^2.0.22",
31 | "gatsby-transformer-remark": "^2.2.6",
32 | "gatsby-transformer-sharp": "^2.1.14",
33 | "la-earthquake-app": "https://api.observablehq.com/@asg017/la-earthquake-app@640.tgz",
34 | "prismjs": "^1.15.0",
35 | "react": "^16.8.3",
36 | "react-dom": "^16.8.3",
37 | "react-helmet": "^5.2.0",
38 | "react-typography": "^0.16.18",
39 | "typeface-merriweather": "0.0.54",
40 | "typeface-montserrat": "0.0.54",
41 | "typography": "^0.16.18",
42 | "typography-theme-wordpress-2016": "^0.16.18"
43 | },
44 | "devDependencies": {
45 | "gh-pages": "^2.0.1",
46 | "prettier": "^1.16.4"
47 | },
48 | "homepage": "https://github.com/asg017/blogX",
49 | "keywords": [
50 | "gatsby"
51 | ],
52 | "license": "MIT",
53 | "main": "n/a",
54 | "repository": {
55 | "type": "git",
56 | "url": "git+https://github.com/asg017/blogX.git"
57 | },
58 | "scripts": {
59 | "build": "gatsby build",
60 | "deploy": "gatsby build --prefix-paths && gh-pages -d public -b gh-pages",
61 | "dev": "npm run develop",
62 | "develop": "gatsby develop",
63 | "format": "prettier --write src/**/*.{js,jsx}",
64 | "start": "npm run develop",
65 | "serve": "gatsby serve",
66 | "test": "echo \"Write tests! -> https://gatsby.app/unit-testing\""
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/pages/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { Link, graphql } from "gatsby"
3 |
4 | import Layout from "../components/Layout"
5 | import SEO from "../components/Seo"
6 | import { timeFormat } from "d3-time-format"
7 | import styles from "./BlogIndex.module.css"
8 | import { scale } from "../utils/typography"
9 |
10 | const formatPostDate = d => {
11 | const date = new Date(d)
12 | return timeFormat("%Y-%m-%d")(date)
13 | }
14 | const PostsList = ({ posts }) => (
15 |
16 | {posts.map(({ node }, i) => {
17 | const title = node.frontmatter.title || node.fields.slug
18 | return (
19 |
20 |
21 |
22 | {title}
23 |
24 |
25 | {formatPostDate(node.frontmatter.date)}
26 |
27 | )
28 | })}
29 |
30 | )
31 |
32 | const Hi = () => (
33 |
34 |
35 | 👋🏼
36 | {" "}
37 | I'm Alex, here's some posts I've written. Here's my{" "}
38 |
39 | site
40 | {" "}
41 | with more stuff about me
42 |
43 | )
44 | class BlogIndex extends React.Component {
45 | render() {
46 | const { data } = this.props
47 | const posts = data.allMdx.edges
48 | return (
49 |
50 |
51 |
52 |
53 |
54 | )
55 | }
56 | }
57 |
58 | export default BlogIndex
59 |
60 | export const pageQuery = graphql`
61 | query {
62 | site {
63 | siteMetadata {
64 | title
65 | }
66 | }
67 | allMdx(
68 | filter: { fileAbsolutePath: { regex: "/index.md/" } }
69 | sort: { fields: [frontmatter___date], order: DESC }
70 | ) {
71 | edges {
72 | node {
73 | fileAbsolutePath
74 | parent {
75 | id
76 | }
77 | excerpt
78 | fields {
79 | slug
80 | }
81 | frontmatter {
82 | date
83 | title
84 | }
85 | }
86 | }
87 | }
88 | }
89 | `
90 |
--------------------------------------------------------------------------------
/src/components/Seo.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import PropTypes from "prop-types"
3 | import Helmet from "react-helmet"
4 | import { StaticQuery, graphql } from "gatsby"
5 |
6 | function SEO({ description, lang, meta, keywords, title }) {
7 | return (
8 | {
11 | const metaDescription =
12 | description || data.site.siteMetadata.description
13 | return (
14 | 0
56 | ? {
57 | name: `keywords`,
58 | content: keywords.join(`, `),
59 | }
60 | : []
61 | )
62 | .concat(meta)}
63 | />
64 | )
65 | }}
66 | />
67 | )
68 | }
69 |
70 | SEO.defaultProps = {
71 | lang: `en`,
72 | meta: [],
73 | keywords: [],
74 | }
75 |
76 | SEO.propTypes = {
77 | description: PropTypes.string,
78 | lang: PropTypes.string,
79 | meta: PropTypes.array,
80 | keywords: PropTypes.arrayOf(PropTypes.string),
81 | title: PropTypes.string.isRequired,
82 | }
83 |
84 | export default SEO
85 |
86 | const detailsQuery = graphql`
87 | query DefaultSEOQuery {
88 | site {
89 | siteMetadata {
90 | title
91 | description
92 | author
93 | }
94 | }
95 | }
96 | `
97 |
--------------------------------------------------------------------------------
/src/html.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import PropTypes from "prop-types"
3 |
4 | export default class HTML extends React.Component {
5 | render() {
6 | return (
7 |
8 |
9 |
10 |
11 |
15 | {this.props.headComponents}
16 |
17 |
18 |
52 | {this.props.preBodyComponents}
53 |
58 | {this.props.postBodyComponents}
59 |
60 |
61 | )
62 | }
63 | }
64 |
65 | HTML.propTypes = {
66 | htmlAttributes: PropTypes.object,
67 | headComponents: PropTypes.array,
68 | bodyAttributes: PropTypes.object,
69 | preBodyComponents: PropTypes.array,
70 | body: PropTypes.string,
71 | postBodyComponents: PropTypes.array,
72 | }
73 |
--------------------------------------------------------------------------------
/gatsby-config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | pathPrefix: "/blogX",
3 | siteMetadata: {
4 | title: `iamprettydamn.cool`,
5 | author: `Alex Garcia`,
6 | description: `blog from Alex Garcia`,
7 | siteUrl: `https://iamprettydamn.cool/blogX`,
8 | social: {
9 | twitter: `agarcia_me`,
10 | },
11 | },
12 | plugins: [
13 | {
14 | resolve: `gatsby-mdx`,
15 | options: {
16 | extensions: [".mdx", ".md"],
17 | gatsbyRemarkPlugins: [
18 | {
19 | resolve: `gatsby-remark-images`,
20 | options: {
21 | maxWidth: 590,
22 | },
23 | },
24 | {
25 | resolve: `gatsby-remark-responsive-iframe`,
26 | options: {
27 | wrapperStyle: `margin-bottom: 1.0725rem`,
28 | },
29 | },
30 | {
31 | resolve: `gatsby-remark-copy-linked-files`,
32 | },
33 |
34 | {
35 | resolve: `gatsby-remark-smartypants`,
36 | },
37 | ],
38 | },
39 | },
40 | {
41 | resolve: `gatsby-source-filesystem`,
42 | options: {
43 | path: `${__dirname}/content/blog`,
44 | name: `blog`,
45 | },
46 | },
47 | {
48 | resolve: `gatsby-source-filesystem`,
49 | options: {
50 | path: `${__dirname}/content/assets`,
51 | name: `assets`,
52 | },
53 | },
54 |
55 | {
56 | resolve: `gatsby-transformer-remark`,
57 | options: {
58 | plugins: [
59 | {
60 | resolve: `gatsby-remark-images`,
61 | options: {
62 | maxWidth: 590,
63 | },
64 | },
65 | {
66 | resolve: `gatsby-remark-responsive-iframe`,
67 | options: {
68 | wrapperStyle: `margin-bottom: 1.0725rem`,
69 | },
70 | },
71 | `gatsby-remark-prismjs`,
72 | `gatsby-remark-copy-linked-files`,
73 | `gatsby-remark-smartypants`,
74 | ],
75 | },
76 | },
77 | `gatsby-transformer-sharp`,
78 | `gatsby-plugin-sharp`,
79 | {
80 | resolve: `gatsby-plugin-google-analytics`,
81 | options: {
82 | //trackingId: `ADD YOUR TRACKING ID HERE`,
83 | },
84 | },
85 | // `gatsby-plugin-feed`,TODO Add this back in after changing default query
86 | {
87 | resolve: `gatsby-plugin-manifest`,
88 | options: {
89 | name: `iamprettydamn.cool blog`,
90 | short_name: `Alex Garcia blog`,
91 | start_url: `/`,
92 | background_color: `#ffffff`,
93 | theme_color: `#000000`,
94 | display: `minimal-ui`,
95 | icon: `content/assets/icon.png`,
96 | },
97 | },
98 | `gatsby-plugin-offline`,
99 | `gatsby-plugin-react-helmet`,
100 | {
101 | resolve: `gatsby-plugin-typography`,
102 | options: {
103 | pathToConfigModule: `src/utils/typography`,
104 | },
105 | },
106 | ],
107 | }
108 |
--------------------------------------------------------------------------------
/src/templates/blog-post.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { Link, graphql } from "gatsby"
3 |
4 | import Bio from "../components/Bio"
5 | import Layout from "../components/Layout"
6 | import SEO from "../components/Seo"
7 | import { rhythm, scale } from "../utils/typography"
8 | import MDXRenderer from "gatsby-mdx/mdx-renderer"
9 | import { MDXProvider } from "@mdx-js/tag"
10 | import { timeFormat } from "d3-time-format"
11 |
12 | const formatPostDate = d => {
13 | const date = new Date(d)
14 | return timeFormat("%A, %B %e, %Y")(date)
15 | }
16 | const formatOtherPostDate = d => {
17 | const date = new Date(d)
18 | console.log(date, d)
19 | return timeFormat("%b. %e %Y")(date)
20 | }
21 | const OtherPost = ({ post }) => (
22 |
23 |
24 | {post.frontmatter.title}
25 | {" "}
26 | -{" "}
27 |
28 | {formatOtherPostDate(post.frontmatter.date)}
29 |
30 |
31 | )
32 | class BlogPostTemplate extends React.Component {
33 | render() {
34 | const post = this.props.data.mdx
35 | const author = this.props.data.site.siteMetadata.author
36 | const { previous, next } = this.props.pageContext
37 | console.log(this.props)
38 | return (
39 |
40 |
44 | {post.frontmatter.title}
45 | {author}
46 |
53 |
{formatPostDate(post.frontmatter.date)}
54 |
55 | {children} ,
58 | wrapper: "article",
59 | }}
60 | >
61 | {this.props.children}
62 |
63 | {this.props.data.mdx.code.body}
64 |
65 |
66 |
72 |
73 |
74 |
75 | {previous && previous.frontmatter && previous.frontmatter.title && (
76 |
77 | Previous:
78 |
79 | )}
80 |
81 | {next && next.frontmatter && next.frontmatter.title && (
82 |
83 | Next:
84 |
85 | )}
86 |
87 |
88 | )
89 | }
90 | }
91 |
92 | export default BlogPostTemplate
93 |
94 | export const pageQuery = graphql`
95 | query BlogPostBySlug($slug: String!) {
96 | site {
97 | siteMetadata {
98 | title
99 | author
100 | }
101 | }
102 | mdx(fields: { slug: { eq: $slug } }) {
103 | id
104 | excerpt(pruneLength: 160)
105 | code {
106 | body
107 | }
108 | frontmatter {
109 | title
110 | date
111 | }
112 | }
113 | }
114 | `
115 |
--------------------------------------------------------------------------------
/src/components/Toggle.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 instructure-react
3 | * Forked from https://github.com/aaronshaf/react-toggle/
4 | **/
5 |
6 | .react-toggle {
7 | touch-action: pan-x;
8 | float: right;
9 | display: inline-block;
10 | position: relative;
11 | cursor: pointer;
12 | background-color: transparent;
13 | border: 0;
14 | padding: 0;
15 |
16 | -webkit-touch-callout: none;
17 | -webkit-user-select: none;
18 | -khtml-user-select: none;
19 | -moz-user-select: none;
20 | -ms-user-select: none;
21 | user-select: none;
22 |
23 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
24 | -webkit-tap-highlight-color: transparent;
25 | }
26 |
27 | .react-toggle-screenreader-only {
28 | border: 0;
29 | clip: rect(0 0 0 0);
30 | height: 1px;
31 | margin: -1px;
32 | overflow: hidden;
33 | padding: 0;
34 | position: absolute;
35 | width: 1px;
36 | }
37 |
38 | .react-toggle-track {
39 | width: 50px;
40 | height: 24px;
41 | padding: 0;
42 | border-radius: 30px;
43 | background-color: hsl(222, 14%, 7%);
44 | -webkit-transition: all 0.2s ease;
45 | -moz-transition: all 0.2s ease;
46 | transition: all 0.2s ease;
47 | }
48 |
49 | .react-toggle-track-check {
50 | position: absolute;
51 | width: 17px;
52 | height: 17px;
53 | left: 5px;
54 | top: 0px;
55 | bottom: 0px;
56 | margin-top: auto;
57 | margin-bottom: auto;
58 | line-height: 0;
59 | opacity: 0;
60 | -webkit-transition: opacity 0.25s ease;
61 | -moz-transition: opacity 0.25s ease;
62 | transition: opacity 0.25s ease;
63 | }
64 |
65 | .react-toggle--checked .react-toggle-track-check {
66 | opacity: 1;
67 | -webkit-transition: opacity 0.25s ease;
68 | -moz-transition: opacity 0.25s ease;
69 | transition: opacity 0.25s ease;
70 | }
71 |
72 | .react-toggle-track-x {
73 | position: absolute;
74 | width: 17px;
75 | height: 17px;
76 | right: 5px;
77 | top: 0px;
78 | bottom: 0px;
79 | margin-top: auto;
80 | margin-bottom: auto;
81 | line-height: 0;
82 | opacity: 1;
83 | -webkit-transition: opacity 0.25s ease;
84 | -moz-transition: opacity 0.25s ease;
85 | transition: opacity 0.25s ease;
86 | }
87 |
88 | .react-toggle--checked .react-toggle-track-x {
89 | opacity: 0;
90 | }
91 |
92 | .react-toggle-thumb {
93 | position: absolute;
94 | top: 1px;
95 | left: 1px;
96 | width: 22px;
97 | height: 22px;
98 | border-radius: 50%;
99 | background-color: #fafafa;
100 | -webkit-box-sizing: border-box;
101 | -moz-box-sizing: border-box;
102 | box-sizing: border-box;
103 | transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1) 0ms;
104 | }
105 |
106 | .react-toggle--checked .react-toggle-thumb {
107 | left: 27px;
108 | border-color: var(--darkBlue);
109 | }
110 |
111 | .light .react-toggle--focus .react-toggle-thumb {
112 | -webkit-box-shadow: 0px 0px 3px 2px var(--darkBlue);
113 | -moz-box-shadow: 0px 0px 3px 2px var(--darkBlue);
114 | box-shadow: 0px 0px 2px 3px var(--darkBlue);
115 | }
116 |
117 | .light .react-toggle:active .react-toggle-thumb {
118 | -webkit-box-shadow: 0px 0px 5px 5px var(--darkBlue);
119 | -moz-box-shadow: 0px 0px 5px 5px var(--darkBlue);
120 | box-shadow: 0px 0px 5px 5px var(--darkBlue);
121 | }
122 |
123 | .dark .react-toggle--focus .react-toggle-thumb {
124 | -webkit-box-shadow: 0px 0px 3px 2px var(--orange);
125 | -moz-box-shadow: 0px 0px 3px 2px var(--orange);
126 | box-shadow: 0px 0px 2px 3px var(--orange);
127 | }
128 |
129 | .dark .react-toggle:active .react-toggle-thumb {
130 | -webkit-box-shadow: 0px 0px 5px 5px var(--orange);
131 | -moz-box-shadow: 0px 0px 5px 5px var(--orange);
132 | box-shadow: 0px 0px 5px 5px var(--orange);
133 | }
134 |
--------------------------------------------------------------------------------
/content/blog/2019/racist-code/index.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 5 ways to write racist code
3 | date: "2019-03-08T22:40:42.046Z"
4 | ---
5 |
6 | This is a post for all the resources and links that I have for my [#NICAR19](https://www.ire.org/conferences/nicar-2019/) lighting talk called “5 ways to write racist code”.
7 |
8 | [Slides here](http://iamprettydamn.cool/racist-code-slides)
9 |
10 | [source code](https://github.com/asg017/racist-code-slides) for slides (warning: it’s disgusting)
11 |
12 | ## Resources
13 | Links to articles and stories I talked about!
14 |
15 | ### #5 Use racist data
16 | - [Dirty Data, Bad Predictions: How Civil Rights Violations Impact Police Data, Predictive Policing Systems, and Justice](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3333423)
17 |
18 | Extras I didn’t include:
19 |
20 | - [Microsoft’s racist twitter bot](https://www.theverge.com/2016/3/25/11306566/microsoft-racist-tay-ai-twitter-chatbot-apology)
21 |
22 |
23 | ### #4 Use non-diverse data
24 |
25 | - [Response: Racial and Gender bias in Amazon Rekognition — Commercial AI System for Analyzing Faces. by Joy Buolamwini](https://medium.com/@Joy.Buolamwini/response-racial-and-gender-bias-in-amazon-rekognition-commercial-ai-system-for-analyzing-faces-a289222eeced)
26 |
27 | Extras I didn’t include:
28 |
29 | - [FaceApp: White is hot](https://techcrunch.com/2017/04/25/faceapp-apologises-for-building-a-racist-ai/)
30 | - [gender data gap](https://amp.theguardian.com/lifeandstyle/2019/feb/23/truth-world-built-for-men-car-crashes?CMP=share_btn_tw&__twitter_impression=true)
31 |
32 | ### #3 Accidentally
33 |
34 | - [Black people in UK 21 times more likely to have university applications investigated, figures show from the Independent](https://www.independent.co.uk/news/education/education-news/uk-black-students-university-applications-investigation-more-likely-ucas-figures-nus-labour-a8314496.html)
35 |
36 | extras that I didn’t include:
37 |
38 | - [Uber’s accidental redlining](https://twitter.com/rouge8/status/781279125596241920)
39 | - [Same but for seattle](https://medium.com/@SherylCababa/i-combined-the-map-for-seattle-uberhop-with-a-racial-segregation-map-sorry-brown-people-9d756168c8b9)
40 | [Amazon accidental redlining](https://www.bloomberg.com/graphics/2016-amazon-same-day/)
41 |
42 | ### #2 Use black bloxes
43 |
44 | [How to make a racist AI without really trying by Robyn Speer](https://blog.conceptnet.io/posts/2017/how-to-make-a-racist-ai-without-really-trying/)
45 |
46 | ### #1 Think that code can’t have bias
47 |
48 | - [AOC is right about algorithms. from Slate](https://slate.com/news-and-politics/2019/02/aoc-algorithms-racist-bias.html)
49 | - [NYT Opinion piece](https://www.nytimes.com/2019/03/02/opinion/sunday/diet-artificial-intelligence-diabetes.html) (says something like “ML took away the biases of the scientists”)
50 | - [Reddit comment about algorithms “defeating” gerrymandering](https://www.reddit.com/r/politics/comments/5s0mcz/politics_are_a_mess_lets_hand_it_over_to_software/ddbkd71)
51 |
52 | ## Random questions
53 |
54 | > Why did you use spectacle instead of Google slides
55 |
56 | It was a series of bad choices.
57 |
58 | My original presentation was going to have a cool, built-in “racist AI” that would be trained during the course of the lightning talk. At the end, I’d have a big reveal and say something like “its so easy to write racist code, that this presetnation just made a racist AI!”
59 |
60 | I didnt end up doing this because:
61 |
62 | 1. I found Tensorflowjs to be pretty hard to work with
63 | 2. I didn’t have time in the final presentation to do it
64 | 3. I didnt want the page to crash
65 | 4. I was spending too much time on that and not the presentation
66 |
67 | > Example X doesn’t really match with #5/4/3/2/1
68 |
69 | Yeah, these examples aren’t too exact - For example, the UK Black applicants story could be about non-diverse data or even racist data - there’s just not enough details. And the Python sentiment analysis tool could fit under “non-diverse” data best.
70 |
71 | So these examples aren’t 💯% - but I still think the 5 points stand pretty well on their own feet.
72 |
73 | (republished bc I lost the original mdx file)
74 |
--------------------------------------------------------------------------------
/src/components/Toggle.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 instructure-react
3 | * Forked from https://github.com/aaronshaf/react-toggle/
4 | * + applied https://github.com/aaronshaf/react-toggle/pull/90
5 | **/
6 |
7 | import "./Toggle.css"
8 |
9 | import React, { PureComponent } from "react"
10 |
11 | // Copyright 2015-present Drifty Co.
12 | // http://drifty.com/
13 | // from: https://github.com/driftyco/ionic/blob/master/src/util/dom.ts
14 | function pointerCoord(event) {
15 | // get coordinates for either a mouse click
16 | // or a touch depending on the given event
17 | if (event) {
18 | const changedTouches = event.changedTouches
19 | if (changedTouches && changedTouches.length > 0) {
20 | const touch = changedTouches[0]
21 | return { x: touch.clientX, y: touch.clientY }
22 | }
23 | const pageX = event.pageX
24 | if (pageX !== undefined) {
25 | return { x: pageX, y: event.pageY }
26 | }
27 | }
28 | return { x: 0, y: 0 }
29 | }
30 |
31 | export default class Toggle extends PureComponent {
32 | constructor(props) {
33 | super(props)
34 | this.handleClick = this.handleClick.bind(this)
35 | this.handleTouchStart = this.handleTouchStart.bind(this)
36 | this.handleTouchMove = this.handleTouchMove.bind(this)
37 | this.handleTouchEnd = this.handleTouchEnd.bind(this)
38 | this.handleTouchCancel = this.handleTouchCancel.bind(this)
39 | this.handleFocus = this.handleFocus.bind(this)
40 | this.handleBlur = this.handleBlur.bind(this)
41 | this.previouslyChecked = !!(props.checked || props.defaultChecked)
42 | this.state = {
43 | checked: !!(props.checked || props.defaultChecked),
44 | hasFocus: false,
45 | }
46 | }
47 |
48 | componentWillReceiveProps(nextProps) {
49 | if ("checked" in nextProps) {
50 | this.setState({ checked: !!nextProps.checked })
51 | this.previouslyChecked = !!nextProps.checked
52 | }
53 | }
54 |
55 | handleClick(event) {
56 | const checkbox = this.input
57 | this.previouslyChecked = checkbox.checked
58 | if (event.target !== checkbox && !this.moved) {
59 | event.preventDefault()
60 | checkbox.focus()
61 | checkbox.click()
62 | return
63 | }
64 |
65 | this.setState({ checked: checkbox.checked })
66 | }
67 |
68 | handleTouchStart(event) {
69 | this.startX = pointerCoord(event).x
70 | this.touchStarted = true
71 | this.hadFocusAtTouchStart = this.state.hasFocus
72 | this.setState({ hasFocus: true })
73 | }
74 |
75 | handleTouchMove(event) {
76 | if (!this.touchStarted) return
77 | this.touchMoved = true
78 |
79 | if (this.startX != null) {
80 | let currentX = pointerCoord(event).x
81 | if (this.state.checked && currentX + 15 < this.startX) {
82 | this.setState({ checked: false })
83 | this.startX = currentX
84 | } else if (!this.state.checked && currentX - 15 > this.startX) {
85 | this.setState({ checked: true })
86 | this.startX = currentX
87 | }
88 | }
89 | }
90 |
91 | handleTouchEnd(event) {
92 | if (!this.touchMoved) return
93 | const checkbox = this.input
94 | event.preventDefault()
95 |
96 | if (this.startX != null) {
97 | if (this.previouslyChecked !== this.state.checked) {
98 | checkbox.click()
99 | }
100 |
101 | this.touchStarted = false
102 | this.startX = null
103 | this.touchMoved = false
104 | }
105 |
106 | if (!this.hadFocusAtTouchStart) {
107 | this.setState({ hasFocus: false })
108 | }
109 | }
110 |
111 | handleTouchCancel(event) {
112 | if (this.startX != null) {
113 | this.touchStarted = false
114 | this.startX = null
115 | this.touchMoved = false
116 | }
117 |
118 | if (!this.hadFocusAtTouchStart) {
119 | this.setState({ hasFocus: false })
120 | }
121 | }
122 |
123 | handleFocus(event) {
124 | const { onFocus } = this.props
125 |
126 | if (onFocus) {
127 | onFocus(event)
128 | }
129 |
130 | this.hadFocusAtTouchStart = true
131 | this.setState({ hasFocus: true })
132 | }
133 |
134 | handleBlur(event) {
135 | const { onBlur } = this.props
136 |
137 | if (onBlur) {
138 | onBlur(event)
139 | }
140 |
141 | this.hadFocusAtTouchStart = false
142 | this.setState({ hasFocus: false })
143 | }
144 |
145 | getIcon(type) {
146 | const { icons } = this.props
147 | if (!icons) {
148 | return null
149 | }
150 | return icons[type] === undefined
151 | ? Toggle.defaultProps.icons[type]
152 | : icons[type]
153 | }
154 |
155 | render() {
156 | const { className, icons: _icons, ...inputProps } = this.props
157 | const classes =
158 | "react-toggle" +
159 | (this.state.checked ? " react-toggle--checked" : "") +
160 | (this.state.hasFocus ? " react-toggle--focus" : "") +
161 | (this.props.disabled ? " react-toggle--disabled" : "") +
162 | (className ? " " + className : "")
163 | return (
164 |
172 |
173 |
174 | {this.getIcon("checked")}
175 |
176 |
177 | {this.getIcon("unchecked")}
178 |
179 |
180 |
181 |
182 |
{
185 | this.input = ref
186 | }}
187 | onFocus={this.handleFocus}
188 | onBlur={this.handleBlur}
189 | className="react-toggle-screenreader-only"
190 | type="checkbox"
191 | aria-label="Switch between Dark and Light mode"
192 | />
193 |
194 | )
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/content/blog/2019/ucsd-fall-career-fair-ice/index.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: UCSD Fall Career Fair Companies that work with ICE (2019)
3 | date: "2019-10-02T10:00:00.000Z"
4 | ---
5 |
6 | Today, thousands of UCSD students will be attending the Fall Career Fair at RIMAC Arena, where nearly 190 employers from around the world will be stationed, talking to students, accepting resumes, and handing out free swag branded with their logos.
7 |
8 | But, there is not much discussion about who these companies are and what they stand for. So, I have compiled a list of companies that are attending the Fall Career Fair that are working with Immigration and Custom Enforcement (ICE) in some capacity.
9 |
10 | **Note**: If there is anything I should add below, or if there is anything wrong in the information below, please let me know!
11 |
12 | ## Caveats
13 |
14 | Just because a company is listed doesn't mean that they support family separation or that they actively participant in the crisis. But, they do have a working relationship with ICE, the organization that *does* separate children and lives, and in many cases, ICE wouldn't be able to function without tools provided by these companies. Many of these companies have also acknowledge their involvement with ICE and have refused to change their ways in the future.
15 |
16 | ## The Companies
17 |
18 | ### Accenture
19 |
20 | Accenture is a management consulting company that, [in 2018](https://www.npr.org/2018/12/11/675923576/customs-border-and-protection-paid-a-firm-13-6-million-to-hire-recruits-it-hired), was given $13.6 million by U.S. Customs And Border Protection to recruit thousands of applicant's to satisfy Trump's "mandate to secure the southern border." They were able to get hire 2 people, then [CBP cancelled the contract](https://www.cnn.com/2019/04/05/politics/cbp-terminate-hiring-contract-accenture/index.html).
21 |
22 | ### Amazon
23 |
24 | Amazon is a large tech company that provides clouding hosting for many large organizations. They also [provide many cloud platforms and services](https://mijente.net/wp-content/uploads/2018/10/WHO%E2%80%99S-BEHIND-ICE_-The-Tech-and-Data-Companies-Fueling-Deportations-_v1.pdf) to many federal immigration and border control agencies. They [host backups](https://fortune.com/2018/10/23/tech-companies-surveillance-ice-immigrants/) of the Department of Homeland Security's database of biometric information, and also [provide cloud support Palantir](https://medium.com/@amazon_employee/im-an-amazon-employee-my-company-shouldn-t-sell-facial-recognition-tech-to-police-36b5fde934ac), a tech company behind much of ICE's "deportation and tracking programs."
25 |
26 | ### Leidos
27 |
28 | Leidos is large defense contracting corporation that, "provide(s) safety and security through cyber security and data analytics techniques applied to cargo, baggage, and vehicle screening (on both the northern and southern borders)" for the Department of Homeland Security ([source](https://www.davisite.org/2018/06/uc-davis-statement-on-chancellor-may-leidos-corp-and-heart-wrenching-political-tactics-for-refugees.html)). Their CFO said that the company was ["positioned for growth"](https://theintercept.com/2016/12/06/defense-companies-trump/) when Trump's administration was set to increase border security spending. They also develop and sell ["Wide Area Surveillance Systems,"](https://investors.leidos.com/news-and-events/news-releases/press-release-details/2012/SAIC-Introduces-Integrated-Wide-Area-Surveillance-System/default.aspx) that are used to "predict, deter, detect, track, identify, classify, respond to, and resolve illegal incursions."
29 |
30 | ### Oracle
31 |
32 | Oracle is a large tech company that provides cloud hosting to many organizations. They have ["multi-million dollar"](https://mijente.net/wp-content/uploads/2018/10/WHO%E2%80%99S-BEHIND-ICE_-The-Tech-and-Data-Companies-Fueling-Deportations-_v1.pdf) cloud contracts with the Department of Homeland Security, and well as [provide cloud infrastructure](https://www.cnbc.com/2019/08/19/google-employees-implore-leaders-to-stop-working-with-us-bcp-ice.html) to the Customs and Border Protection agency.
33 |
34 | ### Serco Inc.
35 |
36 | Serco is a service company that caters or large national organizations and governments. [They have lobbied](https://www.theguardian.com/us-news/2015/jun/19/serco-immigration-detention-centers-united-states) in the US for migration detention facilities contracts, and "boasted" of their record in detaining migrant families.
37 |
38 | ### ServiceNow
39 |
40 | ServiceNow is a cloud software company that serves large enterprises. The US Customs and Border Protection Agency [uses their services](https://www.datacenterdynamics.com/news/google-employees-protest-against-border-agency-scandals/), and [have been subcontracted](https://etc.g2xchange.com/statics/ice-awards-contract-for-servicenow-sms-ppm-licenses-and-discovery-licenses/) by other organizations that work directly with ICE.
41 |
42 | ### Salesforce
43 |
44 | Salesforce is a large tech company that provides CRM systems to large enterprises. The US Customs and Border Protection agency [uses their services](https://www.datacenterdynamics.com/news/google-employees-protest-against-border-agency-scandals/), provides their "Salesforce Government Cloud" [product to ICE](https://mijente.net/wp-content/uploads/2018/10/WHO%E2%80%99S-BEHIND-ICE_-The-Tech-and-Data-Companies-Fueling-Deportations-_v1.pdf), and their CEO has directly refused to sever ties with CBP, despite the urging of hundreds of employees who [signed a petition](https://gizmodo.com/salesforce-ceo-says-they-wont-sever-ties-with-customs-a-1827195457) asking him to do so.
45 |
46 | ## Q&A
47 |
48 | ### What should I do with this information?
49 |
50 | It depends. If you were planning to talk to these companies at the career fair, I would do some more research on their involvement with ICE, and decide on your own accord if you are comfortable with working with them.
51 |
52 | If you weren't going to talk with them, I'd still take a closer look at the companies you *do* talk to. This isn't a complete list, and there may be other reasons to avoid working with a company.
53 |
54 | ### Why just companies that work with ICE?
55 |
56 | There are many, many reasons to take a closer look at companies that you want to interview for - their working relationship with ICE shouldn't be the only thing. For example, what actions do they take to combat climate change? Which political campaigns do they contribute to, and why? Do they have internal policies to ensure that everyone is paid equally and fairly across roles? What steps do they take to ensure they avoid contributing to gentrification in their local communities?
57 |
58 | But for me, at this time and for this career fair, researching a company's history with immigration officials is what is important to me. I encourage others to make their own lists with issues they care about.
59 |
60 | ### Why only companies that are going to the career fair?
61 |
62 | It shouldn't be! There are many different ways companies interact with the UCSD community. I think we should scrutinize company involvement in all levels - including in student orgs, department sponsorships, and hackathon/event sponsorships.
63 |
64 | ### Who are you?
65 |
66 | I'm Alex 👋! I'm a UCSD student, 5th year, Computer Engineering major, from Revelle College, about to graduate this December. I'm not some outsider, I'm not looking to cancel anyone, and I'm not a part of an organized political group. I'm just someone who cares about what's happening at the border and want to help in any way I can (which, for now, is starting a conversation in my community about what's happening).
67 |
68 | ### Why did you make this list?
69 |
70 | Story time: In 2016, when I was a sophomore, I attended SD Hacks at UCSD - my first hackathon! I had no tech experience, never done a interview, only had a few programming classes under my belt, and I hadn't even met a full-time software engineer in my life.
71 |
72 | In terms of hacking, it was great! I met some really cool people, my team won a prize, and I had a blast.
73 |
74 | But, I did have one sour interaction. There were a few companies/organizations that were tabling all weekend, so during a break from coding, one of my teammates and I went to go talk with one of them (I believe it was SPAWAR, but I could be mis-remembering). The representative there chatted with us for a while, about what they do and who they hire. He then started telling some random stories about his work, and at one point he told us a story about how he was working on a project with a border control agency. That project involved doing something at the US-Mexico border, and he said that they had a physical map of the border, and had little figurines on the map to denote specific groups on the map - their group and people crossing the border. He said that he had the idea of putting sombreros on the figurines that represented the people crossing the border. He then said that his teammate told that him that the joke was offensive, but he still laughed it off and started laughing again with the other SPAWAR representative at the table.
75 |
76 | I laughed along too, because I thought I had no choice. I definitely didn't think he was funny - I thought he was a racist asshole. But, at the time, I thought that this was my only opportunity for a software job, so I laughed along and dealt with his stories, hoping to somehow slip my resume to them.
77 |
78 | The companies that visit UCSD have a lot of power - power that we don't talk about a lot, as a community. Yes, they give students jobs and transform our campus with donations and research collaborations. But for many students, they act as the sole representative of entire industries. I thought that all software companies were full of assholes like that representative from SD Hacks. It wasn't until I joined [Code2040](http://www.code2040.org/), met people from other companies, and worked with other engineers did I realize that what happened back then was totally wrong and was not representative on the entire tech industry.
79 |
80 | Yes, only a small handful of companies at the career fair work with ICE in some capacity. But the longer we say nothing and act complicit in their actions, the more comfortable they get and the longer they spend supporting the atrocities that are being committed at the border.
81 |
--------------------------------------------------------------------------------