Merge branch 'master' into space_head_bug

This commit is contained in:
Wolfgang Seeker 2016-04-11 12:11:01 +02:00
commit d328e0b4a8
330 changed files with 30648 additions and 4950 deletions

10
.gitignore vendored
View File

@ -73,6 +73,11 @@ htmlcov/
nosetests.xml
coverage.xml
# Website
website/www/
website/demos/displacy/
website/demos/sense2vec/
# Translations
*.mo
@ -88,11 +93,6 @@ coverage.xml
*.log
*.pot
# Sphinx documentation
docs/_build/
docs/_themes/
setup.py
# Windows local helper files
*.bat

View File

@ -43,7 +43,3 @@ Supports
* OSX
* Linux
* Windows (Cygwin, MinGW, Visual Studio)
Difficult to support:
* PyPy

View File

@ -13,7 +13,7 @@ Requires:
* WordNet
* words.sgt.prob --- Smoothed unigram probabilities
* clusters.txt --- Output of hierarchical clustering, e.g. Brown clusters
* vectors.tgz --- output of something like word2vec
* vectors.bz2 --- output of something like word2vec, compressed with bzip
"""
from __future__ import unicode_literals
@ -98,7 +98,7 @@ def _read_probs(loc):
return probs, probs['-OOV-']
def _read_freqs(loc, max_length=100, min_doc_freq=0, min_freq=200):
def _read_freqs(loc, max_length=100, min_doc_freq=5, min_freq=200):
if not loc.exists():
print("Warning: Frequencies file not found")
return {}, 0.0
@ -109,7 +109,7 @@ def _read_freqs(loc, max_length=100, min_doc_freq=0, min_freq=200):
else:
file_ = loc.open()
for i, line in enumerate(file_):
freq, doc_freq, key = line.split('\t', 2)
freq, doc_freq, key = line.rstrip().split('\t', 2)
freq = int(freq)
counts.inc(i+1, freq)
total += freq
@ -121,15 +121,13 @@ def _read_freqs(loc, max_length=100, min_doc_freq=0, min_freq=200):
file_ = loc.open()
probs = {}
for line in file_:
freq, doc_freq, key = line.split('\t', 2)
freq, doc_freq, key = line.rstrip().split('\t', 2)
doc_freq = int(doc_freq)
freq = int(freq)
if doc_freq >= min_doc_freq and freq >= min_freq and len(key) < max_length:
# word = literal_eval(key)
word = key
word = literal_eval(key)
smooth_count = counts.smoother(int(freq))
log_smooth_count = math.log(smooth_count)
probs[word] = log_smooth_count - log_total
probs[word] = math.log(smooth_count) - log_total
oov_prob = math.log(counts.smoother(0)) - log_total
return probs, oov_prob
@ -157,7 +155,7 @@ def setup_vocab(get_lex_attr, tag_map, src_dir, dst_dir):
if not dst_dir.exists():
dst_dir.mkdir()
vectors_src = src_dir / 'vectors.tgz'
vectors_src = src_dir / 'vectors.bz2'
if vectors_src.exists():
write_binary_vectors(str(vectors_src), str(dst_dir / 'vec.bin'))
else:
@ -166,7 +164,7 @@ def setup_vocab(get_lex_attr, tag_map, src_dir, dst_dir):
clusters = _read_clusters(src_dir / 'clusters.txt')
probs, oov_prob = _read_probs(src_dir / 'words.sgt.prob')
if not probs:
probs, oov_prob = _read_freqs(src_dir / 'freqs.txt')
probs, oov_prob = _read_freqs(src_dir / 'freqs.txt.gz')
if not probs:
oov_prob = -20
else:

View File

@ -141,7 +141,7 @@ def train(Language, gold_tuples, model_dir, n_iter=15, feat_set=u'basic',
nlp.tagger(tokens)
gold = GoldParse(tokens, annot_tuples)
if not gold.is_projective:
raise Exception("Non-projective sentence in training: %s" % annot_tuples)
raise Exception("Non-projective sentence in training: %s" % annot_tuples[1])
loss += nlp.parser.train(tokens, gold)
nlp.entity.train(tokens, gold)
nlp.tagger.train(tokens, gold.tags)

View File

@ -1,7 +1,6 @@
import inventoryCount as mainModule
import os
from spacy.en import English, LOCAL_DATA_DIR
data_dir = os.environ.get('SPACY_DATA', LOCAL_DATA_DIR)
from spacy.en import English
if __name__ == '__main__':
"""

View File

@ -11,49 +11,48 @@ token_properties = {
"are": {"L": "be", "pos": "VBP", "number": 2},
"ca": {"L": "can", "pos": "MD"},
"can": {"L": "can", "pos": "MD"},
"could": {"pos": "MD"}, # no lemma for could?
"could": {"pos": "MD", "L": "could"},
"'d": {"L": "would", "pos": "MD"},
"did": {"L": "do", "pos": "VBD"},
"do": {"L": "do"}, # no POS for do?
"do": {"L": "do"},
"does": {"L": "do", "pos": "VBZ"},
"had": {"L": "have", "pos": "VBD"},
"has": {}, # no POS or lemma for has?
"have": {"pos": "VB"}, # no lemma for have?
"he": {"L": "-PRON-"}, # no POS for he?
"how": {}, # no POS or lemma for how?
"i": {"L": "-PRON-"}, # no POS for i?
"has": {"L": "have", "pos": "VBZ"},
"have": {"pos": "VB"},
"he": {"L": "-PRON-", "pos": "PRP"},
"how": {},
"i": {"L": "-PRON-", "pos": "PRP"},
"is": {"L": "be", "pos": "VBZ"},
"it": {"L": "-PRON-"}, # no POS for it?
"it": {"L": "-PRON-", "pos": "PRP"},
"'ll": {"L": "will", "pos": "MD"},
"'m": {"L": "be", "pos": "VBP", "number": 1, "tenspect": 1},
"'ma": {}, # no POS or lemma for ma?
"might": {}, # no POS or lemma for might?
"must": {}, # no POS or lemma for must?
"need": {}, # no POS or lemma for need?
"'ma": {},
"might": {},
"must": {},
"need": {},
"not": {"L": "not", "pos": "RB"},
"'nt": {"L": "not", "pos": "RB"},
"n't": {"L": "not", "pos": "RB"},
"'re": {}, # no POS or lemma for re?
"'re": {"L": "be", "pos": "VBZ"},
"'s": {}, # no POS or lemma for s?
"sha": {}, # no POS or lemma for sha?
"she": {"L": "-PRON-"}, # no POS for she?
"should": {}, # no POS or lemma for should?
"that": {}, # no POS or lemma for that?
"there": {}, # no POS or lemma for there?
"they": {"L": "-PRON-"}, # no POS for they?
"was": {}, # no POS or lemma for was?
"we": {}, # no POS or lemma for we?
"were": {}, # no POS or lemma for were?
"what": {}, # no POS or lemma for what?
"when": {}, # no POS or lemma for when?
"where": {}, # no POS or lemma for where?
"who": {}, # no POS or lemma for who?
"why": {}, # no POS or lemma for why?
"wo": {}, # no POS or lemma for wo?
"would": {}, # no POS or lemma for would?
"you": {"L": "-PRON-"}, # no POS or lemma for you?
"sha": {"L": "shall", "pos": "MD"},
"she": {"L": "-PRON-", "pos": "PRP"},
"should": {},
"that": {},
"there": {},
"they": {"L": "-PRON-", "pos": "PRP"},
"was": {},
"we": {"L": "-PRON-", "pos": "PRP"},
"were": {},
"what": {},
"when": {},
"where": {},
"who": {},
"why": {},
"wo": {},
"would": {},
"you": {"L": "-PRON-", "pos": "PRP"},
"'ve": {"L": "have", "pos": "VB"}
}
# contains starting tokens with their potential contractions

View File

@ -1,4 +1,5 @@
\.\.\.
(?<=[a-z])\.(?=[A-Z])
(?<=[a-zA-Z])-(?=[a-zA-z])
(?<=[a-zA-Z])--(?=[a-zA-z])
(?<=[0-9])-(?=[0-9])

View File

