Full Code of Pythonity/icon-font-to-png for AI

master 4851fe15c077 cached
26 files
86.3 KB
26.4k tokens
44 symbols
1 requests
Download .txt
Repository: Pythonity/icon-font-to-png
Branch: master
Commit: 4851fe15c077
Files: 26
Total size: 86.3 KB

Directory structure:
gitextract_vzb55rlz/

├── .gitignore
├── .travis.yml
├── LICENSE
├── MANIFEST.in
├── README.md
├── _config.yml
├── bin/
│   ├── font-awesome-to-png
│   └── icon-font-to-png
├── icon_font_to_png/
│   ├── __init__.py
│   ├── command_line.py
│   ├── icon_font.py
│   ├── icon_font_downloader.py
│   └── test/
│       ├── files/
│       │   ├── font-awesome.css
│       │   ├── octicons.css
│       │   ├── test-foo.css
│       │   └── test.css
│       ├── test_command_line.py
│       ├── test_font_awesome.py
│       ├── test_icon_font.py
│       ├── test_icon_font_downloader.py
│       └── test_octicons.py
├── requirements/
│   ├── common.txt
│   └── dev.txt
├── requirements.txt
├── setup.py
└── tox.ini

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Created by https://www.gitignore.io/api/python,pycharm,osx

### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# dotenv
.env

# virtualenv
.venv/
venv/
ENV/

# Spyder project settings
.spyderproject

# Rope project settings
.ropeproject


### PyCharm ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839

# User-specific stuff:
.idea/workspace.xml
.idea/tasks.xml

# Sensitive or high-churn files:
.idea/dataSources/
.idea/dataSources.ids
.idea/dataSources.xml
.idea/dataSources.local.xml
.idea/sqlDataSources.xml
.idea/dynamic.xml
.idea/uiDesigner.xml

# Gradle:
.idea/gradle.xml
.idea/libraries

# Mongo Explorer plugin:
.idea/mongoSettings.xml

## File-based project format:
*.iws

## Plugin-specific files:

# IntelliJ
/out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

### PyCharm Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721

# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr


### OSX ###
*.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

# End of https://www.gitignore.io/api/python,pycharm,osx


================================================
FILE: .travis.yml
================================================
language: python

python:
  - "2.7"
  - "3.4"
  - "3.5"
  - "3.6"

install:
  - pip install -r requirements/dev.txt
  - pip install tox-travis

script:
  - tox
  - coverage run --source icon_font_to_png -m py.test
  - coverage report -m

after_success:
  - coveralls


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2016-2017 Pythonity

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: MANIFEST.in
================================================
include *.md
include *.txt
include *.yml
include LICENSE
include tox.ini
recursive-include icon_font_to_png *.css
recursive-include icon_font_to_png *.png
recursive-include icon_font_to_png *.py
recursive-include icon_font_to_png *.ttf
recursive-include requirements *.txt


