text:
<!doctype html>

	<meta charset="utf-8">
	<meta name="author" content="Science & Design">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<meta name="description" content="A Temporary Tor Snowflake Proxy">

	<title>Relay Love - A Temporary Tor Snowflake Proxy</title>

	<link rel="icon" type="image/x-icon" href="design-system/images/favicon/favicon.ico">
	<link rel="stylesheet" href="design-system/css/style.css">
	<link rel="stylesheet" href="css/style.css">

❤ Is this resource helpful? Support our work!

❄ Relay Love

Clone This Project

Temporarily Share Your Bandwidth

Help people safely access the internet using Snowflake. To share your connection, enable the toggle and keep this tab open. Avoid sharing from censored locations.

Or, add it as a browser extension on Firefox or Chrome!

✊ An anti-censorship project by Science & Design

repo_name: scidsg/relaylove

repo_language: CSS


text:
==================================================================
https://keybase.io/glennsorrentino
--------------------------------------------------------------------

I hereby claim:

  * I am an admin of https://relay.love
  * I am glennsorrentino (https://keybase.io/glennsorrentino) on keybase.
  * I have a public key ASCygMX9r97xdu1Wz0GD5XHzM9zXdteAzWJ6OZZRM8kXTgo

To do so, I am signing this object:

{
  "body": {
    "key": {
      "eldest_kid": "010123ed4a619d56831197a5a583d27c9c10246640bd53f9179c7dd5817ca9c344920a",
      "host": "keybase.io",
      "kid": "0120b280c5fdafdef176ed56cf4183e571f333dcd776d780cd627a39965133c9174e0a",
      "uid": "8e5e3209ef89644436b58deb16ce5f19",
      "username": "glennsorrentino"
    },
    "merkle_root": {
      "ctime": 1662930438,
      "hash": "46b09ab37d1e0378d3da2141b761e760c0159378c23af5c42849de23ee212cd4bef77871a9405b82f578493297a534707e77256bd820ab2299d1574c05e0794d",
      "hash_meta": "809ed99f7a80105ce3545ae21c4c54f74c8107155996c30b44506c1563b3ec1e",
      "seqno": 23177900
    },
    "service": {
      "entropy": "daBHAk+vSADqwiz1jdA1n/tN",
      "hostname": "relay.love",
      "protocol": "https:"
    },
    "type": "web_service_binding",
    "version": 2
  },
  "client": {
    "name": "keybase.io go client",
    "version": "6.0.1"
  },
  "ctime": 1662930511,
  "expire_in": 504576000,
  "prev": "bb073468729da3b2debad43590e870224235087ac1b09255f97feb2f442f5048",
  "seqno": 170,
  "tag": "signature"
}

which yields the signature:

hKRib2R5hqhkZXRhY2hlZMOpaGFzaF90eXBlCqNrZXnEIwEgsoDF/a/e8XbtVs9Bg+Vx8zPc13bXgM1iejmWUTPJF04Kp3BheWxvYWTES5cCzKrEILsHNGhynaOy3rrUNZDocCJCNQh6wbCSVfl/6y9EL1BIxCDGdJytA3594dg2Tl6Buiv1Vl59IkwHcaQc6RsNb3cH+QIBwqNzaWfEQEkLcpss6NF7APIUIm9td+AKr4t0Uj+QvMSuMvj9TH8HdAnEpf67S3IvLJY29Q2hbXLxnlrJJjhFGWY0BMru8Q+oc2lnX3R5cGUgpGhhc2iCpHR5cGUIpXZhbHVlxCDYSm1mNzsu2okdTX8+HWL+zosknd0TlpbBn1Am0Gp0rqN0YWfNAgKndmVyc2lvbgE=

And finally, I am proving ownership of this host by posting or
appending to this document.

View my publicly-auditable identity here: https://keybase.io/glennsorrentino

==================================================================

mime_type: text/plain


text:
# ❄ Relay Love

https://relay.love

[mfhwtydqwv3jcjt2wumjmqww2llltfaqdbivu3hcmcnkhj5dvxjxiaid.onion](http://mfhwtydqwv3jcjt2wumjmqww2llltfaqdbivu3hcmcnkhj5dvxjxiaid.onion)

https://scidsg.github.io/relaylove/

## Temporarily Share Your Bandwidth
Help people safely access the internet using the Tor network. To share your connection, enable the toggle and keep the tab open. Avoid sharing from censored locations.

![rl](https://user-images.githubusercontent.com/28545431/216750638-406fb29b-0474-4516-a82b-c06dd06c5e5a.png)

[Learn more about Snowflake on torproject.org](https://snowflake.torproject.org/).


text:
# These are supported funding model platforms

github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # glennsorrentino
open_collective: scidsg
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']


text:
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Desktop (please complete the following information):**
 - OS: [e.g. iOS]
 - Browser [e.g. chrome, safari]
 - Version [e.g. 22]

**Smartphone (please complete the following information):**
 - Device: [e.g. iPhone6]
 - OS: [e.g. iOS8.1]
 - Browser [e.g. stock browser, safari]
 - Version [e.g. 22]

**Additional context**
Add any other context about the problem here.


text:
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


text:
---
name: Custom issue template
about: Describe this issue template's purpose here.
title: ''
labels: ''
assignees: ''

---


text:
/* The Simple Design System is made with ❤ by Glenn Sorrentino - https://glennsorrentino.com */
/* Please consider contributing! */

/* Add your custom styles in this file... */

@media (prefers-color-scheme: light) {
  header, .intro, nav ul {
    background-color: #7D4698 !important;
  }

  h2 {
    color: #92E7FF !important;
  }

  .primaryBtn {
    background-color: #92E7FF !important;
    color: #59316B !important;
  }

  .btn {
    border: 2px solid #92E7FF;
    color: #92E7FF;
    background: none;
  }

  iframe {
    background-color: white;
  }

}

@media (prefers-color-scheme: dark) {
  header, .intro, nav ul {
    background-color: #321C3D !important;
  }

  h2 {
    color: #92E7FF !important;
  }

  .btn {
    background-color: #8C5EA1;
    color: #FFFFFF !important;
  }

  .primaryBtn {
    background-color: #92E7FF;
    color: #59316B !important;
  }

  iframe {
    background-color: #59316B !important;
  }
}

body {
}

p, a, h1 {
  color: white !important;
}

h2 {
  font-family: "Serif";
  font-weight: inherit;
  font-size: calc(var(--font-size-1) * 1.0125);
  margin-bottom: var(--spacing-small);
}

.intro {
  margin-bottom: 0;
}

.intro .description {
  width: 66%;
}

.intro .group {
  align-items: center;
}

iframe {
  border-radius: .5rem;
  box-shadow: 0 1rem 3rem -.5rem rgba(0,0,0,0.25);
  margin: 0 auto 0 0;
}

@media only screen and (max-width: 1280px) {

}

@media only screen and (max-width: 1024px) {

}

@media only screen and (max-width: 960px) {
  h2 {
    font-size: calc(var(--font-size-1) * .9);
  }
}

@media only screen and (max-width: 768px) {
  p, p.meta {
    margin-right: auto !important;
    margin-left: auto !important;
  }

  .intro .group {
    align-items: flex-start;
    margin-bottom: 0;
    margin-top: 0;
  }

  .intro p {
    margin-left: 0 !important;
  }

  h2 {
    font-size: calc(var(--font-size-1) * .8);
  }

  .intro .description {
    width: 100%;
  }

  iframe {
    margin: var(--spacing-large) auto 0 0;
  }

  nav ul {
    display: initial !important;
    top: 0;
    right: 0;
    position: relative;
    padding: 0;
    box-shadow: none;
  }

  nav .btn {
    margin: 0;
  }
}

@media only screen and (max-width: 640px) {
  h2 {
    font-size: calc(var(--font-size-1) * .7);
  }
}

@media only screen and (max-width: 420px) {
  .intro .group {
    margin-top: var(--spacing-xxlarge);
  }

  .intro {
    padding-bottom: var(--spacing-xxlarge);
  }

}

@media only screen and (max-width: 390px) {

  .intro {
    padding: calc(var(--spacing-xxlarge) * 1.5) 0;
  }

}


text:
<!doctype html>

  <meta charset="utf-8">
  <meta name="author" content="Glenn Sorrentino">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="An on-demand Tor Snowflake proxy.">
  <title>Relay Love ❄🧅❤</title>
  <link rel="stylesheet" href="css/style.css">

❄

An On-Demand Tor Snowflake Proxy

Leave this browser tab open to keep your proxy online.


text:
body {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  background-color: #59316B;
  margin: 0;
  flex-direction: column;
  text-align: center;
  padding: 0 2rem;
}

h1, p {
  font-family: sans-serif;
  color: white;
  margin: 0;
  margin-bottom: 1rem;
}

h1 {
  font-size: 2.5rem;
}

p {
  margin-bottom:  2.5rem;
}

p.emoji {
  font-size: 2.5rem;
  margin: 0;
  margin-bottom: 1rem;
}

iframe {
  background-color: white;
  border-radius: .5rem;
  box-shadow: 0 1rem 3rem -.5rem rgba(0,0,0,0.25);
}


text:
@media (prefers-color-scheme: light) {
  ::selection {
      background-color: var(--color-dark);
      color: var(--color-light);
  }

  a {
    color: var(--color-dark);
  }

  body {
    background-color: var(--color-shade-lm);
  }
}

@media (prefers-color-scheme: dark) {
  ::selection {
      background-color: var(--color-light);
      color: var(--color-dark);
  }

  body {
    background-color: var(--shade-dm);
  }

  a {
    color: var(--color-light);
  }
}

* {
  transition: .3s !important;
}

html {
  scroll-padding-top: calc(var(--spacing-xxlarge) * 1.5);
}

body {
  display: flex;
  flex-flow: column;
  height: 100%;
}

a {
  cursor: pointer;
}

p + ul {
  margin-left: var(--spacing-base);
}

ul {
  margin: var(--spacing-small) 0;
}

ul li {
  margin: var(--spacing-base) 0;
}

ul li:first-of-type {
  margin: 0;
}

img {
  margin: var(--spacing-base) 0;
  width: 100%;
}

header, section, footer {
  display: flex;
  justify-content: center;
}

section {
  margin: 0 0 calc(var(--spacing-xxlarge) * 1.5) 0;
}

.hidden {
  display: none !important;
}

.wrapper {
  max-width: 1280px;
  width: 100%;
  display: flex;
  padding: 0 var(--spacing-large);
  flex-direction: column;
}

@media only screen and (max-width: 768px) {
  .wrapper {
    padding: 0 var(--spacing-medium);
  }

  section {
    margin: 0 0 var(--spacing-xxlarge) 0;
  }

}


text:
/* Firefox and Tor Browser Optimizations */
/* For Tor Browser, use .png images instead of .svg */

@media (prefers-color-scheme: light) {
  @-moz-document url-prefix() {
    header, footer, nav ul {
      background-color: var(--color-light) !important;
    }
  }
}

@media (prefers-color-scheme: dark) {
  @-moz-document url-prefix() {
    header, footer {
      background-color: var(--color-shade-dm) !important;
    }
  }
}

@media only screen and (max-width: 768px) {

  @media (prefers-color-scheme: light) {
    @-moz-document url-prefix() {
      nav ul {
        background-color: var(--color-light) !important;
      }
    }
  }

  @media (prefers-color-scheme: dark) {
    @-moz-document url-prefix() {
      nav ul {
        background-color: var(--color-shade-dm) !important;
      }
    }
  }
}


text:
@font-face {
  font-family: "Sans";
  src: url("../fonts/sans/Atkinson-Hyperlegible-Regular.woff2") format("woff2"),
       url("../fonts/sans/Atkinson-Hyperlegible-Regular.woff") format("woff");
}

@font-face {
  font-family: "Sans Bold";
  src: url("../fonts/sans/Atkinson-Hyperlegible-Bold.woff2") format("woff2"),
       url("../fonts/sans/Atkinson-Hyperlegible-Bold.woff") format("woff");
}

@font-face {
  font-family: "Serif";
  src: url("../fonts/serif/regular.woff2") format("woff2"),
       url("../fonts/serif/regular.woff") format("woff");
}

@font-face {
  font-family: "Mono";
  src: url("../fonts/mono/RobotoMono-Regular.woff2") format("woff2"),
       url("../fonts/mono/RobotoMono-Regular.woff") format("woff");
}

@media (prefers-color-scheme: light) {
  h1, h2, h3, h4, h5, h6, p {
    color: var(--color-dark);
  }

  p.meta {
    color: var(--color-label-lm);
  }

  p.meta a {
    color: var(--color-label-lm);
  }

  ul li {
    color: var(--color-dark);
  }

  .code {
    color: #e83e8c;
    background-color: var(--color-shade-lm);
    border: var(--border-dark);
  }
}

@media (prefers-color-scheme: dark) {
  body {
    background-color: var(--color-dark);
  }

  h1, h2, h3, h4, h5, h6, p {
    color: var(--color-light);
  }

  p.meta {
    color: var(--color-label-dm);
  }

  p.meta a {
    color: var(--color-label-dm);
  }

  ul li {
    color: var(--color-light);
  }

  .code {
    color: #EE72AC;
    background-color: var(--color-shade-dm);
    border: var(--border-light);
  }
}

body {
  font-family: 'Sans', Helvetica, Arial, sans-serif;
}

h1, h2, h3, h4, h5, h6 {
  line-height: var(--line-height-heading);
  font-weight: bold;
}

h2, h3, h4, h5, h6 {
  letter-spacing: var(--letter-spacing-serif-heading);
}

h2 {
  font-size: var(--font-size-1);
}

h3 {
  font-size: var(--font-size-2);
  margin: var(--spacing-xxlarge) 0 var(--spacing-base) 0;
}

h4 {
  font-size:  var(--font-size-3);
  margin: var(--spacing-xxlarge) 0 var(--spacing-xxsmall) 0;
}

h5 {
  font-size:  var(--font-size-4);
  margin: var(--spacing-xlarge) 0 var(--spacing-small) 0;
}

h6 {
  font-size:  var(--font-size-5);
  margin: var(--spacing-large) 0 var(--spacing-small) 0;
}

p {
  max-width: 640px;
  line-height: var(--line-height-body);
  margin: var(--spacing-base) 0;
}

li {
  line-height: var(--line-height-body);
}

.mono {
  font-family: 'Mono';
}

p.meta {
  margin: var(--spacing-small) 0 var(--spacing-xsmall) 0 !important;
  font-size: var(--font-size-small);
}

.highlight {
  padding: var(--spacing-xsmall);
  border-radius: var(--radius-soft);
}

.study p, .study ul {
  font-size: var(--font-size-study);
  font-family: 'Serif';
  line-height: 1.7;
}

.study p, .study ul {
  margin-top: var(--spacing-large);
  margin-bottom: var(--spacing-large);
}

.study p + p {
  margin-top: var(--spacing-small);
}

.study ul {
  list-style: none;
}

.study img + p:not( img + p > h3) {
  margin: var(--spacing-xlarge) auto;
}

.study h3, .study h4, .study h5, .study h6 {
  max-width: 640px;
  margin-left: auto;
  margin-right: auto;
  margin-bottom: 0;
  margin-top: calc(var(--spacing-xxlarge) * 1.25);
  text-align: center;
}

.study p, .study img, .study ul {
  margin-left: auto;
  margin-right: auto;
}

.strong {
  font-weight: bold;
}

h1 .emoji, h2 .emoji, h3 .emoji, h4 .emoji, h5 .emoji, h6 .emoji {
  display: block;
  margin-bottom: var(--spacing-small);
}

.center h1, .center h2, .center h3, .center h4, .center h5, .center h6 {
  text-align: center;
}

.center p {
  margin-left: auto;
  margin-right: auto;
}

.code {
  padding: var(--spacing-xxsmall) var(--spacing-xsmall);
  border-radius: var(--radius-soft);
  font-family: monospace;
  width: max-content !important;
  font-size: var(--font-size-small);
}

@media only screen and (max-width: 1280px) {
  h2 {
    font-size: calc(var(--font-size-1) * .95);
  }
}

@media only screen and (max-width: 1024px) {

  h2 {
    font-size: calc(var(--font-size-1) * .8);
  }
}

@media only screen and (max-width: 1000px) {

  h3 {
    font-size: calc(var(--font-size-2) * .85);
    margin: var(--spacing-xxlarge) 0 var(--spacing-base) 0;
  }

  h4 {
    font-size: calc(var(--font-size-3) * .85);
    margin: calc(var(--spacing-xxlarge) * .85) 0 var(--spacing-xxsmall) 0;
  }

  h5 {
    font-size: calc(var(--font-size-4) * .85);
  }

  h6 {
    font-size: calc(var(--font-size-5) * .85);
  }

}

@media only screen and (max-width: 768px) {

  h2 {
    font-size: calc(var(--font-size-1) * .75);
  }

  h3 {
    font-size: calc(var(--font-size-2) * .75);
    margin: var(--spacing-xxlarge) 0 var(--spacing-base) 0;
  }

  h4 {
    font-size: calc(var(--font-size-3) * .75);
    margin: calc(var(--spacing-xxlarge) * .75) 0 var(--spacing-xxsmall) 0;
  }

  h5 {
    font-size: calc(var(--font-size-4) * .75);
  }

  h6 {
    font-size: calc(var(--font-size-5) * .75);
  }

  p.meta {
    font-size: var(--font-size-xsmall);
  }

}

@media only screen and (max-width: 640px) {
  .study h3, .study h4, .study h5, .study h6 {
    /* margin-left: 0;
    margin-right: ; */
  }
}

@media only screen and (max-width: 480px) {

  h3 {
    font-size: calc(var(--font-size-2) * .7);
    margin: var(--spacing-xxlarge) 0 var(--spacing-base) 0;
  }

  h5 {
    font-size: calc(var(--font-size-4) * .7);
  }

  h6 {
    font-size: calc(var(--font-size-5) * .7);
  }

  .code {
    width: fit-content !important;
  }
}


text:
@media (prefers-color-scheme: light) {
  .btn {
    border: var(--border-dark);
    color: var(--color-dark);
    background-color: var(--color-light);
  }

  .btnIcon {
    background-image: url('../images/nav/lm-icon-menu.png');
  }

  .primaryBtn {
    background-color: var(--color-dark);
    color: var(--color-light);
  }

  .btn:hover {
    filter: brightness(105%);
    box-shadow: 0 2px 0 0 rgba(0,0,0,0.1);
  }

  .btn:active {
     box-shadow: inset 0 2px 0 rgba(0,0,0,0.1);
     filter: brightness(95%);
  }
}

@media (prefers-color-scheme: dark) {
  .btn {
    border: var(--border-light);
    color: var(--color-light);
    background-color: var(--color-shade-dm);
  }

  .btnIcon {
    background-image: url('../images/nav/dm-icon-menu.png');
  }

  .primaryBtn {
    background-color: var(--color-light);
    color: var(--color-dark);
  }

  .btn:hover {
    filter: brightness(105%);
    box-shadow: 0 2px 0 0 rgba(255,255,255,0.1);
  }

  .btn:active {
     box-shadow: inset 0 2px 0 rgba(255,255,255,0.1);
     filter: brightness(95%);
  }
}

.btn {
  padding: var(--spacing-button) !important;
  border-radius: 50vw;
  display: inline-flex !important;
  font-size: var(--font-size-small);
  width: max-content;
  text-decoration: none;
  cursor: pointer;
  margin: var(--spacing-small) 0;
  text-transform: capitalize;
}

.btnLrg {
  padding: var(--spacing-button-lg) !important;
}

.btnIcon {
  display: flex;
  align-items: center;
  background-repeat: no-repeat;
  background-size: contain;
  width: var(--size-btn-icon);
  height: var(--size-btn-icon);
}

@media only screen and (max-width: 768px) {

  .btn {
    margin: var(--spacing-xsmall) 0;
  }
}


text:
/* http://meyerweb.com/eric/tools/css/reset/
   v2.0 | 20110126
   License: none (public domain)
*/

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
	margin: 0;
	padding: 0;
	border: 0;
	font-size: 100%;
	font: inherit;
	vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
	display: block;
}
body {
	line-height: 1;
}
blockquote, q {
	quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
	content: '';
	content: none;
}
table {
	border-collapse: collapse;
	border-spacing: 0;
}


text:
:root {
  /* --font-sans: "Sans", Helvetica, Arial, sans-serif; */

  --color-label-lm: rgba(112,112,112,1);
  --color-label-dm: rgba(168,168,168,1);
  --color-light: rgba(255,255,255,1);
  --color-dark: rgba(51,51,51,1);

  --color-glass-lm: rgba(255,255,255,.8);
  --color-glass-dm: rgba(51,51,51,.9);

  --color-shade-dm: rgba(61,61,61,1);
  --color-shade-lm: rgba(51,51,51,.035);

  --border-dark: 1px solid rgba(0,0,0,0.1);
  --border-light: 1px solid rgba(255,255,255,0.1);

  --spacing-xxsmall: .125rem;
  --spacing-xsmall: .25rem;
  --spacing-small: .5rem;
  --spacing-base: 1rem;
  --spacing-medium: 1.5rem;
  --spacing-large: 2rem;
  --spacing-xlarge: 3rem;
  --spacing-xxlarge: 4rem;
  --spacing-button-lg: .875rem 1.25rem;
  --spacing-button: .625rem .825rem;

  --size-icon-sm: 1rem;
  --size-logo: 1.5rem;
  --size-project-icon: 3rem;
  --size-avatar: 10rem;
  --size-btn-icon: 2.5rem;

  --font-size-xsmall: .75rem;
  --font-size-small: .875rem;
  --font-size-body: 1rem;
  --font-size-logo: 1.125rem;
  --font-size-1: 3.75rem;
  --font-size-2: 3rem;
  --font-size-3: 2.125rem;
  --font-size-4: 2rem;
  --font-size-5: 1.5rem;
  --font-size-6: 1.25rem;
  --font-spacing-small: .0125rem;

  --line-height-heading: 1.2;
  --line-height-body: 1.5;

  --shadow-lm: 0px 20px 40px -20px rgba(0,0,0,0.15);
  --shadow-dm: 0px 20px 40px -20px rgba(0,0,0,0.25);

  --radius-soft: .25rem;
  --radius-round: 50vw;
}


text:
@media (prefers-color-scheme: light) {

}

@media (prefers-color-scheme: dark) {

}

article img.small {
  max-width: 640px;
}

article img.medium {
  max-width: 768px;
}

article img.mobile {
  max-width: 375px;
}

@media only screen and (max-width: 768px) {
  article img {
    width: 100% !important;
  }
}


text:
@keyframes floating {
  0% {
    transform: translate(-50%, -50%);
  }
  50% {
    transform: translate(-50%, -1.5rem);
  }
  100% {
    transform: translate(-50%, -50%);
  }
}


text:
/* The Simple Design System is made with ❤ by Glenn Sorrentino - https://glennsorrentino.com */
/* Please consider contributing! */

@import url("reset.css");
@import url("variables.css");
@import url("article.css");
@import url("base.css");
@import url("buttons.css");
@import url("animation.css");
@import url("typography.css");
@import url("firefox.css");
@import url("../components/header/css/header.css");
@import url("../components/intro/css/intro.css");
@import url("../components/content/css/content.css");
@import url("../components/banner/css/banner.css");
@import url("../components/content/css/cards.css");
@import url("../components/footer/css/footer.css");
@import url("../components/badge/css/badge.css");


text:
@media (prefers-color-scheme: light) {
  footer {
    background-color: var(--color-light);
  }
}

@media (prefers-color-scheme: dark) {
  footer {
    background-color: var(--color-shade-dm);
  }
}

footer {
  font-size: var(--font-size-xsmall);
  letter-spacing: var(--font-spacing-small);
  padding: var(--spacing-base) 0;
}

footer p {
  margin: 0;
}

footer p.donate {
  display: flex;
}

footer p img {
  width: var(--size-icon-sm);
  height: var(--size-icon-sm);
  display: inline-flex;
  margin: 0 var(--spacing-xsmall) 0 0;
}


text:
Simple Design System by Glenn Sorrentino is licensed under CC BY 4.0

View Component Code

Find this resource helpful? Donate Bitcoin: bc1qxn83lsum8kfseh4ujtamjpah7s57daztqxtgj8


text:
@media (prefers-color-scheme: light) {
  .iconAlt {
    color: var(--color-label-lm);
  }

  .description img.avatar {
    box-shadow: var(--shadow-lm);
    border: var(--border-dark-1);
  }
}

@media (prefers-color-scheme: dark) {
  .iconAlt {
    color: var(--color-label-dm);
  }

  .description img.avatar {
    box-shadow: var(--shadow-dm);
    border: var(--border-light);
  }
}

.group {
  display: flex;
  margin: var(--spacing-xxlarge) 0;
}

.group .description {
  padding: 0 var(--spacing-large) 0 0;
  margin: 0 !important;
  width: 50%;
}

.group img {
  width: 50%;
  margin: 0;
  display: flex;
  align-self: center;
}

.description {
  display: flex;
  flex-direction: column;
  justify-content: center;
  margin: var(--spacing-medium) 0;
}

.description.flip {
  order: 2;
  padding: 0 0 0 2rem;
}

.description h3,
.description h4,
.description h5,
.description h6 {
  margin: 0;
  width: 66%;
}

.description p {
  margin: var(--spacing-small) 0;
}

.description .icon {
  width: var(--size-project-icon);
  height: var(--size-project-icon);
  margin: 0 0 var(--spacing-base) 0;
  border-radius: var(--radius-soft);
  align-self: auto;
}

.iconAlt {
  font-weight: bold;
  font-size: var(--font-size-small);
  text-transform: uppercase;
  margin: 0 0 var(--spacing-base) 0 !important;
}

.center .description .icon {
  margin: 0 auto var(--spacing-base) auto;
}

.description ul {
  list-style: none;
  margin-left: 0;
  margin-top: var(--spacing-base);
  font-size: var(--font-size-small);
}

.description img.avatar {
  height: var(--size-avatar);
  width: var(--size-avatar) !important;
  border-radius: var(--radius-round);
}

.groupRow {
  display: flex;
  flex-direction: row;
  margin: var(--spacing-large) 0;
}

.group .description h3,
.group .description h4,
.group .description h5,
.group .description h6 {
  width: 100%;
}

.groupRow .description h3,
.groupRow .description h4,
.groupRow .description h5,
.groupRow .description h6 {
  width: 100%;
}

.groupRow .description:first-of-type {
    padding: 0 var(--spacing-base) 0 0;
}

.groupRow .description:last-of-type {
    padding: 0 0 0 var(--spacing-base);
}

.groupRow .description {
    padding: 0 var(--spacing-base);
    justify-content: flex-start;
    flex: 1 1 0px;
    margin: 0;
}

.study .groupRow .description {
  margin: 0 var(--spacing-base);
}

.groupRow .description img ~ .iconAlt {
  margin-top: var(--spacing-small) !important;
}

.mobileImageContainer {
  display: flex;
  justify-content: center;
  width: 50%;
}

.mobileImageContainer img {
  width: 80%;
  height: auto;
}

.study .groupRow {
  margin: var(--spacing-xxlarge) 0;
}

.study .description h4 {
  text-align: center;
  margin-bottom: var(--spacing-small);
}

.study .description ul {
  font-size: var(--font-size-base);
  margin-left: auto;
  margin-right: auto;
  margin-bottom: 0;
}

@media only screen and (max-width: 1024px) {
  .description h3,
  .description h4,
  .description h5,
  .description h6 {
    width: 80%;
  }

  .group {
    margin: var(--spacing-xlarge) 0;
  }
}

@media only screen and (max-width: 768px) {
  .group {
    flex-direction: column;
    margin: var(--spacing-xlarge) 0;
  }

  .group .description {
    padding: 0;
    margin: var(--spacing-medium) 0;
    width: auto;
  }

  .study .groupRow .description {
    margin: var(--spacing-small) 0 !important;
  }

  .study .groupRow {
    margin: var(--spacing-large) 0 !important;
  }

  .group img {
    width: 100%;
    margin: var(--spacing-base) 0 0 0;
  }

  .mobileImageContainer {
    width: 100%;
    justify-content: flex-start;
  }

  .mobileImageContainer img {
    width: 66%;
  }

  .description {
    padding: 0;
    margin: var(--spacing-base) 0;
  }

  .description.flip {
    padding: 0;
    order: initial;
  }

  .groupRow {
    flex-direction: column;
    margin: 0;
  }

  .groupRow .description {
    padding: 0;
    margin: var(--spacing-base) 0;
  }

  .description h3,
  .description h4,
  .description h5,
  .description h6 {
    margin: 0;
    width: 100%;
  }

  .groupRow .description:first-of-type {
      padding: 0;
  }

  .groupRow .description:last-of-type {
      padding: 0;
  }

  /* .groupRow .description img {
    order: 9;
  } */
}

@media only screen and (max-width: 640px) {
  .mobileImageContainer img {
    width: 100%;
  }

}


text:
@media (prefers-color-scheme: light) {
  .card {
    border: var(--border-dark);
    background-color: var(--color-light);
  }
}

@media (prefers-color-scheme: dark) {
  .card {
    border: var(--border-light);
    background-color: var(--color-shade-dm);
  }
}

.card {
  padding: var(--spacing-xlarge) var(--spacing-large) !important;
  border-radius: var(--radius-soft);
  margin: var(--spacing-base);
}

.card:first-of-type {
  margin-left: 0;
}

.card:last-of-type {
  margin-right: 0;
}

.center .groupRow:first-of-type .card {
  margin-top: var(--spacing-large);
}

@media only screen and (max-width: 768px) {
  .center .groupRow:first-of-type .card:nth-child(2n) {
    margin-top: var(--spacing-base);
  }

  .card {
    margin: var(--spacing-base) 0;
  }
}


text:
Section Heading

However hard he threw himself onto his right, he always rolled back to where he was. He must have tried it a hundred times, shut his eyes so that he wouldn't have to look at the floundering legs, and only stopped when he began to feel a mild, dull pain there that he had never felt before.

🧑💻  View Component Code

💻  HTML Validator

🎨  CSS Validator

🦮  WAVE Accessibility Tool


text:
Secondary Section

Linked Headline

Metadata

His many legs, pitifully thin compared with the size of the rest of him, waved about helplessly as he looked.

View Component Code

Linked Headline With a Button

December 18, 2021

"What's happened to me?" he thought. It wasn't a dream.

Secondary Button

A Longer and Super Compelling Headline for an Article

By Art Vandelay

His room, a proper human room although a little too small, lay peacefully between its four familiar walls.


text:
Personal Section

Drops of rain could be heard hitting the pane, which made him feel quite sad. "How about if I sleep a little bit longer and forget all this nonsense", he thought, but that was something he was unable to do because he was used to sleeping on his right, and in his present state couldn't get into that position.

View Component Code


text:
Tertiary Section

Important Info but Lower Priority

A collection of textile samples lay spread out on the table - Samsa was a travelling salesman - and above it there hung a picture that he had recently cut out of an illustrated magazine and housed in a nice, gilded frame.

View Component Code

Shorter Headlines Work Better

It showed a lady fitted out with a fur hat and fur boa who sat upright, raising a heavy fur muff that covered the whole of her lower arm towards the viewer.

Headline

Gregor then turned to look out the window at the dull weather.


text:
Featured Section

Feature Headline

One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin.

View Component Code

Item With Metadata

🏅 Linked Metadata

He lay on his armour-like back, and if he lifted his head a little he could see his brown belly, slightly domed and divided by arches into stiff sections.

Mobile Feature Headline

The bedding was hardly able to cover it and seemed ready to slide off any moment.


text:
@media (prefers-color-scheme: light) {
  .banner {
    background-color: #92E7FF !important;

  }

  .banner p, .banner a {
    color: #59316B !important;
  }

  .bannerBtn {
    background-image: url('../../../images/banner/lm-icon-close.png');
  }
}

@media (prefers-color-scheme: dark) {
  .banner {
    background-color: #92E7FF;
  }

  .banner p, .banner a {
    color: #59316B !important;
  }

  .bannerBtn {
    background-image: url('../../../images/banner/lm-icon-close.png');
  }
}

.banner {
  text-align: center;
  position: fixed;
  top: 0;
  height: 40px;
  width: 100%;
  z-index: 1;
  display: flex;
  align-items: center;
  flex-direction: row;
}

.banner p {
  padding: 0;
  width: fit-content;
  margin: 0 auto;
  font-size: var(--font-size-small);
}

.banner + header {
  top: 40px !important;
}

.banner.hidden + header {
  top: 0px !important;
}

.banner + header ~ div .intro h2 {
  margin-top: 40px !important;
}

.banner.hidden + header ~ div .intro h2 {
  margin-top: 0px !important;
}

.banner + header ~ div .intro iframe {
  margin-top: 40px !important;
}

.banner.hidden + header ~ div .intro iframe {
  margin-top: 0px !important;
}

.bannerBtn {
  display: flex;
  align-items: center;
  background-repeat: no-repeat;
  background-size: contain;
  width: var(--spacing-large);
  height: var(--spacing-large);
  margin-right: var(--spacing-medium);
}

@media only screen and (max-width: 768px) {
  .bannerBtn {
    margin-right: var(--spacing-base);
  }

  .banner p {
    margin: 0 auto;
  }

  .banner.hidden + header ~ div .intro iframe {
    margin-top: 20px !important;
  }

  .banner + header ~ div .intro iframe {
    margin-top: 20px !important;
  }

}

@media only screen and (max-width: 480px) {
  .bannerBtn {
    margin-right: var(--spacing-large);
  }

  .banner p {
    margin: 0 auto 0 var(--spacing-medium);
    font-size: calc(var(--font-size-small) * 1);
  }

  .banner {
    padding-left: var(--spacing-base) ;
    padding-right: var(--spacing-small) ;
  }

  .banner + header ~ div .intro h2 {
    /* margin-top: 248px !important; */
  }

  .banner.hidden + header ~ div .intro h2 {
    /* margin-top: 208px !important; */
  }

  .banner + header ~ div .intro {
    /* padding-bottom: 148px !important; */
  }

  .banner.hidden + header ~ div .intro iframe {
    margin-top: 20px !important;
  }

}

@media only screen and (max-width: 420px) {
  .banner p {
    font-size: calc(var(--font-size-small) * .9);
    margin: 0 auto 0 var(--spacing-base);
  }

  .banner {
  }
}


text: 🟢 Accepting New Clients


text:
$(document).ready(function() {

  $('.bannerBtn').on('click', function() {
    $('.banner').toggleClass('hidden');
  });

});


text:
@media (prefers-color-scheme: light) {
  .badge {
    border: var(--border-dark);
    background-color: var(--color-shade-lm);
  }
}

@media (prefers-color-scheme: dark) {
  .badge {
    border: var(--border-light);
    background-color: var(--color-shade-dm);
  }
}

.badge {
  padding: var(--spacing-xsmall) var(--spacing-small);
  font-size: var(--font-size-xsmall);
  border-radius: var(--radius-round);
  width: fit-content;
}


text:
@media (prefers-color-scheme: light) {
  .intro {
    background-color: var(--color-light);
  }

  p.hint {
    color: var(--color-label-lm);
  }
}

@media (prefers-color-scheme: dark) {
  .intro {
    background-color: var(--color-shade-dm);
  }

  p.hint {
    color: var(--color-label-dm);
  }
}

.intro {
  height: 100vh;
  align-items: center;
}

.intro h2 {
  width: 90%;
}

.intro p:last-of-type {
  margin-bottom: 0;
}

p.hint {
  position: absolute;
  bottom: var(--spacing-base);
  margin-bottom: 0 !important;
  transform: translate(-50%, -50%);
  left: 50%;
  font-size: var(--font-size-xsmall) !important;
  font-weight: bold;
  animation: floating 3s ease infinite;
  max-width: max-content !important;
  transition: .3s;
}

p.hint a {
  text-decoration: none;
}

.fade {
  opacity: 0 !important;
}

@media only screen and (max-width: 768px) {
  .intro h2 {
    width: 100%;
  }
}


text:
A research-based framework for building durable web experiences 🧑💻

View Component Code

Scroll Down


text:
$(document).ready(function() {
  var pageOffset = $('.wrapper').offset().top;

  $(window).on('scroll', function() {
    if ($(window).scrollTop() > 0) {
      $('.hint').addClass('fade');
    } else {
      $('.hint').removeClass('fade');
    }
  });

});


text:
@media (prefers-color-scheme: light) {
  header {
    background-color: var(--color-light);
  }

  nav ul li a:hover {
    box-shadow: inset 0 -3px var(--color-dark);
  }
}

@media (prefers-color-scheme: dark) {
  header {
    background-color: var(--color-shade-dm);
  }

  nav ul li a:hover {
    box-shadow: inset 0 -3px var(--color-light);
  }
}

header {
  position: fixed;
  top: 0;
  right: 0;
  left: 0;
  flex: 0 1 auto;
}

header .wrapper {
  display: flex;
  justify-content: space-between;
  flex-direction: row;
}

header h1 {
  width: fit-content;
  font-size: var(--font-size-logo) !important;
}

header .logo {
  display: flex;
  align-items: center;
  height: var(--size-logo);
  padding: calc(var(--spacing-medium) * 1.125) 0;
  line-height: var(--line-height-base);
  display: flex;
  width: fit-content;
}

header a {
  text-decoration: none;
}

header h1 a:hover {
  text-decoration: underline;
}

.mobileNav {
  display: none;
}

nav {
  display: flex;
  justify-content: flex-end;
  width: fit-content;
}

nav.staged {
  display: none;
}

.open {
  display: initial !important;
}

nav ul {
  display: flex;
  flex-direction: row;
  list-style: none;
  align-items: center;
  margin: 0;
}

nav ul li {
  display: flex;
  height: 100%;
  align-items: center;
  margin: 0;
}

nav ul li a.wrapper {
  max-width: initial;
  width: initial;
  display: flex;
  padding: 0 calc(var(--spacing-small) * 1.25);
}

nav ul li a {
  display: flex;
  height: 100%;
  align-items: center;
  font-size: var(--font-size-small);
}

nav .btn {
  margin-left: var(--spacing-base);
  height: auto;
}

nav .badge {
  margin-right: var(--spacing-base);
}

@media only screen and (max-width: 768px) {
  @media (prefers-color-scheme: light) {
    nav ul {
      box-shadow: var(--shadow-lm);
      background-color: var(--color-light);
    }

    nav ul li a:hover {
      box-shadow: inset 3px 0 var(--color-dark);
    }
  }

  @media (prefers-color-scheme: dark) {
    nav ul {
      box-shadow: var(--shadow-dm);
      background-color: var(--color-shade-dm);
    }

    nav ul li a:hover {
      box-shadow: inset 3px 0 var(--color-light);
    }
  }

  nav ul {
    display: none;
  }

  .mobileNav {
    display: flex;
    align-self: center;
  }

  nav ul {
    flex-direction: column;
    position: absolute;
    top: 72px;
    left: 0;
    right: 0;
    z-index: 1;
    padding: var(--spacing-small) 0;
    align-items: flex-start;
  }

  nav ul li a.wrapper {
    display: flex;
    width: 100%;
  }

  nav ul li a {
    padding-top: var(--spacing-base) !important;
    padding-bottom: var(--spacing-base) !important;
    padding-left: var(--spacing-medium) !important;
    padding-right: var(--spacing-medium) !important;
  }

  nav .btn {
    margin: var(--spacing-base) var(--spacing-medium);
    display: inline-flex !important;
  }

  nav ul li a.wrapper {
    display: flex;
  }

  nav .badge {
    margin-right: 0;
    margin-left: var(--spacing-medium);
  }
}


text:
Simple Design System

View Code

Section 2

Link 3

Link 4

<button class="btn primaryBtn btnLrg" href="#contact">Primary Button</button>


text:
$(document).ready(function() {

  $('.btnIcon').on('click', function() {
    $('nav ul').toggleClass('open');
  });

  $('NAV li').on('click', function() {
    $('nav ul').removeClass('open');
  });

});


text:
$(document).ready(function() {

  var pageOffset = $('.wrapper').offset().top;

  $(window).on('scroll', function() {
    if ($(window).scrollTop() > 0) {
      $('.hint').addClass('fade');
    } else {
      $('.hint').removeClass('fade');
    }
  });

  $('.btnIcon').on('click', function() {
    $('nav ul').toggleClass('open');
  });

  $('NAV li').on('click', function() {
    $('nav ul').removeClass('open');
  });

  $('.bannerBtn').on('click', function() {
    $('.banner').toggleClass('hidden');
  });

  $('.bannerBtn').on('click', function() {
    $('BODY + div').removeClass('banner');
  });

});


text:
(setq user-full-name "Juanjo Alvarez Martinez")
(setq user-mail-address "juanjo@juanjoalvarez.net")

    ;; "after" macro definition
    (if (fboundp 'with-eval-after-load)
        (defmacro after (feature &rest body)
          "After FEATURE is loaded, evaluate BODY."
          (declare (indent defun))
          `(with-eval-after-load ,feature ,@body))
      (defmacro after (feature &rest body)
        "After FEATURE is loaded, evaluate BODY."
        (declare (indent defun))
        `(eval-after-load ,feature
           '(progn ,@body))))

(add-to-list 'load-path (expand-file-name "subconfigs" user-emacs-directory))
(require 'init-packages)
(require 'init-programming)
(require 'init-server)
(require 'init-colors)
(require 'init-persistence)
(require 'init-interface)
(require 'init-text-edition)
(require 'init-i18n)
(require 'init-helm)
(require 'init-autocomplete)
(require 'init-flycheck)
(require 'init-d)
(require 'init-evil)
(require 'init-tags)
(require 'init-nonevil-bindings)
(require 'init-misc-plugins)
(require 'init-org)

;; some more settings
(setq
      delete-by-moving-to-trash t
      create-lockfiles nil
      gc-cons-threshold 20000000)

(custom-set-variables
 ;; custom-set-variables was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(blink-cursor-mode nil)
 '(custom-safe-themes
   (quote
    ("756597b162f1be60a12dbd52bab71d40d6a2845a3e3c2584c6573ee9c332a66e" "e35ef4f72931a774769da2b0c863e11d94e60a9ad97fb9734e8b28c7ee40f49b" "1e194b1010c026b1401146e24a85e4b7c545276845fc38b8c4b371c8338172ad" "2642fdd168904cc1faefcaa05e609c99095114367b1adbf41fb023291cbd7b87" "3b819bba57a676edf6e4881bd38c777f96d1aa3b3b5bc21d8266fa5b0d0f1ebf" "2fc4f51bcdef89bc7a1b1da7cd9300410b25ea4c1b297c2ce1b308405ffba269" "55fc0d8437cf18c1cfdc35fb6e07c6a3041e5afc8c0988e7bf8298a41a627423" "88e3e15d0a7e039f0515428b71362c25ce36d6a19d5fe1f0c9c11b7f3557f51b" "e6d83e70d2955e374e821e6785cd661ec363091edf56a463d0018dc49fbc92dd" "fc5fcb6f1f1c1bc01305694c59a1a861b008c534cae8d0e48e4d5e81ad718bc6" "25f330cb050c7e7ec402af1b60243e8185a7837b455af0fa026593d4f48a78b2" "a0feb1322de9e26a4d209d1cfa236deaf64662bb604fa513cca6a057ddf0ef64" "ab04c00a7e48ad784b52f34aa6bfa1e80d0c3fcacc50e1189af3651013eb0d58" "7356632cebc6a11a87bc5fcffaa49bae528026a78637acd03cae57c091afd9b9" "2b5aa66b7d5be41b18cc67f3286ae664134b95ccc4a86c9339c886dfd736132d" "b1fdbb009af22a58788857cc5d44a4835a38088492ff0f3fea40857338cf0c3b" "7fbb8d064286706fb1e319c9d3c0a8eafc2efe6b19380aae9734c228b05350ae" "5e3fc08bcadce4c6785fc49be686a4a82a356db569f55d411258984e952f194a" "04dd0236a367865e591927a3810f178e8d33c372ad5bfef48b5ce90d4b476481" "7153b82e50b6f7452b4519097f880d968a6eaf6f6ef38cc45a144958e553fbc6" "1e7e097ec8cb1f8c3a912d7e1e0331caeed49fef6cff220be63bd2a6ba4cc365" "e16a771a13a202ee6e276d06098bc77f008b73bbac4d526f160faa2d76c1dd0e" "d677ef584c6dfc0697901a44b885cc18e206f05114c8a3b7fde674fce6180879" "8aebf25556399b58091e533e455dd50a6a9cba958cc4ebb0aab175863c25b9a4" "bd115791a5ac6058164193164fd1245ac9dc97207783eae036f0bfc9ad9670e0" default)))
 '(display-time-mode t)
 '(flycheck-display-errors-function (function flycheck-pos-tip-error-messages))
 '(line-number-mode nil)
 '(ring-bell-function (quote ignore) t)
 '(tool-bar-mode nil))

(custom-set-faces
 ;; custom-set-faces was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(default ((t (:family "M+ 2m regular" :foundry "outline" :slant normal :weight normal :height 120 :width normal)))))

(put 'narrow-to-region 'disabled nil)

(provide 'init)

repo_name: juanjux/emacs-dotfiles

repo_language: Emacs Lisp

mime_type: text/x-lisp


text:
emacs-dotfiles
==============

This is my Emac config, uploaded to github for convenience.
I'm an Emacs newbie so don't expect to find something that will blow your pants off here.


text:
;; helm settings (TAB in helm window for actions over selected items,
;; C-SPC to select items)
(require 'helm-config)
(require 'helm-misc)
(require 'helm-projectile)
(require 'helm-locate)
(setq helm-quick-update t
      helm-bookmark-show-location t
      helm-buffers-fuzzy-matching t)

(after 'projectile
  (require-package 'helm-projectile))
(global-set-key (kbd "M-x") 'helm-M-x)

(defun helm-my-buffers ()
  (interactive)
  (require 'helm-files)
  (let ((helm-ff-transformer-show-only-basename nil))
  (helm-other-buffer '(helm-c-source-buffers-list
                       helm-c-source-elscreen
                       helm-c-source-occur
                       ;;                        helm-c-source-projectile-files-list
                       helm-c-source-ctags
                       helm-c-source-recentf
                       helm-c-source-locate)
                     "*helm-my-buffers*")))

(provide 'init-helm)


text:
;; my coding style, bsd but with 4 spaces indentation (and no tab
;; characters, only spaces)
    (setq-default c-basic-offset 4 c-default-style "bsd")
    (setq-default tab-width 4 indent-tabs-mode nil)
    (setq-default highlight-tabs t)

;; Auto indent lines after pressing return so I don't have to press TAB
    (define-key global-map (kbd "RET") 'newline-and-indent)

;; remove whitespace before saving
    (add-hook 'before-save-hook 'delete-trailing-whitespace)

;; dont wrap lines
    (setq-default truncate-lines t)

;; show indent guides ;; DISABLED for the moment, enabled when needed
    (require-package 'indent-guide)
    (setq indent-guide-recursive nil)
    ;; (indent-guide-global-mode)

;; guess indentation settings from buffers
    (require-package 'dtrt-indent)
    (dtrt-indent-mode 1)

;; show function names
    (which-function-mode t)

;; always turn on auto-fill/word-wrap in text-mode and set
;; the fill-column for several languages
    (add-hook 'text-mode-hook (lambda ()
                                (turn-on-auto-fill)
                                (set-fill-column 82)))
    (add-hook 'markdown-mode-hook (lambda ()
                                (turn-on-auto-fill)
                                (set-fill-column 82)))

    (add-hook 'python-mode-hook (lambda ()
                                  (set-fill-column 90)))
    (add-hook 'c-mode-hook (lambda ()
                             (set-fill-column 94)))

    (add-hook 'd-mode-hook (lambda ()
                             (set-fill-column 94)))

;; show matching parens
    (show-paren-mode t)

;; ace-jump jumps across windows
    (setq ace-jump-mode-scope 'visible)

;; more text-editing settings
    (setq
        sentence-end-double-space nil
        mark-ring-max 64
        global-mark-ring-max 128
        save-interprogram-paste-before-kill t
    )

;; function to reformat json (python required)
    (defun json-format ()
      (interactive)
      (save-excursion
        (shell-command-on-region
         (mark) (point) "python -m json.tool" (buffer-name) t)))

;; init autopair
    ;; (require-package 'autopair)
    ;; (autopair-global-mode)
    ;; (require 'smartparens-config)
    ;; (smartparens-global-mode t)

(provide 'init-text-edition)


text:
;; utf-8
(prefer-coding-system 'utf-8)
(set-default-coding-systems 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-language-environment 'utf-8)
(set-selection-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(setq locale-coding-system 'utf-8)

;; enable accents
    (require 'iso-transl)

(provide 'init-i18n)


text:
;; fix for compile to find the errors with DMD
    (require 'compile)
    (add-to-list
     'compilation-error-regexp-alist
     '("^\\([^ \n]+\\)(\\([0-9]+\\)): \\(?:error\\|.\\|warnin\\(g\\)\\|remar\\(k\\)\\)"
       1 2 nil (3 . 4)))

;; ac-dcd (auto completion for Dlang)
    (require-package 'ac-dcd)
    (add-hook 'd-mode-hook 'ac-dcd-setup)
    (setq ac-dcd-flags (quote ("-I/usr/include/dmd"
                               "-I~/wodri/backend/source"
                               "-I~/wodri/backend/source/webbackend/source"
                               "-I~/wodri/backend/source/libs"
                               "-I~/.dub/packages/vibe-d-master/source")))

    (setq flycheck-dmd-include-path '("/usr/include/dmd"
                                      "~/wodri/backend/source"
                                      "~/wodri/backend/source/webbackend/source"
                                      "~/wodri/backend/source/libs"
                                      "~/.dub/packages/vibe-d-master/source"))

    (add-hook 'd-mode-hook 'flycheck-dmd-dub-set-include-path)

;; dtags
;; no dtags, just use: use C-c . && C-c , to jump from / to symbol in D

(provide 'init-d)


text:
;; create backup files on a directory inside dotemacs
    (setq backup-directory-alist '(("." . "~/.emacs.d/backups")))

;; Remember last edit positions
    (require-package 'saveplace)
    (setq save-place-file "~/.emacs.d/saveplace")
    (setq-default save-place t)

;; minibuffer history
    (require-package 'savehist)
    (setq savehist-file "~/.emacs.d/savehist"
          savehist-additional-variables '(search ring regexp-search-ring)
          savehist-autosave-interval 60)
    (setq-default history-length 1000)
    (savehist-mode +1)

;; bookmarks
    (setq bookmark-default-file "~/.emacs.d/bookmarks"
          bookmark-save-flag 1) ;; save after every change

;; lots of recent files
    (require 'recentf)
    (setq recentf-save-file "~/.emacs.d/recentf"
          recentf-max-saved-items 1000
          recentf-max-menu-items 500)
    (add-to-list 'recentf-exclude "COMMIT_EDITMSG\\'")
    (recentf-mode +1)
    (run-with-timer 1800 1800 'recentf-save-list)

;; Functions to save and buffers+tabs (elscreens) sessions, source:
;; http://stackoverflow.com/questions/22445670/save-and-restore-elscreen-tabs-and-split-frames
;; http://stackoverflow.com/questions/803812/emacs-reopen-buffers-from-last-session-on-startup
    (defvar emacs-configuration-directory
      "~/.emacs.d/"
      "The directory where the emacs configuration files are stored.")
    (defvar elscreen-tab-configuration-store-filename
      (concat emacs-configuration-directory ".elscreen")
      "The file where the elscreen tab configuration is stored.")

    (defun session-save ()
      "Store the elscreen tab configuration."
      (interactive)
      (if (desktop-save emacs-configuration-directory)
          (with-temp-file elscreen-tab-configuration-store-filename
            (insert (prin1-to-string (elscreen-get-screen-to-name-alist))))))

    (defun session-load ()
      "Restore the elscreen tab configuration."
      (interactive)
      (if (desktop-read)
          (let ((screens (reverse
                          (read
                           (with-temp-buffer
                             (insert-file-contents
                              elscreen-tab-configuration-store-filename)
                             (buffer-string))))))
            (while screens
              (setq screen (car (car screens)))
              (setq buffers (split-string (cdr (car screens)) ":"))
              (if (eq screen 0)
                  (switch-to-buffer (car buffers))
                (elscreen-find-and-goto-by-buffer (car buffers) t t))
              (while (cdr buffers)
                (switch-to-buffer-other-window (car (cdr buffers)))
                (setq buffers (cdr buffers)))
              (setq screens (cdr screens))))))

(provide 'init-persistence)


text:
(require-package 'flycheck)
(add-hook 'after-init-hook #'global-flycheck-mode)

(cond ((eq window-system 'w32)
       (setq flycheck-flake8rc "C:\\installs\\flake8rc")))

(after 'flycheck
  (setq flycheck-check-syntax-automatically '(save mode-enabled)
        flycheck-checkers (delq 'emacs-lisp-checkdoc flycheck-checkers)
        flycheck-checkers (delq 'html-tidy flycheck-checkers)
        flycheck-standard-error-navigation nil))
(global-flycheck-mode t)

;; flycheck errors on a tooltip (doesnt work on console)
(when (display-graphic-p (selected-frame))
  (eval-after-load 'flycheck
    '(custom-set-variables
      '(flycheck-display-errors-function #'flycheck-pos-tip-error-messages))))

(provide 'init-flycheck)


text:
;; C-x (arrow) to move between windows
(global-set-key (kbd "C-x <up>")    'windmove-up)
(global-set-key (kbd "C-x <down>")  'windmove-down)
(global-set-key (kbd "C-x <right>") 'windmove-right)
(global-set-key (kbd "C-x <left>")  'windmove-left)

(provide 'init-nonevil-bindings)


text:
(require-package 'auto-complete)
(require 'auto-complete-config)
    (setq ac-auto-show-menu t
          ac-auto-start t
          ac-quick-help-delay 0.3
          ac-quick-help-height 30
          ac-show-menu-immediately-on-auto-complete t)
    (ac-config-default)

    (after 'yasnippet
      (add-hook 'yas-before-expand-snippet-hook (lambda () (auto-complete-mode -1)))
      (add-hook 'yas-after-exit-snippet-hook (lambda () (auto-complete-mode t)))
      (defadvice ac-expand (before advice-for-ac-expand activate)
        (when (yas-expand)
          (ac-stop))))

(provide 'init-autocomplete)


text:
;; etags
    (cond ((eq system-type 'windows-nt)
           (setq path-to-ctags "C:/installs/gnuglobal/bin/ctags.exe")))
    (cond ((eq system-type 'gnu/linux)
           (setq path-to-ctags "/usr/local/bin/ctags")))

    (defun create-tags (dir-name)
      "Create tags file, asks for dir"
      (interactive "DDirectory: ")
      (shell-command
       (format "%s -f %s/tags -eR %s" path-to-ctags (directory-file-name dir-name) (directory-file-name dir-name)))
      )

(provide 'init-tags)


text:
;; Auto guess dictionary package
    (require-package 'auto-dictionary)
    (add-hook 'flyspell-mode-hook (lambda ()
                                    (auto-dictionary-mode t)))

;; only one dired buffer
    (require-package 'dired-single)

;; fiplr ignore
    (setq fiplr-ignored-globs '((directories (".git" ".svn" "single_emails" "/home/juanjux"))
                (files ("*.jpg" "*.png" "*.zip" "*~" "*/single_emails/*"))))

;; powerline-evil and modeline: DISABLED, problems with Emacs 24.4
    ;; (require-package 'powerline)
    ;; (powerline-evil-vim-color-theme)
    ;; (display-time-mode t)

;; project-explorer
    (require-package 'project-explorer)
    (after 'project-explorer
      (setq pe/cache-directory "~/.emacs.d/cache/project_explorer")
      (setq pe/omit-regex (concat pe/omit-regex "\\|single_emails")))

;; ERC
    (setq erc-hide-list '("JOIN" "PART" "QUIT"))

 (provide 'init-misc-plugins)


text:
(require 'org)

(if (eq system-type 'windows-nt)
    (setq org-directory "C:/ilionData/Users/juanjo.alvarez/Documents/Dropbox/Org")
  (setq org-directory "~/Dropbox/Org"))

(if (eq system-type 'windows-nt)
    (setq org-mobile-directory "C:/ilionData/Users/juanjo.alvarez/Documents/Dropbox/MobileOrg")
  (setq org-mobile-directory "~/Dropbox/MobileOrg"))

(setq org-mobile-inbox-for-pull (concat org-directory "/flagged.org"))

(provide 'init-org)


text:
;; no fringes or scrollbars
    (set-fringe-mode -1)
    (scroll-bar-mode -1)
    (tool-bar-mode -1)

;; start scratch in text mode (usefull to get a faster Emacs load time
;; because it avoids autoloads of elisp modes)
    (setq initial-major-mode 'text-mode)

;; scratch buffer empty
    (setq initial-scratch-message nil)
;;
    (setq redisplay-dont-pause t)

;; auto-refresh dired
    (setq global-auto-revert-non-file-buffers t)
    (setq auto-revert-verbose nil)

;; enable the column fill mark, globally
    (define-globalized-minor-mode global-fci-mode
      fci-mode (
                lambda () (fci-mode 1)))
    (global-fci-mode 1)

;; relative line numbers
    (add-hook 'prog-mode-hook 'relative-line-numbers-mode t)
    (add-hook 'prog-mode-hook 'line-number-mode t)
    (add-hook 'prog-mode-hook 'column-number-mode t)

;; ediff: side-by-side diffs
    (setq ediff-split-window-function 'split-window-horizontally
          ediff-window-setup-function 'ediff-setup-windows-plain) ;; no extra frames

;; ido-mode
    (require 'ido)
    (setq ido-enable-flex-matching t)
    (setq ido-everywhere t)
    (ido-mode t)

;; IDE-like GDB
    (setq gdb-many-windows t)

;; highlight tail, stupid but awesome => disabled, problems in Windows
    ;; (require-package 'highlight-tail)
    ;; (highlight-tail-mode)
    ;; (setq highlight-tail-steps 30
    ;;       highlight-tail-timer 0.025)

;; y or n is enough
    (defalias 'yes-or-no-p 'y-or-n-p)

;; no bell
    (custom-set-variables '(ring-bell-function 'ignore))
    (setq visible-bell nil)

;; some more interface-related settings
    (setq
          read-file-name-completion-ignore-case t
          frame-title-format '("Emacs @ : %b %+%+ %f")
          mouse-yank-at-point t
          inhibit-splash-screen t
          inhibit-startup-echo-area-message t
          inhibit-startup-message t
    )
(blink-cursor-mode -1)

;; non jumpy scrolling
    (setq scroll-margin 5
    scroll-conservatively 9999
    scroll-step 1)

;; better buffer names for duplicates
    (require 'uniquify)
    (setq uniquify-buffer-name-style 'forward
          uniquify-separator "/"
          uniquify-ignore-buffers-re "^\\*" ; leave special buffers alone
          uniquify-after-kill-buffer-p t)

;; dont clutter the modeline bar with minor modes indicators
    (require-package 'diminish)
    (diminish 'visual-line-mode)
    (after 'autopair (diminish 'autopair-mode))
    (after 'undo-tree (diminish 'undo-tree-mode))
    (after 'auto-complete (diminish 'auto-complete-mode))
    (after 'projectile (diminish 'projectile-mode))
    (after 'yasnippet (diminish 'yas-minor-mode))
    (after 'guide-key (diminish 'guide-key-mode))
    (after 'eldoc (diminish 'eldoc-mode))
    (after 'smartparens (diminish 'smartparens-mode))
    (after 'company (diminish 'company-mode))
    (after 'elisp-slime-nav (diminish 'elisp-slime-nav-mode))
    (after 'git-gutter+ (diminish 'git-gutter+-mode))
    (after 'magit (diminish 'magit-auto-revert-mode))
    (after 'hs-minor-mode (diminish 'hs-minor-mode))

;; open a windows explorer on the buffer path
    (defun open-explorer-path ()
      (interactive)
      (shell-command
       (concat "explorer "
               (replace-regexp-in-string "/" "\\"
                                         (file-name-directory
                                          (buffer-file-name)) t t))))

(provide 'init-interface)


text:
;; start emacs-server if not running
(provide 'init-server)
(add-hook 'after-init-hook
          (lambda ()
            (require 'server)
            (unless (server-running-p)
              (server-start))))


text:
;; My current
    ;; (load-theme 'ample-zen t)
    (load-theme 'professional t)

;; color-theme-aproximate to fix colors in console mode
    (color-theme-approximate-on)

;; Colors-Identifiers-Mode to colorize variable names
    (require-package 'diminish)
    (require-package 'color-identifiers-mode)
    (global-color-identifiers-mode)
    (diminish 'color-identifiers-mode)

;; rainbox-delimiters
    (require-package 'rainbow-delimiters)
    (add-hook 'prog-mode-hook 'rainbow-delimiters-mode)

;; highlight current line
    (global-hl-line-mode)

(provide 'init-colors)


text:
(defvar prog-mode-hook nil)

(defun prog-mode-setup ()
  (run-hooks 'prog-mode-hook))

(add-hook 'c-mode-common-hook 'prog-mode-setup)
(add-hook 'javascript-mode-hook 'prog-mode-setup)
(add-hook 'emacs-lisp-mode-hook 'prog-mode-setup)
(add-hook 'cperl-mode-hook 'prog-mode-setup)
(add-hook 'python-mode-hook 'prog-mode-setup)
(add-hook 'd-mode-hook 'prog-mode-setup)
(add-hook 'php-mode-hook 'prog-mode-setup)
(add-hook 'csharp-mode-hook 'prog-mode-setup)
(add-hook 'javascript-mode-hook 'prog-mode-setup)
(add-hook 'js-mode-hook 'prog-mode-setup)
(add-hook 'js2-mode-hook 'prog-mode-setup)
(add-hook 'ruby-mode-hook 'prog-mode-setup)
(add-hook 'fsharp-mode-hook 'prog-mode-setup)

(provide 'init-programming)


text:
(setq package-archives '(("gnu" . "http://elpa.gnu.org/packages/")
                         ("org" . "http://orgmode.org/elpa/")
                         ("marmalade" . "http://marmalade-repo.org/packages/")
                         ("melpa" . "http://melpa.milkbox.net/packages/")))
(package-initialize)

(defun require-package (package)
  (setq-default highlight-tabs t)
  "Install given PACKAGE."
  (unless (package-installed-p package)
    (unless (assoc package package-archive-contents)
      (package-refresh-contents))
    (package-install package)))

;; something asked for this (Helm probably)
(require 'async-bytecomp)

(provide 'init-packages)


text:
(require 'evil)
(evil-mode t)
(global-evil-tabs-mode t) ; tabs (requires evil-tabs)
(require-package 'evil-jumper) ; c-i / c-o
(require-package 'evil-visualstar)
(require-package 'evil-indent-textobject)
(require-package 'evil-surround)
(require-package 'evil-matchit) ; matchit (show matching parenthesis)
(require-package 'evil-search-highlight-persist)

(global-evil-matchit-mode t)
(global-evil-surround-mode t)
(global-evil-search-highlight-persist t)
(global-evil-leader-mode t)
(setq evil-leader/in-all-states t) ; leader

;; DEL in insert mode to go 10 lines up, RET 10 down
;; From: http://stackoverflow.com/questions/8483182/evil-mode-best-practice
(define-key evil-normal-state-map (kbd "DEL") (lambda ()
                                                (interactive)
                                                (previous-line 10)
                                                (evil-scroll-line-up 10)
                                                ))

(define-key evil-normal-state-map (kbd "RET") (lambda ()
                                                (interactive)
                                                (next-line 10)
                                                (evil-scroll-line-down 10)
                                                ))

;; evil settings
(setq evil-ex-substitute-global t ; like Vim's "set gdefault"
      evil-move-cursor-back nil ; dont move back one position after exiting insert mode
      evil-jumper-auto-center t
      evil-jumper-file  "~/.emacs.d/cache/evil-jumps"
      evil-jumper-auto-save-interval 3600
      evil-emacs-state-cursor '("red" box)
      evil-normal-state-cursor '("green" box)
      evil-visual-state-cursor '("orange" box)
      evil-insert-state-cursor '("red" bar)
      evil-replace-state-cursor '("red" bar)
      evil-operator-state-cursor '("red" hollow))

;; terminal colors by mode also on console
(defun my-evil-terminal-cursor-change ()
  (when (string= (getenv "TERM_PROGRAM") "iTerm.app")
    (add-hook 'evil-insert-state-entry-hook (lambda () (my-send-string-to-terminal "\e]50;CursorShape=1\x7")))
    (add-hook 'evil-insert-state-exit-hook  (lambda () (my-send-string-to-terminal "\e]50;CursorShape=0\x7"))))
  (when (and (getenv "TMUX") (string= (getenv "TERM_PROGRAM") "iTerm.app"))
    (add-hook 'evil-insert-state-entry-hook (lambda () (my-send-string-to-terminal "\ePtmux;\e\e]50;CursorShape=1\x7\e\\")))
    (add-hook 'evil-insert-state-exit-hook  (lambda () (my-send-string-to-terminal "\ePtmux;\e\e]50;CursorShape=0\x7\e\\")))))

(add-hook 'after-make-frame-functions (lambda (frame) (my-evil-terminal-cursor-change)))
(my-evil-terminal-cursor-change)

;; recenter after search
(defadvice
  isearch-forward
  (after isearch-forward-recenter activate)
  (recenter))
(ad-activate 'isearch-forward)

(defadvice
  isearch-repeat-forward
  (after isearch-repeat-forward-recenter activate)
  (recenter))
(ad-activate 'isearch-repeat-forward)

(defadvice
  isearch-repeat-backward
  (after isearch-repeat-backward-recenter activate)
  (recenter))
(ad-activate 'isearch-repeat-backward)

;; ex-mode commands
;; Normal map
(defun vimlike-quit ()
  "Vimlike ':q' behavior: close current window if there are split windows;
    otherwise, close current tab (elscreen)."
  (interactive)
  (let ((one-elscreen (elscreen-one-screen-p))
        (one-window (one-window-p))
        )
    (cond
                                        ; if current tab has split windows in it, close the current live window
     ((not one-window)
      (delete-window) ; delete the current window
      (balance-windows) ; balance remaining windows
      nil)
                                        ; if there are multiple elscreens (tabs), close the current elscreen
     ((not one-elscreen)
      (elscreen-kill)
      nil)
                                        ; if there is only one elscreen, just try to quit (calling elscreen-kill
                                        ; will not work, because elscreen-kill fails if there is only one
                                        ; elscreen)
     (one-elscreen
      (evil-quit)
      nil)
     )))

(defun vimlike-write-quit ()
  "Vimlike ':wq' behavior: write then close..."
  (interactive)
  (save-buffer)
  (vimlike-quit))

(evil-ex-define-cmd "q" 'vimlike-quit)
(evil-ex-define-cmd "wq" 'vimlike-write-quit)

;; non-leader shortcuts for making vim mode more bearable on a spanish
;; keyboard
(define-key evil-normal-state-map "-" 'evil-search-forward)
(define-key evil-normal-state-map "ñ" 'evil-ex)
(define-key evil-normal-state-map "  " 'helm-my-buffers)
(define-key evil-normal-state-map " b" 'helm-bookmarks)
(define-key evil-normal-state-map " r" 'helm-recentf)
(define-key evil-normal-state-map " k" 'helm-show-kill-ring)
(define-key evil-normal-state-map " o" 'helm-occur)
(define-key evil-insert-state-map "º" 'evil-normal-state)

;; window move
(define-key evil-normal-state-map (kbd "C-w <up>") 'windmove-up)
(define-key evil-normal-state-map (kbd "C-w <down>") 'windmove-down)
(define-key evil-normal-state-map (kbd "C-w <right>") 'windmove-right)
(define-key evil-normal-state-map (kbd "C-w <left>") 'windmove-left)

;; elscreen kill
(define-key evil-normal-state-map (kbd "C-w d") 'elscreen-kill)

; c-number switch to elscreen (tab) (I also have <leader>-number which I prefer, but these
; binding are useful in modes where the leader doesnt work)
(define-key evil-normal-state-map (kbd "C-0") (lambda() (interactive) (elscreen-goto 0)))
(define-key evil-normal-state-map (kbd "C-º") (lambda() (interactive) (elscreen-goto 0)))
(define-key evil-normal-state-map (kbd "C-1") (lambda() (interactive) (elscreen-goto 1)))
(define-key evil-normal-state-map (kbd "C-2") (lambda() (interactive) (elscreen-goto 2)))
(define-key evil-normal-state-map (kbd "C-3") (lambda() (interactive) (elscreen-goto 3)))
(define-key evil-normal-state-map (kbd "C-4") (lambda() (interactive) (elscreen-goto 4)))
(define-key evil-normal-state-map (kbd "C-5") (lambda() (interactive) (elscreen-goto 5)))
(define-key evil-normal-state-map (kbd "C-6") (lambda() (interactive) (elscreen-goto 6)))
(define-key evil-normal-state-map (kbd "C-7") (lambda() (interactive) (elscreen-goto 7)))
(define-key evil-normal-state-map (kbd "C-8") (lambda() (interactive) (elscreen-goto 8)))
(define-key evil-normal-state-map (kbd "C-9") (lambda() (interactive) (elscreen-goto 9)))
(define-key evil-insert-state-map (kbd "C-0") (lambda() (interactive) (elscreen-goto 0)))
(define-key evil-insert-state-map (kbd "C-º") (lambda() (interactive) (elscreen-goto 0)))
(define-key evil-insert-state-map (kbd "C-1") (lambda() (interactive) (elscreen-goto 1)))
(define-key evil-insert-state-map (kbd "C-2") (lambda() (interactive) (elscreen-goto 2)))
(define-key evil-insert-state-map (kbd "C-3") (lambda() (interactive) (elscreen-goto 3)))
(define-key evil-insert-state-map (kbd "C-4") (lambda() (interactive) (elscreen-goto 4)))
(define-key evil-insert-state-map (kbd "C-5") (lambda() (interactive) (elscreen-goto 5)))
(define-key evil-insert-state-map (kbd "C-6") (lambda() (interactive) (elscreen-goto 6)))
(define-key evil-insert-state-map (kbd "C-7") (lambda() (interactive) (elscreen-goto 7)))
(define-key evil-insert-state-map (kbd "C-8") (lambda() (interactive) (elscreen-goto 8)))
(define-key evil-insert-state-map (kbd "C-9") (lambda() (interactive) (elscreen-goto 9)))

;; c-j / c-k page down/up
(define-key evil-normal-state-map (kbd "C-k") (lambda ()
                                                (interactive)
                                                (evil-scroll-up nil)))
(define-key evil-normal-state-map (kbd "C-j") (lambda ()
                                                (interactive)
                                                (evil-scroll-down nil)))

;; c+ c- to increase/decrease number like Vim's C-a C-x
(define-key evil-normal-state-map (kbd "C-+") 'evil-numbers/inc-at-pt)
(define-key evil-normal-state-map (kbd "C--") 'evil-numbers/dec-at-pt)

;; other shortcuts (prefixed by leader, which is comma here)
(evil-leader/set-leader ",")
(evil-leader/set-key "SPC" 'lazy-highlight-cleanup)
(evil-leader/set-key "SPC" 'evil-search-highlight-persist-remove-all)
(evil-leader/set-key "ea" 'flycheck-list-errors)   ; <leader>ea show all errors
(evil-leader/set-key "en" 'flycheck-next-error)    ; <leader>en next errors
(evil-leader/set-key "f" 'end-of-defun)            ; <leader>f/F end/start of function
(evil-leader/set-key "F" 'beginning-of-defun)
(evil-leader/set-key "gof" 'open-explorer-path)    ; open explorer window of buffer path
(evil-leader/set-key "," 'evil-ace-jump-word-mode) ; <leader>, for Ace Jump (word)
(evil-leader/set-key "l" 'evil-ace-jump-line-mode) ; <leader>l for Ace Jump (line)
(evil-leader/set-key "x" 'evil-ace-jump-char-mode) ; <leader>x for Ace Jump (char)
(evil-leader/set-key "tn" 'elscreen-create)        ; <leader>tn create new tab
(evil-leader/set-key "tc" 'elscreen-kill)          ; <leader>tc close tab
(evil-leader/set-key "gs" 'desktop-save)
(evil-leader/set-key "css" 'desktop-read)
(evil-leader/set-key "cv" 'delete-other-windows)   ; <leader>cv to close other splits
(evil-leader/set-key "im" 'helm-imenu)             ; shows functions
(evil-leader/set-key "co" 'evilnc-comment-or-uncomment-lines) ; nerd commenter
(evil-leader/set-key "m" 'emmet-expand-line) ; emmet
(evil-leader/set-key "=" (lambda(begin end)        ; <leader>= align selection lines by "="
                           (interactive "r")
                           (align-regexp begin end "\\(\\s-*\\)=" 1 1 )))
(evil-leader/set-key "v" (lambda () (interactive)
                           (split-window-horizontally)
                           (evil-window-right 1)))
(evil-leader/set-key "p" (lambda()                 ; paste on a new line below current
                           (interactive)
                           (evil-open-below 1)
                           (evil-paste-after 1)
                           (evil-normal-state)))
(evil-leader/set-key "P" (lambda()                 ; paste on a new line below current
                           (interactive)
                           (evil-open-above 1)
                           (evil-previous-visual-line 1)
                           (evil-paste-after 1)
                           (evil-normal-state)))
(evil-leader/set-key "o" (lambda () ; <leader>o open line below
                           (interactive)
                           (evil-open-below 1)
                           (evil-normal-state)))
(evil-leader/set-key "O" (lambda () ; <leader>o open line below
                           (interactive)
                           (evil-open-above 1)
                           (evil-normal-state)))
(evil-leader/set-key "ct" 'delete-trailing-whitespace)

                                        ; shortcuts for jumping to a tab
(evil-leader/set-key "0" (lambda() (interactive) (elscreen-goto 0)))
(evil-leader/set-key "1" (lambda() (interactive) (elscreen-goto 1)))
(evil-leader/set-key "2" (lambda() (interactive) (elscreen-goto 2)))
(evil-leader/set-key "3" (lambda() (interactive) (elscreen-goto 3)))
(evil-leader/set-key "4" (lambda() (interactive) (elscreen-goto 4)))
(evil-leader/set-key "5" (lambda() (interactive) (elscreen-goto 5)))
(evil-leader/set-key "6" (lambda() (interactive) (elscreen-goto 6)))
(evil-leader/set-key "7" (lambda() (interactive) (elscreen-goto 7)))
(evil-leader/set-key "8" (lambda() (interactive) (elscreen-goto 8)))
(evil-leader/set-key "9" (lambda() (interactive) (elscreen-goto 9)))

;; nerd commenter (,co)
(evil-leader/set-key "co" 'evilnc-comment-or-uncomment-lines)

;; emmet (,m)
(evil-leader/set-key "m" 'emmet-expand-line)

;; j and k move the visual line in long wrapped lines
(define-key evil-normal-state-map (kbd "j") 'evil-next-visual-line)
(define-key evil-normal-state-map (kbd "k") 'evil-previous-visual-line)

;; esc quits!
(defun minibuffer-keyboard-quit ()
  "Abort recursive edit.
    In Delete Selection mode, if the mark is active, just deactivate it;
    then it takes a second \\[keyboard-quit] to abort the minibuffer."
  (interactive)
  (if (and delete-selection-mode transient-mark-mode mark-active)
      (setq deactivate-mark  t)
    (when (get-buffer "*Completions*") (delete-windows-on "*Completions*"))
    (abort-recursive-edit)))

(define-key evil-normal-state-map [escape] 'keyboard-quit)
(define-key evil-visual-state-map [escape] 'keyboard-quit)
(define-key minibuffer-local-map [escape] 'minibuffer-keyboard-quit)
(define-key minibuffer-local-ns-map [escape] 'minibuffer-keyboard-quit)
(define-key minibuffer-local-completion-map [escape] 'minibuffer-keyboard-quit)
(define-key minibuffer-local-must-match-map [escape] 'minibuffer-keyboard-quit)
(define-key minibuffer-local-isearch-map [escape] 'minibuffer-keyboard-quit)
(global-set-key [escape] 'evil-exit-emacs-state)

;; save when exiting insert mode
   ;; (defun my-save-if-bufferfilename ()
   ;;   (if (buffer-file-name)
   ;;       (progn
   ;;         (save-buffer)
   ;;         )
   ;;     (message "no file is associated to this buffer: do nothing")
   ;;     )
   ;; )
   ;; (add-hook 'evil-insert-state-exit-hook 'my-save-if-bufferfilename)

(provide 'init-evil)


text:
/**
 * @file  cfgpath.h
 * @brief Cross platform methods for obtaining paths to configuration files.
 *
 * Copyright (C) 2013 Adam Nielsen <malvineous@shikadi.net>
 *
 * This code is placed in the public domain.  You are free to use it for any
 * purpose.  If you add new platform support, please contribute a patch!
 *
 * Example use:
 *
 * char cfgdir[256];
 * get_user_config_file(cfgdir, sizeof(cfgdir), "myapp");
 * if (cfgdir[0] == 0) {
 *     printf("Unable to find home directory.\n");
 *     return 1;
 * }
 * printf("Saving configuration file to %s\n", cfgdir);
 *
 * A number of constants are also defined:
 *
 *  - MAX_PATH: Maximum length of a path, in characters.  Used to allocate a
 *      char array large enough to hold the returned path.
 *
 *  - PATH_SEPARATOR_CHAR: The separator between folders.  This will be either a
 *      forward slash or a backslash depending on the platform.  This is a
 *      character constant.
 *
 *  - PATH_SEPARATOR_STRING: The same as PATH_SEPARATOR_CHAR but as a C string,
 *      to make it easier to append to other string constants.
 */

#ifndef CFGPATH_H_
#define CFGPATH_H_

#ifdef _MSC_VER
#define inline __inline
#include <direct.h>
#define mkdir _mkdir
#endif

#ifdef __unix__
#include <sys/param.h>
#endif

#if defined(__linux__) || defined(BSD)
#define CFGPATH_LINUX
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#define MAX_PATH 512  /* arbitrary value */
#define PATH_SEPARATOR_CHAR '/'
#define PATH_SEPARATOR_STRING "/"
#elif defined(WIN32)
#define CFGPATH_WINDOWS
#include <shlobj.h>
/* MAX_PATH is defined by the Windows API */
#define PATH_SEPARATOR_CHAR '\\'
#define PATH_SEPARATOR_STRING "\\"
#elif defined(__APPLE__)
#define CFGPATH_MAC
#include <CoreServices/CoreServices.h>
#include <sys/stat.h>
#define MAX_PATH PATH_MAX
#define PATH_SEPARATOR_CHAR '/'
#define PATH_SEPARATOR_STRING "/"
#else
#error cfgpath.h functions have not been implemented for your platform!  Please send patches.
#endif

/** Get an absolute path to a single configuration file, specific to this user.
 *
 * This function is useful for programs that need only a single configuration
 * file.  The file is unique to the user account currently logged in.
 *
 * Output is typically:
 *
 *   Windows: C:\Users\jcitizen\AppData\Roaming\appname.ini
 *   Linux: /home/jcitizen/.config/appname.conf
 *   Mac: /Users/jcitizen/Library/Application Support/appname.conf
 *
 * @param out
 *   Buffer to write the path.  On return will contain the path, or an empty
 *   string on error.
 *
 * @param maxlen
 *   Length of out.  Must be >= MAX_PATH.
 *
 * @param appname
 *   Short name of the application.  Avoid using spaces or version numbers, and
 *   use lowercase if possible.
 *
 * @post The file may or may not exist.
 * @post The folder holding the file is created if needed.
 */
static inline void get_user_config_file(char *out, unsigned int maxlen, const char *appname)
{
#ifdef CFGPATH_LINUX
	const char *out_orig = out;
	char *home = getenv("XDG_CONFIG_HOME");
	unsigned int config_len = 0;
	if (!home) {
		home = getenv("HOME");
		if (!home) {
			// Can't find home directory
			out[0] = 0;
			return;
		}
		config_len = strlen(".config/");
	}

	unsigned int home_len = strlen(home);
	unsigned int appname_len = strlen(appname);
	const int ext_len = strlen(".conf");

	/* first +1 is "/", second is terminating null */
	if (home_len + 1 + config_len + appname_len + ext_len + 1 > maxlen) {
		out[0] = 0;
		return;
	}

	memcpy(out, home, home_len);
	out += home_len;
	*out = '/';
	out++;
	if (config_len) {
		memcpy(out, ".config/", config_len);
		out += config_len;
		/* Make the .config folder if it doesn't already exist */
		mkdir(out_orig, 0755);
	}
	memcpy(out, appname, appname_len);
	out += appname_len;
	memcpy(out, ".conf", ext_len);
	out += ext_len;
	*out = 0;
#elif defined(CFGPATH_WINDOWS)
	if (maxlen < MAX_PATH) {
		out[0] = 0;
		return;
	}
	if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, out))) {
		out[0] = 0;
		return;
	}
	/* We don't try to create the AppData folder as it always exists already */
	unsigned int appname_len = strlen(appname);
	if (strlen(out) + 1 + appname_len + strlen(".ini") + 1 > maxlen) {
		out[0] = 0;
		return;
	}
	strcat(out, "\\");
	strcat(out, appname);
	strcat(out, ".ini");
#elif defined(CFGPATH_MAC)
	FSRef ref;
	FSFindFolder(kUserDomain, kApplicationSupportFolderType, kCreateFolder, &ref);
	char home[MAX_PATH];
	FSRefMakePath(&ref, (UInt8 *)&home, MAX_PATH);
	/* first +1 is "/", second is terminating null */
	const char *ext = ".conf";
	if (strlen(home) + 1 + strlen(appname) + strlen(ext) + 1 > maxlen) {
		out[0] = 0;
		return;
	}

	strcpy(out, home);
	strcat(out, PATH_SEPARATOR_STRING);
	strcat(out, appname);
	strcat(out, ext);
#endif
}

/** Get an absolute path to a configuration folder, specific to this user.
 *
 * This function is useful for programs that need to store multiple
 * configuration files.  The output is a folder (which may not exist and will
 * need to be created) suitable for storing a number of files.
 *
 * The returned path will always end in a platform-specific trailing slash, so
 * that a filename can simply be appended to the path.
 *
 * Output is typically:
 *
 *   Windows: C:\Users\jcitizen\AppData\Roaming\appname\
 *   Linux: /home/jcitizen/.config/appname/
 *   Mac: /Users/jcitizen/Library/Application Support/appname/
 *
 * @param out
 *   Buffer to write the path.  On return will contain the path, or an empty
 *   string on error.
 *
 * @param maxlen
 *   Length of out.  Must be >= MAX_PATH.
 *
 * @param appname
 *   Short name of the application.  Avoid using spaces or version numbers, and
 *   use lowercase if possible.
 *
 * @post The folder is created if needed.
 */
static inline void get_user_config_folder(char *out, unsigned int maxlen, const char *appname)
{
#ifdef CFGPATH_LINUX
	const char *out_orig = out;
	char *home = getenv("XDG_CONFIG_HOME");
	unsigned int config_len = 0;
	if (!home) {
		home = getenv("HOME");
		if (!home) {
			// Can't find home directory
			out[0] = 0;
			return;
		}
		config_len = strlen(".config/");
	}

	unsigned int home_len = strlen(home);
	unsigned int appname_len = strlen(appname);

	/* first +1 is "/", second is trailing "/", third is terminating null */
	if (home_len + 1 + config_len + appname_len + 1 + 1 > maxlen) {
		out[0] = 0;
		return;
	}

	memcpy(out, home, home_len);
	out += home_len;
	*out = '/';
	out++;
	if (config_len) {
		memcpy(out, ".config/", config_len);
		out += config_len;
		/* Make the .config folder if it doesn't already exist */
		*out = '\0';
		mkdir(out_orig, 0755);
	}
	memcpy(out, appname, appname_len);
	out += appname_len;
	/* Make the .config/appname folder if it doesn't already exist */
	*out = '\0';
	mkdir(out_orig, 0755);
	*out = '/';
	out++;
	*out = 0;
#elif defined(CFGPATH_WINDOWS)
	if (maxlen < MAX_PATH) {
		out[0] = 0;
		return;
	}
	if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, out))) {
		out[0] = 0;
		return;
	}
	/* We don't try to create the AppData folder as it always exists already */
	unsigned int appname_len = strlen(appname);
	if (strlen(out) + 1 + appname_len + 1 + 1 > maxlen) {
		out[0] = 0;
		return;
	}
	strcat(out, "\\");
	strcat(out, appname);
	/* Make the AppData\appname folder if it doesn't already exist */
	mkdir(out);
	strcat(out, "\\");
#elif defined(CFGPATH_MAC)
	FSRef ref;
	FSFindFolder(kUserDomain, kApplicationSupportFolderType, kCreateFolder, &ref);
	char home[MAX_PATH];
	FSRefMakePath(&ref, (UInt8 *)&home, MAX_PATH);
	/* first +1 is "/", second is trailing "/", third is terminating null */
	if (strlen(home) + 1 + strlen(appname) + 1 + 1 > maxlen) {
		out[0] = 0;
		return;
	}

	strcpy(out, home);
	strcat(out, PATH_SEPARATOR_STRING);
	strcat(out, appname);
	/* Make the .config/appname folder if it doesn't already exist */
	mkdir(out, 0755);
	strcat(out, PATH_SEPARATOR_STRING);
#endif
}

/** Get an absolute path to a data storage folder, specific to this user.
 *
 * This function is useful for programs that need to store larger amounts of
 * data specific to each user.  The output is a folder (which may not exist and
 * will need to be created) suitable for storing a number of data files.
 *
 * This path should be used for persistent, important data files the user would
 * want to keep.  Do not use this path for temporary files, cache files, or
 * other files that can be recreated if they are deleted.  Use
 * get_user_cache_folder() for those instead.
 *
 * The returned path will always end in a platform-specific trailing slash, so
 * that a filename can simply be appended to the path.
 *
 * Output is typically:
 *
 *   Windows: C:\Users\jcitizen\AppData\Roaming\appname-data\
 *   Linux: /home/jcitizen/.local/share/appname/
 *   Mac: /Users/jcitizen/Library/Application Support/appname-data/
 *
 * @param out
 *   Buffer to write the path.  On return will contain the path, or an empty
 *   string on error.
 *
 * @param maxlen
 *   Length of out.  Must be >= MAX_PATH.
 *
 * @param appname
 *   Short name of the application.  Avoid using spaces or version numbers, and
 *   use lowercase if possible.
 *
 * @post The folder is created if needed.
 */
static inline void get_user_data_folder(char *out, unsigned int maxlen, const char *appname)
{
#ifdef CFGPATH_LINUX
	const char *out_orig = out;
	char *home = getenv("XDG_DATA_HOME");
	unsigned int config_len = 0;
	if (!home) {
		home = getenv("HOME");
		if (!home) {
			// Can't find home directory
			out[0] = 0;
			return;
		}
		config_len = strlen(".local/share/");
	}

	unsigned int home_len = strlen(home);
	unsigned int appname_len = strlen(appname);

	/* first +1 is "/", second is trailing "/", third is terminating null */
	if (home_len + 1 + config_len + appname_len + 1 + 1 > maxlen) {
		out[0] = 0;
		return;
	}

	memcpy(out, home, home_len);
	out += home_len;
	*out = '/';
	out++;
	if (config_len) {
		memcpy(out, ".local/share/", config_len);
		out += config_len;
		/* Make the .local/share folder if it doesn't already exist */
		*out = '\0';
		mkdir(out_orig, 0755);
	}
	memcpy(out, appname, appname_len);
	out += appname_len;
	/* Make the .local/share/appname folder if it doesn't already exist */
	*out = '\0';
	mkdir(out_orig, 0755);
	*out = '/';
	out++;
	*out = 0;
#elif defined(CFGPATH_WINDOWS) || defined(CFGPATH_MAC)
	/* No distinction under Windows or OS X */
	get_user_config_folder(out, maxlen, appname);
#endif
}

/** Get an absolute path to a temporary storage folder, specific to this user.
 *
 * This function is useful for programs that temporarily need to store larger
 * amounts of data specific to each user.  The output is a folder (which may
 * not exist and will need to be created) suitable for storing a number of
 * temporary files.  The files may be lost or deleted when the program
 * terminates.
 *
 * This path should be used for temporary, unimportant data files that can
 * safely be deleted after the program terminates.  Do not use this path for
 * any important files the user would want to keep.  Use get_user_data_folder()
 * for those instead.
 *
 * The returned path will always end in a platform-specific trailing slash, so
 * that a filename can simply be appended to the path.
 *
 * Output is typically:
 *
 *   Windows: C:\Users\jcitizen\AppData\Local\appname\
 *   Linux: /home/jcitizen/.cache/appname/
 *   Mac: /Users/jcitizen/Library/Application Support/appname/
 *
 * @param out
 *   Buffer to write the path.  On return will contain the path, or an empty
 *   string on error.
 *
 * @param maxlen
 *   Length of out.  Must be >= MAX_PATH.
 *
 * @param appname
 *   Short name of the application.  Avoid using spaces or version numbers, and
 *   use lowercase if possible.
 *
 * @post The folder is created if needed.
 */
static inline void get_user_cache_folder(char *out, unsigned int maxlen, const char *appname)
{
#ifdef CFGPATH_LINUX
	const char *out_orig = out;
	char *home = getenv("XDG_CACHE_HOME");
	unsigned int config_len = 0;
	if (!home) {
		home = getenv("HOME");
		if (!home) {
			// Can't find home directory
			out[0] = 0;
			return;
		}
		config_len = strlen(".cache/");
	}

	unsigned int home_len = strlen(home);
	unsigned int appname_len = strlen(appname);

	/* first +1 is "/", second is trailing "/", third is terminating null */
	if (home_len + 1 + config_len + appname_len + 1 + 1 > maxlen) {
		out[0] = 0;
		return;
	}

	memcpy(out, home, home_len);
	out += home_len;
	*out = '/';
	out++;
	if (config_len) {
		memcpy(out, ".cache/", config_len);
		out += config_len;
		/* Make the .cache folder if it doesn't already exist */
		*out = '\0';
		mkdir(out_orig, 0755);
	}
	memcpy(out, appname, appname_len);
	out += appname_len;
	/* Make the .cache/appname folder if it doesn't already exist */
	*out = '\0';
	mkdir(out_orig, 0755);
	*out = '/';
	out++;
	*out = 0;
#elif defined(CFGPATH_WINDOWS)
	if (maxlen < MAX_PATH) {
		out[0] = 0;
		return;
	}
	if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, out))) {
		out[0] = 0;
		return;
	}
	/* We don't try to create the AppData folder as it always exists already */
	unsigned int appname_len = strlen(appname);
	if (strlen(out) + 1 + appname_len + 1 + 1 > maxlen) {
		out[0] = 0;
		return;
	}
	strcat(out, "\\");
	strcat(out, appname);
	/* Make the AppData\appname folder if it doesn't already exist */
	mkdir(out);
	strcat(out, "\\");
#elif defined(CFGPATH_MAC)
	/* No distinction under OS X */
	get_user_config_folder(out, maxlen, appname);
#endif
}

#endif /* CFGPATH_H_ */

repo_name: Malvineous/cfgpath

repo_language: C


text:
/**
 * @file  test-linux.c
 * @brief cfgpath.h test code for the Linux platform.
 *
 * Copyright (C) 2013 Adam Nielsen <malvineous@shikadi.net>
 *
 * This code is placed in the public domain.  You are free to use it for any
 * purpose.  If you add new platform support, please contribute a patch!
 */

#include <string.h>
#include <stdio.h>

#define SHGetFolderPath test_SHGetFolderPath
#define mkdir test_mkdir
#undef __linux__
#ifndef WIN32
#define WIN32
#endif
#include "cfgpath.h"

const char *set_appdata;
const char *set_appdata_local;
int set_retval;

/* Fake implementation of SHGetFolderPath() that fails when and how we want */
int test_SHGetFolderPath(void *hwndOwner, int nFolder, void *hToken,
	int dwFlags, char *pszPath)
{
	/* Hopefully trigger an error if the buffer is too small */
	pszPath[MAX_PATH - 1] = 0;

	switch (nFolder) {
		case CSIDL_APPDATA:
			if (set_appdata) {
				strcpy(pszPath, set_appdata);
				return set_retval;
			}
			break;
		case CSIDL_LOCAL_APPDATA:
			if (set_appdata_local) {
				strcpy(pszPath, set_appdata_local);
				return set_retval;
			}
			break;
	}
	return E_FAIL;
}

int test_mkdir(const char *path)
{
	return 0;
}

#define TOSTRING_X(x) #x
#define TOSTRING(x) TOSTRING_X(x)
#define RUN_TEST(result, msg)	  \
	TEST_FUNC(buffer, sizeof(buffer), "test-win"); \
	CHECK_RESULT(result, msg)

#define CHECK_RESULT(result, msg) \
	if (strcmp(buffer, result) != 0) { \
		printf("FAIL: %s:%d " TOSTRING(TEST_FUNC) "() " msg "  Test failed, " \
			"returning the wrong value.\n" \
			"Expected: %s\nGot: %s\n", __FILE__, __LINE__, result, buffer); \
		return 1; \
	} else { \
		printf("PASS: " TOSTRING(TEST_FUNC) "() " msg "\n"); \
	}

int main(int argc, char *argv[])
{
	char buffer[256];

/*
 * get_user_config_file()
 */

#define TEST_RESULT "C:\\Users\\test-win\\AppData\\Roaming\\test-win.ini"
#define TEST_FUNC get_user_config_file

	set_retval = S_OK;
	set_appdata = "C:\\Users\\test-win\\AppData\\Roaming";

	TEST_FUNC(buffer, 5, "test-win");
	CHECK_RESULT("", "returns empty string when buffer is too small.");

	RUN_TEST(TEST_RESULT, "works with CSIDL_APPDATA.");

	set_retval = S_FALSE;
	RUN_TEST(TEST_RESULT, "works if folder doesn't exist (S_FALSE).");

	set_appdata = NULL;
	RUN_TEST("", "fails with missing CSIDL_APPDATA.");

#undef TEST_FUNC
#undef TEST_RESULT

/*
 * get_user_config_folder()
 */

#define TEST_RESULT "C:\\Users\\test-win\\AppData\\Roaming\\test-win\\"
#define TEST_FUNC get_user_config_folder

	set_retval = S_OK;
	set_appdata = "C:\\Users\\test-win\\AppData\\Roaming";

	TEST_FUNC(buffer, 5, "test-win");
	CHECK_RESULT("", "returns empty string when buffer is too small.");

	RUN_TEST(TEST_RESULT, "works with CSIDL_APPDATA.");

	set_retval = S_FALSE;
	RUN_TEST(TEST_RESULT, "works if folder doesn't exist (S_FALSE).");

	set_appdata = NULL;
	RUN_TEST("", "fails with missing CSIDL_APPDATA.");

#undef TEST_FUNC
#undef TEST_RESULT

/*
 * get_user_data_folder()
 */

#define TEST_RESULT "C:\\Users\\test-win\\AppData\\Roaming\\test-win\\"
#define TEST_FUNC get_user_data_folder

	set_retval = S_OK;
	set_appdata = "C:\\Users\\test-win\\AppData\\Roaming";

	TEST_FUNC(buffer, 5, "test-win");
	CHECK_RESULT("", "returns empty string when buffer is too small.");

	RUN_TEST(TEST_RESULT, "works with CSIDL_APPDATA.");

	set_retval = S_FALSE;
	RUN_TEST(TEST_RESULT, "works if folder doesn't exist (S_FALSE).");

	set_appdata = NULL;
	RUN_TEST("", "fails with missing CSIDL_APPDATA.");

#undef TEST_FUNC
#undef TEST_RESULT

/*
 * get_user_cache_folder()
 */

#define TEST_RESULT "C:\\Users\\test-win\\AppData\\Local\\test-win\\"
#define TEST_FUNC get_user_cache_folder

	set_retval = S_OK;
	set_appdata_local = "C:\\Users\\test-win\\AppData\\Local";

	TEST_FUNC(buffer, 5, "test-win");
	CHECK_RESULT("", "returns empty string when buffer is too small.");

	RUN_TEST(TEST_RESULT, "works with CSIDL_LOCAL_APPDATA.");

	set_retval = S_FALSE;
	RUN_TEST(TEST_RESULT, "works if folder doesn't exist (S_FALSE).");

	set_appdata_local = NULL;
	RUN_TEST("", "fails with missing CSIDL_LOCAL_APPDATA.");

#undef TEST_FUNC
#undef TEST_RESULT

	printf("All tests passed for platform: Windows.\n");
	return 0;
}


text:
/**
 * @file  shlobj.h
 * @brief Dummy file to allow running the Win32 tests on non-Windows platforms.
 *
 * Copyright (C) 2013 Adam Nielsen <malvineous@shikadi.net>
 *
 * This code is placed in the public domain.  You are free to use it for any
 * purpose.  If you add new platform support, please contribute a patch!
 */

#ifdef CSIDL_APPDATA
#error This file should not be used under Windows, use the system version instead!
#endif

#define CSIDL_APPDATA       26 /* roaming appdata */
#define CSIDL_LOCAL_APPDATA 28

#define S_OK 0
#define S_FALSE 1
#define E_FAIL -1

#define SUCCEEDED(hr) ((hr) >= 0)

#define MAX_PATH 256


text:
.PHONY: all check

all: test-linux test-win

check: test-linux test-win
	./test-linux
	./test-win

test-linux: test-linux.c cfgpath.h
	$(CC) -O0 -g -o $@ $<

test-win: test-win.c cfgpath.h shlobj.h
	$(CC) -O0 -g -o $@ $< -I.


text:
/**
 * @file  test-linux.c
 * @brief cfgpath.h test code for the Linux platform.
 *
 * Copyright (C) 2013 Adam Nielsen <malvineous@shikadi.net>
 *
 * This code is placed in the public domain.  You are free to use it for any
 * purpose.  If you add new platform support, please contribute a patch!
 */

#include <string.h>
#include <stdio.h>

#ifndef __linux__
#define __linux__
#endif
#undef WIN32
#define getenv test_getenv
#define mkdir test_mkdir
#include "cfgpath.h"

int test_env_xdg_valid;  /* Does $XDG_CONFIG_HOME exist? */
int test_env_home_valid; /* Does $HOME exist? */

char getenv_buffer[256];

char *test_getenv(const char *var)
{
	if (test_env_xdg_valid && (strcmp(var, "XDG_CONFIG_HOME") == 0)) {
		strcpy(getenv_buffer, "/home/test/.config");
		return getenv_buffer;
	}
	if (test_env_home_valid && (strcmp(var, "HOME") == 0)) {
		strcpy(getenv_buffer, "/home/test");
		return getenv_buffer;
	}
	return NULL;
}

int test_mkdir(const char *path, mode_t mode)
{
	return 0;
}

#define TOSTRING_X(x) #x
#define TOSTRING(x) TOSTRING_X(x)
#define RUN_TEST(result, msg)	  \
	TEST_FUNC(buffer, sizeof(buffer), "test-linux"); \
	CHECK_RESULT(result, msg)

#define CHECK_RESULT(result, msg) \
	if (strcmp(buffer, result) != 0) { \
		printf("FAIL: %s:%d " TOSTRING(TEST_FUNC) "() returned the wrong value.\n" \
			"Expected: %s\nGot: %s\n", __FILE__, __LINE__, result, buffer); \
		return 1; \
	} else { \
		printf("PASS: " TOSTRING(TEST_FUNC) "() " msg "\n"); \
	}

int main(int argc, char *argv[])
{
	char buffer[256];

/*
 * get_user_config_file()
 */

#define TEST_RESULT "/home/test/.config/test-linux.conf"
#define TEST_FUNC get_user_config_file

	test_env_xdg_valid = 1;
	test_env_home_valid = 1;
	TEST_FUNC(buffer, 5, "test-linux");
	CHECK_RESULT("", "returns empty string when buffer is too small.");

	test_env_xdg_valid = 1;
	test_env_home_valid = 1;
	RUN_TEST(TEST_RESULT, "works with $XDG_CONFIG_HOME.");

	test_env_xdg_valid = 0;
	test_env_home_valid = 1;
	RUN_TEST(TEST_RESULT, "works with $HOME and not $XDG_CONFIG_HOME.");

	test_env_xdg_valid = 0;
	test_env_home_valid = 0;
	RUN_TEST("", "returns empty string when $XDG_CONFIG_HOME and $HOME are absent.");

#undef TEST_FUNC
#undef TEST_RESULT

/*
 * get_user_config_folder()
 */

#define TEST_RESULT "/home/test/.config/test-linux/"
#define TEST_FUNC get_user_config_folder

	test_env_xdg_valid = 1;
	test_env_home_valid = 1;
	TEST_FUNC(buffer, 5, "test-linux");
	CHECK_RESULT("", "returns empty string when buffer is too small.");

	test_env_xdg_valid = 1;
	test_env_home_valid = 1;
	RUN_TEST(TEST_RESULT, "works with $XDG_CONFIG_HOME.");

	test_env_xdg_valid = 0;
	test_env_home_valid = 1;
	RUN_TEST(TEST_RESULT, "works with $HOME and not $XDG_CONFIG_HOME.");

	test_env_xdg_valid = 0;
	test_env_home_valid = 0;
	RUN_TEST("", "returns empty string when $XDG_CONFIG_HOME and $HOME are absent.");

#undef TEST_FUNC
#undef TEST_RESULT

/*
 * get_user_data_folder()
 */

#define TEST_RESULT "/home/test/.local/share/test-linux/"
#define TEST_FUNC get_user_data_folder

	test_env_xdg_valid = 1;
	test_env_home_valid = 1;
	TEST_FUNC(buffer, 5, "test-linux");
	CHECK_RESULT("", "returns empty string when buffer is too small.");

	test_env_xdg_valid = 1;
	test_env_home_valid = 1;
	RUN_TEST(TEST_RESULT, "works with $XDG_CONFIG_HOME.");

	test_env_xdg_valid = 0;
	test_env_home_valid = 1;
	RUN_TEST(TEST_RESULT, "works with $HOME and not $XDG_CONFIG_HOME.");

	test_env_xdg_valid = 0;
	test_env_home_valid = 0;
	RUN_TEST("", "returns empty string when $XDG_CONFIG_HOME and $HOME are absent.");

#undef TEST_FUNC
#undef TEST_RESULT

/*
 * get_user_cache_folder()
 */

#define TEST_RESULT "/home/test/.cache/test-linux/"
#define TEST_FUNC get_user_cache_folder

	test_env_xdg_valid = 1;
	test_env_home_valid = 1;
	TEST_FUNC(buffer, 5, "test-linux");
	CHECK_RESULT("", "returns empty string when buffer is too small.");

	test_env_xdg_valid = 1;
	test_env_home_valid = 1;
	RUN_TEST(TEST_RESULT, "works with $XDG_CONFIG_HOME.");

	test_env_xdg_valid = 0;
	test_env_home_valid = 1;
	RUN_TEST(TEST_RESULT, "works with $HOME and not $XDG_CONFIG_HOME.");

	test_env_xdg_valid = 0;
	test_env_home_valid = 0;
	RUN_TEST("", "returns empty string when $XDG_CONFIG_HOME and $HOME are absent.");

#undef TEST_FUNC
#undef TEST_RESULT

	printf("All tests passed for platform: Linux.\n");
	return 0;
}


text:
cfgpath.h: Cross platform methods for obtaining paths to configuration files
============================================================================
Copyright 2013 Adam Nielsen <malvineous@shikadi.net>

---

This is a simple header file that provides a handful of functions to obtain
paths to configuration files, regardless of the operating system the
application is running under.

It requires no dependencies beyond each platform's standard API.

This code is placed in the public domain.  You are free to use it for any
purpose.  If you add new platform support, please contribute a patch!

Basic use:

    #include "cfgpath.h"

    char cfgdir[MAX_PATH];
    get_user_config_file(cfgdir, sizeof(cfgdir), "myapp");
    if (cfgdir[0] == 0) {
        printf("Unable to find home directory.\n");
        return 1;
    }
    printf("Saving configuration file to %s\n", cfgdir);

To integrate it into your own project, just copy cfgpath.h.  All the other
files are for testing to make sure it works correctly, so you don't need them
unless you intend to make changes and send me a patch.

Supported platforms are currently:

  * Linux
  * Mac OS X
  * Windows

Patches adding support for more platforms would be greatly appreciated.


text:
name: C/C++ CI

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - name: make
      run: make
    - name: make check
      run: make check


text: ### This repository contains source code and experimental data of multiple cache side-channel attacks on Intel x86 architecture.

repo_name: ECLab-ITU/Cache-Side-Channel-Attacks

mime_type: text/x-c