@ -1,6 +1,6 @@
{
"name": "en",
"version": "1.0.0",
"version": "1.1.0",
"description": "english test model",
"license": "public domain",
"include": [

View File

@ -1,4 +1,4 @@
cython
cython < 0.24
pathlib
numpy
cymem>=1.30,<1.32

View File

@ -17,6 +17,7 @@ PACKAGES = [
'spacy',
'spacy.tokens',
'spacy.en',
'spacy.de',
'spacy.serialize',
'spacy.syntax',
'spacy.munge',
@ -63,14 +64,15 @@ MOD_NAMES = [
'spacy.cfile',
'spacy.matcher',
'spacy.syntax.ner',
'spacy.symbols']
'spacy.symbols',
'spacy.syntax.iterators']
# By subclassing build_extensions we have the actual compiler that will be used
# which is really known only after finalize_options
# http://stackoverflow.com/questions/724664/python-distutils-how-to-get-a-compiler-that-is-going-to-be-used
compile_options = {
'msvc': ['/Ox', '/EHsc'],
'msvc': ['/Ox', '/EHsc', '/openmp'],
'mingw32' : ['-O3', '-Wno-strict-prototypes', '-Wno-unused-function'],
'other' : ['-O3', '-Wno-strict-prototypes', '-Wno-unused-function']
}
@ -213,3 +215,4 @@ def setup_package():
if __name__ == '__main__':
setup_package()

View File

@ -1,8 +1,15 @@
from . import util
from .util import set_lang_class, get_lang_class, get_package, get_package_by_name
from .en import English
from .de import German
set_lang_class(English.lang, English)
set_lang_class(German.lang, German)
def load(name, vectors=None, via=None):
return English(
package=util.get_package_by_name(name, via=via),
vectors_package=util.get_package_by_name(vectors, via=via))
package = get_package_by_name(name, via=via)
vectors_package = get_package_by_name(vectors, via=via)
cls = get_lang_class(name)
return cls(package=package, vectors_package=vectors_package)

View File

@ -4,10 +4,14 @@
# https://github.com/pypa/warehouse/blob/master/warehouse/__about__.py
__title__ = 'spacy'
__version__ = '0.100.6'
__version__ = '0.100.7'
__summary__ = 'Industrial-strength NLP'
__uri__ = 'https://spacy.io'
__author__ = 'Matthew Honnibal'
__email__ = 'matt@spacy.io'
__license__ = 'MIT'
__default_model__ = 'en>=1.0.0,<1.1.0'
__models__ = {
'en': 'en>=1.1.0,<1.2.0',
'de': 'de>=1.0.0,<1.1.0',
}
__default_lang__ = 'en'

View File

@ -14,12 +14,12 @@ cpdef enum attr_id_t:
LIKE_EMAIL
IS_STOP
IS_OOV
FLAG14 = 14
FLAG15
FLAG16
FLAG17
FLAG18
IS_BRACKET
IS_QUOTE
IS_LEFT_PUNCT
IS_RIGHT_PUNCT
FLAG18 = 18
FLAG19
FLAG20
FLAG21
@ -85,11 +85,7 @@ cpdef enum attr_id_t:
HEAD
SPACY
PROB
LANG
# Move these up to FLAG14--FLAG18 once we finish the functionality and
# are ready to regenerate the model
#IS_BRACKET
#IS_QUOTE
#IS_LEFT_PUNCT
#IS_RIGHT_PUNCT

View File

@ -13,10 +13,10 @@ IDS = {
"LIKE_EMAIL": LIKE_EMAIL,
"IS_STOP": IS_STOP,
"IS_OOV": IS_OOV,
"FLAG14": FLAG14,
"FLAG15": FLAG15,
"FLAG16": FLAG16,
"FLAG17": FLAG17,
"IS_BRACKET": IS_BRACKET,
"IS_QUOTE": IS_QUOTE,
"IS_LEFT_PUNCT": IS_LEFT_PUNCT,
"IS_RIGHT_PUNCT": IS_RIGHT_PUNCT,
"FLAG18": FLAG18,
"FLAG19": FLAG19,
"FLAG20": FLAG20,
@ -83,6 +83,7 @@ IDS = {
"HEAD": HEAD,
"SPACY": SPACY,
"PROB": PROB,
"LANG": LANG,
}
# ATTR IDs, in order of the symbol

13
spacy/de/download.py Normal file
View File

@ -0,0 +1,13 @@
import plac
from ..download import download
@plac.annotations(
force=("Force overwrite", "flag", "f", bool),
)
def main(data_size='all', force=False):
download('de', force)
if __name__ == '__main__':
plac.call(main)

33
spacy/download.py Normal file
View File

@ -0,0 +1,33 @@
from __future__ import print_function
import sys
import sputnik
from sputnik.package_list import (PackageNotFoundException,
CompatiblePackageNotFoundException)
from . import about
def download(lang, force=False):
if force:
sputnik.purge(about.__title__, about.__version__)
try:
sputnik.package(about.__title__, about.__version__, about.__models__[lang])
print("Model already installed. Please run 'python -m "
"spacy.%s.download --force' to reinstall." % lang, file=sys.stderr)
sys.exit(1)
except (PackageNotFoundException, CompatiblePackageNotFoundException):
pass
package = sputnik.install(about.__title__, about.__version__, about.__models__[lang])
try:
sputnik.package(about.__title__, about.__version__, about.__models__[lang])
except (PackageNotFoundException, CompatiblePackageNotFoundException):
print("Model failed to install. Please run 'python -m "
"spacy.%s.download --force'." % lang, file=sys.stderr)
sys.exit(1)
print("Model successfully installed.", file=sys.stderr)

View File

@ -33,10 +33,6 @@ your yours yourself yourselves
STOPWORDS = set(w for w in STOPWORDS.split() if w)
# This is deprecated as of v100
LOCAL_DATA_DIR = path.join(path.dirname(__file__), 'data')
class English(Language):
lang = 'en'

View File

@ -1,57 +1,12 @@
from __future__ import print_function
import sys
import os
import shutil
import plac
import sputnik
from sputnik.package_list import (PackageNotFoundException,
CompatiblePackageNotFoundException)
from .. import about
def migrate(path):
data_path = os.path.join(path, 'data')
if os.path.isdir(data_path):
if os.path.islink(data_path):
os.unlink(data_path)
else:
shutil.rmtree(data_path)
for filename in os.listdir(path):
if filename.endswith('.tgz'):
os.unlink(os.path.join(path, filename))
from ..download import download
@plac.annotations(
force=("Force overwrite", "flag", "f", bool),
)
def main(data_size='all', force=False):
if force:
sputnik.purge(about.__title__, about.__version__)
try:
sputnik.package(about.__title__, about.__version__, about.__default_model__)
print("Model already installed. Please run 'python -m "
"spacy.en.download --force' to reinstall.", file=sys.stderr)
sys.exit(1)
except (PackageNotFoundException, CompatiblePackageNotFoundException):
pass
package = sputnik.install(about.__title__, about.__version__, about.__default_model__)
try:
sputnik.package(about.__title__, about.__version__, about.__default_model__)
except (PackageNotFoundException, CompatiblePackageNotFoundException):
print("Model failed to install. Please run 'python -m "
"spacy.en.download --force'.", file=sys.stderr)
sys.exit(1)
# FIXME clean up old-style packages
migrate(os.path.dirname(os.path.abspath(__file__)))
print("Model successfully installed.", file=sys.stderr)
download('en', force)
if __name__ == '__main__':

View File

@ -33,10 +33,6 @@ class Language(object):
@staticmethod
def norm(string):
return string
@staticmethod
def shape(string):
return orth.word_shape(string)
@staticmethod
def prefix(string):
@ -50,66 +46,14 @@ class Language(object):
def cluster(string):
return 0
@staticmethod
def is_alpha(string):
return orth.is_alpha(string)
@staticmethod
def is_ascii(string):
return orth.is_ascii(string)
@staticmethod
def is_digit(string):
return string.isdigit()
@staticmethod
def is_lower(string):
return orth.is_lower(string)
@staticmethod
def is_punct(string):
return orth.is_punct(string)
@staticmethod
def is_space(string):
return string.isspace()
@staticmethod
def is_title(string):
return orth.is_title(string)
@staticmethod
def is_bracket(string):
return orth.is_bracket(string)
@staticmethod
def is_quote(string):
return orth.is_quote(string)
@staticmethod
def is_left_punct(string):
return orth.is_left_punct(string)
@staticmethod
def is_right_punct(string):
return orth.is_right_punct(string)
@staticmethod
def is_upper(string):
return orth.is_upper(string)
@staticmethod
def like_url(string):
return orth.like_url(string)
@staticmethod
def like_num(string):
return orth.like_number(string)
@staticmethod
def like_email(string):
return orth.like_email(string)
@staticmethod
def is_stop(string):
return 0
@ -120,26 +64,27 @@ class Language(object):
return {
attrs.LOWER: cls.lower,
attrs.NORM: cls.norm,
attrs.SHAPE: cls.shape,
attrs.SHAPE: orth.word_shape,
attrs.PREFIX: cls.prefix,
attrs.SUFFIX: cls.suffix,
attrs.CLUSTER: cls.cluster,
attrs.PROB: lambda string: oov_prob,
attrs.IS_ALPHA: cls.is_alpha,
attrs.IS_ASCII: cls.is_ascii,
attrs.LANG: lambda string: cls.lang,
attrs.IS_ALPHA: orth.is_alpha,
attrs.IS_ASCII: orth.is_ascii,
attrs.IS_DIGIT: cls.is_digit,
attrs.IS_LOWER: cls.is_lower,
attrs.IS_PUNCT: cls.is_punct,
attrs.IS_LOWER: orth.is_lower,
attrs.IS_PUNCT: orth.is_punct,
attrs.IS_SPACE: cls.is_space,
attrs.IS_TITLE: cls.is_title,
attrs.IS_UPPER: cls.is_upper,
attrs.FLAG14: cls.is_bracket,
attrs.FLAG15: cls.is_quote,
attrs.FLAG16: cls.is_left_punct,
attrs.FLAG17: cls.is_right_punct,
attrs.LIKE_URL: cls.like_url,
attrs.LIKE_NUM: cls.like_num,
attrs.LIKE_EMAIL: cls.like_email,
attrs.IS_TITLE: orth.is_title,
attrs.IS_UPPER: orth.is_upper,
attrs.IS_BRACKET: orth.is_bracket,
attrs.IS_QUOTE: orth.is_quote,
attrs.IS_LEFT_PUNCT: orth.is_left_punct,
attrs.IS_RIGHT_PUNCT: orth.is_right_punct,
attrs.LIKE_URL: orth.like_url,
attrs.LIKE_NUM: orth.like_number,
attrs.LIKE_EMAIL: orth.like_email,
attrs.IS_STOP: cls.is_stop,
attrs.IS_OOV: lambda string: True
}

View File

@ -1,6 +1,6 @@
from .typedefs cimport attr_t, hash_t, flags_t, len_t, tag_t
from .attrs cimport attr_id_t
from .attrs cimport ID, ORTH, LOWER, NORM, SHAPE, PREFIX, SUFFIX, LENGTH, CLUSTER
from .attrs cimport ID, ORTH, LOWER, NORM, SHAPE, PREFIX, SUFFIX, LENGTH, CLUSTER, LANG
from .structs cimport LexemeC
from .strings cimport StringStore
@ -41,6 +41,8 @@ cdef class Lexeme:
lex.suffix = value
elif name == CLUSTER:
lex.cluster = value
elif name == LANG:
lex.lang = value
@staticmethod
cdef inline attr_t get_struct_attr(const LexemeC* lex, attr_id_t feat_name) nogil:
@ -67,6 +69,8 @@ cdef class Lexeme:
return lex.length
elif feat_name == CLUSTER:
return lex.cluster
elif feat_name == LANG:
return lex.lang
else:
return 0

View File

@ -18,10 +18,10 @@ import numpy
from .attrs cimport IS_ALPHA, IS_ASCII, IS_DIGIT, IS_LOWER, IS_PUNCT, IS_SPACE
from .attrs cimport IS_TITLE, IS_UPPER, LIKE_URL, LIKE_NUM, LIKE_EMAIL, IS_STOP
from .attrs cimport FLAG14 as IS_BRACKET
from .attrs cimport FLAG15 as IS_QUOTE
from .attrs cimport FLAG16 as IS_LEFT_PUNCT
from .attrs cimport FLAG17 as IS_RIGHT_PUNCT
from .attrs cimport IS_BRACKET
from .attrs cimport IS_QUOTE
from .attrs cimport IS_LEFT_PUNCT
from .attrs cimport IS_RIGHT_PUNCT
from .attrs cimport IS_OOV
@ -74,8 +74,8 @@ cdef class Lexeme:
raise ValueError(
"Word vectors set to length 0. This may be because the "
"data is not installed. If you haven't already, run"
"\npython -m spacy.en.download all\n"
"to install the data."
"\npython -m spacy.%s.download all\n"
"to install the data." % self.vocab.lang
)
vector_view = <float[:length,]>self.c.vector
@ -123,6 +123,10 @@ cdef class Lexeme:
def __get__(self): return self.c.cluster
def __set__(self, int x): self.c.cluster = x
property lang:
def __get__(self): return self.c.lang
def __set__(self, int x): self.c.lang = x
property prob:
def __get__(self): return self.c.prob
def __set__(self, float x): self.c.prob = x
@ -147,6 +151,10 @@ cdef class Lexeme:
def __get__(self): return self.vocab.strings[self.c.suffix]
def __set__(self, unicode x): self.c.suffix = self.vocab.strings[x]
property lang_:
def __get__(self): return self.vocab.strings[self.c.lang]
def __set__(self, unicode x): self.c.lang = self.vocab.strings[x]
property flags:
def __get__(self): return self.c.flags
def __set__(self, flags_t x): self.c.flags = x

View File

@ -5,9 +5,6 @@ import unicodedata
import re
TAGS = 'adj adp adv conj det noun num pdt pos pron prt punct verb'.upper().split()
# Binary string features
cpdef bint is_alpha(unicode string):
return string.isalpha()
@ -36,20 +33,25 @@ cpdef bint is_ascii(unicode string):
else:
return True
cpdef bint is_bracket(unicode string):
return False
brackets = ('(',')','[',']','{','}','<','>')
return string in brackets
cpdef bint is_quote(unicode string):
if string in ('"', "'"):
return True
else:
return False
quotes = ('"',"'",'`','«','»','','','','','','','','','','','','',"''",'``')
return string in quotes
cpdef bint is_left_punct(unicode string):
return False
left_punct = ('(','[','{','<','"',"'",'«','','','','','','','','','``')
return string in left_punct
cpdef bint is_right_punct(unicode string):
return False
right_punct = (')',']','}','>','"',"'",'»','','','','',"''")
return string in right_punct
cpdef bint is_title(unicode string):

View File

@ -24,3 +24,4 @@ cdef class StringStore:
cdef int64_t _resize_at
cdef const Utf8Str* intern(self, unicode py_string) except NULL
cdef const Utf8Str* _intern_utf8(self, char* utf8_string, int length) except NULL

View File

@ -1,30 +1,25 @@
from __future__ import unicode_literals
import codecs
from __future__ import unicode_literals, absolute_import
cimport cython
from libc.string cimport memcpy
from libc.stdint cimport uint64_t
from murmurhash.mrmr cimport hash64
from preshed.maps cimport map_iter, key_t
from cpython cimport PyUnicode_AS_DATA
from cpython cimport PyUnicode_GET_DATA_SIZE
from libc.stdint cimport int64_t
from .typedefs cimport hash_t, attr_t
try:
import codecs as io
except ImportError:
import io
from .typedefs cimport hash_t
import ujson as json
cpdef hash_t hash_string(unicode string) except 0:
chars = string.encode('utf8')
return hash64(<char*>chars, len(chars), 1)
return _hash_utf8(chars, len(chars))
cdef hash_t _hash_utf8(char* utf8_string, int length):
return hash64(utf8_string, length, 1)
cdef unicode _decode(const Utf8Str* string):
@ -92,45 +87,45 @@ cdef class StringStore:
def __getitem__(self, object string_or_id):
cdef bytes byte_string
cdef unicode py_string
cdef const Utf8Str* utf8str
cdef unsigned int int_id
cdef int id_
if isinstance(string_or_id, int) or isinstance(string_or_id, long):
if string_or_id == 0:
return u''
elif string_or_id < 1 or string_or_id >= self.size:
if isinstance(string_or_id, (int, long)):
try:
int_id = string_or_id
except OverflowError:
raise IndexError(string_or_id)
utf8str = &self.c[<int>string_or_id]
if int_id == 0:
return u''
elif int_id >= <uint64_t>self.size:
raise IndexError(string_or_id)
utf8str = &self.c[int_id]
return _decode(utf8str)
elif isinstance(string_or_id, bytes):
if len(string_or_id) == 0:
byte_string = <bytes>string_or_id
if len(byte_string) == 0:
return 0
py_string = string_or_id.decode('utf8')
utf8str = self.intern(py_string)
utf8str = self._intern_utf8(byte_string, len(byte_string))
return utf8str - self.c
elif isinstance(string_or_id, unicode):
if len(string_or_id) == 0:
if len(<unicode>string_or_id) == 0:
return 0
py_string = string_or_id
utf8str = self.intern(py_string)
byte_string = (<unicode>string_or_id).encode('utf8')
utf8str = self._intern_utf8(byte_string, len(byte_string))
return utf8str - self.c
else:
raise TypeError(type(string_or_id))
def __contains__(self, unicode string):
def __contains__(self, unicode string not None):
if len(string) == 0:
return True
cdef hash_t key = hash_string(string)
value = <Utf8Str*>self._map.get(key)
return True if value is not NULL else False
return self._map.get(key) is not NULL
def __iter__(self):
cdef int i
for i in range(self.size):
if i == 0:
yield u''
else:
utf8str = &self.c[i]
yield _decode(utf8str)
yield _decode(&self.c[i]) if i > 0 else u''
def __reduce__(self):
strings = [""]
@ -142,21 +137,26 @@ cdef class StringStore:
cdef const Utf8Str* intern(self, unicode py_string) except NULL:
# 0 means missing, but we don't bother offsetting the index.
cdef hash_t key = hash_string(py_string)
cdef bytes byte_string = py_string.encode('utf8')
return self._intern_utf8(byte_string, len(byte_string))
@cython.final
cdef const Utf8Str* _intern_utf8(self, char* utf8_string, int length) except NULL:
# 0 means missing, but we don't bother offsetting the index.
cdef hash_t key = _hash_utf8(utf8_string, length)
value = <Utf8Str*>self._map.get(key)
if value != NULL:
if value is not NULL:
return value
if self.size == self._resize_at:
self._realloc()
cdef bytes byte_string = py_string.encode('utf8')
self.c[self.size] = _allocate(self.mem, <unsigned char*>byte_string, len(byte_string))
self.c[self.size] = _allocate(self.mem, <unsigned char*>utf8_string, length)
self._map.set(key, <void*>&self.c[self.size])
self.size += 1
return &self.c[self.size-1]
def dump(self, file_):
string_data = json.dumps([s for s in self])
string_data = json.dumps(list(self))
if not isinstance(string_data, unicode):
string_data = string_data.decode('utf8')
file_.write(string_data)
@ -166,8 +166,10 @@ cdef class StringStore:
if strings == ['']:
return None
cdef unicode string
for string in strings:
if string:
for string in strings:
# explicit None/len check instead of simple truth testing
# (bug in Cython <= 0.23.4)
if string is not None and len(string):
self.intern(string)
def _realloc(self):

View File

@ -9,6 +9,8 @@ cdef struct LexemeC:
flags_t flags
attr_t lang
attr_t id
attr_t length

View File

@ -0,0 +1,19 @@
from spacy.tokens.doc cimport Doc
cdef dict CHUNKERS
cdef class DocIterator:
cdef Doc _doc
cdef class EnglishNounChunks(DocIterator):
cdef int i
cdef int _np_label
cdef set _np_deps
cdef int _conjunct
cdef class GermanNounChunks(DocIterator):
cdef int i
cdef int _np_label
cdef set _np_deps
cdef int _close_app

View File

@ -0,0 +1,84 @@
from spacy.structs cimport TokenC
from spacy.tokens.span cimport Span
from spacy.tokens.doc cimport Doc
from spacy.tokens.token cimport Token
from spacy.parts_of_speech cimport NOUN
CHUNKERS = {'en':EnglishNounChunks, 'de':GermanNounChunks}
# base class for document iterators
cdef class DocIterator:
def __init__(self, Doc doc):
self._doc = doc
def __iter__(self):
return self
def __next__(self):
raise NotImplementedError
cdef class EnglishNounChunks(DocIterator):
def __init__(self, Doc doc):
super(EnglishNounChunks,self).__init__(doc)
labels = ['nsubj', 'dobj', 'nsubjpass', 'pcomp', 'pobj', 'attr', 'root']
self._np_label = self._doc.vocab.strings['NP']
self._np_deps = set( self._doc.vocab.strings[label] for label in labels )
self._conjunct = self._doc.vocab.strings['conj']
self.i = 0
def __next__(self):
cdef const TokenC* word
cdef widx
while self.i < self._doc.length:
widx = self.i
self.i += 1
word = &self._doc.c[widx]
if word.pos == NOUN:
if word.dep in self._np_deps:
return Span(self._doc, word.l_edge, widx+1, label=self._np_label)
elif word.dep == self._conjunct:
head = word+word.head
while head.dep == self._conjunct and head.head < 0:
head += head.head
# If the head is an NP, and we're coordinated to it, we're an NP
if head.dep in self._np_deps:
return Span(self._doc, word.l_edge, widx+1, label=self._np_label)
raise StopIteration
# this iterator extracts spans headed by NOUNs starting from the left-most
# syntactic dependent until the NOUN itself
# for close apposition and measurement construction, the span is sometimes
# extended to the right of the NOUN
# example: "eine Tasse Tee" (a cup (of) tea) returns "eine Tasse Tee" and not
# just "eine Tasse", same for "das Thema Familie"
cdef class GermanNounChunks(DocIterator):
def __init__(self, Doc doc):
super(GermanNounChunks,self).__init__(doc)
labels = ['sb', 'oa', 'da', 'nk', 'mo', 'ag', 'root', 'cj', 'pd', 'og', 'app']
self._np_label = self._doc.vocab.strings['NP']
self._np_deps = set( self._doc.vocab.strings[label] for label in labels )
self._close_app = self._doc.vocab.strings['nk']
self.i = 0
def __next__(self):
cdef const TokenC* word
cdef int rbracket
cdef Token rdep
cdef widx
while self.i < self._doc.length:
widx = self.i
self.i += 1
word = &self._doc.c[widx]
if word.pos == NOUN and word.dep in self._np_deps:
rbracket = widx+1
# try to extend the span to the right
# to capture close apposition/measurement constructions
for rdep in self._doc[widx].rights:
if rdep.pos == NOUN and rdep.dep == self._close_app:
rbracket = rdep.i+1
return Span(self._doc, word.l_edge, rbracket, label=self._np_label)
raise StopIteration

View File

@ -47,6 +47,7 @@ from ._parse_features cimport fill_context
from .stateclass cimport StateClass
from ._state cimport StateC
from spacy.syntax.iterators cimport CHUNKERS, DocIterator, EnglishNounChunks, GermanNounChunks
DEBUG = False
@ -113,12 +114,9 @@ cdef class Parser:
cdef int nr_feat = self.model.nr_feat
with nogil:
self.parseC(tokens.c, tokens.length, nr_feat, nr_class)
tokens.is_parsed = True
# Check for KeyboardInterrupt etc. Untested
PyErr_CheckSignals()
# projectivize output
if self._projectivize:
PseudoProjectivity.deprojectivize(tokens)
self._finalize(tokens)
def pipe(self, stream, int batch_size=1000, int n_threads=2):
cdef Pool mem = Pool()
@ -144,7 +142,7 @@ cdef class Parser:
raise ValueError("Error parsing doc: %s" % sent_str)
PyErr_CheckSignals()
for doc in queue:
doc.is_parsed = True
self._finalize(doc)
yield doc
queue = []
batch_size = len(queue)
@ -155,10 +153,19 @@ cdef class Parser:
with gil:
sent_str = queue[i].text
raise ValueError("Error parsing doc: %s" % sent_str)
for doc in queue:
doc.is_parsed = True
yield doc
PyErr_CheckSignals()
for doc in queue:
self._finalize(doc)
yield doc
def _finalize(self, Doc doc):
# deprojectivize output
if self._projectivize:
PseudoProjectivity.deprojectivize(doc)
# set annotation-specific iterators
doc.noun_chunks = CHUNKERS.get(doc.vocab.lang,DocIterator)
# mark doc as parsed
doc.is_parsed = True
cdef int parseC(self, TokenC* tokens, int length, int nr_feat, int nr_class) nogil:
cdef ExampleC eg

View File

@ -32,3 +32,18 @@ def test_email(en_tokenizer):
assert len(tokens) == 1
def test_double_hyphen(en_tokenizer):
tokens = en_tokenizer(u'No decent--let alone well-bred--people.')
assert tokens[0].text == u'No'
assert tokens[1].text == u'decent'
assert tokens[2].text == u'--'
assert tokens[3].text == u'let'
assert tokens[4].text == u'alone'
assert tokens[5].text == u'well'
assert tokens[6].text == u'-'
# TODO: This points to a deeper issue with the tokenizer: it doesn't re-enter
# on infixes.
#assert tokens[7].text == u'bred'
#assert tokens[8].text == u'--'
#assert tokens[9].text == u'people'

View File

@ -3,11 +3,11 @@ import numpy as np
from spacy.attrs import HEAD, DEP
from spacy.symbols import nsubj, dobj, punct, amod, nmod, conj, cc, root
from spacy.en import English
from spacy.syntax.iterators import EnglishNounChunks
def test_not_nested():
nlp = English(parser=False)
nlp = English(parser=False, entity=False)
sent = u'''Peter has chronic command and control issues'''.strip()
tokens = nlp(sent)
tokens.from_array(
@ -22,6 +22,7 @@ def test_not_nested():
[-2, conj],
[-5, dobj]
], dtype='int32'))
tokens.noun_chunks = EnglishNounChunks
for chunk in tokens.noun_chunks:
print(chunk.text)
word_occurred = {}
@ -31,3 +32,4 @@ def test_not_nested():
word_occurred[word.text] += 1
for word, freq in word_occurred.items():
assert freq == 1, (word, [chunk.text for chunk in tokens.noun_chunks])

View File

@ -16,8 +16,7 @@ cimport cython
from . import util
from .tokens.doc cimport Doc
from .util import read_lang_data
from .util import get_package
from .util import read_lang_data, get_package
cdef class Tokenizer:

View File

@ -7,6 +7,8 @@ from ..structs cimport TokenC, LexemeC
from ..typedefs cimport attr_t
from ..attrs cimport attr_id_t
from spacy.syntax.iterators cimport DocIterator
cdef attr_t get_token_attr(const TokenC* token, attr_id_t feat_name) nogil
@ -42,6 +44,8 @@ cdef class Doc:
cdef int length
cdef int max_length
cdef DocIterator noun_chunks_iterator
cdef int push_back(self, LexemeOrToken lex_or_tok, bint trailing_space) except -1
cpdef np.ndarray to_array(self, object features)

View File

@ -8,6 +8,7 @@ import struct
cimport numpy as np
import math
import six
import warnings
from ..lexeme cimport Lexeme
from ..lexeme cimport EMPTY_LEXEME
@ -80,6 +81,7 @@ cdef class Doc:
self.is_parsed = False
self._py_tokens = []
self._vector = None
self.noun_chunks_iterator = DocIterator(self)
def __getitem__(self, object i):
"""Get a Token or a Span from the Doc.
@ -166,7 +168,7 @@ cdef class Doc:
@property
def text(self):
return u' '.join(t.text for t in self)
return u''.join(t.text for t in self)
property ents:
def __get__(self):
@ -230,33 +232,22 @@ cdef class Doc:
# Set start as B
self.c[start].ent_iob = 3
@property
def noun_chunks(self):
"""Yield spans for base noun phrases."""
if not self.is_parsed:
raise ValueError(
"noun_chunks requires the dependency parse, which "
"requires data to be installed. If you haven't done so, run: "
"\npython -m spacy.en.download all\n"
"to install the data")
cdef const TokenC* word
labels = ['nsubj', 'dobj', 'nsubjpass', 'pcomp', 'pobj',
'attr', 'root']
np_deps = [self.vocab.strings[label] for label in labels]
conj = self.vocab.strings['conj']
np_label = self.vocab.strings['NP']
for i in range(self.length):
word = &self.c[i]
if word.pos == NOUN and word.dep in np_deps:
yield Span(self, word.l_edge, i+1, label=np_label)
elif word.pos == NOUN and word.dep == conj:
head = word+word.head
while head.dep == conj and head.head < 0:
head += head.head
# If the head is an NP, and we're coordinated to it, we're an NP
if head.dep in np_deps:
yield Span(self, word.l_edge, i+1, label=np_label)
property noun_chunks:
def __get__(self):
"""Yield spans for base noun phrases."""
if not self.is_parsed:
raise ValueError(
"noun_chunks requires the dependency parse, which "
"requires data to be installed. If you haven't done so, run: "
"\npython -m spacy.%s.download all\n"
"to install the data" % self.vocab.lang)
yield from self.noun_chunks_iterator
def __set__(self, DocIterator):
self.noun_chunks_iterator = DocIterator(self)
@property
def sents(self):
@ -267,8 +258,8 @@ cdef class Doc:
raise ValueError(
"sentence boundary detection requires the dependency parse, which "
"requires data to be installed. If you haven't done so, run: "
"\npython -m spacy.en.download all\n"
"to install the data")
"\npython -m spacy.%s.download all\n"
"to install the data" % self.vocab.lang)
cdef int i
start = 0
for i in range(1, self.length):

View File

@ -18,10 +18,10 @@ from ..attrs cimport POS, LEMMA, TAG, DEP
from ..parts_of_speech cimport CONJ, PUNCT
from ..attrs cimport IS_ALPHA, IS_ASCII, IS_DIGIT, IS_LOWER, IS_PUNCT, IS_SPACE
from ..attrs cimport FLAG14 as IS_BRACKET
from ..attrs cimport FLAG15 as IS_QUOTE
from ..attrs cimport FLAG16 as IS_LEFT_PUNCT
from ..attrs cimport FLAG17 as IS_RIGHT_PUNCT
from ..attrs cimport IS_BRACKET
from ..attrs cimport IS_QUOTE
from ..attrs cimport IS_LEFT_PUNCT
from ..attrs cimport IS_RIGHT_PUNCT
from ..attrs cimport IS_TITLE, IS_UPPER, LIKE_URL, LIKE_NUM, LIKE_EMAIL, IS_STOP
from ..attrs cimport IS_OOV
@ -95,6 +95,10 @@ cdef class Token:
def __get__(self):
return self.c.lex.prob
property lang:
def __get__(self):
return self.c.lex.lang
property idx:
def __get__(self):
return self.c.idx
@ -161,8 +165,8 @@ cdef class Token:
raise ValueError(
"Word vectors set to length 0. This may be because the "
"data is not installed. If you haven't already, run"
"\npython -m spacy.en.download all\n"
"to install the data."
"\npython -m spacy.%s.download all\n"
"to install the data." % self.vocab.lang
)
vector_view = <float[:length,]>self.c.lex.vector
return numpy.asarray(vector_view)
@ -177,23 +181,11 @@ cdef class Token:
property n_lefts:
def __get__(self):
cdef int n = 0
cdef const TokenC* ptr = self.c - self.i
while ptr != self.c:
if ptr + ptr.head == self.c:
n += 1
ptr += 1
return n
return self.c.l_kids
property n_rights:
def __get__(self):
cdef int n = 0
cdef const TokenC* ptr = self.c + (self.array_len - self.i)
while ptr != self.c:
if ptr + ptr.head == self.c:
n += 1
ptr -= 1
return n
return self.c.r_kids
property lefts:
def __get__(self):
@ -415,6 +407,10 @@ cdef class Token:
def __get__(self):
return self.vocab.strings[self.c.lex.suffix]
property lang_:
def __get__(self):
return self.vocab.strings[self.c.lex.lang]
property lemma_:
def __get__(self):
return self.vocab.strings[self.c.lemma]

View File

@ -14,6 +14,21 @@ from . import about
from .attrs import TAG, HEAD, DEP, ENT_IOB, ENT_TYPE
LANGUAGES = {}
def set_lang_class(name, cls):
global LANGUAGES
LANGUAGES[name] = cls
def get_lang_class(name):
lang = re.split('[^a-zA-Z0-9_]', name, 1)[0]
if lang not in LANGUAGES:
raise RuntimeError('Language not supported: %s' % lang)
return LANGUAGES[lang]
def get_package(data_dir):
if not isinstance(data_dir, six.string_types):
raise RuntimeError('data_dir must be a string')
@ -21,17 +36,20 @@ def get_package(data_dir):
def get_package_by_name(name=None, via=None):
package_name = name or about.__models__[about.__default_lang__]
lang = get_lang_class(package_name)
try:
return sputnik.package(about.__title__, about.__version__,
name or about.__default_model__, data_path=via)
package_name, data_path=via)
except PackageNotFoundException as e:
raise RuntimeError("Model %s not installed. Please run 'python -m "
"spacy.en.download' to install latest compatible "
"model." % name)
raise RuntimeError("Model '%s' not installed. Please run 'python -m "
"%s.download' to install latest compatible "
"model." % (name, lang.__module__))
except CompatiblePackageNotFoundException as e:
raise RuntimeError("Installed model is not compatible with spaCy "
"version. Please run 'python -m spacy.en.download "
"--force' to install latest compatible model.")
"version. Please run 'python -m %s.download "
"--force' to install latest compatible model." %
(lang.__module__))
def normalize_slice(length, start, stop, step=None):

View File

@ -25,9 +25,8 @@ from . import attrs
from . import symbols
from cymem.cymem cimport Address
from . import util
from .serialize.packer cimport Packer
from .attrs cimport PROB
from .attrs cimport PROB, LANG
try:
import copy_reg
@ -105,6 +104,13 @@ cdef class Vocab:
self._serializer = Packer(self, self.serializer_freqs)
return self._serializer
property lang:
def __get__(self):
langfunc = None
if self.get_lex_attr:
langfunc = self.get_lex_attr.get(LANG,None)
return langfunc('_') if langfunc else ''
def __len__(self):
"""The current number of lexemes stored."""
return self.length
@ -246,6 +252,7 @@ cdef class Vocab:
fp.write_from(&lexeme.prob, sizeof(lexeme.prob), 1)
fp.write_from(&lexeme.sentiment, sizeof(lexeme.sentiment), 1)
fp.write_from(&lexeme.l2_norm, sizeof(lexeme.l2_norm), 1)
fp.write_from(&lexeme.lang, sizeof(lexeme.lang), 1)
fp.close()
def load_lexemes(self, loc):
@ -278,6 +285,7 @@ cdef class Vocab:
fp.read_into(&lexeme.prob, 1, sizeof(lexeme.prob))
fp.read_into(&lexeme.sentiment, 1, sizeof(lexeme.sentiment))
fp.read_into(&lexeme.l2_norm, 1, sizeof(lexeme.l2_norm))
fp.read_into(&lexeme.lang, 1, sizeof(lexeme.lang))
lexeme.vector = EMPTY_VEC
py_str = self.strings[lexeme.orth]

10
website/404.jade Normal file
View File

@ -0,0 +1,10 @@
include _includes/_mixins
//- 404 Error
//- ============================================================================
+lead.text-center Ooops, this page does not exist. Click #[a(href='javascript:history.go(-1)') here] to go back or check out one of the latest posts below.
+divider('bottom')
!=partial('_includes/_latest-posts', { max: 3 } )

View File

@ -1,29 +1,22 @@
Source for spacy.io
==============================
# Source files for the spacy.io website and docs
This directory contains the source for official spaCy website at http://spacy.io/.
The [spacy.io](https://spacy.io) website is implemented in [Jade (aka Pug)](https://www.jade-lang.org), and is built or served by [Harp](https://harpjs.com).
Fixes, updates and suggestions are welcome.
## Building the site
To build the site and start making changes:
Releases
--------
Changes made to this directory go live on spacy.io. <When / how often?>
sudo npm install --global harp
git clone https://github.com/spacy-io/website
cd website
harp server
This will serve the site on [http://localhost:9000](http://localhost:9000). You can then edit the jade source and refresh the page to see your changes.
The Stack
--------
The site is built with the [Jade](http://jade-lang.com/) template language.
## Reading the source
See [fabfile.py](/fabfile.py) under ```web()``` for more
Jade is an extensible templating language with a readable syntax, that compiles to HTML.
The website source makes extensive use of Jade mixins, so that the design system is abstracted away from the content you're
writing. You can read more about our approach in our blog post, ["Rebuilding a Website with Modular Markup Components"](https://spacy.io/blog/modular-markup).
Developing
--------
To make and test changes
```
npm install jade --global
fab web
cd website/site; python -m SimpleHTTPServer 8000; cd -
```
Then visit [localhost:8000](http://localhost:8000)
If you want to write or edit the pages, the site's [styleguide](http://spacy.io/styleguide) serves as a useful reference of the available mixins.

51
website/_data.json Normal file
View File

@ -0,0 +1,51 @@
{
"index": {
"landing": true
},
"feed": {
"layout": false
},
"robots": {
"layout": false
},
"404": {
"title": "404 Error",
"asides": false
},
"team": {
"title": "Team"
},
"legal": {
"title": "Legal & Imprint",
"sidebar": true,
"asides": true
},
"styleguide": {
"title" : "Styleguide",
"standalone" : true,
"asides": true,
"sidebar": {
"About": [
["Introduction", "#section-introduction", "introduction"]
],
"Design": [
["Colors", "#section-colors", "colors"],
["Logo", "#section-logo", "logo"],
["Typography", "#section-typography", "typography"],
["Grid", "#section-grid", "grid"],
["Elements", "#section-elements", "elements"],
["Components", "#section-components", "components"]
],
"Code": [
["Source", "#section-source", "source"]
]
}
}
}

94
website/_fabfile.py Normal file
View File

@ -0,0 +1,94 @@
from __future__ import print_function
from fabric.api import local
import os
import hashlib
import mimetypes
import shutil
import boto.s3.connection
mimetypes.init()
buckets = {
'staging': 'staging.spacy.io',
'production': 'spacy.io',
}
def compile():
shutil.rmtree('www')
local('NODE_ENV=s3 harp compile')
def publish(env='staging', site_path='www'):
os.environ['S3_USE_SIGV4'] = 'True'
conn = boto.s3.connection.S3Connection(host='s3.eu-central-1.amazonaws.com',
calling_format=boto.s3.connection.OrdinaryCallingFormat())
bucket = conn.get_bucket(buckets[env], validate=False)
keys = {k.name: k for k in bucket.list()}
keys_left = set(keys)
for root, dirnames, filenames in os.walk(site_path):
for dirname in dirnames:
target = os.path.relpath(os.path.join(root, dirname), site_path)
source = os.path.join(target, 'index.html')
if os.path.exists(os.path.join(root, dirname, 'index.html')):
redirect = '//%s/%s' % (bucket.name, target)
key = bucket.lookup(source)
if not key:
key = bucket.new_key(source)
key.set_redirect(redirect)
print('setting redirect for %s' % target)
elif key.get_redirect() != redirect:
key.set_redirect(redirect)
print('setting redirect for %s' % target)
if source in keys_left:
keys_left.remove(source)
for filename in filenames:
source = os.path.join(root, filename)
if filename == 'index.html':
target = os.path.normpath(os.path.relpath(root, site_path))
if target == '.':
target = filename
else:
target = os.path.normpath(os.path.join(os.path.relpath(root, site_path), filename))
if target.endswith('.html'):
target = target[:-len('.html')]
content_type = mimetypes.guess_type(source)[0]
cache_control = 'no-transform,public,max-age=300,s-maxage=300'
checksum = hashlib.md5(open(source).read()).hexdigest()
if (target not in keys
or keys[target].etag.replace('"', '') != checksum):
key = bucket.new_key(target)
if content_type:
key.content_type = content_type
key.set_contents_from_filename(source,
headers={'Cache-Control': cache_control})
print('uploading %s' % target)
elif content_type:
key = bucket.lookup(target)
if (key
and (key.content_type != content_type
or key.cache_control != cache_control)):
key.copy(key.bucket, key.name, preserve_acl=True,
metadata={'Content-Type': content_type,
'Cache-Control': cache_control})
print('update headers %s' % target)
if target in keys_left:
keys_left.remove(target)
for key_name in keys_left:
print('deleting %s' % key_name)
bucket.delete_key(key_name)

85
website/_harp.json Normal file
View File

@ -0,0 +1,85 @@
{
"globals": {
"title": "spaCy.io",
"sitename": "spaCy",
"slogan": "Industrial-strength Natural Language Processing",
"description": "spaCy is a free open-source library featuring state-of-the-art speed and accuracy and a powerful Python API.",
"url": "https://spacy.io",
"email": "contact@spacy.io",
"company": "spaCy GmbH",
"team_members": [ "henning", "matt", "wolfgang", "elmar", "ines" ],
"navigation": { "Docs": "docs", "Demos": "demos", "Team": "team", "Blog": "blog" },
"profiles": { "twitter": "spacy_io", "github": "spacy-io", "reddit": "spacynlp", "medium": "spacy" },
"google_analytics": "UA-58931649-1",
"stylesheets": { "default": "style", "blog": "style_blog" },
"scripts" : [ "main", "prism" ],
"feed": "feed.xml",
"image_sizes" : { "small" : "640", "medium": "1440", "large": "2000" },
"default_syntax" : "python",
"spacy_version": "0.100.6",
"spacy_stars": "1500",
"github_settings": { "user": "spacy-io", "repo": "spacy" },
"apis": {
"displacy": "https://displacy.spacy.io/",
"sense2vec": "https://sense2vec.spacy.io/api/similarity/reddit/"
},
"authors" : {
"matt" : {
"name" : "Matthew Honnibal",
"title": "CTO",
"description" : "is co-founder and CTO of spaCy. He studied linguistics as an undergrad, and never thought he'd be a programmer. By 2009 he had a PhD in computer science, and in 2014 he left academia to write spaCy. He's from Sydney and lives in Berlin.",
"links": {
"twitter": [ "https://twitter.com/honnibal", "Twitter" ],
"website": [ "https://www.semanticscholar.org/search?q=Matthew%20Honnibal", "Semantic Scholar" ]
}
},
"henning": {
"name": "Henning Peters",
"title": "CEO",
"description": "is co-founder and CEO of spaCy. He holds a MSc in computer science and has been co-founder and CTO of Skoobe and Absolventa. His passions are uncommon languages and backcountry skiing.",
"links": {
"twitter": [ "https://twitter.com/henningpeters", "Twitter"],
"linkedin": [ "https://de.linkedin.com/in/hepeters", "LinkedIn"],
"github": [ "https://github.com/henningpeters", "GitHub"]
}
},
"ines": {
"name": "Ines Montani",
"title": "Front-End",
"description": "As Head of Front-End, Ines is in charge of showing people what spaCy can do. She develops, designs and implements our interactive demos and the spacy.io website. Ines has a degree in media, linguistics and communications, and over ten years experience in web development.",
"links": {
"twitter": [ "https://twitter.com/_inesmontani", "Twitter" ],
"codepen": [ "https://codepen.io/inesmontani", "Codepen"],
"github": [ "https://github.com/inesmontani", "GitHub"],
"website": [ "http://ines.io", "Blog" ]
}
},
"wolfgang": {
"name": "Wolfgang Seeker",
"title": "NLP Engineer",
"description": "is a computational linguist from Germany. He is fascinated with the complexity and variety of human language, and spent his PhD looking for ways to make NLP work well with any kind of language in the world. He joined spaCy to build effective and truly multilingual NLP software.",
"links": {
"website": [ "https://www.semanticscholar.org/search?q=Wolfgang%20Seeker", "Semantic Scholar" ]
}
},
"elmar": {
"name": "Elmar Haußmann",
"title": "NLP Engineer",
"description": "is an NLP engineer at spaCy, passionate about deep learning. He has a background in both, academic research, with a PhD in computer science, and industry, as a former consultant and software engineer at IBM. Originally from Stuttgart, the avid snowboarder and mountain biker doesn't only ride powder and trails but also covers distances via plane between the spaCy office in Berlin and his new home in Beijing.",
"links": {
"github": [ "https://github.com/elmar-haussmann", "GitHub"],
"twitter": [ "https://twitter.com/elhaussmann", "Twitter" ]
}
}
}
}
}

View File

@ -0,0 +1,7 @@
if environment != 'development'
script.
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', '#{google_analytics}', 'auto'); ga('send', 'pageview');

View File

@ -0,0 +1,34 @@
include ../_includes/_mixins
//- Article
//- ============================================================================
article.article(id=current.source)
header.article-header
+h2.article-title=title
.article-meta
if author
| by #[a.link(href=(authors[author].url || url) target='_blank')=authors[author].name] on
| #[+date(date)]
.article-body!=yield
footer.article-footer
+grid('padding', 'align-right', 'valign-center')
+tweet(title)
if links
for link, index in links
div: +button('primary', 'small', index.toLowerCase())(href=link target='_blank')
+icon(index.toLowerCase(), 'medium', 'secondary')
| Discussion on #{index}
if author
+divider
!=partial('_profile', { label: 'About the Author', style: 'alt' })
!=partial('_newsletter', { divider: 'both' })
!=partial('_latest-posts', { max: 2, _section: _section } )

View File

@ -0,0 +1,14 @@
include _mixins
//- Footer
//- ============================================================================
footer.footer
span &copy; #{new Date().getFullYear()} #{company}
a(href='/legal') Legal / Imprint
a(href='https://twitter.com/' + profiles.twitter target='_blank' aria-label="Twitter")
+icon('twitter', 'secondary')
a(href='/feed.xml' target='_blank' aria-label="RSS Feed")
+icon('feed', 'secondary')

View File

@ -0,0 +1,101 @@
//- Functions
//- ============================================================================
//- Full page title
- function getPageTitle() {
- if(current.path[0] == 'blog' && current.source != 'index') title += ' | Blog';
- return (current.path[0] == 'index') ? sitename + ' | ' + slogan : title + ' | ' + sitename;
- }
//- Get current URL
current - [string] current path
- function getCurrentUrl() {
- var base = current.path;
- if(current.source == 'index') base.pop();
- return url + '/' + base.join('/');
- }
//- Assign flexbox order, elements are assigned negative values to always move
them to the start of a flexbox in the correct order (i.e. -3, -2, -1)
counter - [integer] index of current item
max - [integer] amount of items in total
start - [integer] index of start position, i.e. 0 -> oder: -1 (optional)
- function assignOrder(counter, max, start) {
- if(counter >= 0 && counter < max) return "order: -" + (max - counter + (start || 0));
- }
//- Create Twitter share URL
current - [string] current path
tweet - [string] text to be shared with link
- function twitterShareUrl(current, tweet) {
- return "https://twitter.com/share?text=" + tweet + "&amp;url=" + getCurrentUrl(current) + ";via=" + profiles.twitter;
- }
//- Add prefix to each item in an array (used for modifier CSS classes)
array - [array] array of strings, taken from mixin arguments
prefix - [string] class prefix (i.e. 'button--')
- function prefixArgs(array, prefix) {
- for(var i = 0; i < array.length; i++) {
- array[i] = prefix + array[i];
- }
- return array.join(' ');
- }
//- Convert date to human readable and timestamp format
input - [string] date in the format YYYY-MM-DD
- function convertDate(input) {
- var dates = [];
- var months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ];
- var date = new Date(input);
- dates.full = months[date.getMonth()] + ' ' + date.getDate() + ', ' + date.getFullYear();
- dates.timestamp = JSON.parse(JSON.stringify(date));
- return dates;
- }
//- Convert date to valid RSS pubDate
input - [string] date in the format YYYY-MM-DD
- function convertPubDate(input) {
- var date = new Date(input);
- var pieces = date.toString().split(' ');
- var offsetTime = pieces[5].match(/[-+]\d{4}/);
- var offset = (offsetTime) ? offsetTime : pieces[5];
- var parts = [ pieces[0] + ',', pieces[2], pieces[1], pieces[3], pieces[4], offset ];
- return parts.join(' ');
- }
//- Compile scrset attribute for hero images
image - [object] article image object from _data.json
path - [string] relative path to image folder
- function getScrset(image, path) {
- var scrset = path + image.file + ' ' + image_sizes.medium + 'w';
- if(image.file_small) scrset += ', ' + path + image.file_small + ' ' + image_sizes.small + 'w';
- if(image.file_large) scrset += ', ' + path + image.file_large + ' ' + image_sizes.large + 'w';
- return scrset;
- }
//- Get meta image
- function getMetaImage() {
- if(current.path[0] == 'blog' && image && image.file) {
- return url + '/blog/img/' + image.file;
- }
- else {
- return url + '/assets/img/social.png';
- }
- }

View File

@ -0,0 +1,31 @@
include _mixins
- var is_blog = (_section == 'blog')
//- Head
//- ============================================================================
head
title=getPageTitle()
meta(charset='utf-8')
meta(name="viewport" content="width=device-width, initial-scale=1.0")
meta(name='referrer' content='always')
meta(property='og:type' content='website')
meta(property='og:site_name' content=sitename)
meta(property='og:url' content=getCurrentUrl())
meta(property='og:title' content=title)
meta(property='og:description' content=description)
meta(property='og:image' content=getMetaImage())
meta(name='twitter:card' content='summary_large_image')
meta(name='twitter:site' content='@' + profiles.twitter)
meta(name='twitter:title' content=title)
meta(name='twitter:description' content=description)
meta(name='twitter:image' content=getMetaImage())
link(rel='icon' type='image/x-icon' href='/assets/img/favicon.ico')
link(href='/assets/css/' + ((is_blog) ? stylesheets.blog : stylesheets.default) + '.css' rel='stylesheet')
link(href='/' + feed rel='alternate' type='application/rss+xml' title='RSS')

View File

@ -0,0 +1,21 @@
include _mixins
//- Header
//- ============================================================================
header.header(class=(image) ? 'hero' : '')
if image
img(srcset=getScrset(image, 'img/') alt=image.alt sizes='100vw')
if image.credit
.hero-credit
if image.url
a(href=image.url target='_blank')=image.credit
else
!=image.credit
else
if !is_article && headline != false
h1.header-title=title

View File

@ -0,0 +1,17 @@
include _mixins
- var post_counter = 0
- var is_docs = (_section == 'docs')
//- Latest Posts
//- ============================================================================
+grid('padding')
each post, slug in ( (_section == 'docs' ) ? public.docs.tutorials._data : public.blog._data)
if slug != 'index' && slug != current.source && post_counter < (max || 3)
+grid-col('space-between', ((max > 2 && max % 3 == 0) ? 'third' : 'half'))
!=partial('_teaser', { teaser: post, slug: slug, _root: (is_docs) ? '/docs/tutorials/' : '/blog/' })
- post_counter++

View File

@ -0,0 +1,5 @@
//- Logo
//- ============================================================================
svg.logo(class=(logo_size) ? 'logo--' + logo_size : '' viewBox='0 0 675 215' width='500')
path(d='M83.6 83.3C68.3 81.5 67.2 61 47.5 62.8c-9.5 0-18.4 4-18.4 12.7 0 13.2 20.3 14.4 32.5 17.7 20.9 6.3 41 10.7 41 33.3 0 28.8-22.6 38.8-52.4 38.8-24.9 0-50.2-8.9-50.2-31.8 0-6.4 6.1-11.3 12-11.3 7.5 0 10.1 3.2 12.7 8.4 5.8 10.2 12.3 15.6 28.3 15.6 10.2 0 20.6-3.9 20.6-12.7 0-12.6-12.8-15.3-26.1-18.4-23.5-6.6-43.6-10-46-36.1C-1 34.5 91.7 32.9 97 71.9c.1 7.1-6.5 11.4-13.4 11.4zm110.2-39c32.5 0 51 27.2 51 60.8 0 33.7-17.9 60.8-51 60.8-18.4 0-29.8-7.8-38.1-19.8v44.5c0 13.4-4.3 19.8-14.1 19.8-11.9 0-14.1-7.6-14.1-19.8V61.3c0-10.6 4.4-17 14.1-17 9.1 0 14.1 7.2 14.1 17v3.6c9.2-11.6 19.7-20.6 38.1-20.6zm-7.7 98.4c19.1 0 27.6-17.6 27.6-38.1 0-20.1-8.6-38.1-27.6-38.1-19.8 0-29 16.3-29 38.1 0 21.2 9.2 38.1 29 38.1zM266.9 76c0-23.4 26.9-31.7 52.9-31.7 36.6 0 51.7 10.7 51.7 46v34c0 8.1 5 24.1 5 29 0 7.4-6.8 12-14.1 12-8.1 0-14.1-9.5-18.4-16.3-11.9 9.5-24.5 16.3-43.8 16.3-21.3 0-38.1-12.6-38.1-33.3 0-18.4 13.2-28.9 29-32.5 0 .1 51-12 51-12.1 0-15.7-5.5-22.6-22-22.6-14.5 0-21.9 4-27.5 12.7-4.5 6.6-4 10.6-12.7 10.6-6.9-.1-13-4.9-13-12.1zm43.6 70.2c22.3 0 31.8-11.8 31.8-35.3v-5c-6 2-30.3 8-36.8 9.1-7 1.4-14.1 6.6-14.1 14.9.1 9.1 9.4 16.3 19.1 16.3zM474.5 0c31.5 0 65.7 18.8 65.7 48.8 0 7.7-5.8 14.1-13.4 14.1-10.3 0-11.8-5.5-16.3-13.4-7.6-13.9-16.5-23.3-36.1-23.3-30.2-.2-43.7 25.6-43.7 57.8 0 32.4 11.2 55.8 42.4 55.8 20.7 0 32.2-12 38.1-27.6 2.4-7.1 6.7-14.1 15.6-14.1 7 0 14.1 7.2 14.1 14.8 0 31.8-32.4 53.8-65.8 53.8-36.5 0-57.2-15.4-68.5-41-5.5-12.2-9.1-24.9-9.1-42.4-.1-49.2 28.6-83.3 77-83.3zm180.3 44.3c8 0 12.7 5.2 12.7 13.4 0 3.3-2.6 9.9-3.6 13.4L625.1 173c-8.6 22.1-15.1 37.4-44.5 37.4-14 0-26.1-1.2-26.1-13.4 0-7 5.3-10.6 12.7-10.6 1.4 0 3.6.7 5 .7 2.1 0 3.6.7 5 .7 14.7 0 16.8-15.1 22-25.5l-37.4-92.6c-2.1-5-3.6-8.4-3.6-11.3 0-8.2 6.4-14.1 14.8-14.1 9.5 0 13.3 7.5 15.6 15.6l24.7 73.5L638 65.5c3.9-10.5 4.2-21.2 16.8-21.2z')

View File

@ -0,0 +1,381 @@
include _functions
//- Mixins
//- ============================================================================
//- Sections for content pages
id - [string] id, can be headline id as it's being prefixed (optional)
block - section content (block and inline elements)
mixin section(id)
section.section(id=(id) ? 'section-' + id : '')&attributes(attributes)
block
//- Flexbox grid to align children elements
...style - [strings] flexbox CSS classes without prefix (optional)
block - container content (block and inline elements)
mixin grid(...style)
.grid(class=prefixArgs(style, 'grid--'))&attributes(attributes)
block
mixin grid-col(...style)
.grid-col(class=prefixArgs(style, 'grid-col--'))&attributes(attributes)
block
//- Aside
headline - [string] Headline of aside (optional)
block - aside content (inline elements)
mixin aside(headline)
span.aside(data-label=headline)&attributes(attributes)
span.aside-body
block
//- Paragraphs
block - paragraph content (inline elements)
mixin lead
p.text-lead&attributes(attributes)
block
//- Various text styles
block - text (inline elements)
mixin example
p.text-example&attributes(attributes)
block
mixin source
span.text-source&attributes(attributes)
block
mixin label(...style)
span(class=(style != '') ? prefixArgs(style, 'label-') : 'label')&attributes(attributes)
block
//- Headings with optional permalinks
id - [string] unique id (optional, no permalink without id)
source - [string] link for source button (optional)
block - headline text (inline elements)
mixin headline(level, id, source)
if level == 2
+h2(id, source)
block
else if level == 3
+h3(id, source)
block
else if level == 4
+h4(id, source)
block
else if level == 5
+h5(id, source)
block
else
+h6(id, source)
block
mixin h1(id, source)
h1(id=id)&attributes(attributes)
+permalink(id, source)
block
mixin h2(id, source)
h2(id=id)&attributes(attributes)
+permalink(id, source)
block
mixin h3(id, source)
h3(id=id)&attributes(attributes)
+permalink(id, source)
block
mixin h4(id, source)
h4(id=id)&attributes(attributes)
+permalink(id, source)
block
mixin h5(id, source)
h5(id=id)&attributes(attributes)
+permalink(id, source)
block
mixin h6(id, source)
h6(id=id)&attributes(attributes)
+permalink(id, source)
block
mixin permalink(id, source)
if id
a.permalink(href='#' + id)
block
else
block
if source
+button('secondary', 'small', 'source')(href=source target='_blank') Source
//- Button
element - [string] specifies HTML element, 'button' or 'link'
...style - [strings] button CSS classes without prefix (optional)
block - button text (inline elements)
mixin button(type, ...style)
- var classname = 'button-' + type + ' ' + ((style) ? prefixArgs(style, 'button--') : '')
a.button(class=classname)&attributes(attributes)
block
mixin form-button(type, ...style)
- var classname = 'button-' + type + ' ' + ((style) ? prefixArgs(style, 'button--') : '')
button(class=classname)&attributes(attributes)
block
//- Input
placeholder - [string] placeholder for input field (optional)
value - [string] value of input field (optional)
mixin input(placeholder, value)
input.input(placeholder=placeholder value=value)&attributes(attributes)
//- Icon
name - [string] icon name, refers to CSS classes
size - [string] 'medium' or 'large' (optional)
type - [string] 'button' (optional)
block - description, if as a text node to the icon element it prevents line
breaks between icon and text (inline elements)
mixin icon(type, ...style)
span(class='icon-' + type + ' ' + prefixArgs(style, 'icon--') aria-hidden="true")&attributes(attributes)
block
//- Image for illustration purposes
file - [string] file name (in /img)
alt - [string] descriptive alt text (optional)
caption - [string] image caption (optional)
mixin image(file, alt, caption)
figure.image-container&attributes(attributes)
img(src='img/' + file alt=alt)
if caption
figcaption.text-caption=caption
block
//- Illustrated code view
title - [string] title of window
mixin code-demo(title)
.x-terminal&attributes(attributes)
.x-terminal-icons: span
.x-terminal-title=title
+code.x-terminal-code
block
//- Data table
head - [array] column headings (optional, without headings no table
head is displayed)
...style - [strings] table CSS classes without prefix (optional)
block - only +row (tr)
mixin table(head, ...style)
table.table(class=prefixArgs(style, 'table--'))&attributes(attributes)
if head
tr.table-row
each column in head
th.table-head-cell=column
block
//- Data table row
block - only +cell (td)
mixin row(...style)
tr.table-row(class=prefixArgs(style, 'table-cell--'))&attributes(attributes)
block
//- Data table cell
block - table cell content (inline elements)
mixin cell(...style)
td.table-cell(class=prefixArgs(style, 'table-cell--'))&attributes(attributes)
block
//- General list (ordered and unordered)
type - [string] 'numbers', 'letters', 'roman' (optional)
start - [integer] starting point of list (1 = list starts at 1 or A)
block - only +item (li)
mixin list(type, start)
if type
ol.list(class='list--' + type style=(start === 0 || start) ? 'counter-reset: li ' + (start - 1) : '')&attributes(attributes)
block
else
ul.list.list--bullets&attributes(attributes)
block
//- List item
block - item text (inline elements)
mixin item
li.list-item&attributes(attributes)
block
//- Blockquote
source - [string] quote source / author (optional)
link - [string] link to quote source (only with source, optional)
block - quote text (inline elements)
mixin quote(source, link)
blockquote.quote&attributes(attributes)
p.quote-text
block
if source && link
| #[a.quote-source(href=link target='_blank')=source]
else if source && !link
.quote-source !{source}
//- Pullquotes with optional 'tweet this' function
tweet - [string] text to be tweeted (optional)
block - pullquote text (inline elements, only shown if no tweet text)
mixin pullquote(tweet)
blockquote.quote&attributes(attributes)
p.quote-text-strong
if tweet
| !{tweet} #[a.quote-source(href=twitterShareUrl(current.path, tweet) target='_blank') Tweet this]
else
block
//- Code block
use as +code(args). to preserve whitespace and prevent code interprettion
language - [string] language for syntax highlighting (optional, default:
'python', see Prism for options: http://prismjs.com)
label - [string] code block headline (optional)
block - code text (inline elements)
mixin code(language, label)
pre.code-block(class='lang-' + (language || default_syntax) data-label=label)&attributes(attributes)
code.code-inline
block
//- Infobox for notes and alerts
label - [string] infobox headline (optional)
block - infobox text (inline and block elements)
mixin infobox(label)
.box.box--info(data-label=label)&attributes(attributes)
p.box-body
block
//- Alerts for notes and updates
mixin alert(button)
.alert&attributes(attributes)
block
if button
+form-button('primary', 'small')(onclick='this.parentNode.parentNode.removeChild(this.parentNode);')=button
else
button.alert-close(onclick='this.parentNode.parentNode.removeChild(this.parentNode);')
//- Embeds
border - [boolean] add border to embed container
caption - [string] embed caption
block - embed content (inline and block elements)
mixin embed(border, caption)
figure.embed(class=(border) ? 'embed--border' : '')&attributes(attributes)
block
if caption
figcaption.embed-caption=caption
//- displaCy
filename - [string] name of file in displacy folder (no .html)
caption - [string] caption (optional)
height - [integer] iframe height in px (optional)
mixin displacy(filename, caption, height)
+embed(true, caption).embed--displacy
iframe(src='/blog/displacy/' + filename height=height)
//- Logo, imports SVG
size - [string] 'tiny', 'small', 'regular' or 'large'
mixin logo(size)
!=partial('/_includes/_logo', { logo_size: size })
//- <time> element with date
input - [string] date in the format YYYY-MM-DD
type - [string] 'timestamp' (optional)
mixin date(input, type)
- var dates = convertDate(input)
if type == 'timestamp'
time=dates.timestamp
else
time(datetime=dates.timestamp)=dates.full
//- Divider
type - [string] divider tpe
mixin divider(type, ...style)
div(class=((type) ? 'divider-' + type : 'divider') + ' ' + prefixArgs(style, 'divider--'))&attributes(attributes)
if type == 'text'
.divider-text-content
block
else
block
//- Twitter Share Button
tweet - [string] text to be shared with the tweet
mixin tweet(tweet)
a(href=twitterShareUrl(current.path, tweet) target='_blank' aria-label="Shsre on Twitter")
+icon('twitter', 'large')

View File

@ -0,0 +1,32 @@
include _mixins
- var nav_active_class = 'nav-item--active'
//- Top Navigation Bar
//- ============================================================================
nav#topnav.nav
a(href='/')
!=partial('_logo', { logo_size: 'small' })
input(type='checkbox' class='nav-checkbox' id='nav-checkbox' aria-hidden='true')
ul.nav-menu
if standalone
li.nav-item(class=nav_active_class)=title
li.nav-item: a(href='/') Back to website
else
li.nav-item(class=(_section == 'index') ? nav_active_class : '')
a(href='/') Home
each slug, item in navigation
li.nav-item(class=(_section == slug) ? nav_active_class : '')
a(href='/' + slug)=item
li.nav-item: a(href='https://github.com/' + profiles.github + '/spaCy' target='_blank') GitHub
label(for='nav-checkbox' class='nav-button' arial-label='Toggle Navigation')

View File

@ -0,0 +1,21 @@
include _mixins
//- Newsletter Signup
//- ============================================================================
.block.text-center(class=(divider) ? 'divider-' + divider : '')
+label('strong') Sign up for the spaCy newsletter
+h3.h1 Stay in the loop!
+lead Receive updates about new releases, tutorials and more.
form(action='https://spacy.us12.list-manage.com/subscribe/post?u=83b0498b1e7fa3c91ce68c3f1&amp;id=89ad33e698' method='post' id='mc-embedded-subscribe-form' name='mc-embedded-subscribe-form' target="_blank" novalidate)
+grid('align-center', 'valign-center', 'margin-right')
+input('Your email address', '')(type='email' name='EMAIL' id='mce-EMAIL')
//- Spam bot protection
div(style='position: absolute; left: -5000px;' aria-hidden='true')
input(type='text' name='b_83b0498b1e7fa3c91ce68c3f1_89ad33e698' tabindex='-1' value='')
+form-button('primary', 'small')(type='submit' name='subscribe' id='mc-embedded-subscribe') Sign up

View File

@ -0,0 +1,21 @@
//- Author profile
//- ============================================================================
include _mixins
if authors[author]
.box.box--info(data-label=label)
if image != false
.box-image: img(src='/assets/img/profile_' + author + ( (style) ? '_' + style : '' ) + '.png')
p.box-body.text-big
if authors[author].name
strong=authors[author].name + ' '
if authors[author].description
!=authors[author].description
if authors[author].links
span.box-links
each link, index in authors[author].links
a(href=link[0] target='_blank') #[+icon(index)=(link[1] || index)]

View File

@ -0,0 +1,12 @@
include _mixins
//- Sidebar
//- ============================================================================
nav#sidebar.sidebar: .sidebar-body
each items, menu in sidebar
ul.sidebar-menu(data-label=menu)
each item in items
li.sidebar-menu-item
a(href=item[1] data-section=(item[2]) ? 'section-' + item[2] : null)=item[0]

View File

@ -0,0 +1,22 @@
include _mixins
//- Teaser
//- ============================================================================
.teaser
if teaser.image
a(href=(_root || '') + slug target=teaser.target)
.image-ratio: img(src=(_root || '') + 'img/' + ((is_featured) ? teaser.image.file : teaser.image.file_small || teaser.image.file))
+h2
if is_featured
div: .label-strong Featured
a.block(href=(_root || '') + slug target=teaser.target class=(is_featured) ? 'h1' : 'h2')=teaser.title
p(class=(is_featured) ? 'text-lead' : '')=teaser.description
if showmeta != false
.text-meta.text-small
//- | by #{authors[teaser.author].name} on
| #[+date(teaser.date)]

43
website/_layout.jade Normal file
View File

@ -0,0 +1,43 @@
include _includes/_mixins
- var _section = current.path[0]
- var _site = current.source
- var is_article = ( (_section == 'blog' && _site != 'index') || template == 'article')
- var has_asides = (is_article || (_section == 'docs' && asides != false) || asides)
//- Layout
//- ============================================================================
doctype html
html(lang="en")
!=partial("_includes/_head", { _section: _section })
body.body
!=partial('_includes/_nav', { _section: _section, _site: _site })
if landing
!= yield
else
!=partial('_includes/_header', { is_article: is_article })
if sidebar
!=partial('_includes/_sidebar')
main.main(class='#{(sidebar) ? "main--sidebar" : "" } #{(has_asides) ? "main--asides" : "" } #{(is_article) ? "main--article" : "" }')
if is_article
!=partial('_includes/_article', { _section: _section })
else
!=yield
!=partial('_includes/_footer')
each script in scripts
script(src='/assets/js/' + script + '.js', type='text/javascript')
!=partial('_includes/_analytics')

View File

@ -0,0 +1,23 @@
// Animations
// ============================================================================
// Element slides in from the top
@keyframes slideInDown
from
transform: translate3d(0, -100%, 0);
visibility: visible;
to
transform: translate3d(0, 0, 0);
// Element blinks
@keyframes blink
0%
opacity: 1
50%
opacity: 0
100%
opacity: 1

View File

@ -0,0 +1,112 @@
// Fonts
// ============================================================================
// Lato (regular, italic, bold, bold italic)
@font-face
font-family: 'Lato'
font-style: normal
font-weight: 400
src: url('../fonts/lato-regular.eot')
src: url('../fonts/lato-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/lato-regular.woff2') format('woff2'), url('../fonts/lato-regular.woff') format('woff'), url('../fonts/lato-regular.ttf') format('truetype'), url('../fonts/lato-regular.svg#latoregular') format('svg')
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF
@font-face
font-family: 'Lato'
font-style: normal
font-weight: 400
src: url('../fonts/lato-regular.eot')
src: url('../fonts/lato-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/lato-regular.woff2') format('woff2'), url('../fonts/lato-regular.woff') format('woff'), url('../fonts/lato-regular.ttf') format('truetype'), url('../fonts/lato-regular.svg#latoregular') format('svg')
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000
@font-face
font-family: 'Lato'
font-style: italic
font-weight: 400
src: url('../fonts/lato-italic.eot')
src: url('../fonts/lato-italic.eot?#iefix') format('embedded-opentype'), url('../fonts/lato-italic.woff2') format('woff2'), url('../fonts/lato-italic.woff') format('woff'), url('../fonts/lato-italic.ttf') format('truetype'), url('../fonts/lato-italic.svg#latoitalic') format('svg')
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF
@font-face
font-family: 'Lato'
font-style: italic
font-weight: 400
src: url('../fonts/lato-italic.eot')
src: url('../fonts/lato-italic.eot?#iefix') format('embedded-opentype'), url('../fonts/lato-italic.woff2') format('woff2'), url('../fonts/lato-italic.woff') format('woff'), url('../fonts/lato-italic.ttf') format('truetype'), url('../fonts/lato-italic.svg#latoitalic') format('svg')
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000
@font-face
font-family: 'Lato'
font-style: normal
font-weight: 700
src: url('../fonts/lato-bold.eot')
src: url('../fonts/lato-bold.eot?#iefix') format('embedded-opentype'), url('../fonts/lato-bold.woff2') format('woff2'), url('../fonts/lato-bold.woff') format('woff'), url('../fonts/lato-bold.ttf') format('truetype'), url('../fonts/lato-bold.svg#latobold') format('svg')
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF
@font-face
font-family: 'Lato'
font-style: normal
font-weight: 700
src: url('../fonts/lato-bold.eot')
src: url('../fonts/lato-bold.eot?#iefix') format('embedded-opentype'), url('../fonts/lato-bold.woff2') format('woff2'), url('../fonts/lato-bold.woff') format('woff'), url('../fonts/lato-bold.ttf') format('truetype'), url('../fonts/lato-bold.svg#latobold') format('svg')
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000
@font-face
font-family: 'Lato'
font-style: italic
font-weight: 700
src: url('../fonts/lato-bolditalic.eot')
src: url('../fonts/lato-bolditalic.eot?#iefix') format('embedded-opentype'), url('../fonts/lato-bolditalic.woff2') format('woff2'), url('../fonts/lato-bolditalic.woff') format('woff'), url('../fonts/lato-bolditalic.ttf') format('truetype'), url('../fonts/lato-bolditalic.svg#latobolditalic') format('svg')
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF
@font-face
font-family: 'Lato'
font-style: italic
font-weight: 700
src: url('../fonts/lato-bolditalic.eot')
src: url('../fonts/lato-bolditalic.eot?#iefix') format('embedded-opentype'), url('../fonts/lato-bolditalic.woff2') format('woff2'), url('../fonts/lato-bolditalic.woff') format('woff'), url('../fonts/lato-bolditalic.ttf') format('truetype'), url('../fonts/lato-bolditalic.svg#latobolditalic') format('svg')
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000
// Work Sans (regular, semibold, bold)
@font-face
font-family: 'Work Sans'
font-style: normal
font-weight: 400
src: url('../fonts/worksans-regular.eot')
src: url('../fonts/worksans-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/worksans-regular.woff2') format('woff2'), url('../fonts/worksans-regular.woff') format('woff'), url('../fonts/worksans-regular.ttf') format('truetype'), url('../fonts/worksans-regular.svg#worksansregular') format('svg')
@font-face
font-family: 'Work Sans'
font-style: normal
font-weight: 600
src: url('../fonts/worksans-semibold.eot')
src: url('../fonts/worksans-semibold.eot?#iefix') format('embedded-opentype'), url('../fonts/worksans-semibold.woff2') format('woff2'), url('../fonts/worksans-semibold.woff') format('woff'), url('../fonts/worksans-semibold.ttf') format('truetype'), url('../fonts/worksans-semibold.svg#worksanssemibold') format('svg')
@font-face
font-family: 'Work Sans'
font-style: normal
font-weight: 700
src: url('../fonts/worksans-bold.eot')
src: url('../fonts/worksans-bold.eot?#iefix') format('embedded-opentype'), url('../fonts/worksans-bold.woff2') format('woff2'), url('../fonts/worksans-bold.woff') format('woff'), url('../fonts/worksans-bold.ttf') format('truetype'), url('../fonts/worksans-bold.svg#worksansbold') format('svg')
// Source Code Pro (semibold)
@font-face
font-family: 'Source Code Pro'
font-style: normal
font-weight: 600
src: url('../fonts/sourcecodepro-semibold.eot')
src: url('../fonts/sourcecodepro-semibold.eot?#iefix') format('embedded-opentype'), url('../fonts/sourcecodepro-semibold.woff') format('woff'), url('../fonts/sourcecodepro-semibold.ttf') format('truetype'), url('../fonts/sourcecodepro-semibold.svg#sourcecodepro_semibold') format('svg')
// Icomoon (regular)
@font-face
font-family: 'Icomoon'
font-style: normal
font-weight: 400
src: url('../fonts/icomoon.eot?nt9usq')
src: url('../fonts/icomoon.eot?nt9usq#iefix') format('embedded-opentype'), url('../fonts/icomoon.ttf?nt9usq') format('truetype'), url('../fonts/icomoon.woff?nt9usq') format('woff'), url('../fonts/icomoon.svg?nt9usq#icomoon') format('svg')

View File

@ -0,0 +1,131 @@
// Grid - Variables
// ============================================================================
$grid-cols : $columns
$grid-padding : 2.25rem
$grid-margin : 1rem
// Grid - Style
// ============================================================================
// Blocks
p,
.block
@extend .has-aside
margin-bottom: 5rem
.no-block.no-block
margin-bottom: 0
// Responsive containers
.responsive-container
max-width: 100%
overflow: auto
width: 100%
// Flexbox grid container
// .grid--wrap - wraps chrildren if bigger than the container
// .grid--space-between - aligns children horizontally, adds space between them
// .grid--space-around - aligns children horizontally, adds space around them
// .grid--align-center - aligns children horizonally and centered
// .grid--align-right - aligns children horizontally on the right
// .grid--valign-bottom - aligns children vertically at the bottom
// .grid-padding - adds padding to children
// .grid--margin-right - adds right margin to children
// .grid--margin-left - adds left margin to children
// .grid--block - extends block style
.grid,
.grid-col
align-items: flex-start
display: flex
flex-wrap: wrap
&.grid--nowrap,
&.grid-col--nowrap
flex-wrap: nowrap
&.grid--space-between,
&.grid-col--space-between
justify-content: space-between
&.grid--space-around,
&.grid-col--space-around
justify-content: space-around
&.grid--align-center,
&.grid-col--align-center
justify-content: center
&.grid--align-right,
&.grid-col--align-right
justify-content: flex-end
&.grid--valign-center,
&.grid-col--valign-center
align-items: center
&.grid--valign-bottom,
&.grid-col--valign-bottom
align-items: flex-end
&.grid--valign-space-between,
&.grid-col--valign-space-between
align-items: space-between
&.grid--text-center,
&.grid-col--text-center
text-align: center
&.grid--block,
&.grid-col--block
@extend .block
.grid
&--padding > *
padding: $grid-padding
&--margin-right > *
margin-right: $grid-margin
&--margin-left > *
margin-left: $grid-margin
.grid-col
overflow: hidden
& > *
flex-shrink: 1
max-width: 100%
// Responsive grid elements
// adapted from Gridly, https://github.com/IonicaBizau/gridly
@media (min-width: #{$screen-size-medium})
.grid
flex-direction: row
align-items: stretch
.grid-col
display: flex
flex: 0 0 100%
flex-direction: column
@each $grid-mode, $grid-percentage in $grid-cols
&--#{$grid-mode}
flex: 0 0 $grid-percentage
max-width: $grid-percentage
@media(max-width: #{$screen-size-medium})
.grid-col.grid-col
flex: 0 0 100%
flex-flow: column wrap

View File

@ -0,0 +1,75 @@
// Reset - Variables
// ============================================================================
$reset-font-size : $base-font-size
$reset-font-size-small : $base-font-size * 0.8
// Reset - Style
// ============================================================================
// normalize.css
@import ../_vendors/normalize
// Clearfix
%clearfix
*zoom: 1
&:before,
&:after
content: ''
display: table
&:after
clear: both
// Custom Resets
*
border: 0
box-sizing: border-box
margin: 0
outline: 0
padding: 0
-webkit-font-smoothing: antialiased
html
font-size: $reset-font-size
@media (max-width: #{$screen-size-small})
font-size: $reset-font-size-small
header,
footer,
figure
width: 100%
max-width: 100%
table
border-collapse: collapse
max-width: 100%
text-align: left
width: 100%
td,
th
vertical-align: top
ul,
ol
list-style: none
a
color: inherit
text-decoration: none
img
height: auto
max-width: 100%
[data-label]:before
content: attr(data-label)

View File

@ -0,0 +1,174 @@
// Typography - Variables
// ============================================================================
$font-size : 1.6rem
$headings : h1, h2, h3, h4, h5, h6
$heading-font-family : $font-secondary
$heading-font-sizes : 5rem, 2.8rem, 2.4rem, 2rem, 1.8rem, 1.6rem
$heading-font-weight : bold
$heading-padding : $height-navbar 0 1.5rem 0
$heading-text-shadow : 2px 2px
$line-height : 1.375
$page-title-size : 6rem
$color-highlight : color($theme)
$color-highlight-dark : color($theme, dark)
// Typography - Style
// ============================================================================
// Placeholders
%font-base
font-size: $font-size
line-height: $line-height
%font-big
font-size: round-dec($font-size * 1.25)
line-height: round-dec($line-height * 1.15)
%font-lead
font-size: round-dec($font-size * 1.75)
line-height: round-dec($line-height * 1.2)
%font-small
font-size: round-dec($font-size * 0.75)
line-height: round-dec($line-height * 1.1)
%font-medium-small
font-size: round-dec($font-size * 0.875)
line-height: round-dec($line-height * 1.1)
%font-primary
font-family: $font-primary
%font-secondary
font-family: $font-secondary
%font-code
font-family: $font-code
// Text styles
// .text - regular text
// .text-big - bigger style for blogs
// .text-lead - large style for intro paragraphs
// .text-small - smaller font size
// .text-quote - style for quotation
// .text-meta - slightly fainter but emphasized font for meta text
// .text-meta-strong - emphasized meta text
// .text-label - text for labels
// .text-credit - meta text with copyright symbol for image credits
// .text-caption - text for figure captions
// .text-source - text for bibliography sources
// .text-example - text for linguistic examples
.text
@extend %font-primary, %font-base
.text-big
@extend %font-primary, %font-big
.text-lead
@extend %font-primary, %font-lead
.text-medium-small
@extend %font-medium-small
.text-small
@extend %font-small
.text-quote
@extend .text-big
font-style: italic
.text-meta
@extend %font-secondary, %font-base
font-style: normal
font-weight: 600
text-transform: uppercase
.text-meta-strong
@extend .text-meta
font-weight: bold
.text-label
@extend %font-secondary
font-size: round-dec($font-size * 0.875)
line-height: $line-height
font-weight: normal
text-transform: uppercase
.text-credit
@extend .text-meta, .text-small
@include icon(copyright, currentColor, 0 0.25em 0 0)
color: color(grey, dark)
.text-caption
@extend .text-small
color: color(grey, dark)
padding-top: 2rem
.text-source
@extend .text-quote
display: block
.text-example
@extend .text-lead
color: color(grey, dark)
font-style: italic
.text-code
@extend %font-code
font-size: round-dec($font-size * 0.875)
font-weight: 600
font-style: normal
line-height: round-dec($line-height * 1.65)
.text-center
text-align: center
// Headings - Style
// ============================================================================
// Global heading style
%heading
font-weight: $heading-font-weight
font-family: $heading-font-family
position: relative
// Headings
.h0
font-size: $page-title-size
line-height: round-dec($line-height * 0.9)
margin: 0
text-shadow: $heading-text-shadow $color-highlight-dark
@for $i from 1 through length($headings)
$heading: nth($headings, $i)
#{$heading},
.#{$heading}
@extend %heading
font-size: nth($heading-font-sizes, $i)
@if $i == 1
.#{$heading}
padding: 0
@else
#{$heading}
padding: $heading-padding
// Selection - Style
// ============================================================================
*::selection
text-shadow: none
background: $color-highlight
color: color(white)

View File

@ -0,0 +1,33 @@
// Variables
// ============================================================================
$alert-background : color(white)
$alert-border : 1px solid
$alert-close-size : 2.25rem
$alert-color : color($theme)
$alert-padding : 1.5rem 2rem
// Style
// ============================================================================
// Alert boxes
// .alert - alert container
// .alert-close - icon to close alert
.alert
@include position(fixed, bottom, left, 0, 0)
align-items: center
background: $alert-background
border-top: $alert-border
color: $alert-color
display: flex
justify-content: space-between
padding: $alert-padding
width: 100%
z-index: 200
.alert-close
@include icon(close, currentColor, 0, $alert-close-size)
background: transparent
color: $alert-color

View File

@ -0,0 +1,69 @@
// Variables
// ============================================================================
$aside-block-margin : 4rem
$aside-border : 1px solid color(grey)
$aside-font-size : 1.4rem
$aside-font-family : $font-primary
$aside-line-height : 1.65
$aside-margin-side : 1.5rem
$aside-opacity : 0.4
$aside-padding : 0 2rem
$aside-transition : $transition
$aside-width : $width-aside
// Style
// ============================================================================
// Aside content
// :hover - show aside on hover
// [data-label] - style of aside headlines
.aside
@extend .text-small
@media (max-width: #{$screen-size-large})
display: block
margin-bottom: $aside-block-margin
margin-top: $aside-block-margin
@media (min-width: #{$screen-size-large})
@include position(absolute, top, left, 0, calc(100% + #{$aside-margin-side}))
border-left: $aside-border
opacity: $aside-opacity
padding: $aside-padding
transition: $aside-transition
white-space: normal
width: $aside-width
&:hover
opacity: 1
&[data-label]:before
@extend .label-strong
display: block
.block
margin-bottom: ($aside-block-margin / 2)
.code-inline
@extend .code-small
.code-block
@extend .code-block-small
.table &
top: initial
.aside-body
display: block
// Aside container
.has-aside
position: relative
&:hover > .aside
opacity: 1

View File

@ -0,0 +1,39 @@
// Boxes - Variables
// ============================================================================
$box-border : 1px solid
$box-padding : 2em
// Boxes - Style
// ============================================================================
// Box for notes and alerts
// [data-label] - style of box labels
// .box--info - emphasized style for info boxes
// .box-image - optional image, like profile image
// .box-body - body text of box
// .box-links - link list
.box
@extend .block, .text
padding: ($box-padding / 2) 0
&[data-label]:before
@extend .label-box
&--info
background: color($theme, light)
border: $box-border darken(color($theme, light), 4)
.box-image
@extend .image-profile
float: right
.box-body
margin-bottom: 0
padding: $box-padding
.box-links
@extend .link-list
padding: $box-padding

View File

@ -0,0 +1,75 @@
// Buttons - Variables
// ============================================================================
$button-border-radius : $border-radius
$button-border-style : solid
$button-border-width : 2px
$button-color : color($theme)
$button-opacity-hover : 0.85
$button-padding : 1em 1.5em 0.75em
$button-margin : 0.5rem
// Buttons - Style
// ============================================================================
// :active - effect on active
// :hover - effect on hover
// .button--small - small style
// .button--#{$social-button} - social button styled according to site
// .button-primary - primary style
// .button-secondary - secondary style
// .button-tertiary - tertiary style
.button
@extend .text-meta
border: $button-border-width $button-border-style
border-radius: $button-border-radius
padding: $button-padding
&--small
@extend .text-small
border-width: ($button-border-width / 2)
&--source
float: right
margin-left: $button-margin
@each $social-button in $social-buttons
&.button--#{$social-button}
background: color(social, $social-button)
border-color: color(social, $social-button)
color: color(white)
.button-primary
@extend .button
background-color: $button-color
border-color: $button-color
color: color(white)
&:hover,
&:active
opacity: $button-opacity-hover
.button-secondary
@extend .button
background: color(white)
color: $button-color
&:hover,
&:active
background: $button-color
color: color(white)
opacity: 1
.button-tertiary
@extend .button
background: color(white)
color: color(grey, dark)
border-color: currentColor
&:hover,
&:active
border-color: $button-color
color: $button-color
opacity: 1

View File

@ -0,0 +1,44 @@
// Cards - Variables
// ============================================================================
$card-border-radius : $border-radius
$card-border : 1px solid color(grey)
$card-figure-background : color(grey, light)
$card-figure-ratio : $image-ratio
$card-padding : 8%
$card-shadow-light : 0 0 5px color(grey, light)
$card-shadow : 0 0 5px color(grey)
$card-transition : $transition
// Cards - Style
// ============================================================================
// .card - card element, ideally used within grids
// .card-strong - highlighted style
// .card-figure - graphic element within card
.card
border: $card-border
border-radius: $border-radius
flex: 1
overflow: auto
padding: $card-padding
width: 100%
.card-strong
@extend .card
box-shadow: $card-shadow
transition: $card-transition
&:hover
box-shadow: $card-shadow-light
.card-figure
background: $card-figure-background
border-radius: $card-border-radius
display: block
height: 0
margin-bottom: $card-padding
overflow: hidden
padding-bottom: 50%

View File

@ -0,0 +1,87 @@
// Variables
// ============================================================================
$code-background : color(grey, light)
$code-background-dark : color(black)
$code-block-border : 4px solid color($theme)
$code-block-padding : 2em 3em
$code-block-padding-small : 1em 1.5em
$code-inline-margin : 0.25em 0.5em 0 0.5em
$code-inline-padding : 0 0.25rem
$code-line-height : 2.25
$code-text-shadow : 1px 1px 0 color(white)
// Style
// ============================================================================
// General code style
// .code-inline - source code
// .code-small - smaller style
.code-inline
@extend .text-code
direction: ltr
text-shadow: $code-text-shadow
white-space: pre
word-spacing: normal
word-break: normal
.code-small
@extend .text-small
padding-top: 0
padding-bottom: 0
// Inline Code
// :not(.code-block) - style for items outside of code blocks
code
@extend .code-inline
:not(.code-block) > .code-inline
background: $code-background
display: inline
line-height: inherit
margin: $code-inline-margin
padding: $code-inline-padding
// Code blocks in preformatted text
// .code-block - block of source code
// .code - text content of code blocks
// [data-label] - style of code labels
// .code-block-small - smaller style
// .code-block-dark - alternative dark style
.code-block
@extend .block
background: $code-background
border-left: $code-block-border
max-width: 100%
overflow: auto
padding: 1em 0
white-space: pre
width: 100%
.code-inline
display: block
padding: $code-block-padding
&[data-label]:before
@extend .label-box
.code-block-small
@extend .code-small
.code-inline
padding: $code-block-padding-small
.code-block-dark
@extend .code-block
background: $code-background-dark
border: none
color: color(white)
.code-inline
text-shadow: none

View File

@ -0,0 +1,72 @@
// Dividers - Variables
// ============================================================================
$divider-border : 1px solid color(grey)
$divider-locations : top, bottom
$divider-margin : 5rem
$divider-padding : 3rem
$divider-text-align : center
// Dividers - Style
// ============================================================================
// General divider
.divider
@extend %clearfix
width: 100%
margin: $divider-margin 0
@each $divider-location in $divider-locations
%divider-#{$divider-location}
@extend .divider
border-#{$divider-location}: $divider-border
// Divider above element
// .divider-top - add divider to top of element
// .divider-bottom - add divider to bottom of element
// .divider-both - add divider to top and bottom of element
.divider-top
@extend %divider-top
padding-top: $divider-padding
.divider-bottom
@extend %divider-bottom
padding-bottom: $divider-padding
.divider-both
@extend .divider-top
@extend .divider-bottom
// Divider bar for text and links
// .divider-bar - container element
.divider-bar
@extend %divider-top, %divider-bottom, .label
margin: 0
text-align: $divider-text-align
// Divider with text
// .divider-text - container element
// .divider-text-content - text content
.divider-text
@extend %divider-top
text-align: $divider-text-align
margin: $divider-margin 0
.divider-text-content
background: color(white)
display: inline-block
line-height: 0.5
margin: -0.5em 0 0 0
padding: 0 0.5em
& > *
margin: 0
padding: 0

View File

@ -0,0 +1,35 @@
// Embeds - Variables
// ============================================================================
$embed-border : 1px solid color(grey)
$embed-caption-align : center
$embed-padding : 2rem
$embed-displacy-min : 325px
// Embeds - Style
// ============================================================================
// iframe - content of embed
// .embed--border - embed with border
// .embed--displacy - embed for displaCy visualization
.embed
@extend .block
margin-left: 0
padding: $embed-padding
iframe
max-width: 100%
width: 100%
&--border
border: $embed-border
&--displacy iframe
min-height: $embed-displacy-min
.embed-caption
@extend .label
display: block
text-align: $embed-caption-align

View File

@ -0,0 +1,28 @@
// Form Elements - Variables
// ============================================================================
$input-border : 1px solid color(grey)
$input-border-radius : $border-radius
$input-color : color(grey, dark)
$input-padding : 0.5em 0.75em
$input-transition : $transition
// Form Elements - Style
// ============================================================================
// Text input field
// :hover - style on hover
// :focus - style on focus
.input
@extend .text
border: $input-border
border-radius: $input-border-radius
color: $input-color
padding: $input-padding
transition: $input-transition
&:hover,
&:focus
border-color: currentColor

View File

@ -0,0 +1,39 @@
// Icons - Variables
// ============================================================================
$icon-padding : 0.5em
$icon-large-size : 3rem
$icon-medium-size : 1.75rem
// Icons - Style
// ============================================================================
// .icon--secondary - non-colored version of icon
// .icon--large - large version of graphic icon
// .icon-#{$icon} - graphic icon
%icon
display: inline-block
font-family: $font-icons
font-style: normal
font-weight: normal
line-height: 1
.icon
display: inline-block
vertical-align: middle
&--secondary:before
color: currentColor !important
&--medium:before
font-size: $icon-medium-size
&--large:before
font-size: $icon-large-size
@each $icon, $unicode in $icons
.icon-#{$icon}
@extend .icon
@include icon($icon, color(social, $icon), 0 $icon-padding)

View File

@ -0,0 +1,39 @@
// Images - Variables
// ============================================================================
$image-background : color(grey, light)
$image-profile-margin : 1rem 3rem
$image-profile-width : $width-profile
$image-ratio : $image-ratio
// Images - Style
// ============================================================================
// Image Containers
// .image-container - container for figures and inline images
// .image-hero - container for hero image for blog posts
// .image-profile - container for profile photo
.image-container
@extend .block
margin-left: 0
margin-right: 0
.image-profile
@include size($image-profile-width)
background: $image-background
border-radius: 50%
margin: $image-profile-margin
overflow: hidden
shape-outside: circle()
// Global image ratio
.image-ratio
background: $image-background
height: 0
overflow: hidden
padding-bottom: (100% / $image-ratio)
width: 100%

View File

@ -0,0 +1,46 @@
// Labels - Variables
// ============================================================================
$label-border-radius : $border-radius
$label-color : color(grey, dark)
$label-color-light : color(grey, light)
$label-color-dark : color($theme)
$label-padding : 0.75em
$label-padding-small : 0.25em 0.75em
$label-margin-side : 1rem
// Labels - Style
// ============================================================================
// .label - regular label
// .label-strong - stronger version
// .label-box - label in box with background
// .label-tag - label in inline-tag style
.label
@extend .text-label
color: $label-color
display: inline-block
padding: $label-padding 0
.label-strong
@extend .label
color: $label-color-dark
font-weight: bold
.label-box
@extend .label
background: $label-color-dark
color: color(white)
font-weight: 600
padding: $label-padding
.label-tag
@extend .label, .text-small
background: $label-color-light
border: 1px solid darken($label-color-light, 7.5)
border-radius: $label-border-radius
margin: 0 $label-margin-side 0 0
padding: $label-padding-small
vertical-align: text-top

View File

@ -0,0 +1,60 @@
// Links - Variables
// ============================================================================
$link-border : 1px solid currentColor
$link-color : color($theme)
$link-icon-color : color(grey, dark)
$link-icon-color-hidden : color(grey)
$link-icon-size : 2rem
$link-list-padding : 0.5em
$link-transition : $transition
// Links - Style
// ============================================================================
.link
color: $link-color
transition: $link-transition
.link-strong
@extend .link
border-bottom: $link-border
p a,
.table-cell a,
.list-item a,
.aside a
@extend .link-strong
// Permalinks
// :before - indicate permalink with icon
// :hover:before - hover effect on permalink indicator
// :active:before - different styling of active permalink indicator
.permalink
@include icon(permalink, $link-icon-color-hidden, 0 $link-icon-size 0 0, $link-icon-size)
position: relative
&:before
@include position(absolute, top, left, calc(50% - #{$link-icon-size / 2}), (-$link-icon-size * 1.5))
transition: $link-transition
width: $link-icon-size
&:hover:before
color: $link-icon-color
&:active:before
color: $link-color
// List of links, like social profiles
.link-list
@extend .text-label
font-weight: 600
& > *
display: inline-block
padding: $link-list-padding

View File

@ -0,0 +1,59 @@
// Lists - Variables
// ============================================================================
$list-alternatives : (letters, upper-latin), (roman, lower-roman)
$list-icon-color : color($theme)
$list-icon-size : 2.4rem
$list-item-padding : 1em
$list-margin-side : 5%
$list-padding-side : 2rem
// Lists - Style
// ============================================================================
// .list - list of items
// .list--bullets - unordered list with bullets
// .list--numbers - ordered list with numbers
// .list--letters - ordered list with letters
// .list--roman - ordered list with roman numerals
// .list-item - list item
.list
@extend .block, .text
padding-left: $list-margin-side
&--bullets
margin-left: $list-margin-side
.list-item
@include icon(bullet, none, 0 $list-padding-side 0 0, $list-icon-size)
&--numbers
counter-reset: li
margin-left: $list-margin-side
.list-item:before
@extend .h3
content: counter(li) '.'
counter-increment: li
padding-right: $list-padding-side
@each $list-type, $list-counter in $list-alternatives
&--#{$list-type}
@extend .list--numbers
.list-item:before
content: counter(li, #{$list-counter}) '.'
.list-item
margin-bottom: $list-item-padding
text-indent: -$list-margin-side
&:before
color: $list-icon-color
display: inline-block
line-height: 1
text-align: center
width: $list-icon-size
vertical-align: middle

View File

@ -0,0 +1,36 @@
// Logo - Variables
// ============================================================================
$logo-size-large : nth($width-logo, 1)
$logo-size-regular : nth($width-logo, 2)
$logo-size-small : nth($width-logo, 3)
$logo-size-tiny : nth($width-logo, 4)
// Logo - Style
// ============================================================================
// path - SVG path of logo
// .logo--small - smaller style
// .logo--regular - regular style
// .logo--large - bigger style
.logo
width: 100%
path
width: 100%
fill: currentColor
&--tiny
vertical-align: text-bottom
width: $logo-size-tiny
&--small
width: $logo-size-small
&--regular
width: $logo-size-regular
&--large
width: $logo-size-large

View File

@ -0,0 +1,88 @@
// Misc - Variables
// ============================================================================
$x-terminal-background : color(grey)
$x-terminal-border-radius : $border-radius * 2
$x-terminal-color : color(black)
$x-terminal-cursor-animation : blink 0.9s infinite
$x-terminal-cursor : '\258B'
$x-terminal-icon-colors : color(red), color(green), color(yellow)
$x-terminal-icon-size : 1em
$x-terminal-padding : 0.75em
$x-bubble-size : 35px
$x-bubble-margin : 1rem
// Misc - Style
// ============================================================================
// Terminal window illustration to display code
// .x-terminal - terminal window
// .x-terminal-title - title of terminal window
// .x-terminal-icons - container for toolbar icons
// .x-terminal-code - code box
// .x-terminal-code:after - cursor in last line
// %x-terminal-icon - general style of toolbar icons
.x-terminal
background: $x-terminal-background
border-radius: $x-terminal-border-radius
color: $x-terminal-color
width: 100%
&--cursor
.code:after
animation: $x-terminal-cursor-animation
opacity: 1
content: $x-terminal-cursor
.x-terminal-title
text-align: center
padding: $x-terminal-padding
.x-terminal-icons
padding: $x-terminal-padding
position: absolute
&:before
@extend %x-terminal-icon
content: ''
background: nth($x-terminal-icon-colors, 1)
span
@extend %x-terminal-icon
background: nth($x-terminal-icon-colors, 2)
&:after
@extend %x-terminal-icon
content: ''
background: nth($x-terminal-icon-colors, 3)
.x-terminal-code
@extend .code-block-dark
border-bottom-left-radius: $x-terminal-border-radius
border-bottom-right-radius: $x-terminal-border-radius
padding: $x-terminal-padding * 2
max-width: 100%
width: 100%
white-space: pre-wrap
&.code-block
margin-bottom: 0
%x-terminal-icon
@include size($x-terminal-icon-size)
display: inline-block
float: left
border-radius: 50%
margin-right: $x-terminal-padding
// Bubble to display colors
.x-bubble
@include size($x-bubble-size)
border-radius: 50%
cursor: pointer
margin-right: $x-bubble-margin

View File

@ -0,0 +1,36 @@
// Quotes - Variables
// ============================================================================
$quote-icon-color : color($theme)
$quote-icon-size : 6rem
$quote-padding-side : 10rem
// Quotes - Style
// ============================================================================
// :before - icon to emphasize blockquote
// .quote-text - quote text content
// .quote-text-strong - emphasized style of quote text content
// .quote-source - source of quote (link optional)
.quote
@extend .block
@include icon(quote, color(grey), 0, $quote-icon-size)
padding-left: $quote-padding-side
&:before
@include position(relative, top, left, ($quote-icon-size / 1.75), -$quote-padding-side)
color: $quote-icon-color
.quote-text
@extend .text-quote
.quote-text-strong
@extend .h2
padding: 0
.quote-source
@extend .text-meta-strong
@include icon(dash, color(grey), 0 0.75rem 0 0)
border: none

View File

@ -0,0 +1,79 @@
// Tables - Variables
// ============================================================================
$table-background-color : color(white)
$table-border-color : color(grey)
$table-border-style : solid
$table-border-width : 1px
$table-color : color($theme)
$table-head-color : color(white)
$table-highlight-border : 3px solid color($theme)
$table-padding : 1em
$table-shade-color : color(grey, light)
$table-shadow-color : color(black, dark)
// Tables - Style
// ============================================================================
// .table - data table
// .table--code - table with code in first column
// .table--params - table with parameters in first column
// .table-row - table row
// .table-cell - table cell
// .table-cell--highlight - style for highlighted table cell(s)
// .table-head-cell - table head cell
// .table-container - block containing table
.table
@extend .table-responsive, .block, .text
vertical-align: top
&--code .table-cell:first-child
background: $table-shade-color
&--params .table-cell:first-child
font-weight: bold
white-space: nowrap
.table-cell
border: $table-border-width $table-border-style $table-border-color
padding: $table-padding
&--highlight
border: $table-highlight-border
.table-head-cell
@extend .text-meta
background: $table-color
border: $table-border-width $table-border-style $table-color
color: $table-head-color
display: table-cell
padding: $table-padding
.table-container
@extend .responsive-container
// Responsive Table Markup
// adapted from David Bushell, http://codepen.io/dbushell/pen/wGaamR
@media(max-width: #{$screen-size-large})
.table-responsive
@include scroll-shadow-base($table-shadow-color)
display: inline-block
overflow-x: auto
width: auto
-webkit-overflow-scrolling: touch
.table-cell
&:first-child
@include scroll-shadow-cover(left, $table-background-color)
&:last-child
@include scroll-shadow-cover(right, $table-background-color)
.table-responsive.table--code
.table-cell
&:first-child
@include scroll-shadow-cover(left, $table-shade-color)

View File

@ -0,0 +1,44 @@
// Tooltips - Variables
// ============================================================================
$tooltip-background : color(black)
$tooltip-border-radius : $border-radius
$tooltip-color : color(white)
$tooltip-padding : 0.15rem 1rem
// Tooltips - Style
// ============================================================================
// [data-tooltip] - tooltip
// :after - tooltip content
// :hover - display tooltip on hover
// .visible - makes tooltip visible
[data-tooltip]
display: inline
position: relative
&:after
@extend .text, .text-small
@include position(absolute, top, left, 125%, 50%)
background: $tooltip-background
border-radius: $tooltip-border-radius
color: $tooltip-color
content: attr(data-tooltip)
opacity: 0
padding: $tooltip-padding
text-shadow: none
text-transform: none
transform: translateX(-50%) translateY(-2px)
transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1)
visibility: hidden
white-space: nowrap
z-index: 200
&:hover:after,
&.visible:after
display: block
opacity: 1
transform: translateX(-50%) translateY(0)
visibility: visible

View File

@ -0,0 +1,25 @@
// Article - Variables
// ============================================================================
$article-header-margin : 6rem
$article-footer-margin : 1.5rem
// Article - Style
// ============================================================================
article p,
article .list
@extend .text-big
.article-header
margin-bottom: $article-header-margin
.article-title
@extend .h1
.article-meta
@extend .text-meta
.article-footer
margin-top: $article-footer-margin

View File

@ -0,0 +1,53 @@
// Body - Variables
// ============================================================================
$body-background : color(white)
$body-color : color(black)
$main-padding-sides : 4rem
$main-padding-bottom : 8rem
$main-article-margin-left : 10rem
// Body - Style
// ============================================================================
.body
@extend .text
background: $body-background
color: $body-color
display: flex
flex-flow: row wrap
// Main content
// .main - main content container
// .main--asides - main content with asides
// .main--article - main content for articles
.main
flex: 1 1 auto
max-width: 100%
padding: $height-navbar $main-padding-sides $main-padding-bottom $main-padding-sides
width: $width-content - $width-aside
// Remove top padding from first element if it's a level 2 headline
& > *:first-child > h2:first-child
padding-top: 0
// Large screens only
@media (min-width: #{$screen-size-large})
&.main--asides
margin-right: $width-aside
&.main--article
margin-left: $main-article-margin-left
// Sections
.section
@extend .block

View File

@ -0,0 +1,20 @@
// Footer - Variables
// ============================================================================
$footer-background : color($theme) pattern($theme)
$footer-color : color(white)
$footer-padding : 2.75rem
$footer-text-align : center
// Footer - Style
// ============================================================================
.footer
@extend .link-list
background: $footer-background
color: $footer-color
overflow: auto
padding: $footer-padding
text-align: $footer-text-align
z-index: 100

View File

@ -0,0 +1,50 @@
// Header - Variables
// ============================================================================
$header-background : color($theme) pattern($theme)
$header-color-highlight : color($theme, dark)
$header-min-height : 250px
$header-padding : 4rem 5rem 5rem
$header-text-color : color(white)
$header-text-shadow : 2px 2px
$hero-credit-bottom : -2em
$hero-credit-right : 1em
// Header - Style
// ============================================================================
.header
background: $header-background
display: flex
flex-flow: column nowrap
justify-content: center
margin-top: $height-navbar
min-height: $header-min-height
text-align: center
.header-title
@extend .h0
color: $header-text-color
&.header-title--center
@extend .text-center
.header-body
color: $header-text-color
padding: $header-padding
text-align: left
.header-text
text-shadow: $header-text-shadow $header-color-highlight
// Hero image
.hero
position: relative
min-height: 0
.hero-credit
@extend .text-credit
@include position(absolute, bottom, right, $hero-credit-bottom, $hero-credit-right)

View File

@ -0,0 +1,108 @@
// Top Navigation Bar - Variables
// ============================================================================
$nav-animation : slideInDown 0.5s ease-in-out
$nav-background : color(white)
$nav-color : color($theme)
$nav-height : $height-navbar
$nav-height-small : $nav-height * 0.8
$nav-icon-size : 3.5rem
$nav-item-spacing : 1em
$nav-mobile-border : 1px solid
$nav-mobile-font-size : 1.25em
$nav-mobile-padding : 1rem
$nav-mobile-width : 20vw
$nav-padding : 0 0 0 2rem
$nav-triangle-size : 8px
// Top Navigation Bar - Style
// ============================================================================
// .nav - top and primary navigation bar
// .fixed - sticky version
// .logo - special styling for logo
// .nav-menu - menu bar containing menu items
// .nav-item - menu list item
// .nav-button - button to toggle mobile navigation
// .nav-checkbox - checkbox for checkbox hack
// .active - active menu item
.nav
@extend .text-label
@include position(absolute, top, left, 0, 0)
@include size(100%, $nav-height)
align-items: center
background: $nav-background
border-color: $nav-background
color: $nav-color
display: flex
justify-content: space-between
padding: $nav-padding
z-index: 10
width: 100%
&.fixed
animation: $nav-animation
background: $nav-color
border-color: $nav-color
color: $nav-background
position: fixed
@media (min-width: #{$screen-size-small})
height: $nav-height-small
.nav-menu
@include size(100%)
justify-content: flex-end
border-color: inherit
display: flex
margin: 0
@media (max-width: #{$screen-size-small})
@include position(absolute, top, left, $nav-height, 0)
flex-flow: row wrap
.nav-checkbox:checked + &
background: inherit
.nav-item
@include visibility(visible)
& + .nav-button:before
color: color(grey)
.nav-item
align-items: center
border-color: inherit
display: flex
height: 100%
position: relative
&--active
font-weight: bold
@media (min-width: #{$screen-size-small})
margin-right: $nav-item-spacing
&--active:after
@include triangle-down($nav-triangle-size)
@include position(absolute, bottom, left, -$nav-triangle-size, calc(50% - #{$nav-triangle-size}))
@media (max-width: #{$screen-size-small})
@include size(100%, auto)
@include visibility(hidden)
background: inherit
border-top: $nav-mobile-border
font-size: $nav-mobile-font-size
justify-content: center
padding: $nav-mobile-padding
.nav-button
@media (max-width: #{$screen-size-small})
@include icon(menu, none, $nav-mobile-padding 0 0 0, $nav-icon-size)
cursor: pointer
padding: 0 1em 1em 0
.nav-checkbox
display: none

View File

@ -0,0 +1,65 @@
// Sidebar - Variables
// ============================================================================
$sidebar-breakpoint : 900px
$sidebar-highlight-color : color($theme)
$sidebar-margin-left : 4rem
$sidebar-margin-right : 6rem
$sidebar-margin-top : $height-navbar
$sidebar-menu-spacing : 3rem
$sidebar-small-border : 1px solid color(grey, light)
$sidebar-small-padding : 2rem 3rem
$sidebar-width : $width-sidebar
// Sidebar - Style
// ============================================================================
// .sidebar - sidebar
// .fixed - sticky version
// .menu - menu list in sidebar
// .active - active menu item
// .sidebar-label - menu label
.sidebar
@media (min-width: #{$sidebar-breakpoint})
flex: 0 0 $sidebar-width
margin-right: $sidebar-margin-right
margin-left: $sidebar-margin-left
padding-top: $height-navbar
width: $sidebar-width
&.fixed .sidebar-body
@include position(fixed, top, left, $sidebar-margin-top, $sidebar-margin-left)
@include size($sidebar-width, calc(100vh - #{$sidebar-margin-top}))
overflow: auto
transition: none
@media (max-width: #{$sidebar-breakpoint})
border-bottom: $sidebar-small-border
flex: 100%
width: 100%
.sidebar-body
display: flex
flex-flow: row wrap
.sidebar-menu
@media (min-width: #{$sidebar-breakpoint})
margin-bottom: $sidebar-menu-spacing
@media (max-width: #{$sidebar-breakpoint})
flex: 1
margin: 0
padding: $sidebar-small-padding
border-top: $sidebar-small-border
&:not(:last-child)
border-right: $sidebar-small-border
.active
color: $sidebar-highlight-color
font-weight: bold
.sidebar-menu[data-label]:before
@extend .label

View File

@ -0,0 +1,23 @@
// Functions
// ============================================================================
// Helper to round to decimals (used for rem units)
// $calculation - value or performed calculation
@function round-dec($calculation)
@return round($calculation * 10) / 10
// Helper for colors (refers to $colors in colors)
// $color-name - name of predefined color (i.e. blue)
// $color-variant - predefined hue (default: base)
@function color($color-name, $color-variant: base)
@return map-get(map-get($colors, $color-name), $color-variant)
// Helper for patterns, returns pattern image of color
// $color-name - name of predefined color (i.e. blue)
@function pattern($color-name)
@return url('../img/pattern_#{$color-name}.jpg') center center repeat scroll

View File

@ -0,0 +1,96 @@
// Mixins
// ============================================================================
// Helper for position
// $position - valid position value (static, absolute, fixed, relative)
// $pos-y - position direction Y (top, bottom)
// $pos-x - position direction X (left, right)
// $pos-y-value - value of position Y direction
// $pos-x-value - value of position X direction
@mixin position($position, $pos-y, $pos-x, $pos-y-value, $pos-x-value)
position: $position
#{$pos-y}: $pos-y-value
#{$pos-x}: $pos-x-value
// Helper for width and height
// $width - width of element
// $height - height of element (default: $width)
@mixin size($width, $height: $width)
height: $height
width: $width
// Icon before or after an element
// $icon-name - name of icon, refers to icon specified in settings
// $icon-color - color of icon (default: no color specified)
// $icon-padding - padding around icon (in shorthand style, default: 0)
// $icon-size - font size of icon (default: no size specified)
@mixin icon($icon-name, $icon-color: none, $icon-padding: 0, $icon-size: none)
&:before
@extend %icon
content: map-get($icons, $icon-name)
padding: $icon-padding
@if $icon-color != none
color: $icon-color
@if $icon-size != none
font-size: $icon-size
// Triangle pointing down
// $triangle-size - width of the triangle
@mixin triangle-down($triangle-size)
@include size(0)
border-color: transparent
border-style: solid
border-top-color: inherit
border-width: $triangle-size $triangle-size 0 $triangle-size
content: ''
// Make element visible or invisible (included as mixin to work in media queries)
// $visibility-state - visible or invisible
// $visibility-transition - transition (default: $transition)
@mixin visibility($visibility-state, $visibility-transition: $transition)
transition: $visibility-transition
@if $visibility-state == hidden
opacity: 0
pointer-events: none
visibility: hidden
@else
opacity: 1
pointer-events: initial
visibility: visible
// Scroll shadows for reponsive tables
// adapted from David Bushell, http://codepen.io/dbushell/pen/wGaamR
// $scroll-shadow-color - color of shadow
// $scroll-shadow-side - side to cover shadow (left or right)
// $scroll-shadow-background - original background color to match
@mixin scroll-shadow-base($scroll-shadow-color)
background: radial-gradient(left, ellipse, rgba(0,0,0, .2) 0%, rgba(0,0,0, 0) 75%) 0 center, radial-gradient(right, ellipse, rgba(0,0,0, .2) 0%, rgba(0,0,0, 0) 75%) 100% center
background-size: 10px 100%, 10px 100%
background-attachment: scroll, scroll
background-repeat: no-repeat
@mixin scroll-shadow-cover($scroll-shadow-side, $scroll-shadow-background)
$scroll-gradient-direction: right !default
@if $scroll-shadow-side == right
$scroll-gradient-direction: left
background-position: 100% 0
background-image: linear-gradient(to #{$scroll-gradient-direction}, rgba($scroll-shadow-background, 1) 50%, rgba($scroll-shadow-background, 0) 100%)
background-repeat: no-repeat
background-size: 20px 100%

View File

@ -0,0 +1,93 @@
// Variables
// ============================================================================
// Settings and Sizes
$theme : blue !default;
$base-font-size : 10px !default;
$width-logo : 500px, 250px, 100px, 65px !default;
$width-content : 800px;
$width-aside : 300px;
$width-sidebar : 230px;
$width-profile : 160px;
$height-navbar : 55px;
$border-radius : 4px;
$image-ratio : 3 / 1;
$transition : all 0.2s;
$social-buttons : twitter, reddit, hackernews, producthunt;
$screen-size-small : 480px;
$screen-size-medium : 800px;
$screen-size-large : 1200px;
// Grid Columns
$columns: ( fifth, 20% ),
( quarter, 25% ),
( third, (100% / 3) ),
( half, 50% ),
( two-thirds, (100% / 1.5) ),
( full, 100% );
// Fonts
$font-primary : Lato, Tahoma, Geneva, sans-serif !default;
$font-secondary : 'Work Sans', 'Arial Black', Gadget, sans-serif !default;
$font-code : 'Source Code Pro', Consolas, 'Andale Mono', Menlo, Monaco, Courier, monospace !default;
$font-icons : Icomoon !default;
// Colors
// only to be used with the color() function, i.e. color(blue, light)
$colors: (
blue : ( base: #09a3d5, dark: #008ebc, light: #e2f7fe ),
red : ( base: #e4514f, dark: #dd2422, light: #fceeed ),
grey : ( base: #dddddd, dark: #999999, light: #f6f6f6 ),
black : ( base: #222222, dark: #000000 ),
white : ( base: #ffffff ),
yellow : ( base: #f4c025 ),
green : ( base: #3ec930 ),
purple : ( base: #8130c9 ),
orange : ( base: #f47725 ),
social: (
twitter : #5ea9dd,
hackernews : #ff6600,
reddit : #ff4500,
producthunt : #da552f,
github : #000000,
linkedin : #0077b5,
facebook : #3b5999,
medium : #02b875,
),
);
// Icons
$icons: (
website : '\1f310',
search : '\1f50d',
feed : '\1f525',
quote : '\275d',
twitter : '\e900',
github : '\e901',
producthunt : '\e902',
linkedin : '\e903',
hackernews : '\e904',
reddit : '\e905',
facebook : '\e906',
medium : '\e907',
codepen : '\e908',
dash : '\2014',
bullet : '\2022',
menu : '\2261',
close : '\2715',
copyright : '\00a9',
permalink : '\0023',
);

View File

@ -0,0 +1,42 @@
// displaCy Custom Visualization - Variables
// ============================================================================
$displacy-classes: ( bad: color(red), good: color(green), highlight: color(yellow), lowlight: color(grey, dark) )
$displacy-word-margin : 3rem
// displaCy Custom Visualization - Style
// ============================================================================
// displaCy visualization (refers to exports from displaCy v1)
// .word - token container
// .word span - word
// .arrow:before - arrow label
// .word:after - part-of-speech tag
// .arrow.#{$displacy-class}:before - arrow with special styling
// .arrow.#{$displacy-class}:after - arrow head with special styling
// .word.#{$displacy-class} span - word with special styling
// $displacy-classes - refers to $displacy-classes in settings
#displacy
width: 100%
.word
margin-top: $displacy-word-margin
.word span
@extend .h4
.arrow:before,
.word:after
@extend .text-label
@each $displacy-class, $displacy-color in $displacy-classes
.arrow.#{$displacy-class}:before
border-color: $displacy-color
.arrow.#{$displacy-class}:after
border-top-color: $displacy-color
.word.#{$displacy-class} span
color: $displacy-color

View File

@ -0,0 +1,181 @@
// Normalize
// ============================================================================
// adapted from normalize.css, https://github.com/necolas/normalize.css
html
font-family: sans-serif
-ms-text-size-adjust: 100%
-webkit-text-size-adjust: 100%
body
margin: 0
article,
aside,
details,
figcaption,
figure,
footer,
header,
main,
menu,
nav,
section,
summary
display: block
audio,
canvas,
progress,
video
display: inline-block
vertical-align: baseline
audio:not([controls])
display: none
height: 0
[hidden],
template
display: none
a
background-color: transparent
a:active,
a:hover
outline: 0
abbr[title]
border-bottom: none
text-decoration: underline
text-decoration: underline dotted
b,
strong
font-weight: inherit
b,
strong
font-weight: bolder
dfn
font-style: italic
h1
font-size: 2em
margin: 0.67em 0
mark
background-color: #ff0
color: #000
small
font-size: 80%
sub,
sup
font-size: 75%
line-height: 0
position: relative
vertical-align: baseline
sup
top: -0.5em
sub
bottom: -0.25em
img
border: 0
svg:not(:root)
overflow: hidden
figure
margin: 1em 40px
hr
box-sizing: content-box
height: 0
overflow: visible
pre
overflow: auto
code,
kbd,
pre,
samp
font-family: monospace, monospace
font-size: 1em
button,
input,
optgroup,
select,
textarea
font: inherit
margin: 0
button
overflow: visible
button,
select
text-transform: none
button,
html input[type="button"],
input[type="reset"],
input[type="submit"]
-webkit-appearance: button
cursor: pointer
button[disabled],
html input[disabled]
cursor: default
input,
button
&::-moz-focus-inner
border: 0
padding: 0
&:-moz-focusring
outline: 1px dotted ButtonText
input
line-height: normal
&[type="checkbox"],
&[type="radio"]
box-sizing: border-box
padding: 0
&[type="number"]::-webkit-inner-spin-button,
&[type="number"]::-webkit-outer-spin-button
height: auto
&[type="search"]
-webkit-appearance: textfield
&[type="search"]::-webkit-search-cancel-button,
&[type="search"]::-webkit-search-decoration
-webkit-appearance: none
fieldset
border: 1px solid #c0c0c0
margin: 0 2px
padding: 0.35em 0.625em 0.75em
legend
border: 0
padding: 0
textarea
overflow: auto
optgroup
font-weight: bold

View File

@ -0,0 +1,77 @@
// prism.js Syntax Highlighting
// ============================================================================
// Commment, prolog, doctype, CDATA, punctuation
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata,
.token.punctuation
color: color(grey, dark)
// Property, tag, constant, symbol, deleted
.token.property,
.token.tag,
.token.constant,
.token.symbol,
.token.deleted
color: color(green)
// Boolean, number
.token.boolean,
.token.number
color: color(purple)
// Selector, attribute name, string, char, built in, inserted
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted
color: color(blue)
// Operator, entity, URL, CSS string, variable
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string,
.token.variable
color: color(red)
// @-rule, attribute value, function
.token.atrule,
.token.attr-value,
.token.function
color: color(blue)
// Keyword
.token.keyword
color: color(red)
// Regex, important
.token.regex,
.token.important
color: color(yellow)
// Italic
.token.italic
font-style: italic

View File

@ -0,0 +1,60 @@
// Style
// ============================================================================
// Variables
@import variables
// Utilities
@import _utils/functions
@import _utils/mixins
// Base
@import _base/animations
@import _base/fonts
@import _base/reset
@import _base/grid
@import _base/typography
// Layout
@import _layout/article
@import _layout/body
@import _layout/footer
@import _layout/header
@import _layout/nav
@import _layout/sidebar
// Components
@import _components/alerts
@import _components/asides
@import _components/boxes
@import _components/buttons
@import _components/cards
@import _components/code
@import _components/dividers
@import _components/embeds
@import _components/forms
@import _components/icons
@import _components/links
@import _components/logo
@import _components/images
@import _components/labels
@import _components/lists
@import _components/misc
@import _components/quotes
@import _components/tables
@import _components/tooltips
// Vendors
@import _vendors/prism
@import _vendors/displacy

View File

@ -0,0 +1,6 @@
// Style Blog
// ============================================================================
$theme: red
@import style

Binary file not shown.

View File

@ -0,0 +1,27 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Generated by IcoMoon</metadata>
<defs>
<font id="icomoon" horiz-adv-x="1024">
<font-face units-per-em="1024" ascent="960" descent="-64" />
<missing-glyph horiz-adv-x="1024" />
<glyph unicode="&#x20;" horiz-adv-x="512" d="" />
<glyph unicode="&#x23;" glyph-name="link" d="M440.236 324.234c-13.31 0-26.616 5.076-36.77 15.23-95.134 95.136-95.134 249.934 0 345.070l192 192c46.088 46.086 107.36 71.466 172.534 71.466s126.448-25.38 172.536-71.464c95.132-95.136 95.132-249.934 0-345.070l-87.766-87.766c-20.308-20.308-53.23-20.308-73.54 0-20.306 20.306-20.306 53.232 0 73.54l87.766 87.766c54.584 54.586 54.584 143.404 0 197.99-26.442 26.442-61.6 41.004-98.996 41.004s-72.552-14.562-98.996-41.006l-192-191.998c-54.586-54.586-54.586-143.406 0-197.992 20.308-20.306 20.306-53.232 0-73.54-10.15-10.152-23.462-15.23-36.768-15.23zM256-52c-65.176 0-126.45 25.38-172.534 71.464-95.134 95.136-95.134 249.934 0 345.070l87.764 87.764c20.308 20.306 53.234 20.306 73.54 0 20.308-20.306 20.308-53.232 0-73.54l-87.764-87.764c-54.586-54.586-54.586-143.406 0-197.992 26.44-26.44 61.598-41.002 98.994-41.002s72.552 14.562 98.998 41.006l192 191.998c54.584 54.586 54.584 143.406 0 197.992-20.308 20.308-20.306 53.232 0 73.54 20.306 20.306 53.232 20.306 73.54-0.002 95.132-95.134 95.132-249.932 0.002-345.068l-192.002-192c-46.090-46.088-107.364-71.466-172.538-71.466z" />
<glyph unicode="&#x2022;" glyph-name="Bullet" d="M768 426.667c0 70.699-28.672 134.699-74.965 181.035-46.336 46.293-110.336 74.965-181.035 74.965-70.656 0-134.656-28.672-180.992-74.965-46.336-46.336-75.008-110.336-75.008-181.035 0-70.656 28.672-134.656 75.008-180.992s110.336-75.008 180.992-75.008c70.699 0 134.699 28.672 181.035 75.008 46.293 46.336 74.965 110.336 74.965 180.992z" />
<glyph unicode="&#x2261;" glyph-name="menu" d="M128 725.334h768q17.667 0 30.167-12.5t12.5-30.167-12.5-30.167-30.167-12.5h-768q-17.667 0-30.167 12.5t-12.5 30.167 12.5 30.167 30.167 12.5zM128 213.334h768q17.667 0 30.167-12.5t12.5-30.167-12.5-30.167-30.167-12.5h-768q-17.667 0-30.167 12.5t-12.5 30.167 12.5 30.167 30.167 12.5zM128 469.334h768q17.667 0 30.167-12.5t12.5-30.167-12.5-30.167-30.167-12.5h-768q-17.667 0-30.167 12.5t-12.5 30.167 12.5 30.167 30.167 12.5z" />
<glyph unicode="&#x2715;" glyph-name="cross" d="M810.667 768q18.333 0 30.5-12.167t12.167-30.5q0-18-12.333-30.333l-268.667-268.333 268.667-268.333q12.333-12.333 12.333-30.333 0-18.333-12.167-30.5t-30.5-12.167q-18 0-30.333 12.333l-268.333 268.667-268.333-268.667q-12.333-12.333-30.333-12.333-18.333 0-30.5 12.167t-12.167 30.5q0 18 12.333 30.333l268.667 268.333-268.667 268.333q-12.333 12.333-12.333 30.333 0 18.333 12.167 30.5t30.5 12.167q18 0 30.333-12.333l268.333-268.667 268.333 268.667q12.333 12.333 30.333 12.333z" />
<glyph unicode="&#x275d;" glyph-name="Quote" d="M1024 64v384h-256c0 141.12 114.752 256 256 256v128c-211.744 0-384-172.256-384-384v-384h384zM384 64v384h-256c0 141.12 114.752 256 256 256v128c-211.744 0-384-172.256-384-384v-384h384z" />
<glyph unicode="&#xe900;" glyph-name="Twitter" d="M1024 733.6c-37.6-16.8-78.2-28-120.6-33 43.4 26 76.6 67.2 92.4 116.2-40.6-24-85.6-41.6-133.4-51-38.4 40.8-93 66.2-153.4 66.2-116 0-210-94-210-210 0-16.4 1.8-32.4 5.4-47.8-174.6 8.8-329.4 92.4-433 219.6-18-31-28.4-67.2-28.4-105.6 0-72.8 37-137.2 93.4-174.8-34.4 1-66.8 10.6-95.2 26.2 0-0.8 0-1.8 0-2.6 0-101.8 72.4-186.8 168.6-206-17.6-4.8-36.2-7.4-55.4-7.4-13.6 0-26.6 1.4-39.6 3.8 26.8-83.4 104.4-144.2 196.2-146-72-56.4-162.4-90-261-90-17 0-33.6 1-50.2 3 93.2-59.8 203.6-94.4 322.2-94.4 386.4 0 597.8 320.2 597.8 597.8 0 9.2-0.2 18.2-0.6 27.2 41 29.4 76.6 66.4 104.8 108.6z" />
<glyph unicode="&#xe901;" glyph-name="Github" d="M512.008 947.358c-282.738 0-512.008-229.218-512.008-511.998 0-226.214 146.704-418.132 350.136-485.836 25.586-4.738 34.992 11.11 34.992 24.632 0 12.204-0.48 52.542-0.696 95.324-142.448-30.976-172.504 60.41-172.504 60.41-23.282 59.176-56.848 74.916-56.848 74.916-46.452 31.778 3.51 31.124 3.51 31.124 51.4-3.61 78.476-52.766 78.476-52.766 45.672-78.27 119.776-55.64 149.004-42.558 4.588 33.086 17.852 55.68 32.506 68.464-113.73 12.942-233.276 56.85-233.276 253.032 0 55.898 20.004 101.574 52.76 137.428-5.316 12.9-22.854 64.972 4.952 135.5 0 0 43.006 13.752 140.84-52.49 40.836 11.348 84.636 17.036 128.154 17.234 43.502-0.198 87.336-5.886 128.256-17.234 97.734 66.244 140.656 52.49 140.656 52.49 27.872-70.528 10.35-122.6 5.036-135.5 32.82-35.856 52.694-81.532 52.694-137.428 0-196.654-119.778-239.95-233.79-252.624 18.364-15.89 34.724-47.046 34.724-94.812 0-68.508-0.596-123.644-0.596-140.508 0-13.628 9.222-29.594 35.172-24.566 203.322 67.776 349.842 259.626 349.842 485.768 0 282.78-229.234 511.998-511.992 511.998z" />
<glyph unicode="&#xe902;" glyph-name="product-hunt" d="M657.143 515.428q0-32-22.571-54.286t-54.571-22.286h-144.571v153.714h144.571q32 0 54.571-22.571t22.571-54.571zM759.429 515.428q0 74.286-52.286 126.857t-127.143 52.571h-247.429v-512h102.857v153.714h144.571q74.286 0 126.857 52.286t52.571 126.571zM1024 438.857q0-104-40.571-198.857t-109.143-163.429-163.429-109.143-198.857-40.571-198.857 40.571-163.429 109.143-109.143 163.429-40.571 198.857 40.571 198.857 109.143 163.429 163.429 109.143 198.857 40.571 198.857-40.571 163.429-109.143 109.143-163.429 40.571-198.857z" />
<glyph unicode="&#xe903;" glyph-name="linkedin-square" horiz-adv-x="878" d="M135.429 142.857h132v396.571h-132v-396.571zM276 661.714q-0.571 29.714-20.571 49.143t-53.143 19.429-54-19.429-20.857-49.143q0-29.143 20.286-48.857t52.857-19.714h0.571q33.714 0 54.286 19.714t20.571 48.857zM610.286 142.857h132v227.429q0 88-41.714 133.143t-110.286 45.143q-77.714 0-119.429-66.857h1.143v57.714h-132q1.714-37.714 0-396.571h132v221.714q0 21.714 4 32 8.571 20 25.714 34t42.286 14q66.286 0 66.286-89.714v-212zM877.714 713.143v-548.571q0-68-48.286-116.286t-116.286-48.286h-548.571q-68 0-116.286 48.286t-48.286 116.286v548.571q0 68 48.286 116.286t116.286 48.286h548.571q68 0 116.286-48.286t48.286-116.286z" />
<glyph unicode="&#xe904;" glyph-name="Hacker-News" horiz-adv-x="878" d="M462.286 386.286l152 285.143h-64l-89.714-178.286q-13.714-27.429-25.143-52.571l-24 52.571-88.571 178.286h-68.571l150.286-281.714v-185.143h57.714v181.714zM877.714 722.286v-548.571q0-68-48.286-116.286t-116.286-48.286h-548.571q-68 0-116.286 48.286t-48.286 116.286v548.571q0 68 48.286 116.286t116.286 48.286h548.571q68 0 116.286-48.286t48.286-116.286z" />
<glyph unicode="&#xe905;" glyph-name="reddit" d="M256 310.857c0 35.346 28.654 64 64 64s64-28.654 64-64c0-35.346-28.654-64-64-64s-64 28.654-64 64zM640 310.857c0 35.346 28.654 64 64 64s64-28.654 64-64c0-35.346-28.654-64-64-64s-64 28.654-64 64zM643.112 174.079c16.482 12.986 40.376 10.154 53.364-6.332s10.152-40.378-6.334-53.366c-45.896-36.158-115.822-59.524-178.142-59.524-62.322 0-132.248 23.366-178.144 59.522-16.486 12.99-19.32 36.882-6.332 53.368 12.99 16.482 36.882 19.318 53.366 6.332 26.422-20.818 78.722-43.222 131.11-43.222s104.688 22.404 131.112 43.222zM1024 438.857c0 70.692-57.308 128-128 128-48.116 0-89.992-26.57-111.852-65.82-65.792 35.994-145.952 59.246-233.28 64.608l76.382 171.526 146.194-42.2c13.152-37.342 48.718-64.114 90.556-64.114 53.020 0 96 42.98 96 96s-42.98 96-96 96c-36.56 0-68.342-20.442-84.554-50.514l-162.906 47.024c-18.224 5.258-37.538-3.722-45.252-21.052l-103.77-233.026c-85.138-5.996-163.262-29.022-227.636-64.236-21.864 39.25-63.766 65.804-111.882 65.804-70.692 0-128-57.308-128-128 0-52.312 31.402-97.254 76.372-117.102-8.070-24.028-12.372-49.104-12.372-74.898 0-176.73 200.576-320 448-320 247.422 0 448 143.27 448 320 0 25.792-4.3 50.862-12.368 74.886 44.97 19.85 76.368 64.802 76.368 117.114zM864 762.857c19.882 0 36-16.118 36-36s-16.118-36-36-36-36 16.118-36 36 16.118 36 36 36zM64 438.857c0 35.29 28.71 64 64 64 25.508 0 47.572-15.004 57.846-36.646-33.448-25.366-61.166-54.626-81.666-86.738-23.524 9.47-40.18 32.512-40.18 59.384zM512 2.857c-205.45 0-372 109.242-372 244s166.55 244 372 244c205.45 0 372-109.242 372-244s-166.55-244-372-244zM919.82 379.473c-20.5 32.112-48.218 61.372-81.666 86.738 10.276 21.642 32.338 36.646 57.846 36.646 35.29 0 64-28.71 64-64 0-26.872-16.656-49.914-40.18-59.384z" />
<glyph unicode="&#xe906;" glyph-name="Facebook" horiz-adv-x="878" d="M713.143 877.714q68 0 116.286-48.286t48.286-116.286v-548.571q0-68-48.286-116.286t-116.286-48.286h-107.429v340h113.714l17.143 132.571h-130.857v84.571q0 32 13.429 48t52.286 16l69.714 0.571v118.286q-36 5.143-101.714 5.143-77.714 0-124.286-45.714t-46.571-129.143v-97.714h-114.286v-132.571h114.286v-340h-304q-68 0-116.286 48.286t-48.286 116.286v548.571q0 68 48.286 116.286t116.286 48.286h548.571z" />
<glyph unicode="&#xe907;" glyph-name="Medium" d="M341.143 710.286v-670.286q0-14.286-7.143-24.286t-20.857-10q-9.714 0-18.857 4.571l-265.714 133.143q-12 5.714-20.286 19.143t-8.286 26.571v651.429q0 11.429 5.714 19.429t16.571 8q8 0 25.143-8.571l292-146.286q1.714-1.714 1.714-2.857zM377.714 652.571l305.143-494.857-305.143 152v342.857zM1024 642.286v-602.286q0-14.286-8-23.143t-21.714-8.857-26.857 7.429l-252 125.714zM1022.286 710.857q0-1.714-146.571-239.714t-171.714-278.571l-222.857 362.286 185.143 301.143q9.714 16 29.714 16 8 0 14.857-3.429l309.143-154.286q2.286-1.143 2.286-3.429z" />
<glyph unicode="&#xe908;" glyph-name="codepen" d="M945.75 582.815l-448 298.666c-10.748 7.166-24.752 7.166-35.5 0l-448-298.666c-8.902-5.934-14.25-15.926-14.25-26.624v-298.666c0-10.7 5.348-20.692 14.25-26.624l448-298.666c5.374-3.584 11.562-5.376 17.75-5.376s12.376 1.792 17.75 5.376l448 298.666c8.902 5.934 14.25 15.926 14.25 26.624v298.666c0 10.698-5.348 20.69-14.25 26.624zM480 295.981l-166.312 110.876 166.312 110.874 166.312-110.874-166.312-110.876zM512 573.315v221.75l358.31-238.876-166.31-110.874-192 128zM448 573.315l-192-128-166.312 110.874 358.312 238.876v-221.75zM198.312 406.857l-134.312-89.542v179.082l134.312-89.54zM256 368.399l192-128v-221.748l-358.312 238.872 166.312 110.876zM512 240.399l192 128 166.312-110.876-358.312-238.874v221.75zM761.688 406.857l134.312 89.54v-179.084l-134.312 89.544z" />
<glyph unicode="&#x1f310;" glyph-name="Globe" d="M480 896c-265.096 0-480-214.904-480-480 0-265.098 214.904-480 480-480 265.098 0 480 214.902 480 480 0 265.096-214.902 480-480 480zM751.59 256c8.58 40.454 13.996 83.392 15.758 128h127.446c-3.336-44.196-13.624-87.114-30.68-128h-112.524zM208.41 576c-8.58-40.454-13.996-83.392-15.758-128h-127.444c3.336 44.194 13.622 87.114 30.678 128h112.524zM686.036 576c9.614-40.962 15.398-83.854 17.28-128h-191.316v128h174.036zM512 640v187.338c14.59-4.246 29.044-11.37 43.228-21.37 26.582-18.74 52.012-47.608 73.54-83.486 14.882-24.802 27.752-52.416 38.496-82.484h-155.264zM331.232 722.484c21.528 35.878 46.956 64.748 73.54 83.486 14.182 10 28.638 17.124 43.228 21.37v-187.34h-155.264c10.746 30.066 23.616 57.68 38.496 82.484zM448 576v-128h-191.314c1.88 44.146 7.666 87.038 17.278 128h174.036zM95.888 256c-17.056 40.886-27.342 83.804-30.678 128h127.444c1.762-44.608 7.178-87.546 15.758-128h-112.524zM256.686 384h191.314v-128h-174.036c-9.612 40.96-15.398 83.854-17.278 128zM448 192v-187.34c-14.588 4.246-29.044 11.372-43.228 21.37-26.584 18.74-52.014 47.61-73.54 83.486-14.882 24.804-27.75 52.418-38.498 82.484h155.266zM628.768 109.516c-21.528-35.876-46.958-64.746-73.54-83.486-14.184-9.998-28.638-17.124-43.228-21.37v187.34h155.266c-10.746-30.066-23.616-57.68-38.498-82.484zM512 256v128h191.314c-1.88-44.146-7.666-87.040-17.28-128h-174.034zM767.348 448c-1.762 44.608-7.178 87.546-15.758 128h112.524c17.056-40.886 27.344-83.806 30.68-128h-127.446zM830.658 640h-95.9c-18.638 58.762-44.376 110.294-75.316 151.428 42.536-20.34 81.058-47.616 114.714-81.272 21.48-21.478 40.362-44.938 56.502-70.156zM185.844 710.156c33.658 33.658 72.18 60.932 114.714 81.272-30.942-41.134-56.676-92.666-75.316-151.428h-95.898c16.138 25.218 35.022 48.678 56.5 70.156zM129.344 192h95.898c18.64-58.762 44.376-110.294 75.318-151.43-42.536 20.34-81.058 47.616-114.714 81.274-21.48 21.478-40.364 44.938-56.502 70.156zM774.156 121.844c-33.656-33.658-72.18-60.934-114.714-81.274 30.942 41.134 56.678 92.668 75.316 151.43h95.9c-16.14-25.218-35.022-48.678-56.502-70.156z" />
<glyph unicode="&#x1f50d;" glyph-name="Search" d="M426.667 896q78 0 149.167-30.5t122.5-81.833 81.833-122.5 30.5-149.167q0-67-21.833-128.333t-62.167-111.333l242.333-242q12.333-12.333 12.333-30.333 0-18.333-12.167-30.5t-30.5-12.167q-18 0-30.333 12.333l-242 242.333q-50-40.333-111.333-62.167t-128.333-21.833q-78 0-149.167 30.5t-122.5 81.833-81.833 122.5-30.5 149.167 30.5 149.167 81.833 122.5 122.5 81.833 149.167 30.5zM426.667 810.667q-60.667 0-116-23.667t-95.333-63.667-63.667-95.333-23.667-116 23.667-116 63.667-95.333 95.333-63.667 116-23.667 116 23.667 95.333 63.667 63.667 95.333 23.667 116-23.667 116-63.667 95.333-95.333 63.667-116 23.667z" />
<glyph unicode="&#x1f525;" glyph-name="feed" horiz-adv-x="805" d="M219.429 182.857q0-45.714-32-77.714t-77.714-32-77.714 32-32 77.714 32 77.714 77.714 32 77.714-32 32-77.714zM512 112.571q1.143-16-9.714-27.429-10.286-12-26.857-12h-77.143q-14.286 0-24.571 9.429t-11.429 23.714q-12.571 130.857-105.429 223.714t-223.714 105.429q-14.286 1.143-23.714 11.429t-9.429 24.571v77.143q0 16.571 12 26.857 9.714 9.714 24.571 9.714h2.857q91.429-7.429 174.857-46t148-103.714q65.143-64.571 103.714-148t46-174.857zM804.571 111.428q1.143-15.429-10.286-26.857-10.286-11.429-26.286-11.429h-81.714q-14.857 0-25.429 10t-11.143 24.286q-6.857 122.857-57.714 233.429t-132.286 192-192 132.286-233.429 58.286q-14.286 0.571-24.286 11.143t-10 24.857v81.714q0 16 11.429 26.286 10.286 10.286 25.143 10.286h1.714q149.714-7.429 286.571-68.571t243.143-168q106.857-106.286 168-243.143t68.571-286.571z" />
</font></defs></svg>

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

2787
website/assets/fonts/lato-bold.svg Executable file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 197 KiB

Some files were not shown because too many files have changed in this diff Show More