================================================
FILE: README.md
================================================
# Icon Font to PNG
[![Build status](https://img.shields.io/travis/Pythonity/icon-font-to-png.svg)][travis]
[![Test coverage](https://img.shields.io/coveralls/Pythonity/icon-font-to-png.svg)][coveralls]
[![PyPI version](https://img.shields.io/pypi/v/icon_font_to_png.svg)][pypi]
[![Python versions](https://img.shields.io/pypi/pyversions/icon_font_to_png.svg)][pypi]
[![License](https://img.shields.io/github/license/Pythonity/icon-font-to-png.svg)][license]

Python script (and library) for easy and simple export of icons from web
icon fonts (e.g. Font Awesome, Octicons) as PNG images. The best part is
the provided shell script, but you can also use it's functionality
directly in your (*probably awesome*) Python project.

There's also `font-awesome-to-png` script for backwards compatibility
with the [first][odyniec fa2p] iteration of the concept.

## Installation
Make sure you have required packages for [Pillow installation][pillow].

From PyPI (recommended):

```
$ pip install icon_font_to_png
```

With `git clone`:

```shell
$ git clone https://github.com/Pythonity/icon-font-to-png
$ pip install -r icon-font-to-png/requirements.txt
$ cd icon-font-to-png/bin
```

### OS X
As reported [here][if2p osx bug], to install it on OS X:

```
$ pip install icon_font_to_png --ignore-installed six
```

## Usage

```
usage: icon-font-to-png [-h] [--list] [--download {font-awesome,octicons}]
                        [--ttf TTF-FILE] [--css CSS-FILE] [--size SIZE]
                        [--scale SCALE] [--color COLOR] [--filename FILENAME]
                        [--keep_prefix]
                        [icons [icons ...]]

Exports font icons as PNG images.

optional arguments:
  -h, --help            show this help message and exit
  --list                list all available icon names and exit
  --download {font-awesome,octicons}
                        download latest icon font and exit

required arguments:
  --ttf TTF-FILE        path to TTF file
  --css CSS-FILE        path to CSS file

exporting icons:
  icons                 names of the icons to export (or 'ALL' for all icons)
  --size SIZE           icon size in pixels (default: 16)
  --scale SCALE         scaling factor between 0 and 1, or 'auto' for
                        automatic scaling (default: auto); be careful, as
                        setting it may lead to icons being cropped
  --color COLOR         color name or hex value (default: black)
  --filename FILENAME   name of the output file (without '.png' extension);
                        it's used as a prefix if multiple icons are exported
  --keep_prefix         do not remove common icon prefix (i.e. 'fa-arrow-
                        right' instead of 'arrow-right')

```

## Examples
Download latest Font Awesome:

```
$ icon-font-to-png --download font-awesome
```

List all available icons:

```
$ icon-font-to-png --css font-awesome.css --ttf fontawesome-webfont.ttf --list
```

Export 'play' and 'stop' icons, size 64x64:

```
$ icon-font-to-png --css font-awesome.css --ttf fontawesome-webfont.ttf --size 64 play stop
```

Export all icons in blue:

```
$ icon-font-to-png --css font-awesome.css --ttf fontawesome-webfont.ttf --color blue ALL
```

Export all icons in blue, but using it's hex value:

```
$ icon-font-to-png --css font-awesome.css --ttf fontawesome-webfont.ttf --color '#0000ff' ALL
```

Or you can use `font-awesome-to-png`, without css and ttf arguments:

```
$ font-awesome-to-png ALL
```

## API
You can use `IconFont` (and `IconFontDownloader` for that matter)
directly inside your Python project. There's no proper documentation as of now,
but the code is commented and *should* be pretty straightforward to use.

That said - feel free to ask me via [email](mailto:pawel.ad@gmail.com) or 
[GitHub issues][github add issue] if anything is unclear.

## Tests
Package was tested with the help of `py.test` and `tox` on Python 2.7, 3.4, 3.5
and 3.6 (see `tox.ini`).

Code coverage is available at [Coveralls][coveralls].

To run tests yourself you need to run `tox` inside the repository:

```shell
$ pip install -r requirements/dev.txt
$ tox
```

## Contributions
Package source code is available at [GitHub][github].

Feel free to use, ask, fork, star, report bugs, fix them, suggest enhancements,
add functionality and point out any mistakes. Thanks!

## Authors
Developed and maintained by [Pythonity][pythonity], a group of Python enthusiasts who love open source, have a neat [blog][pythonity blog] and are available [for hire][pythonity].

Original version by [Michał Wojciechowski][odyniec], refactored by 
[Paweł Adamczak][pawelad].


[coveralls]: https://coveralls.io/github/Pythonity/icon-font-to-png
[github]: https://github.com/Pythonity/icon-font-to-png
[github add issue]: https://github.com/Pythonity/icon-font-to-png/issues/new
[if2p osx bug]: https://github.com/Pythonity/icon-font-to-png/issues/2#issuecomment-197068427
[license]: https://github.com/Pythonity/icon-font-to-png/blob/master/LICENSE
[odyniec]: https://github.com/odyniec
[odyniec fa2p]: https://github.com/odyniec/font-awesome-to-png
[pawelad]: https://github.com/pawelad
[pillow]: https://pillow.readthedocs.org/en/latest/installation.html
[pypi]: https://pypi.python.org/pypi/icon_font_to_png
[pythonity]: https://pythonity.com/
[pythonity blog]: http://blog.pythonity.com/
[travis]: https://travis-ci.org/Pythonity/icon-font-to-png


================================================
FILE: _config.yml
================================================
theme: jekyll-theme-leap-day

gems:
  - jekyll-default-layout
  - jekyll-optional-front-matter
  - jekyll-readme-index
  - jekyll-titles-from-headings


================================================
FILE: bin/font-awesome-to-png
================================================
#!/usr/bin/env python

import os
import sys

try:
    # Installed system wide
    from icon_font_to_png import command_line
except ImportError:
    # Locally
    sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
    from icon_font_to_png import command_line


if __name__ == '__main__':
    # TODO: Download only once, and load after?
    # Download Font Awesome to temp directory
    font_awesome = command_line.download_icon_font('font-awesome',
                                                   directory=None)

    # Append paths to Font Awesome files
    args = sys.argv[1:]
    args.append('--css')
    args.append(font_awesome.css_path)
    args.append('--ttf')
    args.append(font_awesome.ttf_path)

    # Execute original script
    command_line.run(args)


================================================
FILE: bin/icon-font-to-png
================================================
#!/usr/bin/env python

import os
import sys

try:
    # Installed system wide
    from icon_font_to_png import command_line
except ImportError:
    # Locally
    sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
    from icon_font_to_png import command_line


if __name__ == '__main__':
    command_line.run(sys.argv[1:])


================================================
FILE: icon_font_to_png/__init__.py
================================================
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals

from icon_font_to_png.icon_font import IconFont  # noqa
from icon_font_to_png.icon_font_downloader import (  # noqa
    FontAwesomeDownloader, OcticonsDownloader, AVAILABLE_ICON_FONTS
)


__version__ = '0.4.1'


================================================
FILE: icon_font_to_png/command_line.py
================================================
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals, print_function

import os
import argparse

from icon_font_to_png import IconFont, AVAILABLE_ICON_FONTS


def run(arguments):
    """Main function for command line usage"""
    parser = argparse.ArgumentParser(
        description="Exports font icons as PNG images."
    )
    parser.add_argument(
        '--list',
        action='store_true',
        help="list all available icon names and exit"
    )
    parser.add_argument(
        '--download',
        choices=[x for x in AVAILABLE_ICON_FONTS.keys()],
        help="download latest icon font and exit"
    )

    required_group = parser.add_argument_group("required arguments")
    required_group.add_argument(
        '--ttf',
        metavar='TTF-FILE',
        type=open,
        help='path to TTF file'
    )
    required_group.add_argument(
        '--css',
        metavar='CSS-FILE',
        type=open,
        help="path to CSS file"
    )

    exp_group = parser.add_argument_group("exporting icons")
    exp_group.add_argument(
        'icons',
        type=str,
        nargs='*',
        help="names of the icons to export (or 'ALL' for all icons)"
    )
    exp_group.add_argument(
        '--size',
        type=int,
        default=16,
        help="icon size in pixels (default: 16)"
    )
    exp_group.add_argument(
        '--scale',
        type=str,
        default='auto',
        help="scaling factor between 0 and 1, or 'auto' for automatic scaling "
             "(default: auto); be careful, as setting it may lead to icons "
             "being cropped"
    )
    exp_group.add_argument(
        '--color',
        type=str,
        default='black',
        help="color name or hex value (default: black)"
    )
    exp_group.add_argument(
        '--filename',
        type=str,
        help="name of the output file (without '.png' extension); "
             "it's used as a prefix if multiple icons are exported"
    )
    exp_group.add_argument(
        '--keep_prefix',
        default=False,
        action='store_true',
        help="do not remove common icon prefix "
             "(i.e. 'fa-arrow-right' instead of 'arrow-right')"
    )

    args = parser.parse_args(arguments)

    # Parse '--download' argument first
    if args.download:
        downloader = download_icon_font(args.download, os.getcwd())
        downloader.download_files()
        print("Icon font '{name}' successfully downloaded".format(
            name=args.download)
        )
        parser.exit()

    # If not '--download', then css and tff files are required
    if not args.css or not args.ttf:
        parser.error("You have to provide CSS and TTF files")

    icon_font = IconFont(css_file=args.css.name,
                         ttf_file=args.ttf.name,
                         keep_prefix=args.keep_prefix)
    args.css.close()
    args.ttf.close()

    # Then '--list'
    if args.list:
        for icon in icon_font.css_icons.keys():
            print(icon)
        parser.exit()

    # If not '--list' or '--download', parse passed icons
    selected_icons = list()
    if not args.icons:
        parser.error("You have to pass at least one icon name")
    elif args.icons == ['ALL']:
        selected_icons = icon_font.css_icons.keys()
    else:
        for icon in args.icons:
            if (args.keep_prefix and
                    not icon.startswith(icon_font.common_prefix)):
                # Prepend icon name with prefix
                icon = icon_font.common_prefix + icon
            elif (not args.keep_prefix and
                  icon.startswith(icon_font.common_prefix)):
                # Remove prefix from icon name
                icon = icon[len(icon_font.common_prefix):]

            # Check if given icon names exist
            if icon in icon_font.css_icons:
                selected_icons.append(icon)
            else:
                parser.error("Unknown icon name '{icon}'".format(icon=icon))

    # Parse filename and remove the extension if necessary
    given_filename = args.filename or ''
    if given_filename.lower().endswith('.png'):
        given_filename = given_filename[:-4]

    # Some fonts have empty values
    # (prefix only - which we remove - for common styles)
    selected_icons = list(filter(None, selected_icons))

    # Commence exporting
    for icon in selected_icons:
        if len(selected_icons) > 1:
            # Multiple icons - treat the filename option as name prefix
            filename = '{prefix}{icon}.png'.format(
                prefix=given_filename, icon=icon,
            )
        else:
            if given_filename:
                # Use the specified filename
                filename = given_filename + '.png'
            else:
                # Use icon name as filename
                filename = str(icon) + '.png'

        print("Exporting icon '{icon}' as '{filename}'"
              "({size}x{size} pixels)".format(icon=icon,
                                              filename=filename,
                                              size=args.size))

        icon_font.export_icon(icon=icon, filename=filename, size=args.size,
                              color=args.color, scale=args.scale)

    print()
    print("All done")


# Isolated for use in wrapper scripts
def download_icon_font(icon_font, directory):
    """Download given (implemented) icon font into passed directory"""
    try:
        downloader = AVAILABLE_ICON_FONTS[icon_font]['downloader'](directory)
        downloader.download_files()
        return downloader
    except KeyError:  # pragma: no cover
        raise Exception("We don't support downloading font '{name}'".format(
            name=icon_font)
        )


================================================
FILE: icon_font_to_png/icon_font.py
================================================
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals

import os
import re
from collections import OrderedDict

import tinycss
from PIL import Image, ImageFont, ImageDraw
from six import unichr


class IconFont(object):
    """Base class that represents web icon font"""
    def __init__(self, css_file, ttf_file, keep_prefix=False):
        """
        :param css_file: path to icon font CSS file
        :param ttf_file: path to icon font TTF file
        :param keep_prefix: whether to keep common icon prefix
        """
        self.css_file = css_file
        self.ttf_file = ttf_file
        self.keep_prefix = keep_prefix

        self.css_icons, self.common_prefix = self.load_css()

    def load_css(self):
        """
        Creates a dict of all icons available in CSS file, and finds out
        what's their common prefix.

        :returns sorted icons dict, common icon prefix
        """
        icons = dict()
        common_prefix = None
        parser = tinycss.make_parser('page3')
        stylesheet = parser.parse_stylesheet_file(self.css_file)

        is_icon = re.compile("\.(.*):before,?")

        for rule in stylesheet.rules:
            selector = rule.selector.as_css()

            # Skip CSS classes that are not icons
            if not is_icon.match(selector):
                continue

            # Find out what the common prefix is
            if common_prefix is None:
                common_prefix = selector[1:]
            else:
                common_prefix = os.path.commonprefix((common_prefix,
                                                      selector[1:]))

            for match in is_icon.finditer(selector):
                name = match.groups()[0]
                for declaration in rule.declarations:
                    if declaration.name == "content":
                        val = declaration.value.as_css()
                        # Strip quotation marks
                        if re.match("^['\"].*['\"]$", val):
                            val = val[1:-1]
                        icons[name] = unichr(int(val[1:], 16))

        common_prefix = common_prefix or ''

        # Remove common prefix
        if not self.keep_prefix and len(common_prefix) > 0:
            non_prefixed_icons = {}
            for name in icons.keys():
                non_prefixed_icons[name[len(common_prefix):]] = icons[name]
            icons = non_prefixed_icons

        sorted_icons = OrderedDict(sorted(icons.items(), key=lambda t: t[0]))

        return sorted_icons, common_prefix

    def export_icon(self, icon, size, color='black', scale='auto',
                    filename=None, export_dir='exported'):
        """
        Exports given icon with provided parameters.

        If the desired icon size is less than 150x150 pixels, we will first
        create a 150x150 pixels image and then scale it down, so that
        it's much less likely that the edges of the icon end up cropped.

        :param icon: valid icon name
        :param filename: name of the output file
        :param size: icon size in pixels
        :param color: color name or hex value
        :param scale: scaling factor between 0 and 1,
                      or 'auto' for automatic scaling
        :param export_dir: path to export directory
        """
        org_size = size
        size = max(150, size)

        image = Image.new("RGBA", (size, size), color=(0, 0, 0, 0))
        draw = ImageDraw.Draw(image)

        if scale == 'auto':
            scale_factor = 1
        else:
            scale_factor = float(scale)

        font = ImageFont.truetype(self.ttf_file, int(size * scale_factor))
        width, height = draw.textsize(self.css_icons[icon], font=font)

        # If auto-scaling is enabled, we need to make sure the resulting
        # graphic fits inside the boundary. The values are rounded and may be
        # off by a pixel or two, so we may need to do a few iterations.
        # The use of a decrementing multiplication factor protects us from
        # getting into an infinite loop.
        if scale == 'auto':
            iteration = 0
            factor = 1

            while True:
                width, height = draw.textsize(self.css_icons[icon], font=font)

                # Check if the image fits
                dim = max(width, height)
                if dim > size:
                    font = ImageFont.truetype(self.ttf_file,
                                              int(size * size/dim * factor))
                else:
                    break

                # Adjust the factor every two iterations
                iteration += 1
                if iteration % 2 == 0:
                    factor *= 0.99

        draw.text((float(size - width) / 2, float(size - height) / 2),
                  self.css_icons[icon], font=font, fill=color)

        # Get bounding box
        bbox = image.getbbox()

        # Create an alpha mask
        image_mask = Image.new("L", (size, size), 0)
        draw_mask = ImageDraw.Draw(image_mask)

        # Draw the icon on the mask
        draw_mask.text((float(size - width) / 2, float(size - height) / 2),
                       self.css_icons[icon], font=font, fill=255)

        # Create a solid color image and apply the mask
        icon_image = Image.new("RGBA", (size, size), color)
        icon_image.putalpha(image_mask)

        if bbox:
            icon_image = icon_image.crop(bbox)

        border_w = int((size - (bbox[2] - bbox[0])) / 2)
        border_h = int((size - (bbox[3] - bbox[1])) / 2)

        # Create output image
        out_image = Image.new("RGBA", (size, size), (0, 0, 0, 0))
        out_image.paste(icon_image, (border_w, border_h))

        # If necessary, scale the image to the target size
        if org_size != size:
            out_image = out_image.resize((org_size, org_size), Image.ANTIALIAS)

        # Make sure export directory exists
        if not os.path.exists(export_dir):
            os.makedirs(export_dir)

        # Default filename
        if not filename:
            filename = icon + '.png'

        # Save file
        out_image.save(os.path.join(export_dir, filename))


================================================
FILE: icon_font_to_png/icon_font_downloader.py
================================================
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals

import os
from abc import ABCMeta, abstractmethod

import requests
import six
from six.moves.urllib.request import urlretrieve


@six.add_metaclass(ABCMeta)
class IconFontDownloader(object):
    """Abstract class for downloading icon font CSS and TTF files"""
    css_path = None
    ttf_path = None

    @property
    def css_url(self):
        """Icon font CSS file URL"""
        raise NotImplementedError

    @property
    def ttf_url(self):
        """Icon font TTF file URL"""
        raise NotImplementedError

    def __init__(self, directory=None):
        """
        :param directory: path to download directory; temporary dir if None
        """
        self.directory = directory

    @staticmethod
    def _download_file_from_url(url, directory=None):
        """
        Download file from given URL and save it in given directory

        :param url: URL of file
        :param directory: path to download directory
        :return: path to downloaded file
        """
        # Files are saved in temporary folder if `directory` isn't specified
        if not directory:
            return urlretrieve(url)[0]
        else:
            # Get the filename from URL
            css_filename = os.path.join(directory, url.split('/')[-1])
            return urlretrieve(url, filename=css_filename)[0]

    @staticmethod
    def _get_latest_tag_from_github(repo_api_url):
        """Get latest icon font tag via GitHub API"""
        url = '/'.join([repo_api_url, 'tags'])
        r = requests.get(url)
        latest = r.json()[0]

        return latest['name']

    @abstractmethod
    def get_latest_version_number(self):
        """Get latest icon font version number"""
        return

    def download_css(self, directory):
        """Downloads icon font CSS file and returns its path"""
        return self._download_file_from_url(self.css_url, directory)

    def download_ttf(self, directory):
        """Downloads icon font TTF file and returns its path"""
        return self._download_file_from_url(self.ttf_url, directory)

    def download_files(self):
        """Download CSS and TTF files"""
        self.css_path = self.download_css(self.directory)
        self.ttf_path = self.download_ttf(self.directory)


class FontAwesomeDownloader(IconFontDownloader):
    """
    Font Awesome icon font downloader.

    Project page:
        https://fortawesome.github.io/Font-Awesome/
    """
    css_url = (
        'https://cdn.rawgit.com/FortAwesome/Font-Awesome/'
        'master/css/font-awesome.css'
    )
    ttf_url = (
        'https://cdn.rawgit.com/FortAwesome/Font-Awesome/'
        'master/fonts/fontawesome-webfont.ttf'
    )

    def get_latest_version_number(self):
        return self._get_latest_tag_from_github(
            'https://api.github.com/repos/FortAwesome/Font-Awesome'
        )


class OcticonsDownloader(IconFontDownloader):
    """
    Octicons icon font downloader.

    They unfortunately deleted compiled files from their GitHub repo, so let's
    get them via CDN fow now.

    Project page:
        https://octicons.github.com/
    """
    css_url = (
        'https://cdnjs.cloudflare.com/ajax/libs/'
        'octicons/4.4.0/font/octicons.css'
    )
    ttf_url = (
        'https://cdnjs.cloudflare.com/ajax/libs/'
        'octicons/4.4.0/font/octicons.ttf'
    )

    def get_latest_version_number(self):
        return self._get_latest_tag_from_github(
            'https://api.github.com/repos/github/octicons'
        )


# List of implemented icon font downloader classes
AVAILABLE_ICON_FONTS = {
    'font-awesome': {
        'name': 'Font Awesome',
        'downloader': FontAwesomeDownloader,
    },
    'octicons': {
        'name': 'Octicons',
        'downloader': OcticonsDownloader,
    },
}


================================================
FILE: icon_font_to_png/test/files/font-awesome.css
================================================
/*!
 *  Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
 *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
 */
/* FONT PATH
 * -------------------------- */
@font-face {
  font-family: 'FontAwesome';
  src: url('../fonts/fontawesome-webfont.eot?v=4.7.0');
  src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');
  font-weight: normal;
  font-style: normal;
}
.fa {
  display: inline-block;
  font: normal normal normal 14px/1 FontAwesome;
  font-size: inherit;
  text-rendering: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
/* makes the font 33% larger relative to the icon container */
.fa-lg {
  font-size: 1.33333333em;
  line-height: 0.75em;
  vertical-align: -15%;
}
.fa-2x {
  font-size: 2em;
}
.fa-3x {
  font-size: 3em;
}
.fa-4x {
  font-size: 4em;
}
.fa-5x {
  font-size: 5em;
}
.fa-fw {
  width: 1.28571429em;
  text-align: center;
}
.fa-ul {
  padding-left: 0;
  margin-left: 2.14285714em;
  list-style-type: none;
}
.fa-ul > li {
  position: relative;
}
.fa-li {
  position: absolute;
  left: -2.14285714em;
  width: 2.14285714em;
  top: 0.14285714em;
  text-align: center;
}
.fa-li.fa-lg {
  left: -1.85714286em;
}
.fa-border {
  padding: .2em .25em .15em;
  border: solid 0.08em #eeeeee;
  border-radius: .1em;
}
.fa-pull-left {
  float: left;
}
.fa-pull-right {
  float: right;
}
.fa.fa-pull-left {
  margin-right: .3em;
}
.fa.fa-pull-right {
  margin-left: .3em;
}
/* Deprecated as of 4.4.0 */
.pull-right {
  float: right;
}
.pull-left {
  float: left;
}
.fa.pull-left {
  margin-right: .3em;
}
.fa.pull-right {
  margin-left: .3em;
}
.fa-spin {
  -webkit-animation: fa-spin 2s infinite linear;
  animation: fa-spin 2s infinite linear;
}
.fa-pulse {
  -webkit-animation: fa-spin 1s infinite steps(8);
  animation: fa-spin 1s infinite steps(8);
}
@-webkit-keyframes fa-spin {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(359deg);
    transform: rotate(359deg);
  }
}
@keyframes fa-spin {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(359deg);
    transform: rotate(359deg);
  }
}
.fa-rotate-90 {
  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";
  -webkit-transform: rotate(90deg);
  -ms-transform: rotate(90deg);
  transform: rotate(90deg);
}
.fa-rotate-180 {
  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";
  -webkit-transform: rotate(180deg);
  -ms-transform: rotate(180deg);
  transform: rotate(180deg);
}
.fa-rotate-270 {
  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";
  -webkit-transform: rotate(270deg);
  -ms-transform: rotate(270deg);
  transform: rotate(270deg);
}
.fa-flip-horizontal {
  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";
  -webkit-transform: scale(-1, 1);
  -ms-transform: scale(-1, 1);
  transform: scale(-1, 1);
}
.fa-flip-vertical {
  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";
  -webkit-transform: scale(1, -1);
  -ms-transform: scale(1, -1);
  transform: scale(1, -1);
}
:root .fa-rotate-90,
:root .fa-rotate-180,
:root .fa-rotate-270,
:root .fa-flip-horizontal,
:root .fa-flip-vertical {
  filter: none;
}
.fa-stack {
  position: relative;
  display: inline-block;
  width: 2em;
  height: 2em;
  line-height: 2em;
  vertical-align: middle;
}
.fa-stack-1x,
.fa-stack-2x {
  position: absolute;
  left: 0;
  width: 100%;
  text-align: center;
}
.fa-stack-1x {
  line-height: inherit;
}
.fa-stack-2x {
  font-size: 2em;
}
.fa-inverse {
  color: #ffffff;
}
/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
   readers do not read off random characters that represent icons */
.fa-glass:before {
  content: "\f000";
}
.fa-music:before {
  content: "\f001";
}
.fa-search:before {
  content: "\f002";
}
.fa-envelope-o:before {
  content: "\f003";
}
.fa-heart:before {
  content: "\f004";
}
.fa-star:before {
  content: "\f005";
}
.fa-star-o:before {
  content: "\f006";
}
.fa-user:before {
  content: "\f007";
}
.fa-film:before {
  content: "\f008";
}
.fa-th-large:before {
  content: "\f009";
}
.fa-th:before {
  content: "\f00a";
}
.fa-th-list:before {
  content: "\f00b";
}
.fa-check:before {
  content: "\f00c";
}
.fa-remove:before,
.fa-close:before,
.fa-times:before {
  content: "\f00d";
}
.fa-search-plus:before {
  content: "\f00e";
}
.fa-search-minus:before {
  content: "\f010";
}
.fa-power-off:before {
  content: "\f011";
}
.fa-signal:before {
  content: "\f012";
}
.fa-gear:before,
.fa-cog:before {
  content: "\f013";
}
.fa-trash-o:before {
  content: "\f014";
}
.fa-home:before {
  content: "\f015";
}
.fa-file-o:before {
  content: "\f016";
}
.fa-clock-o:before {
  content: "\f017";
}
.fa-road:before {
  content: "\f018";
}
.fa-download:before {
  content: "\f019";
}
.fa-arrow-circle-o-down:before {
  content: "\f01a";
}
.fa-arrow-circle-o-up:before {
  content: "\f01b";
}
.fa-inbox:before {
  content: "\f01c";
}
.fa-play-circle-o:before {
  content: "\f01d";
}
.fa-rotate-right:before,
.fa-repeat:before {
  content: "\f01e";
}
.fa-refresh:before {
  content: "\f021";
}
.fa-list-alt:before {
  content: "\f022";
}
.fa-lock:before {
  content: "\f023";
}
.fa-flag:before {
  content: "\f024";
}
.fa-headphones:before {
  content: "\f025";
}
.fa-volume-off:before {
  content: "\f026";
}
.fa-volume-down:before {
  content: "\f027";
}
.fa-volume-up:before {
  content: "\f028";
}
.fa-qrcode:before {
  content: "\f029";
}
.fa-barcode:before {
  content: "\f02a";
}
.fa-tag:before {
  content: "\f02b";
}
.fa-tags:before {
  content: "\f02c";
}
.fa-book:before {
  content: "\f02d";
}
.fa-bookmark:before {
  content: "\f02e";
}
.fa-print:before {
  content: "\f02f";
}
.fa-camera:before {
  content: "\f030";
}
.fa-font:before {
  content: "\f031";
}
.fa-bold:before {
  content: "\f032";
}
.fa-italic:before {
  content: "\f033";
}
.fa-text-height:before {
  content: "\f034";
}
.fa-text-width:before {
  content: "\f035";
}
.fa-align-left:before {
  content: "\f036";
}
.fa-align-center:before {
  content: "\f037";
}
.fa-align-right:before {
  content: "\f038";
}
.fa-align-justify:before {
  content: "\f039";
}
.fa-list:before {
  content: "\f03a";
}
.fa-dedent:before,
.fa-outdent:before {
  content: "\f03b";
}
.fa-indent:before {
  content: "\f03c";
}
.fa-video-camera:before {
  content: "\f03d";
}
.fa-photo:before,
.fa-image:before,
.fa-picture-o:before {
  content: "\f03e";
}
.fa-pencil:before {
  content: "\f040";
}
.fa-map-marker:before {
  content: "\f041";
}
.fa-adjust:before {
  content: "\f042";
}
.fa-tint:before {
  content: "\f043";
}
.fa-edit:before,
.fa-pencil-square-o:before {
  content: "\f044";
}
.fa-share-square-o:before {
  content: "\f045";
}
.fa-check-square-o:before {
  content: "\f046";
}
.fa-arrows:before {
  content: "\f047";
}
.fa-step-backward:before {
  content: "\f048";
}
.fa-fast-backward:before {
  content: "\f049";
}
.fa-backward:before {
  content: "\f04a";
}
.fa-play:before {
  content: "\f04b";
}
.fa-pause:before {
  content: "\f04c";
}
.fa-stop:before {
  content: "\f04d";
}
.fa-forward:before {
  content: "\f04e";
}
.fa-fast-forward:before {
  content: "\f050";
}
.fa-step-forward:before {
  content: "\f051";
}
.fa-eject:before {
  content: "\f052";
}
.fa-chevron-left:before {
  content: "\f053";
}
.fa-chevron-right:before {
  content: "\f054";
}
.fa-plus-circle:before {
  content: "\f055";
}
.fa-minus-circle:before {
  content: "\f056";
}
.fa-times-circle:before {
  content: "\f057";
}
.fa-check-circle:before {
  content: "\f058";
}
.fa-question-circle:before {
  content: "\f059";
}
.fa-info-circle:before {
  content: "\f05a";
}
.fa-crosshairs:before {
  content: "\f05b";
}
.fa-times-circle-o:before {
  content: "\f05c";
}
.fa-check-circle-o:before {
  content: "\f05d";
}
.fa-ban:before {
  content: "\f05e";
}
.fa-arrow-left:before {
  content: "\f060";
}
.fa-arrow-right:before {
  content: "\f061";
}
.fa-arrow-up:before {
  content: "\f062";
}
.fa-arrow-down:before {
  content: "\f063";
}
.fa-mail-forward:before,
.fa-share:before {
  content: "\f064";
}
.fa-expand:before {
  content: "\f065";
}
.fa-compress:before {
  content: "\f066";
}
.fa-plus:before {
  content: "\f067";
}
.fa-minus:before {
  content: "\f068";
}
.fa-asterisk:before {
  content: "\f069";
}
.fa-exclamation-circle:before {
  content: "\f06a";
}
.fa-gift:before {
  content: "\f06b";
}
.fa-leaf:before {
  content: "\f06c";
}
.fa-fire:before {
  content: "\f06d";
}
.fa-eye:before {
  content: "\f06e";
}
.fa-eye-slash:before {
  content: "\f070";
}
.fa-warning:before,
.fa-exclamation-triangle:before {
  content: "\f071";
}
.fa-plane:before {
  content: "\f072";
}
.fa-calendar:before {
  content: "\f073";
}
.fa-random:before {
  content: "\f074";
}
.fa-comment:before {
  content: "\f075";
}
.fa-magnet:before {
  content: "\f076";
}
.fa-chevron-up:before {
  content: "\f077";
}
.fa-chevron-down:before {
  content: "\f078";
}
.fa-retweet:before {
  content: "\f079";
}
.fa-shopping-cart:before {
  content: "\f07a";
}
.fa-folder:before {
  content: "\f07b";
}
.fa-folder-open:before {
  content: "\f07c";
}
.fa-arrows-v:before {
  content: "\f07d";
}
.fa-arrows-h:before {
  content: "\f07e";
}
.fa-bar-chart-o:before,
.fa-bar-chart:before {
  content: "\f080";
}
.fa-twitter-square:before {
  content: "\f081";
}
.fa-facebook-square:before {
  content: "\f082";
}
.fa-camera-retro:before {
  content: "\f083";
}
.fa-key:before {
  content: "\f084";
}
.fa-gears:before,
.fa-cogs:before {
  content: "\f085";
}
.fa-comments:before {
  content: "\f086";
}
.fa-thumbs-o-up:before {
  content: "\f087";
}
.fa-thumbs-o-down:before {
  content: "\f088";
}
.fa-star-half:before {
  content: "\f089";
}
.fa-heart-o:before {
  content: "\f08a";
}
.fa-sign-out:before {
  content: "\f08b";
}
.fa-linkedin-square:before {
  content: "\f08c";
}
.fa-thumb-tack:before {
  content: "\f08d";
}
.fa-external-link:before {
  content: "\f08e";
}
.fa-sign-in:before {
  content: "\f090";
}
.fa-trophy:before {
  content: "\f091";
}
.fa-github-square:before {
  content: "\f092";
}
.fa-upload:before {
  content: "\f093";
}
.fa-lemon-o:before {
  content: "\f094";
}
.fa-phone:before {
  content: "\f095";
}
.fa-square-o:before {
  content: "\f096";
}
.fa-bookmark-o:before {
  content: "\f097";
}
.fa-phone-square:before {
  content: "\f098";
}
.fa-twitter:before {
  content: "\f099";
}
.fa-facebook-f:before,
.fa-facebook:before {
  content: "\f09a";
}
.fa-github:before {
  content: "\f09b";
}
.fa-unlock:before {
  content: "\f09c";
}
.fa-credit-card:before {
  content: "\f09d";
}
.fa-feed:before,
.fa-rss:before {
  content: "\f09e";
}
.fa-hdd-o:before {
  content: "\f0a0";
}
.fa-bullhorn:before {
  content: "\f0a1";
}
.fa-bell:before {
  content: "\f0f3";
}
.fa-certificate:before {
  content: "\f0a3";
}
.fa-hand-o-right:before {
  content: "\f0a4";
}
.fa-hand-o-left:before {
  content: "\f0a5";
}
.fa-hand-o-up:before {
  content: "\f0a6";
}
.fa-hand-o-down:before {
  content: "\f0a7";
}
.fa-arrow-circle-left:before {
  content: "\f0a8";
}
.fa-arrow-circle-right:before {
  content: "\f0a9";
}
.fa-arrow-circle-up:before {
  content: "\f0aa";
}
.fa-arrow-circle-down:before {
  content: "\f0ab";
}
.fa-globe:before {
  content: "\f0ac";
}
.fa-wrench:before {
  content: "\f0ad";
}
.fa-tasks:before {
  content: "\f0ae";
}
.fa-filter:before {
  content: "\f0b0";
}
.fa-briefcase:before {
  content: "\f0b1";
}
.fa-arrows-alt:before {
  content: "\f0b2";
}
.fa-group:before,
.fa-users:before {
  content: "\f0c0";
}
.fa-chain:before,
.fa-link:before {
  content: "\f0c1";
}
.fa-cloud:before {
  content: "\f0c2";
}
.fa-flask:before {
  content: "\f0c3";
}
.fa-cut:before,
.fa-scissors:before {
  content: "\f0c4";
}
.fa-copy:before,
.fa-files-o:before {
  content: "\f0c5";
}
.fa-paperclip:before {
  content: "\f0c6";
}
.fa-save:before,
.fa-floppy-o:before {
  content: "\f0c7";
}
.fa-square:before {
  content: "\f0c8";
}
.fa-navicon:before,
.fa-reorder:before,
.fa-bars:before {
  content: "\f0c9";
}
.fa-list-ul:before {
  content: "\f0ca";
}
.fa-list-ol:before {
  content: "\f0cb";
}
.fa-strikethrough:before {
  content: "\f0cc";
}
.fa-underline:before {
  content: "\f0cd";
}
.fa-table:before {
  content: "\f0ce";
}
.fa-magic:before {
  content: "\f0d0";
}
.fa-truck:before {
  content: "\f0d1";
}
.fa-pinterest:before {
  content: "\f0d2";
}
.fa-pinterest-square:before {
  content: "\f0d3";
}
.fa-google-plus-square:before {
  content: "\f0d4";
}
.fa-google-plus:before {
  content: "\f0d5";
}
.fa-money:before {
  content: "\f0d6";
}
.fa-caret-down:before {
  content: "\f0d7";
}
.fa-caret-up:before {
  content: "\f0d8";
}
.fa-caret-left:before {
  content: "\f0d9";
}
.fa-caret-right:before {
  content: "\f0da";
}
.fa-columns:before {
  content: "\f0db";
}
.fa-unsorted:before,
.fa-sort:before {
  content: "\f0dc";
}
.fa-sort-down:before,
.fa-sort-desc:before {
  content: "\f0dd";
}
.fa-sort-up:before,
.fa-sort-asc:before {
  content: "\f0de";
}
.fa-envelope:before {
  content: "\f0e0";
}
.fa-linkedin:before {
  content: "\f0e1";
}
.fa-rotate-left:before,
.fa-undo:before {
  content: "\f0e2";
}
.fa-legal:before,
.fa-gavel:before {
  content: "\f0e3";
}
.fa-dashboard:before,
.fa-tachometer:before {
  content: "\f0e4";
}
.fa-comment-o:before {
  content: "\f0e5";
}
.fa-comments-o:before {
  content: "\f0e6";
}
.fa-flash:before,
.fa-bolt:before {
  content: "\f0e7";
}
.fa-sitemap:before {
  content: "\f0e8";
}
.fa-umbrella:before {
  content: "\f0e9";
}
.fa-paste:before,
.fa-clipboard:before {
  content: "\f0ea";
}
.fa-lightbulb-o:before {
  content: "\f0eb";
}
.fa-exchange:before {
  content: "\f0ec";
}
.fa-cloud-download:before {
  content: "\f0ed";
}
.fa-cloud-upload:before {
  content: "\f0ee";
}
.fa-user-md:before {
  content: "\f0f0";
}
.fa-stethoscope:before {
  content: "\f0f1";
}
.fa-suitcase:before {
  content: "\f0f2";
}
.fa-bell-o:before {
  content: "\f0a2";
}
.fa-coffee:before {
  content: "\f0f4";
}
.fa-cutlery:before {
  content: "\f0f5";
}
.fa-file-text-o:before {
  content: "\f0f6";
}
.fa-building-o:before {
  content: "\f0f7";
}
.fa-hospital-o:before {
  content: "\f0f8";
}
.fa-ambulance:before {
  content: "\f0f9";
}
.fa-medkit:before {
  content: "\f0fa";
}
.fa-fighter-jet:before {
  content: "\f0fb";
}
.fa-beer:before {
  content: "\f0fc";
}
.fa-h-square:before {
  content: "\f0fd";
}
.fa-plus-square:before {
  content: "\f0fe";
}
.fa-angle-double-left:before {
  content: "\f100";
}
.fa-angle-double-right:before {
  content: "\f101";
}
.fa-angle-double-up:before {
  content: "\f102";
}
.fa-angle-double-down:before {
  content: "\f103";
}
.fa-angle-left:before {
  content: "\f104";
}
.fa-angle-right:before {
  content: "\f105";
}
.fa-angle-up:before {
  content: "\f106";
}
.fa-angle-down:before {
  content: "\f107";
}
.fa-desktop:before {
  content: "\f108";
}
.fa-laptop:before {
  content: "\f109";
}
.fa-tablet:before {
  content: "\f10a";
}
.fa-mobile-phone:before,
.fa-mobile:before {
  content: "\f10b";
}
.fa-circle-o:before {
  content: "\f10c";
}
.fa-quote-left:before {
  content: "\f10d";
}
.fa-quote-right:before {
  content: "\f10e";
}
.fa-spinner:before {
  content: "\f110";
}
.fa-circle:before {
  content: "\f111";
}
.fa-mail-reply:before,
.fa-reply:before {
  content: "\f112";
}
.fa-github-alt:before {
  content: "\f113";
}
.fa-folder-o:before {
  content: "\f114";
}
.fa-folder-open-o:before {
  content: "\f115";
}
.fa-smile-o:before {
  content: "\f118";
}
.fa-frown-o:before {
  content: "\f119";
}
.fa-meh-o:before {
  content: "\f11a";
}
.fa-gamepad:before {
  content: "\f11b";
}
.fa-keyboard-o:before {
  content: "\f11c";
}
.fa-flag-o:before {
  content: "\f11d";
}
.fa-flag-checkered:before {
  content: "\f11e";
}
.fa-terminal:before {
  content: "\f120";
}
.fa-code:before {
  content: "\f121";
}
.fa-mail-reply-all:before,
.fa-reply-all:before {
  content: "\f122";
}
.fa-star-half-empty:before,
.fa-star-half-full:before,
.fa-star-half-o:before {
  content: "\f123";
}
.fa-location-arrow:before {
  content: "\f124";
}
.fa-crop:before {
  content: "\f125";
}
.fa-code-fork:before {
  content: "\f126";
}
.fa-unlink:before,
.fa-chain-broken:before {
  content: "\f127";
}
.fa-question:before {
  content: "\f128";
}
.fa-info:before {
  content: "\f129";
}
.fa-exclamation:before {
  content: "\f12a";
}
.fa-superscript:before {
  content: "\f12b";
}
.fa-subscript:before {
  content: "\f12c";
}
.fa-eraser:before {
  content: "\f12d";
}
.fa-puzzle-piece:before {
  content: "\f12e";
}
.fa-microphone:before {
  content: "\f130";
}
.fa-microphone-slash:before {
  content: "\f131";
}
.fa-shield:before {
  content: "\f132";
}
.fa-calendar-o:before {
  content: "\f133";
}
.fa-fire-extinguisher:before {
  content: "\f134";
}
.fa-rocket:before {
  content: "\f135";
}
.fa-maxcdn:before {
  content: "\f136";
}
.fa-chevron-circle-left:before {
  content: "\f137";
}
.fa-chevron-circle-right:before {
  content: "\f138";
}
.fa-chevron-circle-up:before {
  content: "\f139";
}
.fa-chevron-circle-down:before {
  content: "\f13a";
}
.fa-html5:before {
  content: "\f13b";
}
.fa-css3:before {
  content: "\f13c";
}
.fa-anchor:before {
  content: "\f13d";
}
.fa-unlock-alt:before {
  content: "\f13e";
}
.fa-bullseye:before {
  content: "\f140";
}
.fa-ellipsis-h:before {
  content: "\f141";
}
.fa-ellipsis-v:before {
  content: "\f142";
}
.fa-rss-square:before {
  content: "\f143";
}
.fa-play-circle:before {
  content: "\f144";
}
.fa-ticket:before {
  content: "\f145";
}
.fa-minus-square:before {
  content: "\f146";
}
.fa-minus-square-o:before {
  content: "\f147";
}
.fa-level-up:before {
  content: "\f148";
}
.fa-level-down:before {
  content: "\f149";
}
.fa-check-square:before {
  content: "\f14a";
}
.fa-pencil-square:before {
  content: "\f14b";
}
.fa-external-link-square:before {
  content: "\f14c";
}
.fa-share-square:before {
  content: "\f14d";
}
.fa-compass:before {
  content: "\f14e";
}
.fa-toggle-down:before,
.fa-caret-square-o-down:before {
  content: "\f150";
}
.fa-toggle-up:before,
.fa-caret-square-o-up:before {
  content: "\f151";
}
.fa-toggle-right:before,
.fa-caret-square-o-right:before {
  content: "\f152";
}
.fa-euro:before,
.fa-eur:before {
  content: "\f153";
}
.fa-gbp:before {
  content: "\f154";
}
.fa-dollar:before,
.fa-usd:before {
  content: "\f155";
}
.fa-rupee:before,
.fa-inr:before {
  content: "\f156";
}
.fa-cny:before,
.fa-rmb:before,
.fa-yen:before,
.fa-jpy:before {
  content: "\f157";
}
.fa-ruble:before,
.fa-rouble:before,
.fa-rub:before {
  content: "\f158";
}
.fa-won:before,
.fa-krw:before {
  content: "\f159";
}
.fa-bitcoin:before,
.fa-btc:before {
  content: "\f15a";
}
.fa-file:before {
  content: "\f15b";
}
.fa-file-text:before {
  content: "\f15c";
}
.fa-sort-alpha-asc:before {
  content: "\f15d";
}
.fa-sort-alpha-desc:before {
  content: "\f15e";
}
.fa-sort-amount-asc:before {
  content: "\f160";
}
.fa-sort-amount-desc:before {
  content: "\f161";
}
.fa-sort-numeric-asc:before {
  content: "\f162";
}
.fa-sort-numeric-desc:before {
  content: "\f163";
}
.fa-thumbs-up:before {
  content: "\f164";
}
.fa-thumbs-down:before {
  content: "\f165";
}
.fa-youtube-square:before {
  content: "\f166";
}
.fa-youtube:before {
  content: "\f167";
}
.fa-xing:before {
  content: "\f168";
}
.fa-xing-square:before {
  content: "\f169";
}
.fa-youtube-play:before {
  content: "\f16a";
}
.fa-dropbox:before {
  content: "\f16b";
}
.fa-stack-overflow:before {
  content: "\f16c";
}
.fa-instagram:before {
  content: "\f16d";
}
.fa-flickr:before {
  content: "\f16e";
}
.fa-adn:before {
  content: "\f170";
}
.fa-bitbucket:before {
  content: "\f171";
}
.fa-bitbucket-square:before {
  content: "\f172";
}
.fa-tumblr:before {
  content: "\f173";
}
.fa-tumblr-square:before {
  content: "\f174";
}
.fa-long-arrow-down:before {
  content: "\f175";
}
.fa-long-arrow-up:before {
  content: "\f176";
}
.fa-long-arrow-left:before {
  content: "\f177";
}
.fa-long-arrow-right:before {
  content: "\f178";
}
.fa-apple:before {
  content: "\f179";
}
.fa-windows:before {
  content: "\f17a";
}
.fa-android:before {
  content: "\f17b";
}
.fa-linux:before {
  content: "\f17c";
}
.fa-dribbble:before {
  content: "\f17d";
}
.fa-skype:before {
  content: "\f17e";
}
.fa-foursquare:before {
  content: "\f180";
}
.fa-trello:before {
  content: "\f181";
}
.fa-female:before {
  content: "\f182";
}
.fa-male:before {
  content: "\f183";
}
.fa-gittip:before,
.fa-gratipay:before {
  content: "\f184";
}
.fa-sun-o:before {
  content: "\f185";
}
.fa-moon-o:before {
  content: "\f186";
}
.fa-archive:before {
  content: "\f187";
}
.fa-bug:before {
  content: "\f188";
}
.fa-vk:before {
  content: "\f189";
}
.fa-weibo:before {
  content: "\f18a";
}
.fa-renren:before {
  content: "\f18b";
}
.fa-pagelines:before {
  content: "\f18c";
}
.fa-stack-exchange:before {
  content: "\f18d";
}
.fa-arrow-circle-o-right:before {
  content: "\f18e";
}
.fa-arrow-circle-o-left:before {
  content: "\f190";
}
.fa-toggle-left:before,
.fa-caret-square-o-left:before {
  content: "\f191";
}
.fa-dot-circle-o:before {
  content: "\f192";
}
.fa-wheelchair:before {
  content: "\f193";
}
.fa-vimeo-square:before {
  content: "\f194";
}
.fa-turkish-lira:before,
.fa-try:before {
  content: "\f195";
}
.fa-plus-square-o:before {
  content: "\f196";
}
.fa-space-shuttle:before {
  content: "\f197";
}
.fa-slack:before {
  content: "\f198";
}
.fa-envelope-square:before {
  content: "\f199";
}
.fa-wordpress:before {
  content: "\f19a";
}
.fa-openid:before {
  content: "\f19b";
}
.fa-institution:before,
.fa-bank:before,
.fa-university:before {
  content: "\f19c";
}
.fa-mortar-board:before,
.fa-graduation-cap:before {
  content: "\f19d";
}
.fa-yahoo:before {
  content: "\f19e";
}
.fa-google:before {
  content: "\f1a0";
}
.fa-reddit:before {
  content: "\f1a1";
}
.fa-reddit-square:before {
  content: "\f1a2";
}
.fa-stumbleupon-circle:before {
  content: "\f1a3";
}
.fa-stumbleupon:before {
  content: "\f1a4";
}
.fa-delicious:before {
  content: "\f1a5";
}
.fa-digg:before {
  content: "\f1a6";
}
.fa-pied-piper-pp:before {
  content: "\f1a7";
}
.fa-pied-piper-alt:before {
  content: "\f1a8";
}
.fa-drupal:before {
  content: "\f1a9";
}
.fa-joomla:before {
  content: "\f1aa";
}
.fa-language:before {
  content: "\f1ab";
}
.fa-fax:before {
  content: "\f1ac";
}
.fa-building:before {
  content: "\f1ad";
}
.fa-child:before {
  content: "\f1ae";
}
.fa-paw:before {
  content: "\f1b0";
}
.fa-spoon:before {
  content: "\f1b1";
}
.fa-cube:before {
  content: "\f1b2";
}
.fa-cubes:before {
  content: "\f1b3";
}
.fa-behance:before {
  content: "\f1b4";
}
.fa-behance-square:before {
  content: "\f1b5";
}
.fa-steam:before {
  content: "\f1b6";
}
.fa-steam-square:before {
  content: "\f1b7";
}
.fa-recycle:before {
  content: "\f1b8";
}
.fa-automobile:before,
.fa-car:before {
  content: "\f1b9";
}
.fa-cab:before,
.fa-taxi:before {
  content: "\f1ba";
}
.fa-tree:before {
  content: "\f1bb";
}
.fa-spotify:before {
  content: "\f1bc";
}
.fa-deviantart:before {
  content: "\f1bd";
}
.fa-soundcloud:before {
  content: "\f1be";
}
.fa-database:before {
  content: "\f1c0";
}
.fa-file-pdf-o:before {
  content: "\f1c1";
}
.fa-file-word-o:before {
  content: "\f1c2";
}
.fa-file-excel-o:before {
  content: "\f1c3";
}
.fa-file-powerpoint-o:before {
  content: "\f1c4";
}
.fa-file-photo-o:before,
.fa-file-picture-o:before,
.fa-file-image-o:before {
  content: "\f1c5";
}
.fa-file-zip-o:before,
.fa-file-archive-o:before {
  content: "\f1c6";
}
.fa-file-sound-o:before,
.fa-file-audio-o:before {
  content: "\f1c7";
}
.fa-file-movie-o:before,
.fa-file-video-o:before {
  content: "\f1c8";
}
.fa-file-code-o:before {
  content: "\f1c9";
}
.fa-vine:before {
  content: "\f1ca";
}
.fa-codepen:before {
  content: "\f1cb";
}
.fa-jsfiddle:before {
  content: "\f1cc";
}
.fa-life-bouy:before,
.fa-life-buoy:before,
.fa-life-saver:before,
.fa-support:before,
.fa-life-ring:before {
  content: "\f1cd";
}
.fa-circle-o-notch:before {
  content: "\f1ce";
}
.fa-ra:before,
.fa-resistance:before,
.fa-rebel:before {
  content: "\f1d0";
}
.fa-ge:before,
.fa-empire:before {
  content: "\f1d1";
}
.fa-git-square:before {
  content: "\f1d2";
}
.fa-git:before {
  content: "\f1d3";
}
.fa-y-combinator-square:before,
.fa-yc-square:before,
.fa-hacker-news:before {
  content: "\f1d4";
}
.fa-tencent-weibo:before {
  content: "\f1d5";
}
.fa-qq:before {
  content: "\f1d6";
}
.fa-wechat:before,
.fa-weixin:before {
  content: "\f1d7";
}
.fa-send:before,
.fa-paper-plane:before {
  content: "\f1d8";
}
.fa-send-o:before,
.fa-paper-plane-o:before {
  content: "\f1d9";
}
.fa-history:before {
  content: "\f1da";
}
.fa-circle-thin:before {
  content: "\f1db";
}
.fa-header:before {
  content: "\f1dc";
}
.fa-paragraph:before {
  content: "\f1dd";
}
.fa-sliders:before {
  content: "\f1de";
}
.fa-share-alt:before {
  content: "\f1e0";
}
.fa-share-alt-square:before {
  content: "\f1e1";
}
.fa-bomb:before {
  content: "\f1e2";
}
.fa-soccer-ball-o:before,
.fa-futbol-o:before {
  content: "\f1e3";
}
.fa-tty:before {
  content: "\f1e4";
}
.fa-binoculars:before {
  content: "\f1e5";
}
.fa-plug:before {
  content: "\f1e6";
}
.fa-slideshare:before {
  content: "\f1e7";
}
.fa-twitch:before {
  content: "\f1e8";
}
.fa-yelp:before {
  content: "\f1e9";
}
.fa-newspaper-o:before {
  content: "\f1ea";
}
.fa-wifi:before {
  content: "\f1eb";
}
.fa-calculator:before {
  content: "\f1ec";
}
.fa-paypal:before {
  content: "\f1ed";
}
.fa-google-wallet:before {
  content: "\f1ee";
}
.fa-cc-visa:before {
  content: "\f1f0";
}
.fa-cc-mastercard:before {
  content: "\f1f1";
}
.fa-cc-discover:before {
  content: "\f1f2";
}
.fa-cc-amex:before {
  content: "\f1f3";
}
.fa-cc-paypal:before {
  content: "\f1f4";
}
.fa-cc-stripe:before {
  content: "\f1f5";
}
.fa-bell-slash:before {
  content: "\f1f6";
}
.fa-bell-slash-o:before {
  content: "\f1f7";
}
.fa-trash:before {
  content: "\f1f8";
}
.fa-copyright:before {
  content: "\f1f9";
}
.fa-at:before {
  content: "\f1fa";
}
.fa-eyedropper:before {
  content: "\f1fb";
}
.fa-paint-brush:before {
  content: "\f1fc";
}
.fa-birthday-cake:before {
  content: "\f1fd";
}
.fa-area-chart:before {
  content: "\f1fe";
}
.fa-pie-chart:before {
  content: "\f200";
}
.fa-line-chart:before {
  content: "\f201";
}
.fa-lastfm:before {
  content: "\f202";
}
.fa-lastfm-square:before {
  content: "\f203";
}
.fa-toggle-off:before {
  content: "\f204";
}
.fa-toggle-on:before {
  content: "\f205";
}
.fa-bicycle:before {
  content: "\f206";
}
.fa-bus:before {
  content: "\f207";
}
.fa-ioxhost:before {
  content: "\f208";
}
.fa-angellist:before {
  content: "\f209";
}
.fa-cc:before {
  content: "\f20a";
}
.fa-shekel:before,
.fa-sheqel:before,
.fa-ils:before {
  content: "\f20b";
}
.fa-meanpath:before {
  content: "\f20c";
}
.fa-buysellads:before {
  content: "\f20d";
}
.fa-connectdevelop:before {
  content: "\f20e";
}
.fa-dashcube:before {
  content: "\f210";
}
.fa-forumbee:before {
  content: "\f211";
}
.fa-leanpub:before {
  content: "\f212";
}
.fa-sellsy:before {
  content: "\f213";
}
.fa-shirtsinbulk:before {
  content: "\f214";
}
.fa-simplybuilt:before {
  content: "\f215";
}
.fa-skyatlas:before {
  content: "\f216";
}
.fa-cart-plus:before {
  content: "\f217";
}
.fa-cart-arrow-down:before {
  content: "\f218";
}
.fa-diamond:before {
  content: "\f219";
}
.fa-ship:before {
  content: "\f21a";
}
.fa-user-secret:before {
  content: "\f21b";
}
.fa-motorcycle:before {
  content: "\f21c";
}
.fa-street-view:before {
  content: "\f21d";
}
.fa-heartbeat:before {
  content: "\f21e";
}
.fa-venus:before {
  content: "\f221";
}
.fa-mars:before {
  content: "\f222";
}
.fa-mercury:before {
  content: "\f223";
}
.fa-intersex:before,
.fa-transgender:before {
  content: "\f224";
}
.fa-transgender-alt:before {
  content: "\f225";
}
.fa-venus-double:before {
  content: "\f226";
}
.fa-mars-double:before {
  content: "\f227";
}
.fa-venus-mars:before {
  content: "\f228";
}
.fa-mars-stroke:before {
  content: "\f229";
}
.fa-mars-stroke-v:before {
  content: "\f22a";
}
.fa-mars-stroke-h:before {
  content: "\f22b";
}
.fa-neuter:before {
  content: "\f22c";
}
.fa-genderless:before {
  content: "\f22d";
}
.fa-facebook-official:before {
  content: "\f230";
}
.fa-pinterest-p:before {
  content: "\f231";
}
.fa-whatsapp:before {
  content: "\f232";
}
.fa-server:before {
  content: "\f233";
}
.fa-user-plus:before {
  content: "\f234";
}
.fa-user-times:before {
  content: "\f235";
}
.fa-hotel:before,
.fa-bed:before {
  content: "\f236";
}
.fa-viacoin:before {
  content: "\f237";
}
.fa-train:before {
  content: "\f238";
}
.fa-subway:before {
  content: "\f239";
}
.fa-medium:before {
  content: "\f23a";
}
.fa-yc:before,
.fa-y-combinator:before {
  content: "\f23b";
}
.fa-optin-monster:before {
  content: "\f23c";
}
.fa-opencart:before {
  content: "\f23d";
}
.fa-expeditedssl:before {
  content: "\f23e";
}
.fa-battery-4:before,
.fa-battery:before,
.fa-battery-full:before {
  content: "\f240";
}
.fa-battery-3:before,
.fa-battery-three-quarters:before {
  content: "\f241";
}
.fa-battery-2:before,
.fa-battery-half:before {
  content: "\f242";
}
.fa-battery-1:before,
.fa-battery-quarter:before {
  content: "\f243";
}
.fa-battery-0:before,
.fa-battery-empty:before {
  content: "\f244";
}
.fa-mouse-pointer:before {
  content: "\f245";
}
.fa-i-cursor:before {
  content: "\f246";
}
.fa-object-group:before {
  content: "\f247";
}
.fa-object-ungroup:before {
  content: "\f248";
}
.fa-sticky-note:before {
  content: "\f249";
}
.fa-sticky-note-o:before {
  content: "\f24a";
}
.fa-cc-jcb:before {
  content: "\f24b";
}
.fa-cc-diners-club:before {
  content: "\f24c";
}
.fa-clone:before {
  content: "\f24d";
}
.fa-balance-scale:before {
  content: "\f24e";
}
.fa-hourglass-o:before {
  content: "\f250";
}
.fa-hourglass-1:before,
.fa-hourglass-start:before {
  content: "\f251";
}
.fa-hourglass-2:before,
.fa-hourglass-half:before {
  content: "\f252";
}
.fa-hourglass-3:before,
.fa-hourglass-end:before {
  content: "\f253";
}
.fa-hourglass:before {
  content: "\f254";
}
.fa-hand-grab-o:before,
.fa-hand-rock-o:before {
  content: "\f255";
}
.fa-hand-stop-o:before,
.fa-hand-paper-o:before {
  content: "\f256";
}
.fa-hand-scissors-o:before {
  content: "\f257";
}
.fa-hand-lizard-o:before {
  content: "\f258";
}
.fa-hand-spock-o:before {
  content: "\f259";
}
.fa-hand-pointer-o:before {
  content: "\f25a";
}
.fa-hand-peace-o:before {
  content: "\f25b";
}
.fa-trademark:before {
  content: "\f25c";
}
.fa-registered:before {
  content: "\f25d";
}
.fa-creative-commons:before {
  content: "\f25e";
}
.fa-gg:before {
  content: "\f260";
}
.fa-gg-circle:before {
  content: "\f261";
}
.fa-tripadvisor:before {
  content: "\f262";
}
.fa-odnoklassniki:before {
  content: "\f263";
}
.fa-odnoklassniki-square:before {
  content: "\f264";
}
.fa-get-pocket:before {
  content: "\f265";
}
.fa-wikipedia-w:before {
  content: "\f266";
}
.fa-safari:before {
  content: "\f267";
}
.fa-chrome:before {
  content: "\f268";
}
.fa-firefox:before {
  content: "\f269";
}
.fa-opera:before {
  content: "\f26a";
}
.fa-internet-explorer:before {
  content: "\f26b";
}
.fa-tv:before,
.fa-television:before {
  content: "\f26c";
}
.fa-contao:before {
  content: "\f26d";
}
.fa-500px:before {
  content: "\f26e";
}
.fa-amazon:before {
  content: "\f270";
}
.fa-calendar-plus-o:before {
  content: "\f271";
}
.fa-calendar-minus-o:before {
  content: "\f272";
}
.fa-calendar-times-o:before {
  content: "\f273";
}
.fa-calendar-check-o:before {
  content: "\f274";
}
.fa-industry:before {
  content: "\f275";
}
.fa-map-pin:before {
  content: "\f276";
}
.fa-map-signs:before {
  content: "\f277";
}
.fa-map-o:before {
  content: "\f278";
}
.fa-map:before {
  content: "\f279";
}
.fa-commenting:before {
  content: "\f27a";
}
.fa-commenting-o:before {
  content: "\f27b";
}
.fa-houzz:before {
  content: "\f27c";
}
.fa-vimeo:before {
  content: "\f27d";
}
.fa-black-tie:before {
  content: "\f27e";
}
.fa-fonticons:before {
  content: "\f280";
}
.fa-reddit-alien:before {
  content: "\f281";
}
.fa-edge:before {
  content: "\f282";
}
.fa-credit-card-alt:before {
  content: "\f283";
}
.fa-codiepie:before {
  content: "\f284";
}
.fa-modx:before {
  content: "\f285";
}
.fa-fort-awesome:before {
  content: "\f286";
}
.fa-usb:before {
  content: "\f287";
}
.fa-product-hunt:before {
  content: "\f288";
}
.fa-mixcloud:before {
  content: "\f289";
}
.fa-scribd:before {
  content: "\f28a";
}
.fa-pause-circle:before {
  content: "\f28b";
}
.fa-pause-circle-o:before {
  content: "\f28c";
}
.fa-stop-circle:before {
  content: "\f28d";
}
.fa-stop-circle-o:before {
  content: "\f28e";
}
.fa-shopping-bag:before {
  content: "\f290";
}
.fa-shopping-basket:before {
  content: "\f291";
}
.fa-hashtag:before {
  content: "\f292";
}
.fa-bluetooth:before {
  content: "\f293";
}
.fa-bluetooth-b:before {
  content: "\f294";
}
.fa-percent:before {
  content: "\f295";
}
.fa-gitlab:before {
  content: "\f296";
}
.fa-wpbeginner:before {
  content: "\f297";
}
.fa-wpforms:before {
  content: "\f298";
}
.fa-envira:before {
  content: "\f299";
}
.fa-universal-access:before {
  content: "\f29a";
}
.fa-wheelchair-alt:before {
  content: "\f29b";
}
.fa-question-circle-o:before {
  content: "\f29c";
}
.fa-blind:before {
  content: "\f29d";
}
.fa-audio-description:before {
  content: "\f29e";
}
.fa-volume-control-phone:before {
  content: "\f2a0";
}
.fa-braille:before {
  content: "\f2a1";
}
.fa-assistive-listening-systems:before {
  content: "\f2a2";
}
.fa-asl-interpreting:before,
.fa-american-sign-language-interpreting:before {
  content: "\f2a3";
}
.fa-deafness:before,
.fa-hard-of-hearing:before,
.fa-deaf:before {
  content: "\f2a4";
}
.fa-glide:before {
  content: "\f2a5";
}
.fa-glide-g:before {
  content: "\f2a6";
}
.fa-signing:before,
.fa-sign-language:before {
  content: "\f2a7";
}
.fa-low-vision:before {
  content: "\f2a8";
}
.fa-viadeo:before {
  content: "\f2a9";
}
.fa-viadeo-square:before {
  content: "\f2aa";
}
.fa-snapchat:before {
  content: "\f2ab";
}
.fa-snapchat-ghost:before {
  content: "\f2ac";
}
.fa-snapchat-square:before {
  content: "\f2ad";
}
.fa-pied-piper:before {
  content: "\f2ae";
}
.fa-first-order:before {
  content: "\f2b0";
}
.fa-yoast:before {
  content: "\f2b1";
}
.fa-themeisle:before {
  content: "\f2b2";
}
.fa-google-plus-circle:before,
.fa-google-plus-official:before {
  content: "\f2b3";
}
.fa-fa:before,
.fa-font-awesome:before {
  content: "\f2b4";
}
.fa-handshake-o:before {
  content: "\f2b5";
}
.fa-envelope-open:before {
  content: "\f2b6";
}
.fa-envelope-open-o:before {
  content: "\f2b7";
}
.fa-linode:before {
  content: "\f2b8";
}
.fa-address-book:before {
  content: "\f2b9";
}
.fa-address-book-o:before {
  content: "\f2ba";
}
.fa-vcard:before,
.fa-address-card:before {
  content: "\f2bb";
}
.fa-vcard-o:before,
.fa-address-card-o:before {
  content: "\f2bc";
}
.fa-user-circle:before {
  content: "\f2bd";
}
.fa-user-circle-o:before {
  content: "\f2be";
}
.fa-user-o:before {
  content: "\f2c0";
}
.fa-id-badge:before {
  content: "\f2c1";
}
.fa-drivers-license:before,
.fa-id-card:before {
  content: "\f2c2";
}
.fa-drivers-license-o:before,
.fa-id-card-o:before {
  content: "\f2c3";
}
.fa-quora:before {
  content: "\f2c4";
}
.fa-free-code-camp:before {
  content: "\f2c5";
}
.fa-telegram:before {
  content: "\f2c6";
}
.fa-thermometer-4:before,
.fa-thermometer:before,
.fa-thermometer-full:before {
  content: "\f2c7";
}
.fa-thermometer-3:before,
.fa-thermometer-three-quarters:before {
  content: "\f2c8";
}
.fa-thermometer-2:before,
.fa-thermometer-half:before {
  content: "\f2c9";
}
.fa-thermometer-1:before,
.fa-thermometer-quarter:before {
  content: "\f2ca";
}
.fa-thermometer-0:before,
.fa-thermometer-empty:before {
  content: "\f2cb";
}
.fa-shower:before {
  content: "\f2cc";
}
.fa-bathtub:before,
.fa-s15:before,
.fa-bath:before {
  content: "\f2cd";
}
.fa-podcast:before {
  content: "\f2ce";
}
.fa-window-maximize:before {
  content: "\f2d0";
}
.fa-window-minimize:before {
  content: "\f2d1";
}
.fa-window-restore:before {
  content: "\f2d2";
}
.fa-times-rectangle:before,
.fa-window-close:before {
  content: "\f2d3";
}
.fa-times-rectangle-o:before,
.fa-window-close-o:before {
  content: "\f2d4";
}
.fa-bandcamp:before {
  content: "\f2d5";
}
.fa-grav:before {
  content: "\f2d6";
}
.fa-etsy:before {
  content: "\f2d7";
}
.fa-imdb:before {
  content: "\f2d8";
}
.fa-ravelry:before {
  content: "\f2d9";
}
.fa-eercast:before {
  content: "\f2da";
}
.fa-microchip:before {
  content: "\f2db";
}
.fa-snowflake-o:before {
  content: "\f2dc";
}
.fa-superpowers:before {
  content: "\f2dd";
}
.fa-wpexplorer:before {
  content: "\f2de";
}
.fa-meetup:before {
  content: "\f2e0";
}
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
}
.sr-only-focusable:active,
.sr-only-focusable:focus {
  position: static;
  width: auto;
  height: auto;
  margin: 0;
  overflow: visible;
  clip: auto;
}


================================================
FILE: icon_font_to_png/test/files/octicons.css
================================================

@font-face {
  font-family:"Octicons";
  src:url("octicons.eot?ef21c39f0ca9b1b5116e5eb7ac5eabe6");
  src:url("octicons.eot?#iefix") format("embedded-opentype"),
		url("octicons.woff2?ef21c39f0ca9b1b5116e5eb7ac5eabe6") format("woff2"),
		url("octicons.woff?ef21c39f0ca9b1b5116e5eb7ac5eabe6") format("woff"),
		url("octicons.ttf?ef21c39f0ca9b1b5116e5eb7ac5eabe6") format("truetype"),
		url("octicons.svg?ef21c39f0ca9b1b5116e5eb7ac5eabe6#octicons") format("svg");
  font-weight:normal;
  font-style:normal;
}


/*

.octicon is optimized for 16px.
.mega-octicon is optimized for 32px but can be used larger.

*/
.octicon, .mega-octicon {
  font: normal normal normal 16px/1 Octicons;
  display: inline-block;
  text-decoration: none;
  text-rendering: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  -webkit-user-select: none;
  -ms-user-select: none;
  user-select: none;
  speak: none;
}
.mega-octicon { font-size: 32px; }

.octicon-alert:before { content:"\f02d"; }

.octicon-arrow-down:before { content:"\f03f"; }

.octicon-arrow-left:before { content:"\f040"; }

.octicon-arrow-right:before { content:"\f03e"; }

.octicon-arrow-small-down:before { content:"\f0a0"; }

.octicon-arrow-small-left:before { content:"\f0a1"; }

.octicon-arrow-small-right:before { content:"\f071"; }

.octicon-arrow-small-up:before { content:"\f09f"; }

.octicon-arrow-up:before { content:"\f03d"; }

.octicon-beaker:before { content:"\f0dd"; }

.octicon-bell:before { content:"\f0de"; }

.octicon-bold:before { content:"\f0e2"; }

.octicon-book:before { content:"\f007"; }

.octicon-bookmark:before { content:"\f07b"; }

.octicon-briefcase:before { content:"\f0d3"; }

.octicon-broadcast:before { content:"\f048"; }

.octicon-browser:before { content:"\f0c5"; }

.octicon-bug:before { content:"\f091"; }

.octicon-calendar:before { content:"\f068"; }

.octicon-check:before { content:"\f03a"; }

.octicon-checklist:before { content:"\f076"; }

.octicon-chevron-down:before { content:"\f0a3"; }

.octicon-chevron-left:before { content:"\f0a4"; }

.octicon-chevron-right:before { content:"\f078"; }

.octicon-chevron-up:before { content:"\f0a2"; }

.octicon-circle-slash:before { content:"\f084"; }

.octicon-circuit-board:before { content:"\f0d6"; }

.octicon-clippy:before { content:"\f035"; }

.octicon-clock:before { content:"\f046"; }

.octicon-cloud-download:before { content:"\f00b"; }

.octicon-cloud-upload:before { content:"\f00c"; }

.octicon-code:before { content:"\f05f"; }

.octicon-comment-discussion:before { content:"\f04f"; }

.octicon-comment:before { content:"\f02b"; }

.octicon-credit-card:before { content:"\f045"; }

.octicon-dash:before { content:"\f0ca"; }

.octicon-dashboard:before { content:"\f07d"; }

.octicon-database:before { content:"\f096"; }

.octicon-desktop-download:before { content:"\f0dc"; }

.octicon-device-camera-video:before { content:"\f057"; }

.octicon-device-camera:before { content:"\f056"; }

.octicon-device-desktop:before { content:"\f27c"; }

.octicon-device-mobile:before { content:"\f038"; }

.octicon-diff-added:before { content:"\f06b"; }

.octicon-diff-ignored:before { content:"\f099"; }

.octicon-diff-modified:before { content:"\f06d"; }

.octicon-diff-removed:before { content:"\f06c"; }

.octicon-diff-renamed:before { content:"\f06e"; }

.octicon-diff:before { content:"\f04d"; }

.octicon-ellipses:before { content:"\f101"; }

.octicon-ellipsis:before { content:"\f09a"; }

.octicon-eye:before { content:"\f04e"; }

.octicon-file-binary:before { content:"\f094"; }

.octicon-file-code:before { content:"\f010"; }

.octicon-file-directory:before { content:"\f016"; }

.octicon-file-media:before { content:"\f012"; }

.octicon-file-pdf:before { content:"\f014"; }

.octicon-file-submodule:before { content:"\f017"; }

.octicon-file-symlink-directory:before { content:"\f0b1"; }

.octicon-file-symlink-file:before { content:"\f0b0"; }

.octicon-file-text:before { content:"\f011"; }

.octicon-file-zip:before { content:"\f013"; }

.octicon-file:before { content:"\f102"; }

.octicon-flame:before { content:"\f0d2"; }

.octicon-fold:before { content:"\f0cc"; }

.octicon-gear:before { content:"\f02f"; }

.octicon-gift:before { content:"\f042"; }

.octicon-gist-secret:before { content:"\f08c"; }

.octicon-gist:before { content:"\f00e"; }

.octicon-git-branch:before { content:"\f020"; }

.octicon-git-commit:before { content:"\f01f"; }

.octicon-git-compare:before { content:"\f0ac"; }

.octicon-git-merge:before { content:"\f023"; }

.octicon-git-pull-request:before { content:"\f009"; }

.octicon-globe:before { content:"\f0b6"; }

.octicon-grabber:before { content:"\f103"; }

.octicon-graph:before { content:"\f043"; }

.octicon-heart:before { content:"\2665"; }

.octicon-history:before { content:"\f07e"; }

.octicon-home:before { content:"\f08d"; }

.octicon-horizontal-rule:before { content:"\f070"; }

.octicon-hubot:before { content:"\f09d"; }

.octicon-inbox:before { content:"\f0cf"; }

.octicon-info:before { content:"\f059"; }

.octicon-issue-closed:before { content:"\f028"; }

.octicon-issue-opened:before { content:"\f026"; }

.octicon-issue-reopened:before { content:"\f027"; }

.octicon-italic:before { content:"\f0e4"; }

.octicon-jersey:before { content:"\f019"; }

.octicon-key:before { content:"\f049"; }

.octicon-keyboard:before { content:"\f00d"; }

.octicon-law:before { content:"\f0d8"; }

.octicon-light-bulb:before { content:"\f000"; }

.octicon-link-external:before { content:"\f07f"; }

.octicon-link:before { content:"\f05c"; }

.octicon-list-ordered:before { content:"\f062"; }

.octicon-list-unordered:before { content:"\f061"; }

.octicon-location:before { content:"\f060"; }

.octicon-lock:before { content:"\f06a"; }

.octicon-logo-gist:before { content:"\f0ad"; }

.octicon-logo-github:before { content:"\f092"; }

.octicon-mail-read:before { content:"\f03c"; }

.octicon-mail-reply:before { content:"\f051"; }

.octicon-mail:before { content:"\f03b"; }

.octicon-mark-github:before { content:"\f00a"; }

.octicon-markdown:before { content:"\f0c9"; }

.octicon-megaphone:before { content:"\f077"; }

.octicon-mention:before { content:"\f0be"; }

.octicon-milestone:before { content:"\f075"; }

.octicon-mirror:before { content:"\f024"; }

.octicon-mortar-board:before { content:"\f0d7"; }

.octicon-mute:before { content:"\f080"; }

.octicon-no-newline:before { content:"\f09c"; }

.octicon-octoface:before { content:"\f008"; }

.octicon-organization:before { content:"\f037"; }

.octicon-package:before { content:"\f0c4"; }

.octicon-paintcan:before { content:"\f0d1"; }

.octicon-pencil:before { content:"\f058"; }

.octicon-person:before { content:"\f018"; }

.octicon-pin:before { content:"\f041"; }

.octicon-plug:before { content:"\f0d4"; }

.octicon-plus-small:before { content:"\f104"; }

.octicon-plus:before { content:"\f05d"; }

.octicon-primitive-dot:before { content:"\f052"; }

.octicon-primitive-square:before { content:"\f053"; }

.octicon-pulse:before { content:"\f085"; }

.octicon-question:before { content:"\f02c"; }

.octicon-quote:before { content:"\f063"; }

.octicon-radio-tower:before { content:"\f030"; }

.octicon-reply:before { content:"\f105"; }

.octicon-repo-clone:before { content:"\f04c"; }

.octicon-repo-force-push:before { content:"\f04a"; }

.octicon-repo-forked:before { content:"\f002"; }

.octicon-repo-pull:before { content:"\f006"; }

.octicon-repo-push:before { content:"\f005"; }

.octicon-repo:before { content:"\f001"; }

.octicon-rocket:before { content:"\f033"; }

.octicon-rss:before { content:"\f034"; }

.octicon-ruby:before { content:"\f047"; }

.octicon-search:before { content:"\f02e"; }

.octicon-server:before { content:"\f097"; }

.octicon-settings:before { content:"\f07c"; }

.octicon-shield:before { content:"\f0e1"; }

.octicon-sign-in:before { content:"\f036"; }

.octicon-sign-out:before { content:"\f032"; }

.octicon-smiley:before { content:"\f0e7"; }

.octicon-squirrel:before { content:"\f0b2"; }

.octicon-star:before { content:"\f02a"; }

.octicon-stop:before { content:"\f08f"; }

.octicon-sync:before { content:"\f087"; }

.octicon-tag:before { content:"\f015"; }

.octicon-tasklist:before { content:"\f0e5"; }

.octicon-telescope:before { content:"\f088"; }

.octicon-terminal:before { content:"\f0c8"; }

.octicon-text-size:before { content:"\f0e3"; }

.octicon-three-bars:before { content:"\f05e"; }

.octicon-thumbsdown:before { content:"\f0db"; }

.octicon-thumbsup:before { content:"\f0da"; }

.octicon-tools:before { content:"\f031"; }

.octicon-trashcan:before { content:"\f0d0"; }

.octicon-triangle-down:before { content:"\f05b"; }

.octicon-triangle-left:before { content:"\f044"; }

.octicon-triangle-right:before { content:"\f05a"; }

.octicon-triangle-up:before { content:"\f0aa"; }

.octicon-unfold:before { content:"\f039"; }

.octicon-unmute:before { content:"\f0ba"; }

.octicon-unverified:before { content:"\f0e8"; }

.octicon-verified:before { content:"\f0e6"; }

.octicon-versions:before { content:"\f064"; }

.octicon-watch:before { content:"\f0e0"; }

.octicon-x:before { content:"\f081"; }

.octicon-zap:before { content:"\26a1"; }



================================================
FILE: icon_font_to_png/test/files/test-foo.css
================================================
.foo-bar:before { content: '\f001' }
.foo-test:before { content: '\f002' }


================================================
FILE: icon_font_to_png/test/files/test.css
================================================
.foo:before { content: '\f001' }
.bar:before { content: '\f002' }



================================================
FILE: icon_font_to_png/test/test_command_line.py
================================================
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals

import os
import shutil

import pytest

from icon_font_to_png import command_line


BASE_DIR = os.path.dirname(os.path.realpath(__file__))


# Tests
def test_list_option(capfd):
    """Test listing CSS icons"""
    css_file = os.path.join(BASE_DIR, 'files', 'test-foo.css')
    ttf_file = os.path.join(BASE_DIR, 'files', 'test.ttf')  # Required argument

    # No CSS and TTF files
    with pytest.raises(SystemExit):
        command_line.run(
            '--list'.split()
        )
    out, err = capfd.readouterr()
    assert out == ''

    # Lists correctly
    with pytest.raises(SystemExit):
        command_line.run(
            '--css {css_file} --ttf {ttf_file} --list'.format(
                css_file=css_file, ttf_file=ttf_file
            ).split()
        )
    out, err = capfd.readouterr()
    assert out == 'bar\ntest\n'

    # Lists correctly, with the prefix
    with pytest.raises(SystemExit):
        command_line.run(
            '--css {css_file} --ttf {ttf_file} --keep_prefix --list'.format(
                css_file=css_file, ttf_file=ttf_file
            ).split()
        )
    out, err = capfd.readouterr()
    assert out == 'foo-bar\nfoo-test\n'


def test_icon_export(capfd):
    """Test exporting icons (on Font Awesome files)"""
    css_file = os.path.join(BASE_DIR, 'files', 'font-awesome.css')
    ttf_file = os.path.join(BASE_DIR, 'files', 'fontawesome-webfont.ttf')

    # Export none icons
    with pytest.raises(SystemExit):
        command_line.run(
            '--css {css_file} --ttf {ttf_file}'.format(
                css_file=css_file, ttf_file=ttf_file
            ).split()
        )
    out, err = capfd.readouterr()  # For skipping stdout

    # Export one icon
    command_line.run(
        '--css {css_file} --ttf {ttf_file} github'.format(
            css_file=css_file, ttf_file=ttf_file
        ).split()
    )
    out, err = capfd.readouterr()  # For skipping stdout

    assert os.path.isfile(os.path.join('exported', 'github.png'))

    # Export two icons
    command_line.run(
        '--css {css_file} --ttf {ttf_file} github star'.format(
            css_file=css_file, ttf_file=ttf_file
        ).split()
    )
    out, err = capfd.readouterr()  # For skipping stdout

    assert os.path.isfile(os.path.join('exported', 'github.png'))
    assert os.path.isfile(os.path.join('exported', 'star.png'))

    # Export all icons
    command_line.run(
        '--css {css_file} --ttf {ttf_file} ALL'.format(
            css_file=css_file, ttf_file=ttf_file
        ).split()
    )
    out, err = capfd.readouterr()  # For skipping stdout


def test_filename_option(capfd):
    """Test filename option"""
    css_file = os.path.join(BASE_DIR, 'files', 'font-awesome.css')
    ttf_file = os.path.join(BASE_DIR, 'files', 'fontawesome-webfont.ttf')

    # Export one icon
    command_line.run(
        '--css {css_file} --ttf {ttf_file} '
        '--filename foo github'.format(
            css_file=css_file, ttf_file=ttf_file
        ).split()
    )
    out, err = capfd.readouterr()  # For skipping stdout

    assert os.path.isfile(os.path.join('exported', 'foo.png'))

    # Export multiple icons
    command_line.run(
        '--css {css_file} --ttf {ttf_file} '
        '--filename foo- github star'.format(
            css_file=css_file, ttf_file=ttf_file
        ).split()
    )
    out, err = capfd.readouterr()  # For skipping stdout

    assert os.path.isfile(os.path.join('exported', 'foo-github.png'))
    assert os.path.isfile(os.path.join('exported', 'foo-star.png'))


def test_download_option(capfd):
    """Test icon font download option"""
    with pytest.raises(SystemExit):
        command_line.run(
            '--download {font_name}'.format(font_name='font-awesome').split()
        )
    out, err = capfd.readouterr()  # For skipping stdout
    assert out == "Icon font 'font-awesome' successfully downloaded\n"

    assert os.path.isfile('font-awesome.css')
    assert os.path.isfile('fontawesome-webfont.ttf')


# Teardown
def teardown_module():
    """Delete exported icons directory and downloaded FontAwesome files"""
    if os.path.isdir('exported'):
        shutil.rmtree('exported')

    if os.path.isfile('font-awesome.css'):
        os.remove('font-awesome.css')

    if os.path.isfile('fontawesome-webfont.ttf'):
        os.remove('fontawesome-webfont.ttf')


================================================
FILE: icon_font_to_png/test/test_font_awesome.py
================================================
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals

import os
import random

import pytest

from icon_font_to_png import icon_font


BASE_DIR = os.path.dirname(os.path.realpath(__file__))


# Fixtures
@pytest.fixture(scope='module')
def font_awesome():
    """Create a IconFont instance from Font Awesome files"""
    css_file = os.path.join(BASE_DIR, 'files', 'font-awesome.css')
    ttf_file = os.path.join(BASE_DIR, 'files', 'fontawesome-webfont.ttf')
    return icon_font.IconFont(css_file=css_file, ttf_file=ttf_file)


# Tests
def test_font_awesome_load_icons(font_awesome):
    """Test Font Awesome icon loading"""
    assert len(font_awesome.css_icons) > 0


def test_font_awesome_prefix(font_awesome):
    """Test Font Awesome common prefix"""
    assert font_awesome.common_prefix == 'fa-'


def test_font_awesome_export_icon(font_awesome):
    """Test Font Awesome random icon exporting"""
    icon = random.choice(list(font_awesome.css_icons.keys()))
    font_awesome.export_icon(icon, size=128, export_dir='/tmp')
    font_awesome.export_icon(icon, size=128, color='blue', export_dir='/tmp')
    font_awesome.export_icon(icon, size=256, export_dir='/tmp')
    font_awesome.export_icon(icon, size=256, color='blue', export_dir='/tmp')


================================================
FILE: icon_font_to_png/test/test_icon_font.py
================================================
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals

import os
import shutil
import tempfile
import uuid

import pytest
from PIL import Image, ImageChops

from icon_font_to_png import icon_font


BASE_DIR = os.path.dirname(os.path.realpath(__file__))


# Fixtures
@pytest.fixture(scope='module')
def font_awesome():
    """Create a IconFont instance from Font Awesome files"""
    css_file = os.path.join(BASE_DIR, 'files', 'font-awesome.css')
    ttf_file = os.path.join(BASE_DIR, 'files', 'fontawesome-webfont.ttf')
    return icon_font.IconFont(css_file=css_file, ttf_file=ttf_file)


# Tests
def test_init():
    """Test initializing"""
    # No arguments
    with pytest.raises(TypeError):
        icon_font.IconFont()

    # Non-existent files
    with pytest.raises(IOError):
        icon_font.IconFont(css_file=str(uuid.uuid4()),
                           ttf_file=str(uuid.uuid4()))

    obj = icon_font.IconFont(css_file=tempfile.mkstemp()[1],
                             ttf_file=tempfile.mkstemp()[1])
    assert len(obj.css_icons) == 0


def test_common_prefix():
    """Test finding out what the common prefix is"""
    css_file = os.path.join(BASE_DIR, 'files', 'test-foo.css')
    obj = icon_font.IconFont(css_file=css_file, ttf_file=None,
                             keep_prefix=True)
    assert obj.common_prefix == 'foo-'

    css_file = os.path.join(BASE_DIR, 'files', 'test.css')
    obj = icon_font.IconFont(css_file=css_file, ttf_file=None,
                             keep_prefix=True)
    assert obj.common_prefix == ''


@pytest.mark.parametrize("image,size", [
    ("rocket_16.png", 16),
    ("rocket_100.png", 100),
    ("rocket_256.png", 256),
])
def test_size(font_awesome, image, size):
    """Test size option"""
    original_file = os.path.join(BASE_DIR, 'files', image)

    font_awesome.export_icon(icon='rocket', size=size)
    exported_file = os.path.join('exported', 'rocket.png')

    img1 = Image.open(original_file)
    img2 = Image.open(exported_file)

    # Check dimensions
    assert img1.size == (size, size)
    assert img2.size == (size, size)

    # Check if the images are equal
    assert ImageChops.difference(img1, img2).getbbox() is None


@pytest.mark.parametrize("image,color", [
    ("rocket_blue.png", 'blue'),
    ("rocket_cyan.png", 'cyan'),
    ("rocket_123123.png", '#123123'),
])
def test_color(font_awesome, image, color):
    """Test color option"""
    original_file = os.path.join(BASE_DIR, 'files', image)

    font_awesome.export_icon(icon='rocket', size=16, color=color)
    exported_file = os.path.join('exported', 'rocket.png')

    img1 = Image.open(original_file)
    img2 = Image.open(exported_file)

    # Check if the images are equal
    assert ImageChops.difference(img1, img2).getbbox() is None


@pytest.mark.parametrize("image,scale", [
    ("rocket_x1.png", 1),
    ("rocket_x05.png", 0.5),
    ("rocket_auto.png", 'auto'),
])
def test_scale(font_awesome, image, scale):
    """Test scale option"""
    original_file = os.path.join(BASE_DIR, 'files', image)

    font_awesome.export_icon(icon='rocket', size=16, scale=scale)
    exported_file = os.path.join('exported', 'rocket.png')

    img1 = Image.open(original_file)
    img2 = Image.open(exported_file)

    # Check if the images are equal
    assert ImageChops.difference(img1, img2).getbbox() is None


# Teardown
def teardown_module():
    """Delete exported icons directory"""
    if os.path.isdir('exported'):
        shutil.rmtree('exported')


================================================
FILE: icon_font_to_png/test/test_icon_font_downloader.py
================================================
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals

import os
import tempfile

import pytest
from flaky import flaky

from icon_font_to_png.icon_font_downloader import (
    FontAwesomeDownloader, OcticonsDownloader
)


# Tests
@flaky
@pytest.mark.parametrize("downloader", [
    FontAwesomeDownloader,
    OcticonsDownloader,
])
def test_icon_font_downloader(downloader):
    """Test initializing Font Awesome Downloader"""
    # With directory
    obj = downloader(tempfile.mkdtemp())
    obj.download_files()

    assert os.path.isfile(obj.css_path)
    assert os.path.isfile(obj.ttf_path)

    # Without directory
    obj = downloader()
    obj.download_files()

    assert os.path.isfile(obj.css_path)
    assert os.path.isfile(obj.ttf_path)


@pytest.mark.parametrize("downloader", [
    FontAwesomeDownloader,
    OcticonsDownloader,
])
def test_font_awesome_latest_version_number(downloader):
    """Test that getting latest version number"""
    obj = downloader(tempfile.mkdtemp())
    assert obj.get_latest_version_number()


================================================
FILE: icon_font_to_png/test/test_octicons.py
================================================
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals

import os
import random

import pytest

from icon_font_to_png import icon_font


BASE_DIR = os.path.dirname(os.path.realpath(__file__))


# Fixtures
@pytest.fixture(scope='module')
def octicons():
    """Create a IconFont instance from Octicons files"""
    css_file = os.path.join(BASE_DIR, 'files', 'octicons.css')
    ttf_file = os.path.join(BASE_DIR, 'files', 'octicons.ttf')
    return icon_font.IconFont(css_file=css_file, ttf_file=ttf_file)


# Tests
def test_octicons_load_icons(octicons):
    """Test Octicons icon loading"""
    assert len(octicons.css_icons) > 0


def test_octicons_prefix(octicons):
    """Test Octicons common prefix"""
    assert octicons.common_prefix == 'octicon-'


def test_octicons_export_icon(octicons):
    """Test Octicons random icon exporting"""
    icon = random.choice(list(octicons.css_icons.keys()))
    octicons.export_icon(icon=icon, size=128, export_dir='/tmp')
    octicons.export_icon(icon=icon, size=128, color='blue', export_dir='/tmp')
    octicons.export_icon(icon=icon, size=256, export_dir='/tmp')
    octicons.export_icon(icon=icon, size=256, color='blue', export_dir='/tmp')


================================================
FILE: requirements/common.txt
================================================
Pillow>=4.0.0
requests>=2.13.0
six>=1.10.0
tinycss>=0.4


================================================
FILE: requirements/dev.txt
================================================
-r common.txt

check-manifest>=0.35
coverage>=4.3.4
coveralls>=1.1
flake8>=3.2.1
flaky>=3.3.0
pypandoc>=1.3.3
pytest>=3.0.6
tox>=2.6.0
twine>=1.8.1


================================================
FILE: requirements.txt
================================================
-r requirements/common.txt


================================================
FILE: setup.py
================================================
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import io
import os
import re

from setuptools import setup, find_packages


# Convert description from markdown to reStructuredText
try:
    import pypandoc
    description = pypandoc.convert('README.md', 'rst', 'markdown')
except (OSError, ImportError):
    description = ''


# Get package version number
# Source: https://packaging.python.org/single_source_version/
def read(*names, **kwargs):
    with io.open(
        os.path.join(os.path.dirname(__file__), *names),
        encoding=kwargs.get('encoding', 'utf8')
    ) as fp:
        return fp.read()


def find_version(*file_paths):
    version_file = read(*file_paths)
    version_match = re.search(
        r"^__version__ = ['\"]([^'\"]*)['\"]",
        version_file, re.M
    )
    if version_match:
        return version_match.group(1)
    raise RuntimeError("Unable to find version string.")


setup(
    name='icon_font_to_png',
    url='https://github.com/Pythonity/icon-font-to-png',
    download_url='https://github.com/Pythonity/icon-font-to-png/releases/'
                 'latest',
    bugtrack_url='https://github.com/Pythonity/icon-font-to-png/issues',
    version=find_version('icon_font_to_png', '__init__.py'),
    license='MIT License',
    author='Pythonity',
    author_email='pythonity@pythonity.com',
    maintainer='Paweł Adamczak',
    maintainer_email='pawel.adamczak@sidnet.info',
    description="Python script (and library) for exporting icons from "
                "icon fonts (e.g. Font Awesome, Octicons) as PNG images.",
    long_description=description,
    packages=find_packages(),
    include_package_data=True,
    install_requires=[
        'Pillow>=4.0.0',
        'requests>=2.12.5',
        'six>=1.10.0',
        'tinycss>=0.4',
    ],
    extras_require={
        'testing': ['pytest'],
    },
    scripts=['bin/font-awesome-to-png', 'bin/icon-font-to-png'],
    keywords='icon font export font awesome octicons',
    classifiers=[
        'Development Status :: 4 - Beta',
        'Environment :: Console',
        'Intended Audience :: End Users/Desktop',
        'License :: OSI Approved :: MIT License',
        'Operating System :: OS Independent',
        'Programming Language :: Python',
        'Programming Language :: Python :: 2',
        'Programming Language :: Python :: 2.7',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.4',
        'Programming Language :: Python :: 3.5',
        'Programming Language :: Python :: 3.6',
        'Topic :: Utilities',
    ],
)


================================================
FILE: tox.ini
================================================
[tox]
envlist = py27,py34,py35,py36,py36-flake8

[testenv]
commands = py.test -v
deps = -r{toxinidir}/requirements/dev.txt
passenv =
    TRAVIS*

[testenv:flake8]
commands = flake8 .
deps = flake8

[pytest]
addopts = --ignore=setup.py
python_files = *.py
python_functions = test_

[flake8]
exclude =
    .git,
    .tox,
    build,
    dist
Download .txt
gitextract_vzb55rlz/

├── .gitignore
├── .travis.yml
├── LICENSE
├── MANIFEST.in
├── README.md
├── _config.yml
├── bin/
│   ├── font-awesome-to-png
│   └── icon-font-to-png
├── icon_font_to_png/
│   ├── __init__.py
│   ├── command_line.py
│   ├── icon_font.py
│   ├── icon_font_downloader.py
│   └── test/
│       ├── files/
│       │   ├── font-awesome.css
│       │   ├── octicons.css
│       │   ├── test-foo.css
│       │   └── test.css
│       ├── test_command_line.py
│       ├── test_font_awesome.py
│       ├── test_icon_font.py
│       ├── test_icon_font_downloader.py
│       └── test_octicons.py
├── requirements/
│   ├── common.txt
│   └── dev.txt
├── requirements.txt
├── setup.py
└── tox.ini
Download .txt
SYMBOL INDEX (44 symbols across 9 files)

FILE: icon_font_to_png/command_line.py
  function run (line 10) | def run(arguments):
  function download_icon_font (line 168) | def download_icon_font(icon_font, directory):

FILE: icon_font_to_png/icon_font.py
  class IconFont (line 13) | class IconFont(object):
    method __init__ (line 15) | def __init__(self, css_file, ttf_file, keep_prefix=False):
    method load_css (line 27) | def load_css(self):
    method export_icon (line 78) | def export_icon(self, icon, size, color='black', scale='auto',

FILE: icon_font_to_png/icon_font_downloader.py
  class IconFontDownloader (line 13) | class IconFontDownloader(object):
    method css_url (line 19) | def css_url(self):
    method ttf_url (line 24) | def ttf_url(self):
    method __init__ (line 28) | def __init__(self, directory=None):
    method _download_file_from_url (line 35) | def _download_file_from_url(url, directory=None):
    method _get_latest_tag_from_github (line 52) | def _get_latest_tag_from_github(repo_api_url):
    method get_latest_version_number (line 61) | def get_latest_version_number(self):
    method download_css (line 65) | def download_css(self, directory):
    method download_ttf (line 69) | def download_ttf(self, directory):
    method download_files (line 73) | def download_files(self):
  class FontAwesomeDownloader (line 79) | class FontAwesomeDownloader(IconFontDownloader):
    method get_latest_version_number (line 95) | def get_latest_version_number(self):
  class OcticonsDownloader (line 101) | class OcticonsDownloader(IconFontDownloader):
    method get_latest_version_number (line 120) | def get_latest_version_number(self):

FILE: icon_font_to_png/test/test_command_line.py
  function test_list_option (line 16) | def test_list_option(capfd):
  function test_icon_export (line 50) | def test_icon_export(capfd):
  function test_filename_option (line 94) | def test_filename_option(capfd):
  function test_download_option (line 123) | def test_download_option(capfd):
  function teardown_module (line 137) | def teardown_module():

FILE: icon_font_to_png/test/test_font_awesome.py
  function font_awesome (line 17) | def font_awesome():
  function test_font_awesome_load_icons (line 25) | def test_font_awesome_load_icons(font_awesome):
  function test_font_awesome_prefix (line 30) | def test_font_awesome_prefix(font_awesome):
  function test_font_awesome_export_icon (line 35) | def test_font_awesome_export_icon(font_awesome):

FILE: icon_font_to_png/test/test_icon_font.py
  function font_awesome (line 20) | def font_awesome():
  function test_init (line 28) | def test_init():
  function test_common_prefix (line 44) | def test_common_prefix():
  function test_size (line 62) | def test_size(font_awesome, image, size):
  function test_color (line 85) | def test_color(font_awesome, image, color):
  function test_scale (line 104) | def test_scale(font_awesome, image, scale):
  function teardown_module (line 119) | def teardown_module():

FILE: icon_font_to_png/test/test_icon_font_downloader.py
  function test_icon_font_downloader (line 21) | def test_icon_font_downloader(downloader):
  function test_font_awesome_latest_version_number (line 42) | def test_font_awesome_latest_version_number(downloader):

FILE: icon_font_to_png/test/test_octicons.py
  function octicons (line 17) | def octicons():
  function test_octicons_load_icons (line 25) | def test_octicons_load_icons(octicons):
  function test_octicons_prefix (line 30) | def test_octicons_prefix(octicons):
  function test_octicons_export_icon (line 35) | def test_octicons_export_icon(octicons):

FILE: setup.py
  function read (line 21) | def read(*names, **kwargs):
  function find_version (line 29) | def find_version(*file_paths):
Condensed preview — 26 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (97K chars).
[
  {
    "path": ".gitignore",
    "chars": 2636,
    "preview": "# Created by https://www.gitignore.io/api/python,pycharm,osx\n\n### Python ###\n# Byte-compiled / optimized / DLL files\n__p"
  },
  {
    "path": ".travis.yml",
    "chars": 267,
    "preview": "language: python\n\npython:\n  - \"2.7\"\n  - \"3.4\"\n  - \"3.5\"\n  - \"3.6\"\n\ninstall:\n  - pip install -r requirements/dev.txt\n  - "
  },
  {
    "path": "LICENSE",
    "chars": 1081,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2016-2017 Pythonity\n\nPermission is hereby granted, free of charge, to any person ob"
  },
  {
    "path": "MANIFEST.in",
    "chars": 273,
    "preview": "include *.md\ninclude *.txt\ninclude *.yml\ninclude LICENSE\ninclude tox.ini\nrecursive-include icon_font_to_png *.css\nrecurs"
  },
  {
    "path": "README.md",
    "chars": 5394,
    "preview": "# Icon Font to PNG\n[![Build status](https://img.shields.io/travis/Pythonity/icon-font-to-png.svg)][travis]\n[![Test cover"
  },
  {
    "path": "_config.yml",
    "chars": 151,
    "preview": "theme: jekyll-theme-leap-day\n\ngems:\n  - jekyll-default-layout\n  - jekyll-optional-front-matter\n  - jekyll-readme-index\n "
  },
  {
    "path": "bin/font-awesome-to-png",
    "chars": 780,
    "preview": "#!/usr/bin/env python\n\nimport os\nimport sys\n\ntry:\n    # Installed system wide\n    from icon_font_to_png import command_l"
  },
  {
    "path": "bin/icon-font-to-png",
    "chars": 335,
    "preview": "#!/usr/bin/env python\n\nimport os\nimport sys\n\ntry:\n    # Installed system wide\n    from icon_font_to_png import command_l"
  },
  {
    "path": "icon_font_to_png/__init__.py",
    "chars": 292,
    "preview": "# -*- coding: utf-8 -*-\nfrom __future__ import absolute_import, unicode_literals\n\nfrom icon_font_to_png.icon_font import"
  },
  {
    "path": "icon_font_to_png/command_line.py",
    "chars": 5746,
    "preview": "# -*- coding: utf-8 -*-\nfrom __future__ import absolute_import, unicode_literals, print_function\n\nimport os\nimport argpa"
  },
  {
    "path": "icon_font_to_png/icon_font.py",
    "chars": 6185,
    "preview": "# -*- coding: utf-8 -*-\nfrom __future__ import absolute_import, unicode_literals\n\nimport os\nimport re\nfrom collections i"
  },
  {
    "path": "icon_font_to_png/icon_font_downloader.py",
    "chars": 3848,
    "preview": "# -*- coding: utf-8 -*-\nfrom __future__ import absolute_import, unicode_literals\n\nimport os\nfrom abc import ABCMeta, abs"
  },
  {
    "path": "icon_font_to_png/test/files/font-awesome.css",
    "chars": 37414,
    "preview": "/*!\n *  Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome\n *  License - http://fontawesome.io/lice"
  },
  {
    "path": "icon_font_to_png/test/files/octicons.css",
    "chars": 9147,
    "preview": "\n@font-face {\n  font-family:\"Octicons\";\n  src:url(\"octicons.eot?ef21c39f0ca9b1b5116e5eb7ac5eabe6\");\n  src:url(\"octicons."
  },
  {
    "path": "icon_font_to_png/test/files/test-foo.css",
    "chars": 75,
    "preview": ".foo-bar:before { content: '\\f001' }\n.foo-test:before { content: '\\f002' }\n"
  },
  {
    "path": "icon_font_to_png/test/files/test.css",
    "chars": 67,
    "preview": ".foo:before { content: '\\f001' }\n.bar:before { content: '\\f002' }\n\n"
  },
  {
    "path": "icon_font_to_png/test/test_command_line.py",
    "chars": 4426,
    "preview": "# -*- coding: utf-8 -*-\nfrom __future__ import absolute_import, unicode_literals\n\nimport os\nimport shutil\n\nimport pytest"
  },
  {
    "path": "icon_font_to_png/test/test_font_awesome.py",
    "chars": 1277,
    "preview": "# -*- coding: utf-8 -*-\nfrom __future__ import absolute_import, unicode_literals\n\nimport os\nimport random\n\nimport pytest"
  },
  {
    "path": "icon_font_to_png/test/test_icon_font.py",
    "chars": 3521,
    "preview": "# -*- coding: utf-8 -*-\nfrom __future__ import absolute_import, unicode_literals\n\nimport os\nimport shutil\nimport tempfil"
  },
  {
    "path": "icon_font_to_png/test/test_icon_font_downloader.py",
    "chars": 1065,
    "preview": "# -*- coding: utf-8 -*-\nfrom __future__ import absolute_import, unicode_literals\n\nimport os\nimport tempfile\n\nimport pyte"
  },
  {
    "path": "icon_font_to_png/test/test_octicons.py",
    "chars": 1215,
    "preview": "# -*- coding: utf-8 -*-\nfrom __future__ import absolute_import, unicode_literals\n\nimport os\nimport random\n\nimport pytest"
  },
  {
    "path": "requirements/common.txt",
    "chars": 56,
    "preview": "Pillow>=4.0.0\nrequests>=2.13.0\nsix>=1.10.0\ntinycss>=0.4\n"
  },
  {
    "path": "requirements/dev.txt",
    "chars": 148,
    "preview": "-r common.txt\n\ncheck-manifest>=0.35\ncoverage>=4.3.4\ncoveralls>=1.1\nflake8>=3.2.1\nflaky>=3.3.0\npypandoc>=1.3.3\npytest>=3."
  },
  {
    "path": "requirements.txt",
    "chars": 27,
    "preview": "-r requirements/common.txt\n"
  },
  {
    "path": "setup.py",
    "chars": 2594,
    "preview": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nimport io\nimport os\nimport re\n\nfrom setuptools import s"
  },
  {
    "path": "tox.ini",
    "chars": 340,
    "preview": "[tox]\nenvlist = py27,py34,py35,py36,py36-flake8\n\n[testenv]\ncommands = py.test -v\ndeps = -r{toxinidir}/requirements/dev.t"
  }
]

About this extraction

This page contains the full source code of the Pythonity/icon-font-to-png GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 26 files (86.3 KB), approximately 26.4k tokens, and a symbol index with 44 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!